DAC,即Digital to Analog Convertor,是数字到模拟转换器,也称为D/A转换器。其核心部分由R-2R电阻网络(也称倒T型电阻网络)、模拟开关和运算放大器组成。它可以将二进制码或BCD码表示的数字量转换为与其成正比的模拟量输出。. v2 q4 A( Y" a( b
9 X n# z. l9 d" F9 }1 W
DAC的工作原理主要包括数字信号采样、量化、编码和模拟信号输出几个步骤。首先,将连续变化的模拟信号在一定的时间间隔内进行离散取样,即数字信号采样。接着,对采样后的数字信号进行量化,将其转换为离散的数值。然后,通过编码将量化后的数值进行转换,以便DAC能够识别和处理。最后,DAC将这些数字信号转换为模拟信号输出。
- Z1 l' n1 G, F- Q/ e: u( J U, ^, f( d
DAC是数字系统和模拟系统之间的桥梁,具有广泛的应用领域。在音频处理中,DAC被用来将数字音频信号转换为模拟音频信号,以驱动扬声器和耳机,其性能对音频质量有着决定性的影响。在通信系统中,DAC用于将数字信号转换为模拟信号,以实现信号调制和解调。此外,在仪器仪表领域,DAC也被广泛应用于各种测量和控制设备中。. k5 `* i2 [% `7 z/ }, b3 n: \
; Q# E1 l+ G/ ^( d' A$ z1 C3 j
- x$ Q( W4 i0 k* l
* b( V+ u- ]7 a, ` k) j
STM32中的DAC(视芯片而定例如F407ZGT6是2个DAC通道,有些芯片不支持DAC功能)支持12模式的数据输入,可以双通道同时转换。
2 ]5 C" m2 o2 k. ^/ g, J
: R* L( g/ r. X. I- ]0 T) Q+ B/ D8 {本期我们将介绍如何使用STM32F407和CubeMX利用HAL库实现DAC的输出。(本来是想使用C8T6的,结果突然想起来C8T6)没有DAC。/ u) I# W% _5 j
1 R. _. s6 `" Y# [
CubeMX配置
0 X* `* B2 F) M4 A* H) I* {+ Z9 ~' z1 X0 U4 I" H
/ e- V( Y7 p2 e3 A3 N! J, u& Y
& }) E0 i3 I, G2 B在DAC通道中开启DAC,在F407ZGT6中DAC1对应PA4,DAC2对应PA5。
1 j9 C+ r. S4 n7 V- a: u2 }, ?, e* w! r& B" l% l- K
" d3 D; g5 c) {$ @; C) u K' |; K# O$ {* E
OutputBuffer这里设置DAC的输出缓存使能,Trigger是DAC是触发方式,这里我们选择不触发(手动写入)。
3 A1 X: w0 b: R0 g& `0 g" [7 y1 R& Z! ~8 _8 Y: c
如果选择触发的话是从缓存区写入数据。
% S% q& U' `% L% a6 J. e
2 x* a7 O# k3 L
& c) m8 X; @" P2 e) x$ x7 G% P- ~) R0 h' }0 ?: C
这里顺带加一路ADC采样,因为手上没有示波器,所以使用ADC来进行查看。0 {6 j6 q! z# T: ~2 A3 V3 e0 M
{* v8 k! a8 U0 f& o
这里使用DMA进行采样,具体可以参考公众号之前的关于DMA+ADC采样的内容。3 V- {/ l9 i% B: m- H5 W1 F) [
; r7 L; C% y f" x2 E3 A! R/ [
STM32的DMA采样+FFT时域分析(STM32F407)6 t: L1 K2 I6 W/ b) u* C8 D. J
0 C# Z. S, p" c/ ^5 U; s" P但是相比于之前的,需要更改一些设置,首先是DMA的设置& W0 r1 g( {" Q8 }. u$ ?
) Q; v2 y' T4 Y* O
4 B/ G0 s6 }" l- l- ^* k
/ k# Y! y z/ z/ P% W" d! C, @# J' L8 g这里设置单词请求,而不是循环模式防止数据跑飞掉。# r) Z- _2 l0 I. D
g( G8 K: |5 i( a4 L1 E; i% u W* h5 Z0 g9 C/ _7 ~, w
- MX_GPIO_Init();' z+ @' ]) y: d+ x: T% B
- MX_DMA_Init();
* h. t. t, ]$ ^$ O3 B - MX_ADC1_Init();: U: S- m- z& R# S3 W
- MX_DAC_Init();
) V; ~# }8 R+ r - MX_USART1_UART_Init();
- F! |* a) |/ V1 F1 G8 o; J - MX_TIM1_Init();4 Z! h/ f4 {# q/ c: I3 e5 z
- MX_TIM2_Init();5 V# I) b: Q$ @5 h- @ k
- /* USER CODE BEGIN 2 */
# Z6 b2 j$ t* i) u5 s: q! R: X% [ - HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //用来触发adc采样
" a/ B9 ~0 r$ J- b% b; ~: F - HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC
: |" i$ p' D0 E - HAL_DAC_Start(&hdac,DAC_CHANNEL_1);6 `* Q t$ }' @7 D2 @4 `
- /* USER CODE END 2 */* C# e7 [; c$ R) K: y! H7 Y$ h6 w
- # Q. k0 Q1 Q& K: o- u3 J
- /* Infinite loop */
' L9 B! N% ~6 O% u- f+ O" G - /* USER CODE BEGIN WHILE */
" u8 l0 m5 I' P/ ^0 z9 l- o1 v - while (1)! G: |% r- R! A3 A: S) p
- {
( c6 Z8 t% \; o; u6 s# r - /* USER CODE END WHILE */0 C, t! v# P$ P* p {) O9 Z. ~
8 J6 H6 }* B) b& H A- /* USER CODE BEGIN 3 */( T+ H3 ~* R' ~' H3 `
- if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0))4 i+ `* {. z7 r/ P+ l+ N
- {
6 O- c6 Q) R+ {8 U. n+ E - HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC/ N) L7 N' |8 r$ e6 f8 y
* A5 n" E' s" S( x- HAL_Delay(20);1 C! Q7 ~( {2 G) A- H3 Y1 K
- . w; R2 c" z$ o
- while(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0));
6 v" z+ _6 r) X5 ^2 k - HAL_Delay(1000);; q$ G; Z5 }4 I& R3 b
- for(int i = 0;i<ADLenth;i++)0 p. [7 ^7 O! p
- {
8 L* w. c% s9 S% s2 `# I - printf("A:%d\r\n",AD_Value[i]);, C! C0 z: I1 u5 r
- }; d D9 Z- }- u# V
-
8 X" S$ j3 E- F+ v - : H" w+ F3 @) J& `9 K" Q" O
- }* q( W3 K4 k" S! m6 F1 i9 f
- }* n: o# l+ j9 P* {. H, n4 b
- /* USER CODE END 3 */1 h7 i* X- Y. }+ x9 s
- }
复制代码
) H, m! l3 _/ y) [% @1 T$ G$ X! e$ A' \/ }6 x/ u% K$ D, c; n& X
我们编写一段代码。
/ s2 U4 s: S5 s, Z2 W
$ X6 }6 C7 f/ b3 g按下按键的时候设置DAC的值,开启DMA传输,再加上ADC采样,之后输出结果。+ ^( A! k' c" Y H$ s; f
/ Z! h7 _$ ]; p6 l9 E" P( M2 P; v6 ]
9 J& G, m3 h3 v3 i2 z4 G
9 v# D, e9 \# p' d. b" w
可以看到,我们按下按键之后,ADC的值会呈阶梯状上升。
! V$ n6 C7 O+ {) X4 `1 v: i M. {, W' s7 S$ k/ ?# U. R
三角波发生器2 r4 H9 s% z: B" s! y* _
$ ?- J& q) t0 z6 S! j# T0 @
8 v3 s5 B! _" H5 E' Q0 ^" L3 I; `+ u5 q# x
在DAC配置中打开波形发生器,触发方式选择定时器2触发,三角波最大振幅511。
3 h: ~# J& ~( l$ l; O# Z2 ~1 f+ o3 X* ]& W8 X2 b' o
; k& J! _; ]. w* `" P( }* f% \: n. ]+ ]4 {; a5 K+ p2 _
之后开启定时器2,由于ADC的采样率是1000HZ,因此根据奈奎斯特采样定律,信号的最大频率不能超过500HZ,因此我们使用100HZ的三角波。
/ Y) ]5 o6 P$ Z2 g$ x/ g4 I2 j1 f( ?2 a3 v7 ^
# d: V- q) {1 b" }$ y
_: g. ~: f6 S) F6 [+ ~, Z
定时器设置好时间之后,设置触发事件。
) D$ C; U: V5 a+ e& V$ ~/ p* s& N
0 p9 b( C# M" H% {7 f p! d
4 g7 C! x" E7 s
' _% B* ?2 ~) m2 q7 \/ ?6 u芯片手册中简单的介绍了一下如何计算三角波的频率。当触发信号发生后,内部计数器的值就会+1,所以频率可以用如下公式计算:
" N% z1 K* A/ {) E5 {
# m4 _, D& l; G Y# A6 F- ^' S# M定时器频率/分频系数+1/Period/三角波最大值/21 H/ G- h& [$ K
- ~" Q5 @% Y+ G+ {; z7 C0 x- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //用来触发adc采样" ?# I3 S1 d- s) r) ?
- HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //用来触发DAC输出
5 l+ a" m) i% Y- V2 z# k# O - HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC* T+ \; b. N! G7 {/ L1 f
- HAL_DAC_Start(&hdac,DAC_CHANNEL_1);3 J( S; P8 e& @2 F. m
- HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_L,0);//设置直流信号
复制代码 p0 l# Q9 d* U) ], p! ^3 S, {9 c7 A
# R* J) @# D# D5 J* q" s3 N1 h5 |7 A. G& H0 P
正弦波发生器
7 m: r* R& s- T* G0 H
8 R9 g+ ?- W7 t) X6 \$ Y& M
! m, x+ L5 M. F3 u
, |$ S! Z2 W$ N' U0 |: ~6 e
首先是定时器触发(方便控制频率)。但是关闭波形发生器。
! w; e' a& X' J) `% ~# @6 s6 \6 |+ P& Y4 Y9 Z
/ i8 x. E# C9 T F+ w8 D; `3 B( v
$ k" m& B+ }$ ?8 z( z, k- ^: p
添加DMA,模式选择循环模式。
8 Y: M7 j- c# D/ w9 H! {
3 _) s: [8 p8 x/ m! r还有改变一下定时器的频率! ?5 ?2 \5 ?! }# U$ n
- V Y: x6 v, E
其他几乎不做改变。2 I# `: i* @8 E# e% L
) F P6 c) L; S. Z; h. y5 ?/ G6 D
4 J3 ?3 [; O7 t0 X% s- #define POINTS 256 6 x1 ~% [+ J$ ~9 K; Y, G$ F r
- #define MIN_VALUE 50
+ ]1 ~6 P; O+ o# L - #define MAX_VALUE 650
2 _; c6 d1 M: P: `& S& d: G - #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0)
0 m4 Q$ N& x8 W - #define OFFSET 50
; n+ _+ p+ Q& S5 C6 E/ d8 P - #define M_PI 3.14159265
) Z7 h, C& o: K3 } - ) Y/ K: e4 S: M/ m7 n- _& j% [
- uint16_t SinWaveInt[POINTS];
# H8 A: x/ D7 m3 ? - int SinWave[POINTS];
) W) v. B) O! h6 I - void SinInit(void)
1 f; F9 o2 N! s: ], V$ s! ` - { 2 |0 P5 g4 x# ?: y
- for (int i = 0; i < POINTS; i++) $ f6 G) E7 a0 m$ b) E0 Y4 A9 A$ \' F* O
- { & @0 M3 {. a0 b/ x( M, p
- double x = ((double)i / (POINTS - 1)) * 2 * M_PI; 9 E# z8 D8 U+ A* J" a. a
- double sin_value = sin(x); // 计算正弦值
! d, [: M2 r- Y- b# ]' ?8 f5 X8 I - SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET);
/ m: q6 @# a7 b5 N9 m) { - SinWaveInt[i] = (uint16_t)SinWave[i];
; [/ \9 k- Q8 b1 { - }
5 i5 w2 ?, f+ E- K! D! h - }
复制代码
T7 N8 \/ k3 r: `' }计算一个正弦表。: q% H5 j5 N" Q9 d' s: e
: q* D8 l P$ u/ w' T Y
这里的Points决定了分辨率,结合定时器触发频率决定了正弦波的信号。
* m3 g) s: D2 O9 q- E# U
/ ~" v7 T, E$ B N# l
; u, j3 d" K. B
+ ], X) A8 x7 J
测试一下正弦表,输出的是正弦信号。
1 x, J5 T! L6 D$ R) F- i2 S
8 l& u A6 s5 e' F4 J! I1 M4 d我们之后将正弦信号表导入DMA中。- _3 k- N2 E6 P+ o6 U
* w. x+ ^/ a% ? r
- SinInit();
; I5 N/ H3 Z \+ ^" Q7 P7 h - HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)SinWave, POINTS, DAC_ALIGN_12B_R);
复制代码 ' C+ \8 P& k: V5 T0 Z8 w
正弦表初始化,之后启动DMA传输,导入正弦信号。# l% E2 Z+ K8 Z; H0 [2 p
& _/ s: Z& t U3 [3 E* k9 V. ^
U7 r: t; T& k9 ] z
z! b# ?3 B6 Z# h
测试正弦信号成功。
8 R" G7 h3 M* R2 N& E! X) n, N- c0 \4 m+ Z9 I! A( ]0 V
FM调制- #define POINTS 1024
5 Z% H: Q9 G3 p! ]9 p* ]6 |3 M - #define MIN_VALUE 50
* F, K. u" [; q9 H - #define MAX_VALUE 650
# N! T: x1 T1 }/ q - #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0) ) @: ]9 v1 f/ R+ w4 R* c
- #define OFFSET 50
- ], Z8 l/ L& y( R4 b+ ~9 v" | - #define M_PI 3.14159265
6 e% ^. s3 g" O; U. l3 l -
9 s% z6 a! U, R; r3 x7 A! Q7 A( } - uint16_t SinWaveInt[POINTS];/ I6 [7 h9 T7 L2 I& f6 O
- int SinWave[POINTS]; " {1 S& g, [0 Q
- void SinInit(void)
9 y9 V1 l3 |1 P% x2 | - {
V9 e. G0 W3 W8 U4 H& h s - for (int i = 0; i < POINTS; i++) ( j _! ~7 \: c* g7 S; P
- { 0 A. H2 C$ a1 D! h6 ? H5 ~
- double x = ((double)i / (POINTS/4 - 1)) * 2 * M_PI; 7 x) _4 J" U8 G
- double sin_val = sin(x)*sin(x/4); // 计算正弦值 / _" _3 f1 S4 Z4 O+ h$ {
- SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET);
5 ] X* v6 h2 L* L% d - SinWaveInt[i] = (uint16_t)SinWave[i];
' ]( A ~: ^3 Z" x4 H - }
" ]+ }9 ]1 S; W; q- b/ I - }
复制代码 ) M4 [ r; V: m' f
; G! ~/ e( w3 O拓宽点数,加上载波,即可构成FM调制信号。5 b5 M! p' G+ W! u
& r, W8 Y ?+ k- u! B/ } R/ l
8 t& S; H1 _- `7 H6 p+ t2 U( p
& M; T0 n+ l/ K
6 K+ V% W2 l9 c( I& @; X, B- z转载自:电路小白
; r3 m$ g0 S5 J9 j1 E如有侵权请联系删除
9 P! H* B( W3 o3 z* V6 G# X) i4 p) C% K, O7 w* }
% O7 V. Q: Z( ?. K% W/ h7 `
0 L# N+ i' T, \, \
|
资料不错,值得参考学习。
dac+dma?