DAC,即Digital to Analog Convertor,是数字到模拟转换器,也称为D/A转换器。其核心部分由R-2R电阻网络(也称倒T型电阻网络)、模拟开关和运算放大器组成。它可以将二进制码或BCD码表示的数字量转换为与其成正比的模拟量输出。, i Y) g% e( ^
( a0 k! K+ L3 k e8 {) j. IDAC的工作原理主要包括数字信号采样、量化、编码和模拟信号输出几个步骤。首先,将连续变化的模拟信号在一定的时间间隔内进行离散取样,即数字信号采样。接着,对采样后的数字信号进行量化,将其转换为离散的数值。然后,通过编码将量化后的数值进行转换,以便DAC能够识别和处理。最后,DAC将这些数字信号转换为模拟信号输出。
( C0 V$ D1 E9 G6 m+ c, G0 r6 @- t4 a. B7 q4 W8 U6 ?% V$ r' h
DAC是数字系统和模拟系统之间的桥梁,具有广泛的应用领域。在音频处理中,DAC被用来将数字音频信号转换为模拟音频信号,以驱动扬声器和耳机,其性能对音频质量有着决定性的影响。在通信系统中,DAC用于将数字信号转换为模拟信号,以实现信号调制和解调。此外,在仪器仪表领域,DAC也被广泛应用于各种测量和控制设备中。' ]1 m7 ?! J0 s) C0 Z% K
: k3 L' O, ~; m# y1 H3 _! N5 \$ \
4 @. Q! f" n5 N$ W0 p
! Y/ D: }6 n7 A& q5 a4 hSTM32中的DAC(视芯片而定例如F407ZGT6是2个DAC通道,有些芯片不支持DAC功能)支持12模式的数据输入,可以双通道同时转换。
$ |$ r- E7 H: \" [6 U# q1 I$ }" c8 I
8 B4 D7 p/ \$ t本期我们将介绍如何使用STM32F407和CubeMX利用HAL库实现DAC的输出。(本来是想使用C8T6的,结果突然想起来C8T6)没有DAC。
! O& {6 Q, E; U( T+ m
/ V: J6 y0 v7 E* ]& dCubeMX配置
, ?0 [7 _( @& Y8 r; g! L, `; D+ |1 A5 ^- z6 w- J% S
6 H# X6 Q7 ?4 q: w t. n# d5 J
, m' o/ q5 J9 T2 L在DAC通道中开启DAC,在F407ZGT6中DAC1对应PA4,DAC2对应PA5。
) [/ U# c+ c% P0 h( j( R8 o) H4 Y( E$ Y' ?$ u
4 O8 [/ u4 I/ \7 E: h7 q/ \, @3 u5 Y( i% O$ N0 u& C
OutputBuffer这里设置DAC的输出缓存使能,Trigger是DAC是触发方式,这里我们选择不触发(手动写入)。- Y7 s+ r3 h( c0 B5 z4 w
4 e' s4 t8 G+ {, k5 U
如果选择触发的话是从缓存区写入数据。
' u6 I3 t- ~% M$ H+ d
9 m8 m. q" y8 i3 s% {8 H
9 a; r; O/ L# T3 I
; s0 y) }5 Q! K; ?9 V5 g这里顺带加一路ADC采样,因为手上没有示波器,所以使用ADC来进行查看。
! H3 l# X* C! O9 @1 O F5 T2 ]' F. u8 n- z6 z; @( s' p& n
这里使用DMA进行采样,具体可以参考公众号之前的关于DMA+ADC采样的内容。
( I# W d$ G: L! q# G/ _
$ ?0 u# Z$ o2 P) S- U& D% ]6 jSTM32的DMA采样+FFT时域分析(STM32F407)& v+ N" H8 e1 U9 u* U/ q
3 F0 a0 `8 Q2 d2 M但是相比于之前的,需要更改一些设置,首先是DMA的设置
% N! H) O& k( T" L
: o4 G7 L1 Q2 O; n
5 s, t- o# e7 A, j9 L9 |: ?0 a
3 m; E" s9 ^ u( Q3 P' U2 J
这里设置单词请求,而不是循环模式防止数据跑飞掉。
$ {( e6 j6 ]9 q5 P) r, @5 G' _
" G+ k0 z! ~% W3 p$ V7 ~$ _8 Z9 b8 b7 k: a
- MX_GPIO_Init();
! r$ Q* c& G g8 \9 z - MX_DMA_Init();0 T1 ?: b" v" B, \1 L
- MX_ADC1_Init();
2 ^* E7 x! R( K# p2 j9 Q - MX_DAC_Init();: y, z: q6 \; E5 I
- MX_USART1_UART_Init();' l5 Y X! P+ S2 c
- MX_TIM1_Init();8 S9 R- h# e& |- j" d# t1 v
- MX_TIM2_Init();
$ m/ M9 g* ~+ z# E - /* USER CODE BEGIN 2 */
% U) R, O/ j d7 Y$ p1 y- A - HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //用来触发adc采样
P6 {& y4 D/ x# _ - HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC
7 n+ l+ \0 R: k( y. u0 Z! M: }3 T - HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
4 d" N9 A! V% F3 D$ z2 T( ~ - /* USER CODE END 2 */
3 s0 Q, m/ F1 @6 w9 T9 m$ B - 9 c" b1 @% c% M9 B- P% U/ C" D
- /* Infinite loop */8 D& H+ D3 K) S9 }, b
- /* USER CODE BEGIN WHILE */' [ Q9 }/ z# R. E* `+ e9 H, h( Q
- while (1)
5 ^% U! k; }" g. U8 @ - {
3 W3 v, c6 x4 x- _7 ~! O7 P - /* USER CODE END WHILE */1 o, r; X8 l/ V& M
- . s4 [4 Q1 P$ F/ Z
- /* USER CODE BEGIN 3 */. ^1 B- K. `. b7 u: `
- if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0))) O9 m3 [3 D ~: Y) L
- {' m9 M7 M1 }3 W7 C" v! [- N) H. w9 q7 w
- HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC
5 A3 f, G* M; O
1 I* ?/ ~/ k" L( ?1 u- HAL_Delay(20);
0 F) v. [! t$ l5 o' k -
/ q* t6 a( A( V - while(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0));8 [$ a0 E+ Z/ t+ x( W2 m2 X$ I
- HAL_Delay(1000);' g6 M5 o# P, q' n0 y! W9 {) i
- for(int i = 0;i<ADLenth;i++)
, M! E# G5 J( K5 t - {
" {' x- e3 a- |$ v. Q - printf("A:%d\r\n",AD_Value[i]);
9 `1 Z% g/ E* f/ I: R4 n - }
( J+ {; R W' ^5 `, p4 y: y; { - 8 q$ P: H) P2 s7 T1 c/ T
- 5 Z' Y' b9 A0 d! h( s6 T& X' s6 l
- }; f% }2 |& \ W1 T" B o8 d, k
- }2 {: Y) \! L) L( z
- /* USER CODE END 3 */
! F& ^' B' X# i2 T" G - }
复制代码
* o- ?5 T- l/ f& L' w0 Z0 m9 ]. d( P2 z! m+ g: l4 ^4 P
我们编写一段代码。
: U+ s4 x/ F3 I* D+ r& _5 \
9 \2 k* A* f2 ~0 O- r4 k4 J按下按键的时候设置DAC的值,开启DMA传输,再加上ADC采样,之后输出结果。& ^ P* Z) A. Z) r/ @3 {1 h
9 v( | d, N2 }1 X- x1 e* ?
* [- P* T. K7 i" n K6 k5 H8 o
$ J8 I7 X9 i: m& u
可以看到,我们按下按键之后,ADC的值会呈阶梯状上升。
) x; p5 D% T+ t2 u; I
0 I4 D& [ S G6 Y6 C0 w4 Z8 y三角波发生器
/ d, U! ~% h! j# Q& Z; o" _1 V) d$ M4 K
! r7 u9 S' z( b! I( U: `5 K5 Z0 f
/ z [ n8 }8 t6 T+ w9 K$ k4 P在DAC配置中打开波形发生器,触发方式选择定时器2触发,三角波最大振幅511。. w; ?4 k4 y' T# ^
; H" X0 a& Y! c$ d; V& V8 f
) C" ^0 O! S7 ^2 d/ v% }, J; Y. K8 r
3 y/ L) \% K/ Q8 n之后开启定时器2,由于ADC的采样率是1000HZ,因此根据奈奎斯特采样定律,信号的最大频率不能超过500HZ,因此我们使用100HZ的三角波。# y' Y8 M. N9 I2 l6 V- t; }
9 H) U0 M% l& O% b' s6 D- E
4 n4 A6 Z4 e1 R
6 i* u! P# \' a2 K3 S6 b# R定时器设置好时间之后,设置触发事件。
6 g N$ M& S m/ o3 m# H" X$ i9 t$ ^9 R; l/ u2 n) j9 ~2 l
9 ?4 F. n& b( Z9 D& ]% o
7 a2 t% p1 G7 `% _芯片手册中简单的介绍了一下如何计算三角波的频率。当触发信号发生后,内部计数器的值就会+1,所以频率可以用如下公式计算:4 Q5 _# W3 X7 N! W' [4 |
8 x& o4 K* Q1 Y, B4 D
定时器频率/分频系数+1/Period/三角波最大值/2" n1 k; T2 P/ ]" `1 n& ~# d
8 r8 h+ U8 q( K, h- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //用来触发adc采样; D7 S% R6 v1 f
- HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //用来触发DAC输出% y( W5 S* K' B% k, o7 a
- HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC
1 k/ b+ x6 s6 V/ ?6 [& X$ R4 l6 k - HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
4 o( _4 E7 C6 H) a5 B0 i - HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_L,0);//设置直流信号
复制代码
. |% M) S+ j7 A5 K9 G
, ^7 I% Z3 J9 a% ?: q
: j" A8 |1 \. o4 h正弦波发生器! s! |$ J F/ H; b' Z
3 | B4 Q+ C' |5 T% H/ |
+ ~ k) F/ {1 X, ~; l$ ?% h0 t
) R, d8 b: d/ u. v首先是定时器触发(方便控制频率)。但是关闭波形发生器。
8 z$ T$ Q6 N% Z- d7 D
( t5 D( }) P* D. h; }( B
/ j6 d) a2 r! b [% j' f1 L! u- f, h$ E- ?
添加DMA,模式选择循环模式。
3 F- c& y) W# B% Y( T
e. I" i7 O. J还有改变一下定时器的频率!4 ~7 J6 Y$ D+ m: ~* o0 G6 W! M( R
/ ]) Z: o4 `2 t/ a6 D
其他几乎不做改变。' N5 B% e( Z$ x1 a/ k8 G9 ^
5 e# v5 ]. G, {+ c: j* o) d! V- b
6 V( W; a. e& R& }
- #define POINTS 256
4 J% n. D) y+ G0 Z+ @ - #define MIN_VALUE 50
& x7 N9 U( V" d x - #define MAX_VALUE 650 . ?# s% [8 F: q M1 \7 }! V
- #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0) % y' X* r4 G* ~. C5 u
- #define OFFSET 50
B H4 j7 O: P: W% b- N$ S$ @ - #define M_PI 3.141592656 L. S7 w5 S, Y
-
s8 p! \# q5 T - uint16_t SinWaveInt[POINTS];
/ e8 W: S* _/ [; P2 O. {5 ^: W - int SinWave[POINTS];
5 g/ Q8 c1 ~+ U- S2 t5 o - void SinInit(void) # I+ a M" s* I4 W1 \9 m# h. f9 n
- {
& G4 r2 X5 z5 r$ n. p - for (int i = 0; i < POINTS; i++) + f! H8 N# p; f% x5 l/ X
- {
/ W; m+ E& f3 r2 a% H/ P - double x = ((double)i / (POINTS - 1)) * 2 * M_PI; 9 }7 ~. l( a. L" V
- double sin_value = sin(x); // 计算正弦值 ! l8 n0 V6 Q( O) z+ ^
- SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET); g; ^5 A. f4 l4 n0 b( i
- SinWaveInt[i] = (uint16_t)SinWave[i];
/ r: r8 r! e- [, B( L! S. p; d - }$ F4 O" F2 w* a% v. M; u4 f
- }
复制代码
' S- ]( o* X8 y: j# u# m计算一个正弦表。: S; [& _5 t8 _' ^1 W
. U5 z2 X' k# V. @/ F \
这里的Points决定了分辨率,结合定时器触发频率决定了正弦波的信号。
9 |& c1 J- P/ f5 g, e, ?! q/ b. u% w& `' g P) K& P( I
$ d1 ]$ S3 c: ]0 M! B
& L6 D" j: W1 h& E, u测试一下正弦表,输出的是正弦信号。- s A0 b( X4 O% M( p' c0 \) @
- h% P1 p: i0 K/ b& W {
我们之后将正弦信号表导入DMA中。
. Q0 `! z4 k4 E( ]4 ~6 e9 a/ }- W3 y$ K9 X6 @/ F
- SinInit();
: O$ X3 }4 j% M - HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)SinWave, POINTS, DAC_ALIGN_12B_R);
复制代码 5 j( n: s! P9 B! C8 t. P
正弦表初始化,之后启动DMA传输,导入正弦信号。' H+ N, c3 c6 I- D1 O, I
4 c4 d2 B) q3 A1 D/ R3 \4 b" O5 k
2 }5 P& e; |- J: j! J" ~; z5 M) O% q
测试正弦信号成功。
3 E, ^" M" ~5 s$ s
8 G8 a6 f' i+ I3 P, U+ hFM调制- #define POINTS 1024 : [( n% M; O' z& j/ E
- #define MIN_VALUE 50 9 Q$ i7 F1 P$ m- T1 r+ R/ U) m4 m
- #define MAX_VALUE 650 4 f3 g& Y* j* S8 P' H
- #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0) ]7 x, m( W; T0 l1 n
- #define OFFSET 50
: ^! w" F( g' @. V& h' o - #define M_PI 3.14159265" W+ p" Z) L# G+ }( [/ b
- & l* X. F) G) p1 G( k6 O y
- uint16_t SinWaveInt[POINTS];
- b9 q: Q3 @1 F# ?+ k* V - int SinWave[POINTS]; ' Q% C; K8 i$ X) a8 k. [4 J- ?# T
- void SinInit(void)
/ C/ o* u! A, v, U: v' P - { " ^0 U( S6 [( r7 z' H: W, l
- for (int i = 0; i < POINTS; i++) 8 q; S# O- l6 }! v3 q; R" I
- {
, j3 U' ]6 e% x0 P - double x = ((double)i / (POINTS/4 - 1)) * 2 * M_PI; ! B( j. c4 k7 _: d8 ?% n/ Q* W
- double sin_val = sin(x)*sin(x/4); // 计算正弦值
, B, \( b! O3 o* s# W8 m, c0 K - SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET); 8 ?! F/ |0 q6 `2 Q6 Z
- SinWaveInt[i] = (uint16_t)SinWave[i];
e9 e K8 l/ U. L2 Y - }9 H6 t7 ^: v( P) H; D& v
- }
复制代码 % C$ V- g' M8 {8 b+ w- F) t
. i# F% j7 M6 }9 x( ]' _# q1 L拓宽点数,加上载波,即可构成FM调制信号。" S- e. T8 q+ v4 q+ Y4 m
, M6 \/ ?$ |8 M
4 O; O' `5 D& F" W5 s4 N3 E0 N6 @6 K7 w d
. N* X6 M y* [# D7 L( s8 z转载自:电路小白
' X. B* G0 b+ Y如有侵权请联系删除: [5 q$ G: V8 G0 w/ W/ e4 N3 @
3 T B/ p$ l7 I& W( p* Q+ r) R# Q- \: i; l
+ I$ r5 |1 v/ q
|
资料不错,值得参考学习。
dac+dma?