DAC,即Digital to Analog Convertor,是数字到模拟转换器,也称为D/A转换器。其核心部分由R-2R电阻网络(也称倒T型电阻网络)、模拟开关和运算放大器组成。它可以将二进制码或BCD码表示的数字量转换为与其成正比的模拟量输出。, \1 g" }1 l: R+ m+ n# S
" X- M" H: t v# [1 I% T( ~# L
DAC的工作原理主要包括数字信号采样、量化、编码和模拟信号输出几个步骤。首先,将连续变化的模拟信号在一定的时间间隔内进行离散取样,即数字信号采样。接着,对采样后的数字信号进行量化,将其转换为离散的数值。然后,通过编码将量化后的数值进行转换,以便DAC能够识别和处理。最后,DAC将这些数字信号转换为模拟信号输出。
; g |# x3 y2 l: b' V
q4 `1 L+ E2 L( nDAC是数字系统和模拟系统之间的桥梁,具有广泛的应用领域。在音频处理中,DAC被用来将数字音频信号转换为模拟音频信号,以驱动扬声器和耳机,其性能对音频质量有着决定性的影响。在通信系统中,DAC用于将数字信号转换为模拟信号,以实现信号调制和解调。此外,在仪器仪表领域,DAC也被广泛应用于各种测量和控制设备中。 ]# F# a% w+ m; X9 x" s
1 |. c2 A2 o# J
1 ?9 g" P" ?; Z
( _' \, Y4 i% p, KSTM32中的DAC(视芯片而定例如F407ZGT6是2个DAC通道,有些芯片不支持DAC功能)支持12模式的数据输入,可以双通道同时转换。
- G! o5 K8 f- D( {, O. A
$ M7 q3 H9 h; ?% z: d( |本期我们将介绍如何使用STM32F407和CubeMX利用HAL库实现DAC的输出。(本来是想使用C8T6的,结果突然想起来C8T6)没有DAC。/ s2 a" U5 W! |+ [( I+ a
" K! B! `, W) v6 ?5 \, G
CubeMX配置/ o3 q- ~" l& ]1 U# f, e
, {2 s o! \ W! p
* ~& a$ I3 V/ d" d& ~. _& D- t. |
! z# G* W6 I( M# X" N' _; L Y# W在DAC通道中开启DAC,在F407ZGT6中DAC1对应PA4,DAC2对应PA5。
6 D+ w8 o0 A; Q- ?+ J" ` D# `5 t3 L# [2 {
" P# X7 n4 ?# P' S5 {
, K& |, m, J; G0 D5 h' POutputBuffer这里设置DAC的输出缓存使能,Trigger是DAC是触发方式,这里我们选择不触发(手动写入)。! p2 ]- g" p& g: Z. S, L5 A
) A0 u& Q1 T% _, o: V4 b# g T/ o如果选择触发的话是从缓存区写入数据。8 \/ C5 y8 a( m; p0 k
, [3 M: O: e2 n8 c V
9 H+ [9 `8 Q' [" |% T" Q- c) y7 ]$ t9 J
这里顺带加一路ADC采样,因为手上没有示波器,所以使用ADC来进行查看。
, M, N8 g$ Q" m8 G/ D$ L! i- U. c' ~! e
这里使用DMA进行采样,具体可以参考公众号之前的关于DMA+ADC采样的内容。
7 f: T, y% @( v+ E' N9 v$ O' R; m, j2 Y7 f/ m3 B( D Z
STM32的DMA采样+FFT时域分析(STM32F407)
, F- c6 a: s9 A- ~+ u) @9 L& X4 A0 H. i8 l# p+ @1 O. S6 |5 Q
但是相比于之前的,需要更改一些设置,首先是DMA的设置% ?' Z( ^+ F2 K+ A( p
" y+ \$ ^1 C! N) H$ f
2 \& r& j. p0 T& x2 w5 Z0 B
, T7 ?8 \3 V0 Q: Y. d, t这里设置单词请求,而不是循环模式防止数据跑飞掉。
* x5 @' ?; i( i
% m3 D% B/ J. n$ `2 a/ b& O" L" E6 G5 e( W) A# n/ m6 b' z7 ^
- MX_GPIO_Init();% i, p& L6 F+ r" [- f3 R& b' U
- MX_DMA_Init();7 ~2 L S0 C# C5 S
- MX_ADC1_Init();# S, }3 A1 g# u& r. m$ A- X" c
- MX_DAC_Init(); @$ Q- w; w7 U4 M7 |1 y0 Z% j
- MX_USART1_UART_Init();- J3 }; \' v3 N* i
- MX_TIM1_Init();
, |- z2 q/ v' ]9 } - MX_TIM2_Init();+ v# a5 l& j4 H8 \5 m: _
- /* USER CODE BEGIN 2 */+ J' o F/ ]9 h8 T3 R# K, B( j
- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //用来触发adc采样
- K4 \& `0 r1 u1 r1 O9 t/ M1 P - HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC& L# K$ x: a' c) E6 ~
- HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
+ t Q' U6 o1 R% X0 O - /* USER CODE END 2 */! \+ { w- V/ i, a' o
- 5 b+ `- F' d6 L/ X
- /* Infinite loop */1 } h; { l6 D
- /* USER CODE BEGIN WHILE */ s% w4 ^$ U A6 c) S7 G
- while (1)3 ]" k" T) x* [" R7 y# B
- {
- `# _ e( D1 P! \7 @ - /* USER CODE END WHILE */* }7 Z& ]8 T3 v6 I$ X2 |7 S4 q
& i! x. r' i9 X. [# B- /* USER CODE BEGIN 3 */- g8 b, [3 N. R
- if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0))
1 [5 ]9 `1 ~$ d3 s! d - {! H) E$ a* |* T
- HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC1 R' ^1 M9 u. k
6 d* s% Z# L y- HAL_Delay(20);
; m) }/ Y" X( {3 U - ( w) j8 X$ ^8 k4 c: w: y, Y
- while(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0));
1 \7 v8 t1 {( d# I* ] - HAL_Delay(1000);5 t, b, L* i2 C, n. U5 d
- for(int i = 0;i<ADLenth;i++)
! z8 ~$ p$ d8 G% M - {
8 s1 j% N8 y" U4 \, n8 n9 Y7 M& s8 a - printf("A:%d\r\n",AD_Value[i]);
0 L T) B, B! R0 A - }4 |" O( i/ k% O/ n
- * P& {9 U/ V8 k1 t6 ?
-
" p0 g0 n1 U9 B+ g, }( P - }
* b$ X' s" O; s; }! I- M! G/ R1 c - }
* Q& K, I: w% T3 H/ p8 R! N - /* USER CODE END 3 */
- t* C. b% {% e& A; P0 F - }
复制代码
& T5 ^: ?5 k( r( ~5 `
( ]1 ^0 m4 O- m4 W/ L我们编写一段代码。
. B c; J( _ g' p5 y" ^
7 Z7 r& o. b$ f! @$ Z7 v3 x按下按键的时候设置DAC的值,开启DMA传输,再加上ADC采样,之后输出结果。
4 h: R. c3 \2 E' g7 a4 D0 S; A b
% {% {/ {' w" }
* `+ ]" k V! N0 i/ E可以看到,我们按下按键之后,ADC的值会呈阶梯状上升。
4 d* N( q$ v7 ~2 K; q: j
4 v3 _, g U; ^6 b7 ?# c三角波发生器
9 X) Y5 H, C1 d/ M! o) F
. q# f) p. j7 U4 P5 W+ P
2 o R# [* ~4 V$ m+ `, F ]+ C: p6 R
3 _: e# `1 k( `在DAC配置中打开波形发生器,触发方式选择定时器2触发,三角波最大振幅511。7 F; l7 D2 R- C E# X' Z( ?
# W& U' m( ~7 S0 k5 V
) J9 v1 Y6 \- M) B, Y
8 h" M; H% G& r0 }& M! Z之后开启定时器2,由于ADC的采样率是1000HZ,因此根据奈奎斯特采样定律,信号的最大频率不能超过500HZ,因此我们使用100HZ的三角波。
& z% E" \" l: _5 u0 P! ?7 ]' ` I5 j
0 k, }2 Q H2 A7 m; K; y# K2 q/ V
9 B/ G" o, U- |* g% ?0 Y( }定时器设置好时间之后,设置触发事件。. I- ^7 F' N, P5 U, I
$ m& C6 r8 x5 Z! ]( ]1 d
6 g5 s5 F$ ` e Z5 @1 m: s5 l
0 M! P" Z0 D- r3 ?3 V$ @6 \8 N
芯片手册中简单的介绍了一下如何计算三角波的频率。当触发信号发生后,内部计数器的值就会+1,所以频率可以用如下公式计算:
& K* k9 K4 |0 W4 j% _$ ], A" E; m' p
定时器频率/分频系数+1/Period/三角波最大值/22 L: j+ @5 G6 G, d: X
4 l# ^9 Y0 [/ \2 E* m' w, P
- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //用来触发adc采样, H; L1 c8 T' `* B; t9 Q
- HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //用来触发DAC输出( J6 j% C- M- @" x% z' z- T
- HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC
' U4 Z5 ?. n! X( k2 a" B - HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
: F1 q5 P- q. A0 @: T5 B/ z - HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_L,0);//设置直流信号
复制代码
3 i: n1 w" f4 R" o5 _
0 f5 r: I4 v: R: ~8 n4 g$ a% M4 W0 z7 v m# s7 x3 j7 K' o
正弦波发生器! v6 N, Q( k$ F
0 E* r' |' L$ S1 Y, u* n' C
4 M/ |0 a8 h7 f7 W1 _
/ k2 p1 H/ E- S4 |. S2 C首先是定时器触发(方便控制频率)。但是关闭波形发生器。7 L3 `/ L$ b; ~+ ]
+ }: d: |* p3 k4 c9 w7 H4 s
4 X* q: {* j9 C! b- \4 B% l+ _
# Q* P+ [, W+ B8 Z2 A; m
添加DMA,模式选择循环模式。
& o& f& t* x8 I$ {- v* {1 W6 X k
: p1 T4 X1 g- [8 A- B还有改变一下定时器的频率!
6 q0 O0 s5 J. F- F, ?/ a; J) C$ ~5 n* y$ e0 v1 E$ o
其他几乎不做改变。- N0 Z! Y0 }% Q0 L
& C c5 H9 H6 v) `/ O
2 Y* B1 ?( X2 D2 Q- V h0 M
- #define POINTS 256
/ O1 R. W( x! C$ X8 o - #define MIN_VALUE 50 $ L" J$ A9 r) w
- #define MAX_VALUE 650 " p# D' R) U B0 ?; \ s
- #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0) 5 K: c8 w1 i" o
- #define OFFSET 50
6 G/ M+ t/ [$ {( r0 P8 m/ F - #define M_PI 3.14159265
; y* X$ l2 G; ~( x( o9 y - + t1 `6 {; g/ L0 ^ E
- uint16_t SinWaveInt[POINTS];
; a- Q4 Y) R" F1 j& r% I2 c - int SinWave[POINTS];
' n, s# }7 R+ C) e# D+ I - void SinInit(void)
( k# @; L. z3 J5 W2 [- M; q - {
# t$ U, J3 f9 I+ C) P# W/ f - for (int i = 0; i < POINTS; i++) : O. O& b4 I( l9 L: W" _
- { : s! [4 [1 b! F/ B% Q+ [
- double x = ((double)i / (POINTS - 1)) * 2 * M_PI; ! p7 A% ^4 R+ X5 `
- double sin_value = sin(x); // 计算正弦值 ! O( i% M, q% V
- SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET); * [1 E( D z) \( e/ l* h' H
- SinWaveInt[i] = (uint16_t)SinWave[i]; $ Y9 T6 q8 P2 E4 O
- }6 K: ]6 R' T( k6 k' v
- }
复制代码
9 z) l: ?, \9 D _9 A3 }* w+ y计算一个正弦表。0 O& m4 x/ T$ Z3 r
6 O# w1 T/ X0 {1 S这里的Points决定了分辨率,结合定时器触发频率决定了正弦波的信号。
! N. X' l* Z# Q1 s8 H% V6 n
6 C3 i5 d+ J+ o9 _. `9 S
1 K* }$ c. j& d& @+ s& b: Z
' W p; _/ Z5 V$ |- E- F# [9 \
测试一下正弦表,输出的是正弦信号。
6 j4 k8 S7 L4 L2 E. g l- ? M6 C8 l f3 \2 e8 L' `3 ^& i
我们之后将正弦信号表导入DMA中。
3 Y: J! @. Y0 ~4 t$ n* c9 e# h7 ?/ n7 C6 z. I, P
- SinInit();1 k5 o. c! X7 `( E
- HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)SinWave, POINTS, DAC_ALIGN_12B_R);
复制代码
8 E7 {9 q3 D* W+ K) _- p正弦表初始化,之后启动DMA传输,导入正弦信号。
7 f% q% Q9 i$ w( S0 H
. f* ^6 W2 F- C2 }# B! D& R' B- Y
$ X* [% F6 l: l. q7 p1 Z G
( ?# W+ q( {! M# X; P' N测试正弦信号成功。7 C' j* a- ?$ t, ~+ S
# c: M( x* e# L9 T1 q9 HFM调制- #define POINTS 1024 6 f% c2 X4 O( z. l9 }5 m
- #define MIN_VALUE 50 - x2 r, s4 ~4 z1 F# \! l1 n, n2 K
- #define MAX_VALUE 650 # D: m$ C/ ~" G. l0 k$ O, x0 j
- #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0)
3 d9 ~6 r1 A$ w! g2 u9 C+ z. Z - #define OFFSET 50
6 x5 o) }$ {: X& w: c4 C - #define M_PI 3.141592655 G; T" {- E) c- s; O% d R$ H% t7 `
-
! y% I7 ]+ C6 l0 N" u2 k1 r+ ` - uint16_t SinWaveInt[POINTS];
1 [% K& X5 p6 Z1 A+ [ - int SinWave[POINTS];
5 W2 J& _& ]+ A. h Q - void SinInit(void) 6 }. i, W$ ^% d# M) T3 K% e
- {
! ~' B4 w& R( ~6 L& }- t8 ` - for (int i = 0; i < POINTS; i++)
5 f! {3 p* O$ E' |, G4 ]) E - { . R K3 n: G3 Y/ }% Q% e. _5 e
- double x = ((double)i / (POINTS/4 - 1)) * 2 * M_PI;
! _! [9 h' i. W - double sin_val = sin(x)*sin(x/4); // 计算正弦值
6 t& c: Y- J- i* I7 @ - SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET);
2 O1 h, j* i" H3 [7 g1 m. X - SinWaveInt[i] = (uint16_t)SinWave[i]; ; {: N, j# ~# M ?
- }/ J; Q: l$ W% A3 V, @; {
- }
复制代码 & z" I; Y" I2 ~) o* k
0 _1 X/ J8 p3 {% l: ]: L
拓宽点数,加上载波,即可构成FM调制信号。
( R; r" |4 C' R- \
, h E1 @. ]$ ? f2 {' C
6 }, v; q- g( h. L0 k, X$ J( ?) t5 k
# n) @' [% v9 R. a0 M
转载自:电路小白; d, n! M" o) T$ f8 M" g0 L7 X% l
如有侵权请联系删除
) Y: k; N7 R" k* h: H$ z1 L6 W3 c
) m5 [& s* P- z3 k; T
; X4 p$ S6 Y' s9 c) n0 K; t+ v8 N- a. w u' J$ Z/ H- ?, ~
|
资料不错,值得参考学习。
dac+dma?