DAC,即Digital to Analog Convertor,是数字到模拟转换器,也称为D/A转换器。其核心部分由R-2R电阻网络(也称倒T型电阻网络)、模拟开关和运算放大器组成。它可以将二进制码或BCD码表示的数字量转换为与其成正比的模拟量输出。$ f m* b, ~8 X8 W. K
- v! S0 ?8 M; P7 o7 \2 PDAC的工作原理主要包括数字信号采样、量化、编码和模拟信号输出几个步骤。首先,将连续变化的模拟信号在一定的时间间隔内进行离散取样,即数字信号采样。接着,对采样后的数字信号进行量化,将其转换为离散的数值。然后,通过编码将量化后的数值进行转换,以便DAC能够识别和处理。最后,DAC将这些数字信号转换为模拟信号输出。
( V* W* P, L3 `7 ~! `8 j$ s+ k& m) t1 @* U( Z7 A8 `* R
DAC是数字系统和模拟系统之间的桥梁,具有广泛的应用领域。在音频处理中,DAC被用来将数字音频信号转换为模拟音频信号,以驱动扬声器和耳机,其性能对音频质量有着决定性的影响。在通信系统中,DAC用于将数字信号转换为模拟信号,以实现信号调制和解调。此外,在仪器仪表领域,DAC也被广泛应用于各种测量和控制设备中。6 N2 K8 E5 D K) z, X
1 S0 u! o/ w' m. N3 p
! P' t$ M8 J( `$ U8 m1 Q& P# e7 v: V5 \0 K$ Y h2 C+ ^5 {1 Y
STM32中的DAC(视芯片而定例如F407ZGT6是2个DAC通道,有些芯片不支持DAC功能)支持12模式的数据输入,可以双通道同时转换。# O0 S3 j! }1 o* p
* A+ x- \4 U+ ]' h4 b本期我们将介绍如何使用STM32F407和CubeMX利用HAL库实现DAC的输出。(本来是想使用C8T6的,结果突然想起来C8T6)没有DAC。/ q: w0 c) O! J1 k, L/ [
, N" \/ w1 w/ D( J y' XCubeMX配置! @, u- d; H$ t# H$ R
* R; a# C. s5 p8 P% ~, o) S( {
' @% Z& f' d" A) P9 s1 I
7 j9 y) D- y2 K; K5 S4 N$ ?在DAC通道中开启DAC,在F407ZGT6中DAC1对应PA4,DAC2对应PA5。) H+ W6 i+ U1 D6 K
& q/ \. I7 m6 m! [" C
# O3 S" U F, w" _! }. ~
: x; Z. k `2 _! COutputBuffer这里设置DAC的输出缓存使能,Trigger是DAC是触发方式,这里我们选择不触发(手动写入)。9 a8 E3 a) N3 D" R) B8 H
; b& V& l" q- B如果选择触发的话是从缓存区写入数据。
6 C) W6 l% Z j
0 f+ \! E# _9 e5 K# D
( K3 q5 s* Y3 b
0 k2 e, q- `' |这里顺带加一路ADC采样,因为手上没有示波器,所以使用ADC来进行查看。
) z! O* ?" X d, R: y
+ O, s2 `/ |6 \- p* W# W这里使用DMA进行采样,具体可以参考公众号之前的关于DMA+ADC采样的内容。% ?" ~! |1 e( O% Q
2 r8 [' I4 A7 @5 z" T; G9 U: a3 f
STM32的DMA采样+FFT时域分析(STM32F407)
! |3 {5 m e0 T' T- b5 H2 o
4 n8 d; b3 R! R6 R) w0 Z+ b& z% l* D& S+ A但是相比于之前的,需要更改一些设置,首先是DMA的设置
3 m) `6 f+ [- `$ M: D
" p! t% S* K1 T9 r# }
+ ^/ H! m& V! j4 ]! s% w' S8 e) q
8 i7 e! c) }; W
这里设置单词请求,而不是循环模式防止数据跑飞掉。
8 T) ~5 j4 \4 l- A& z3 R- i& {, V" K, f0 `( A0 m. I5 S# B! u1 ~
5 i$ t6 m3 Z8 R& C7 p
- MX_GPIO_Init();
5 x( |; v5 t# O# D$ q - MX_DMA_Init();
7 a$ |4 V! k8 L m2 J$ I - MX_ADC1_Init();" x4 M7 l% u: M3 l' J
- MX_DAC_Init();
, A* B7 ]4 E- d" p; W6 Y2 ]" _ - MX_USART1_UART_Init();
, v6 k* Z2 E5 U) r) K - MX_TIM1_Init();' q- p7 b- F2 Q( o" Q6 F
- MX_TIM2_Init();
. R- o+ u. d2 k - /* USER CODE BEGIN 2 */5 r7 G7 Y7 z/ q# H4 {' A0 B
- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //用来触发adc采样 . O: ~0 B! p0 `2 Q
- HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC, b3 F8 M$ }) }
- HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
; Q# @, \9 d) ^0 R1 |$ { - /* USER CODE END 2 */
# k) B' z# z/ @3 J. i; g( e - ( Y4 O% D ?- ]! ?( B! ]! m5 P) K
- /* Infinite loop */
! x8 g, c1 v2 p3 { X$ w3 J - /* USER CODE BEGIN WHILE */! |# _# }; `' C2 K4 z: _5 M: ~
- while (1)
: S8 U5 Q8 O( S) U8 }$ A - {
: j& H5 W7 O4 h, O) Y - /* USER CODE END WHILE */9 N- I: r, L+ l$ k% w
- 8 K& f( e6 Q2 I. g- }
- /* USER CODE BEGIN 3 */
: p5 C# l8 S) l7 C$ c; T - if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)) {% \$ D& K% i; l
- {; T. }: C0 R( Y$ s% [! L, {
- HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC
) X8 L+ z- F, q1 ], ?1 n; _
4 A& B& p$ E- J- HAL_Delay(20); y" G( A. l) _7 f
-
" |7 B1 b: F+ s9 j7 T T7 | - while(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0));
9 ^7 n% S2 O) g. q, u! S3 V* v - HAL_Delay(1000); h7 g* K8 H4 A Q" C, H: T( }% C8 }
- for(int i = 0;i<ADLenth;i++)# u) H: t. I9 H5 n+ s
- {2 |3 {, R# Z% O) K
- printf("A:%d\r\n",AD_Value[i]);
4 w& F3 y/ n: T+ c7 b. l0 C; b - }
. p7 X+ z6 I. k6 Y1 Q+ S- K -
0 t/ \8 Z. a) n$ ^- L8 ~ \$ d -
3 T& s* A! u7 B, q# J9 a2 J( S7 w- ? - }9 W$ _, }6 z ^: w% v G7 C. T: ?- \
- }( {3 W' Y: R9 {% ]
- /* USER CODE END 3 */
+ C7 J; i9 C" |0 \5 T0 q0 C - }
复制代码 / C8 {/ _# _2 m1 y7 H
& d2 i& x3 {! ~
我们编写一段代码。
! q1 }/ P5 ^2 y8 A- R$ o3 c. ]
按下按键的时候设置DAC的值,开启DMA传输,再加上ADC采样,之后输出结果。
5 a1 l/ a+ [0 b8 l: j. U# I+ F5 U/ v( i2 R& H( P/ G# V
- n' f/ R2 x2 w3 b3 m( T9 ~+ ~7 F1 ?5 i4 S3 g( Y0 _& g, p6 |
可以看到,我们按下按键之后,ADC的值会呈阶梯状上升。
1 o6 d$ p3 [- Z: O) R% n- H6 F+ ~+ q5 o! K: {; M# R
三角波发生器1 g5 }' n% l& G' H, T
- t: V, i* F6 d0 G2 h8 L
- f g0 H! N" {2 C0 G$ J- C) \- r) C5 q/ b# x5 M
在DAC配置中打开波形发生器,触发方式选择定时器2触发,三角波最大振幅511。8 M% x2 W- W+ E8 C7 e
, E- U& n, @* r T5 G8 {* g" |1 D( n
7 j' o# \ c- z7 y, @4 G& s8 s) ~- l5 L+ Z. R1 j
之后开启定时器2,由于ADC的采样率是1000HZ,因此根据奈奎斯特采样定律,信号的最大频率不能超过500HZ,因此我们使用100HZ的三角波。
+ L* z0 h+ j# @9 }9 Z; I. x
2 K( S! P Z/ _6 ^
7 r& l c5 l2 x% \% I: T
2 ~; W$ e" W. K4 n" w定时器设置好时间之后,设置触发事件。1 i" ^6 k1 r, j) b/ w
# B6 @8 u- ?. V
/ {9 J* P$ C8 o" z& B
: b# w8 Y; N! V: B3 ~芯片手册中简单的介绍了一下如何计算三角波的频率。当触发信号发生后,内部计数器的值就会+1,所以频率可以用如下公式计算:
! k4 b+ D! y4 J! N9 G0 g# C
6 `$ M% n k5 N$ u" J% G( ~定时器频率/分频系数+1/Period/三角波最大值/2
; u1 X: y# {7 y" d. a/ `4 g- h* s
8 [" |+ \6 U% h, d: ^9 I; N+ f, q- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //用来触发adc采样
1 ^" V+ r8 p: f' \3 d3 m- `9 v& n - HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //用来触发DAC输出
4 o2 ^: i5 F1 X c' Y - HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC
" f |6 |5 O$ r7 c; g$ K - HAL_DAC_Start(&hdac,DAC_CHANNEL_1);' H2 F `# O8 R; x, w
- HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_L,0);//设置直流信号
复制代码 % o" j/ ^3 ?- C) V* t
! h# I4 f* C' |) N8 X/ D
* z# v+ x6 ^$ a% O3 _5 D% A H正弦波发生器
4 j( @, ^% r! r, f5 T) `( J" A. r( N
4 Q2 b) c, F& w- \. n
, O% X% W$ p. t, r8 m8 w6 p3 ^
' y- ^' o. x) E- J' Y首先是定时器触发(方便控制频率)。但是关闭波形发生器。9 m' D! I# Q3 I+ s8 G) {
& J7 e' W8 F8 I0 f
9 N& r: D0 A! D0 [1 V' m5 Y% T8 @6 @% M
添加DMA,模式选择循环模式。4 a0 H! |6 r) E+ i2 W7 ]3 b6 P
* {8 \! U& X& @
还有改变一下定时器的频率!& g! A s4 O5 {( [( Y- U$ U2 t
0 N* i4 d+ i1 [0 C: W, p# _5 K
其他几乎不做改变。" q |0 h& {9 e
6 ]" U; Q* y- y
" y% w& Q8 ~- @' W. X. p$ d- \- #define POINTS 256
" Z7 V8 m3 ?3 `" s. I6 J5 Z8 S - #define MIN_VALUE 50 5 M X, Y! {5 ^/ J1 L/ }
- #define MAX_VALUE 650
9 S; Y, Z- d$ a' ^; N - #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0)
) q9 @/ L5 j! v& ] - #define OFFSET 50
& x* E# d3 ^. U/ o- U0 n - #define M_PI 3.14159265
# o1 P& E2 w2 K, w9 y7 [ -
8 t3 X* N/ y5 _; C3 d) v - uint16_t SinWaveInt[POINTS];! m( d m4 ]$ C& T4 x- l
- int SinWave[POINTS];
# Z# B( j* |- ~5 ~6 `& |& c - void SinInit(void)
3 ?, q6 e7 E6 t9 ~9 K5 T) o - { 0 H: M7 c, b/ p; w ^) {3 o
- for (int i = 0; i < POINTS; i++)
2 A2 z5 E8 D. @7 ?; h) G - { 5 G6 P* A+ x0 a' k
- double x = ((double)i / (POINTS - 1)) * 2 * M_PI;
) J/ h# e d$ B# P7 l8 C/ [ - double sin_value = sin(x); // 计算正弦值
( R1 Q; E) P6 `; H, i - SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET); 3 n6 W& B+ t2 j0 t; R
- SinWaveInt[i] = (uint16_t)SinWave[i];
5 C" `# M9 @3 |) i - }7 g% \/ N! n2 q) c
- }
复制代码 ( q& z$ F. W" H2 E0 i; X# l
计算一个正弦表。
3 {/ Q' q* G3 @. N- ?9 y ?
+ c+ s1 I& J; B) j8 Q4 Y: T% R这里的Points决定了分辨率,结合定时器触发频率决定了正弦波的信号。9 D! W0 z3 g) v q
! K% F' F; o* a$ A& Y! y9 I& y! I
; W- Q' X; U, u5 m
! Y4 J4 H( f: i$ T$ Y
测试一下正弦表,输出的是正弦信号。
1 R8 q" r" _8 J+ N* g8 t, W: s" N: x$ X0 l
我们之后将正弦信号表导入DMA中。" D- e" x0 Q2 J, ?' a* {# \
# S3 ~5 S' z% g/ S5 h/ `$ `) F9 b- SinInit();6 a0 B& ]3 _1 e/ a; p; L* e
- HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)SinWave, POINTS, DAC_ALIGN_12B_R);
复制代码
u) ~( ]( ~9 |3 Z3 t正弦表初始化,之后启动DMA传输,导入正弦信号。
9 ?) [2 h( \0 _$ U* i% h% g6 [4 f
6 h0 ^ g3 }0 a- N1 q' D
+ Z7 L5 `3 p; u& A, v- V4 |4 p! s; v' O- }" Y! {7 l- F5 d
测试正弦信号成功。
1 p" H" S( I+ A2 B; [* ?( X
* X6 }* Q6 D: K- \5 K9 tFM调制- #define POINTS 1024 1 x6 m" p' W5 o9 W- H" h t- @ K* j
- #define MIN_VALUE 50
+ V% X% s w0 ^5 i) o$ Q# \/ y - #define MAX_VALUE 650 ) x0 ^, t) Z' b) Z! f
- #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0) / A3 K1 Y& b7 r8 a8 [7 @/ y. G
- #define OFFSET 50
; O0 Z3 Z& H% d( h) f - #define M_PI 3.14159265- ?4 J7 o. o# w* ]8 I2 M
- / Q( N, U/ O4 W
- uint16_t SinWaveInt[POINTS]; L& c) m. c. _: T# g+ x5 E
- int SinWave[POINTS]; & L) p9 E5 b- q% b }, { d- @
- void SinInit(void)
3 Y7 l# A: ]: u j( Q/ x; e+ W9 \ - {
. i( y% z V/ {. e y; m* c6 |( X5 P - for (int i = 0; i < POINTS; i++) 7 Y" y1 s0 ?; J1 } R1 `
- {
- Z1 j5 Q, P0 K- b: G, Q/ b" D - double x = ((double)i / (POINTS/4 - 1)) * 2 * M_PI; % p+ ~& U& q3 Z7 g# `
- double sin_val = sin(x)*sin(x/4); // 计算正弦值
2 A0 u. H" w. Z9 |+ @% C* ^ - SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET); 0 y' ^6 C" Y2 J
- SinWaveInt[i] = (uint16_t)SinWave[i]; |1 T* z) |4 a4 t9 W
- }+ M: D( l$ t2 r; u
- }
复制代码 5 R5 b+ ^0 f7 `( b
4 I/ I7 _, z5 T
拓宽点数,加上载波,即可构成FM调制信号。5 ^- L# F1 b) Q9 _7 V( W! e. [
8 E L2 [2 C) z
, y7 o" q' \$ u! L4 s2 f* h) G6 s
+ F4 d& V8 ^: y( G2 E2 J, Z转载自:电路小白) F/ D- P+ X; C$ e( I9 G- N0 J# j7 h
如有侵权请联系删除
J" T; L1 X- @' M# Q
" |3 Q2 R% @7 [. M8 H- X4 z2 x
& |" J3 k9 o ~. I! n: Y. G) E" m: Z! O
|
资料不错,值得参考学习。
dac+dma?