DAC,即Digital to Analog Convertor,是数字到模拟转换器,也称为D/A转换器。其核心部分由R-2R电阻网络(也称倒T型电阻网络)、模拟开关和运算放大器组成。它可以将二进制码或BCD码表示的数字量转换为与其成正比的模拟量输出。- n6 o5 d! q' S3 t. D
e' a3 [* F5 k* V( D
DAC的工作原理主要包括数字信号采样、量化、编码和模拟信号输出几个步骤。首先,将连续变化的模拟信号在一定的时间间隔内进行离散取样,即数字信号采样。接着,对采样后的数字信号进行量化,将其转换为离散的数值。然后,通过编码将量化后的数值进行转换,以便DAC能够识别和处理。最后,DAC将这些数字信号转换为模拟信号输出。
' z% w9 f! [) }0 p' h( j( l, o! l% a5 ^; |' C5 u z/ F; t, [% _7 {
DAC是数字系统和模拟系统之间的桥梁,具有广泛的应用领域。在音频处理中,DAC被用来将数字音频信号转换为模拟音频信号,以驱动扬声器和耳机,其性能对音频质量有着决定性的影响。在通信系统中,DAC用于将数字信号转换为模拟信号,以实现信号调制和解调。此外,在仪器仪表领域,DAC也被广泛应用于各种测量和控制设备中。5 l2 R+ g( I) u
' {' j. ~/ k5 Y: L1 X2 K
" r( X9 b9 V% n! j
: x& P; ~# U* I+ ]- l
STM32中的DAC(视芯片而定例如F407ZGT6是2个DAC通道,有些芯片不支持DAC功能)支持12模式的数据输入,可以双通道同时转换。
3 ?& U7 d$ [" C6 N# f3 i9 y9 F" T
本期我们将介绍如何使用STM32F407和CubeMX利用HAL库实现DAC的输出。(本来是想使用C8T6的,结果突然想起来C8T6)没有DAC。
5 w" H: C. Z& x$ ^2 S9 U. u8 T2 V* Q4 m# N; G( z5 U! }2 h* d F
CubeMX配置
" \+ K" ]8 [( y5 |" X6 J
Q* ~, k+ a3 C& h
( ]6 B' ]( }, L% [; T. @! N9 z* q5 w3 @6 X
在DAC通道中开启DAC,在F407ZGT6中DAC1对应PA4,DAC2对应PA5。( J f" ]( n) V+ z6 ?; `' C
1 Q- P! I; ?- b6 Y* O( w _- d$ |3 m
9 B( G9 _, G5 i6 }5 s6 k& n* F$ s6 y6 u9 Z
OutputBuffer这里设置DAC的输出缓存使能,Trigger是DAC是触发方式,这里我们选择不触发(手动写入)。" h8 Y/ u! D, _* b" P u* @* |3 ?
; @' t' h1 Q$ t2 P" p# V, m/ T2 p2 P
如果选择触发的话是从缓存区写入数据。
# Y. u: R& s; k& G B# v8 ^0 p L9 V" L3 y4 n# I" o; ~
8 j a' _: ^' W/ e$ L7 w& @- L- T
$ I6 [# n. K4 e: u$ x4 Z. Z2 v这里顺带加一路ADC采样,因为手上没有示波器,所以使用ADC来进行查看。 m. {, R( v" V, A4 i. Q: I
' o6 m8 s3 i/ t0 B7 y& w
这里使用DMA进行采样,具体可以参考公众号之前的关于DMA+ADC采样的内容。: `# r) Z' B7 e, |! A5 c) S- N
& p- E' Z r* V2 L# }6 u1 Q4 qSTM32的DMA采样+FFT时域分析(STM32F407)
l. x4 R) {5 S# D3 L
' k8 b* I8 r0 w' e% n8 ^但是相比于之前的,需要更改一些设置,首先是DMA的设置7 |9 V! P7 W5 Q( n* V
' X( I+ h$ q6 r7 r
5 U4 S2 e, h: W5 i* J) T- A, i, G; ?. Z4 U3 A1 r
这里设置单词请求,而不是循环模式防止数据跑飞掉。6 w0 S9 _' M* Y) D9 M% l
; a: m( X: [7 z7 V; M. _+ R
3 |! g& ?0 @0 Z$ i' p0 V! _: |
- MX_GPIO_Init();
. D5 ]9 B8 x0 d0 @- {9 o - MX_DMA_Init();
/ U) A) J! M+ `! j$ ^9 D, M - MX_ADC1_Init();
% V" W, V$ M. T - MX_DAC_Init();
4 w+ y/ O, _4 ?+ B5 f( G - MX_USART1_UART_Init();
9 c+ ^* t5 y' f' Y9 c a) ` - MX_TIM1_Init();& t% z' k7 U' _# o% O7 Z
- MX_TIM2_Init();
2 G6 f$ N- [: ^7 g - /* USER CODE BEGIN 2 */ S M( p5 Q- i4 d6 ]1 W7 R( m
- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //用来触发adc采样
; B' @- Y" |" E; A4 u& y! o - HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC0 P5 G: }) n) Y9 I: k2 b8 {6 J
- HAL_DAC_Start(&hdac,DAC_CHANNEL_1); T5 K$ s+ z5 Z+ w. R5 \' z
- /* USER CODE END 2 */3 Q% O0 E" B3 G3 e! ^$ x" R
6 z' M, f# X8 m# X& B' R$ G5 Y; O- /* Infinite loop */0 T, Z. N( V' ]" n+ m, ?
- /* USER CODE BEGIN WHILE */
' B& ~1 I! ~) X, l7 a - while (1)
. I4 T$ ~! p& O' O/ p - {6 s- W! f0 Q# z5 ?! |5 F
- /* USER CODE END WHILE */$ Z/ t& b0 N# \7 d$ x/ i
- : }: F0 Q! v: X% s, o% C
- /* USER CODE BEGIN 3 */
( D m5 x7 s C) ^- f0 s- f, d - if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0))
3 ~6 c7 e! ^+ x2 `9 t# [ - {
% O" J( g) }9 ?7 E0 ~/ E; U: h h - HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC- r6 p1 f' T5 R" R+ j1 a
- - i$ {- [0 G5 Q# z+ f% B
- HAL_Delay(20);
7 @$ U: u5 w: T0 R- y- ^/ w - 8 Y" l, R6 O$ w, ?
- while(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0));$ {( W6 |7 t% A9 s& u
- HAL_Delay(1000);0 U$ l3 M5 ]# Y9 W* X
- for(int i = 0;i<ADLenth;i++)' R4 c5 [# Z; U1 w7 F/ S$ T) ~+ r
- {
1 C' z# a2 ?+ X - printf("A:%d\r\n",AD_Value[i]);% Q0 @& c |& P9 i" `2 j
- }
; S$ E$ S* ?# S/ z( {# n - + V6 G. b- N# j x1 G8 h4 `: [
-
7 ]0 W& U$ m% ?) l: X2 X: m - }' l- n2 {' q0 A+ C1 Y0 k
- } ?/ f' T+ X, Z$ _5 W
- /* USER CODE END 3 */& O( U5 t3 e4 |
- }
复制代码
6 i" R- H) {- @# S: P8 y ?& b' n3 _" f Z1 R
我们编写一段代码。 o/ @) q( D$ [: s' j% @$ \, U c
. n* `4 Y% w1 M6 S* E a按下按键的时候设置DAC的值,开启DMA传输,再加上ADC采样,之后输出结果。
( R% i9 z" M- o; A+ V w" Z- s- T
( m' w; m6 v6 u# E& u8 E# ]* H
1 I5 \ z% p! e0 e9 B. C1 [4 B
1 W& `" D$ b% {6 p5 M9 f可以看到,我们按下按键之后,ADC的值会呈阶梯状上升。4 F2 P$ l; Y% T/ Z. T
& ?1 L L, \; I) `* |
三角波发生器, Y f, }- f3 |3 x/ [
7 P) a. A+ l T! i
) |1 B; _2 u3 m% Q1 h
" W1 i- s% u/ ?2 n" M& P在DAC配置中打开波形发生器,触发方式选择定时器2触发,三角波最大振幅511。
7 s: s5 K t: w/ k$ L! D2 e- B F% N9 W2 y0 }8 E" Y) v
& T% {1 I; X+ D
: \) H! V: D: h
之后开启定时器2,由于ADC的采样率是1000HZ,因此根据奈奎斯特采样定律,信号的最大频率不能超过500HZ,因此我们使用100HZ的三角波。9 H; K* j% I9 \- s: Y4 n
9 y! a/ T( M% E) ], [
' |5 q6 S$ j& _6 j+ q& C% z' p
+ M- @: ]& }3 A定时器设置好时间之后,设置触发事件。. s9 A) j7 A$ E$ t" W
0 _7 O. C+ ?3 _' H
+ D! A" _1 p- E: {
; z- l; y+ B* D. E, D
芯片手册中简单的介绍了一下如何计算三角波的频率。当触发信号发生后,内部计数器的值就会+1,所以频率可以用如下公式计算:
% v7 x$ C( E' E4 F" U
7 k0 Y( n* D* Q2 u# d: U3 x定时器频率/分频系数+1/Period/三角波最大值/2
2 S5 D" ?( @, ~- h5 j( z0 K) G2 F: ^( ]
- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //用来触发adc采样. D+ n: x& Z1 W1 G% l
- HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //用来触发DAC输出
1 f( M* H7 B5 P( K - HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC% U, m X4 E6 y/ {, ]8 X) V
- HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
/ k7 v' j2 M8 V/ p - HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_L,0);//设置直流信号
复制代码
. a+ K7 q- l" ?+ G$ {9 `
5 [: X, d* d; L: t& G! H2 s! d5 I5 Q$ Q5 v0 c" R3 q$ ~0 s
正弦波发生器
9 z" q% X4 o8 B8 J3 y
7 W1 F: _$ {! k! O# L( L, {7 S+ E3 W
* N/ C7 H7 o6 a2 G! k$ w. V: J, V/ K1 G, N+ h6 R
首先是定时器触发(方便控制频率)。但是关闭波形发生器。
6 X8 ?0 J, Y/ y0 ]
4 A, F9 j6 k+ I1 h5 U& A
; x( j+ a. v2 _9 V. Q4 X* j4 H' T& w$ M5 H0 |1 Q
添加DMA,模式选择循环模式。0 ]4 g5 `2 I* V$ y
; O, ^ y# E$ P- e还有改变一下定时器的频率!
$ f' M1 [5 w4 u. c; o/ b; K4 G+ H& A
其他几乎不做改变。$ E- r0 P3 T0 b5 [& \5 O$ {
F7 U8 @' F [8 N2 | D
+ T2 Z6 u6 e- ~
- #define POINTS 256
9 l& J+ u7 F: H - #define MIN_VALUE 50
6 v# r B# ^% H4 I6 d - #define MAX_VALUE 650 $ h$ C7 \' n, o; a
- #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0) % ]6 _. P/ g$ U6 {. k x- a
- #define OFFSET 50 " x% J( {: I B" @7 {% ?1 b/ ~' _
- #define M_PI 3.14159265
1 A8 W( U4 }8 I2 A4 F2 O8 ? - , V/ b2 Q, p! J$ X, \
- uint16_t SinWaveInt[POINTS];
6 C5 y% f# n; c l8 A9 T - int SinWave[POINTS];
7 Z3 {- G* Y0 `- J( B6 _0 @; W - void SinInit(void)
8 R3 i m5 c: s - { & j$ P" D v8 G& m. }% h
- for (int i = 0; i < POINTS; i++)
, i! I8 W; c, L: Y& j - {
. a( h. O+ ?4 w% C" Q3 Z/ [; N - double x = ((double)i / (POINTS - 1)) * 2 * M_PI; ( E* J- K" X X" d& L9 C
- double sin_value = sin(x); // 计算正弦值 ' F6 u. _& p5 }# W
- SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET);
R7 t' Z! q* N# @8 @ - SinWaveInt[i] = (uint16_t)SinWave[i]; 3 d& }6 Y1 N, P1 |$ L( s+ O) g
- }% T2 X' c- N! l4 ?0 t3 ^' r( m! G
- }
复制代码
- S4 q, N6 o- Y( {" ]6 d) D计算一个正弦表。$ u( C0 O% h) c* o& G+ M
, }5 v7 b; Q; X# h+ a ] o这里的Points决定了分辨率,结合定时器触发频率决定了正弦波的信号。" c7 |2 v, G0 Z4 i; Z7 ]
% V' z- V6 H* g; |' u
1 R" ^1 S; n( A+ i5 ?: Q% b# R0 ?' f
测试一下正弦表,输出的是正弦信号。, B2 c. i9 x* i' _
. G9 @ t9 J n# v% U
我们之后将正弦信号表导入DMA中。
% z# t4 r1 _, t. P3 p- p# ]0 O# a! _; X, @ k# s( ]
- SinInit();$ h) x7 G4 t; w- n3 ]' H9 v
- HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)SinWave, POINTS, DAC_ALIGN_12B_R);
复制代码 : V) E9 D1 m4 D+ F$ i9 r7 k
正弦表初始化,之后启动DMA传输,导入正弦信号。. F. R: L! \ s1 S
4 n( ]+ S* d# V- a' D
4 v4 e8 l* m* S. k2 y* r
* Z' w9 w! n! z6 D( `测试正弦信号成功。
; j# a6 j$ V8 C h9 Q5 L
+ x' @3 A4 _6 S0 h* |, t: ZFM调制- #define POINTS 1024
9 H2 m$ H- C- J2 U3 y1 [- ?2 _ - #define MIN_VALUE 50 2 a" z& ?1 K# D
- #define MAX_VALUE 650
& n2 G9 C4 K7 I& f6 w3 i% p ? - #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0) 5 u w$ {3 G' n% O3 D/ p
- #define OFFSET 50 & w ]( j) ^( K
- #define M_PI 3.14159265
G6 W1 P/ g; `* N - ! j3 `7 _! k% x! N: l. ~! H0 p
- uint16_t SinWaveInt[POINTS];
~+ @/ j% p5 x/ F6 u7 e1 z3 n - int SinWave[POINTS]; . s2 x0 E' T; [: q9 B" {
- void SinInit(void)
: r, g4 z4 e* \: o( U# t; T - { : a3 i2 ~( y p/ D- g2 l
- for (int i = 0; i < POINTS; i++)
T9 X9 f+ Q! n9 E) O - {
7 J3 c! g2 h& A- H - double x = ((double)i / (POINTS/4 - 1)) * 2 * M_PI; . [0 W9 ]+ r5 s
- double sin_val = sin(x)*sin(x/4); // 计算正弦值
# M) J$ Y/ k& \+ C0 c - SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET);
$ `5 A+ W* s! N$ Q4 ^1 g# v - SinWaveInt[i] = (uint16_t)SinWave[i];
8 h Z' H9 k' t& z8 u - }$ R1 ?* a/ {, ~ x0 z
- }
复制代码
' H6 Y7 e8 t1 b7 z# o% y1 ?% ~5 r! B
: [& [* N8 |! q7 v拓宽点数,加上载波,即可构成FM调制信号。
' P3 e& c: [4 \4 Z" m" [5 n6 b; x) J/ g; z7 s
7 b$ l3 e4 [0 `
3 Z! n( h2 `5 I: Z; F# R1 O3 x$ s: s3 N
转载自:电路小白
/ H! D: n2 W3 N( _( m3 Z1 w' I如有侵权请联系删除
" {4 C; ^" I, p1 f, o" \6 w. s2 m! t2 l+ n
% p3 k* S7 [ L3 B& Q
( i& _& X7 G) x |
资料不错,值得参考学习。
dac+dma?