DAC,即Digital to Analog Convertor,是数字到模拟转换器,也称为D/A转换器。其核心部分由R-2R电阻网络(也称倒T型电阻网络)、模拟开关和运算放大器组成。它可以将二进制码或BCD码表示的数字量转换为与其成正比的模拟量输出。. n4 K% b% c1 P! ^2 i' [! r
% S5 P! P l' c
DAC的工作原理主要包括数字信号采样、量化、编码和模拟信号输出几个步骤。首先,将连续变化的模拟信号在一定的时间间隔内进行离散取样,即数字信号采样。接着,对采样后的数字信号进行量化,将其转换为离散的数值。然后,通过编码将量化后的数值进行转换,以便DAC能够识别和处理。最后,DAC将这些数字信号转换为模拟信号输出。
6 a) u4 ]4 n% t; `
8 ^* z0 y+ ^ }: Q" ~8 ?DAC是数字系统和模拟系统之间的桥梁,具有广泛的应用领域。在音频处理中,DAC被用来将数字音频信号转换为模拟音频信号,以驱动扬声器和耳机,其性能对音频质量有着决定性的影响。在通信系统中,DAC用于将数字信号转换为模拟信号,以实现信号调制和解调。此外,在仪器仪表领域,DAC也被广泛应用于各种测量和控制设备中。
' @; `& S$ ~% M* k( j
% G% F* h5 ?7 l5 N. N( m8 p
& U7 S1 ?3 T! ?2 {
3 F6 i1 h+ O: b4 z$ V+ z
STM32中的DAC(视芯片而定例如F407ZGT6是2个DAC通道,有些芯片不支持DAC功能)支持12模式的数据输入,可以双通道同时转换。
! ~( Z( ]; x: Y; {' S/ U
9 y# A: z Y" d8 B' {- D5 f本期我们将介绍如何使用STM32F407和CubeMX利用HAL库实现DAC的输出。(本来是想使用C8T6的,结果突然想起来C8T6)没有DAC。) ?! f3 P$ a' V: _/ W% i; m, Q
7 L. L& _2 a! C1 B9 nCubeMX配置
0 m% h9 U6 \ i' Q6 j. {* c1 P: b) w4 N {9 l* N# ^
2 U7 L! C& p: \) k
- R% j5 C7 u% Z' ~9 {1 G3 t在DAC通道中开启DAC,在F407ZGT6中DAC1对应PA4,DAC2对应PA5。
) z% Z5 V) I. `) m# O5 K' v5 L3 P
: C9 p* L8 z# f( i+ j
, c( L; [* W* Q8 f. u
OutputBuffer这里设置DAC的输出缓存使能,Trigger是DAC是触发方式,这里我们选择不触发(手动写入)。: U+ A& H3 a! h7 N( ^7 {+ @
4 r* g+ g; g; X& i1 @$ G如果选择触发的话是从缓存区写入数据。! a4 v2 Y# g% }$ G8 l* c. \
1 a5 q$ W! R. f- y/ f
+ Z, L# w) d2 D" I6 `
; g, k# [: o- T4 T1 A0 I* i; y3 u( \! _这里顺带加一路ADC采样,因为手上没有示波器,所以使用ADC来进行查看。
2 ], B+ a4 O6 v5 X, Y/ R O2 W$ J5 C
这里使用DMA进行采样,具体可以参考公众号之前的关于DMA+ADC采样的内容。
$ [9 m* Z- W- V0 W, r: d
0 C2 f/ r7 T5 q+ W+ N, JSTM32的DMA采样+FFT时域分析(STM32F407); Q: ?2 ]$ i; P/ J5 Z/ ^' @
$ c3 `- ]: x7 z H5 y
但是相比于之前的,需要更改一些设置,首先是DMA的设置
+ M5 s) N9 a. D, j& _+ Z/ A" r; `! A b* k
/ N4 O3 o0 j' G2 _3 Z
7 @1 G/ P V0 {7 ]这里设置单词请求,而不是循环模式防止数据跑飞掉。8 X4 M+ J6 O% A
3 L8 L7 j: n _; V+ Z, B' L' \7 r
$ Y6 R/ h, V6 Z4 l1 m/ `4 N2 E- MX_GPIO_Init();7 r: n. e( p1 h/ c: I) X) a" c
- MX_DMA_Init();
% L$ P3 c5 A8 a. U3 Z' ] - MX_ADC1_Init();7 ?/ ]# M6 X& J) ~ u% }
- MX_DAC_Init();
; b" g* b# e! M) o( I0 h3 j - MX_USART1_UART_Init();
5 G/ K- t: F G - MX_TIM1_Init();
) f" k9 k5 Y) x! h8 {- u2 ] - MX_TIM2_Init();8 B( u6 c5 e3 G9 [. I" u
- /* USER CODE BEGIN 2 */& ~; x! h$ ^! y% v; I3 s- Y
- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //用来触发adc采样
# i1 P& S) G; O4 S1 D - HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC# @3 W# y$ t7 p
- HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
1 t+ X4 l6 T6 C; S2 F8 | - /* USER CODE END 2 */
7 \; ]3 o* t# e6 J8 _8 X5 n% l
/ j+ n7 |8 ?7 c1 u$ L- /* Infinite loop */
, Q! Z: F4 }3 P1 ^ - /* USER CODE BEGIN WHILE */
. q8 _% T/ p: h3 r2 A* _ - while (1)
6 h) a0 [% P4 {/ U! y9 | - {! q$ P+ l' U5 }/ M
- /* USER CODE END WHILE */; }; C7 V" q/ h
- & z% W& G( K0 n0 R' f+ L
- /* USER CODE BEGIN 3 */
, {# R% r; j+ e( O: x; z+ g4 e+ {5 u - if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0))' p, _, H5 K8 v W
- {9 [: A! y0 M8 P9 s$ n
- HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC
D: y2 D2 t2 {5 z5 i2 P1 j' j - ^* P9 W4 l0 G5 A/ y
- HAL_Delay(20);
/ s0 I- B! ~9 A. @% Z -
: v9 A Q0 c$ {: Y - while(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0));& a6 t- P& m0 U+ \8 l( I
- HAL_Delay(1000);
( U0 Y5 M; d) q* w, C7 R - for(int i = 0;i<ADLenth;i++)
$ m! ^$ W( f' e' G3 D# _- c, a& m - {- b6 W; Q# u. ~2 K# \$ o
- printf("A:%d\r\n",AD_Value[i]);2 O( D4 C4 q1 U
- }
# g2 {! [9 N1 E# g - ( s6 c6 N+ q" i* j5 I# k% n* Z9 l
-
7 i2 L* i; P! _) i - }
, W: m6 ~1 s+ Z - }( w1 z2 E0 v' e
- /* USER CODE END 3 */% C$ r+ N% z9 D. l3 S) R# k3 K
- }
复制代码
9 U: R1 ~% ?1 J2 Y/ V/ H; Y8 [% h/ }8 O9 }1 F3 h& Q+ ~3 D
我们编写一段代码。3 k& O0 _7 E4 S6 R x8 Q4 S! t
* U l% I3 R4 [8 _7 p/ H, U按下按键的时候设置DAC的值,开启DMA传输,再加上ADC采样,之后输出结果。
* j" T4 S' e5 C* F) w
0 t. C; T4 X- t) _8 t# {6 w. I, Q
$ |9 {0 P/ o0 T8 v
* ?, k* y* K9 k* \4 S& c+ R Y可以看到,我们按下按键之后,ADC的值会呈阶梯状上升。
* l7 g" ~* V+ I
) v$ U/ e" d1 j6 X/ V6 @; W三角波发生器6 r5 l) `% H, W" h
. k* Q: H1 e# i' L
: q2 L+ {# b- H W" h F
* l% I# @0 v, H; a- c# ^
在DAC配置中打开波形发生器,触发方式选择定时器2触发,三角波最大振幅511。. _: v! z) l: w
/ {. t4 `, T. h7 Y! j! r
; W c& A8 }; C7 R2 Y% I
! k0 ^9 o4 X( B4 Z8 L# V2 P
之后开启定时器2,由于ADC的采样率是1000HZ,因此根据奈奎斯特采样定律,信号的最大频率不能超过500HZ,因此我们使用100HZ的三角波。3 a0 F/ H" T8 d% n, C
! a" `& L) _* g; P7 W+ Z2 X2 ^) \
& V/ l2 }* J& ?& r* r
# O' `& l/ |/ {) ?: z8 Z* o' H8 j; |定时器设置好时间之后,设置触发事件。
: G* T* g; M- |3 x" y" X3 Q1 t. I- o& K- O0 s8 u
' u1 ]6 v, l+ K A! K
* P( @+ G& \* G: G芯片手册中简单的介绍了一下如何计算三角波的频率。当触发信号发生后,内部计数器的值就会+1,所以频率可以用如下公式计算:& Y- P- |) h0 a2 c E- ?
) E$ T: A. V$ L8 w+ J; _定时器频率/分频系数+1/Period/三角波最大值/2! Y% ^: E1 m) @$ R& p) Y
6 U N. h& c2 C, I( S( |4 i- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //用来触发adc采样
; u' D ^3 {5 {1 D& b% v1 q$ ~5 i - HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //用来触发DAC输出& @* H" Z- r h+ i! q$ {
- HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC' O- @2 z( s4 ^
- HAL_DAC_Start(&hdac,DAC_CHANNEL_1);) i' h k, h& y1 x2 M
- HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_L,0);//设置直流信号
复制代码 . ^: h. \8 `# W6 e
" F% f5 J# D' t2 A( ?( Q! \4 K! `
) W2 k* ~7 G+ G. o% p) {
正弦波发生器; q( Y$ m( g* g0 x, k5 T8 I d! Z# g
; A0 d2 D/ f4 ]- S; C8 X# o7 ~! J
: D* Z; I% K) Q& A* e, k8 h) o1 J
9 w* M. G: X. m9 ]1 b: o
首先是定时器触发(方便控制频率)。但是关闭波形发生器。
: C$ u' n5 b$ {+ N* t% c: ?
" b G7 c/ W: A3 H7 j1 Y3 D
# R% S/ r2 L' h4 D% N2 q
+ {4 ]1 ^, k6 h% k9 y& f! \3 E添加DMA,模式选择循环模式。
& ^$ X3 K* m& _7 h N
' e' ~ m" o/ X$ R8 P+ W- K/ x" q) B还有改变一下定时器的频率!
3 Y0 T) [. M, ?: O: x
W- {. W$ m% ^其他几乎不做改变。" W& k1 F5 q" _3 S
1 ?9 `" q# o! d# j1 |% y% ~6 p% T; c; x8 x
- #define POINTS 256
}8 q( p) _$ w/ I y - #define MIN_VALUE 50
0 A- H: B/ _2 K+ a+ p1 J - #define MAX_VALUE 650
; Q' X3 M) v; a, _ \ - #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0) " H+ t6 G4 g) F
- #define OFFSET 50 ) j' h+ S. ~! k7 F, T. R; [' w3 {* B
- #define M_PI 3.14159265: k1 b0 f" ^ [2 b
- $ e, Q4 @ Z% l( h
- uint16_t SinWaveInt[POINTS];
/ _9 O l- p9 r. W# [" p - int SinWave[POINTS];
; N" r2 W, P) E5 [ - void SinInit(void) ) y* C) O/ y9 ]
- {
4 H& b3 q' X% f4 s6 W- L) a5 z; q4 }5 q - for (int i = 0; i < POINTS; i++)
7 h# G( e0 V9 G - {
' q, v, w5 e/ v: T. x# X3 Z1 {" T - double x = ((double)i / (POINTS - 1)) * 2 * M_PI; + ?0 ~: \8 W: I, `, p6 i: u0 \
- double sin_value = sin(x); // 计算正弦值
+ X" O% |7 a; L" Q - SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET);
: q" u' P" m& J; k - SinWaveInt[i] = (uint16_t)SinWave[i];
" q+ ]# M# k# O* D# C0 c. I - }! j) o! K8 l3 }) [
- }
复制代码
3 ?) E' l3 n$ O3 _. U- A4 _8 S计算一个正弦表。- v7 O: ~! j! t
- Z5 C3 c4 W0 d( h这里的Points决定了分辨率,结合定时器触发频率决定了正弦波的信号。
0 o! f$ w* [+ b7 }9 ]0 @# J4 Y$ u' U4 y% o+ U
/ O- K h* f) ^4 w" u1 g+ r0 c
3 f: b4 p2 x$ ~' Q$ k& a- M/ Q# D: w测试一下正弦表,输出的是正弦信号。
: ]7 x0 S1 k' C+ X# Q7 F! I l. {3 N5 z1 O0 i% W
我们之后将正弦信号表导入DMA中。
+ }8 O p( O0 b. j+ B4 \' o3 f7 \, O2 _
- SinInit();
, T. g6 Q6 _0 F$ F0 q# f - HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)SinWave, POINTS, DAC_ALIGN_12B_R);
复制代码 8 x7 w6 r/ R% ~
正弦表初始化,之后启动DMA传输,导入正弦信号。. V- r7 X+ F S- m, w* H4 H. `
( K2 s5 d S0 V6 G1 Y2 R4 y
1 u% k/ \8 k C8 {& H
8 q6 Q2 O) ]3 H$ w$ d
测试正弦信号成功。
c4 _( m. K; G& k3 S* c% I2 \4 M0 w2 M
FM调制- #define POINTS 1024
. b; _* R9 j" j& T. o! g - #define MIN_VALUE 50
6 S4 \; z Y7 w/ `2 P, V. O - #define MAX_VALUE 650
0 x; F: M/ Q: q4 ? - #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0)
- _- n$ F) T- k7 O) T4 i - #define OFFSET 50 % |& f l1 n0 N
- #define M_PI 3.14159265: C2 f: U) S' Z/ r. a& P* y
-
. A4 [4 W r" O' q - uint16_t SinWaveInt[POINTS];
$ u% m# J8 k: d: [$ r' z* S x - int SinWave[POINTS];
% K: ]* f( e5 e/ r& h) ]2 @ - void SinInit(void)
7 f. b( y S; \7 M - { r; K$ c/ S) h. p' q
- for (int i = 0; i < POINTS; i++)
) |9 Y* ~0 K5 K" r% B* r7 L/ ], o - {
4 w5 R$ R# A# f8 U: N - double x = ((double)i / (POINTS/4 - 1)) * 2 * M_PI;
) h9 U2 u4 t# V1 u8 A% | - double sin_val = sin(x)*sin(x/4); // 计算正弦值
% l, s) @! I! ], e, G: X - SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET); ) _' ` ~) g0 U- ~
- SinWaveInt[i] = (uint16_t)SinWave[i];
& Y1 f4 ]0 f5 ~4 c* S7 o, k - }
3 B8 q M+ g$ S5 }. s( r/ d; a - }
复制代码 3 g. a' N0 p4 j2 x1 @1 T$ c
0 R$ g- ^' X) E3 h; e. k# ?
拓宽点数,加上载波,即可构成FM调制信号。3 g( J3 k2 f1 q* C% l, E2 t
3 O: y: Q8 B& ?5 _. Z h1 _
6 {: U; k8 [4 c, w3 t( S
' F! B$ Q1 q" l8 ]6 G% ^
% m- @4 }$ S7 f7 [) `; ~) _5 G转载自:电路小白& d r& S& P7 \5 s+ ]" n( q
如有侵权请联系删除
- T% K4 N( C& M. M9 u: _ B" |/ G( c( b+ F
# T6 C2 C3 Q# P) o+ y6 m
' \4 E! z/ y2 h d# d$ } |
资料不错,值得参考学习。
dac+dma?