DAC,即Digital to Analog Convertor,是数字到模拟转换器,也称为D/A转换器。其核心部分由R-2R电阻网络(也称倒T型电阻网络)、模拟开关和运算放大器组成。它可以将二进制码或BCD码表示的数字量转换为与其成正比的模拟量输出。1 k( j4 |: V! F! g) }% j7 T& ~4 C
/ H2 @# Z3 Y6 O& _5 Y3 S
DAC的工作原理主要包括数字信号采样、量化、编码和模拟信号输出几个步骤。首先,将连续变化的模拟信号在一定的时间间隔内进行离散取样,即数字信号采样。接着,对采样后的数字信号进行量化,将其转换为离散的数值。然后,通过编码将量化后的数值进行转换,以便DAC能够识别和处理。最后,DAC将这些数字信号转换为模拟信号输出。
0 ~, x O+ k* a4 A' k
9 h1 C6 j: @. a/ ?( J5 f# I XDAC是数字系统和模拟系统之间的桥梁,具有广泛的应用领域。在音频处理中,DAC被用来将数字音频信号转换为模拟音频信号,以驱动扬声器和耳机,其性能对音频质量有着决定性的影响。在通信系统中,DAC用于将数字信号转换为模拟信号,以实现信号调制和解调。此外,在仪器仪表领域,DAC也被广泛应用于各种测量和控制设备中。9 ?$ [0 d6 M" t9 d7 ?
" q2 N" ~/ D4 |' w$ _# B
' [4 U* h* p' c3 g5 ]& M
& g, c) I# k6 G% [STM32中的DAC(视芯片而定例如F407ZGT6是2个DAC通道,有些芯片不支持DAC功能)支持12模式的数据输入,可以双通道同时转换。6 ?3 \5 V7 A" j' k3 l, ?6 _
$ z/ D0 G' a$ F% e' _: C本期我们将介绍如何使用STM32F407和CubeMX利用HAL库实现DAC的输出。(本来是想使用C8T6的,结果突然想起来C8T6)没有DAC。
1 L+ c3 q* b7 y1 c! Q' ^$ b. X* }" @
CubeMX配置
! _/ {* e) ^3 h& {/ e
# G; a; l0 |( ]
0 J$ ^) H6 U/ D5 K7 l; U
' X& m* G0 g/ j* g
在DAC通道中开启DAC,在F407ZGT6中DAC1对应PA4,DAC2对应PA5。- Y( } ] P+ d
3 Q8 T, g! \8 j" \, G3 o
( d! u. n8 n7 W% z; \/ u
& m4 W$ \* ?6 r! h
OutputBuffer这里设置DAC的输出缓存使能,Trigger是DAC是触发方式,这里我们选择不触发(手动写入)。3 c9 Z. K9 Q& ?& R& T- f6 q
. U: d, C+ f/ X: _; _& V3 E如果选择触发的话是从缓存区写入数据。
, \5 D" E! d9 s, w1 }4 i5 z) `! l$ a) L* g8 |/ \
6 p3 a5 A+ m( {# {1 I5 }/ I- Q
- P" e$ l* k3 s7 M$ T( Q这里顺带加一路ADC采样,因为手上没有示波器,所以使用ADC来进行查看。7 i O, i7 E& ~ w/ D
: H$ T' |# ^; _0 K- [6 u- X4 S这里使用DMA进行采样,具体可以参考公众号之前的关于DMA+ADC采样的内容。
& r/ u% y) w1 }/ ?( N/ Z: p* L5 A. e/ I$ ]3 i
STM32的DMA采样+FFT时域分析(STM32F407)
1 G9 y- w, V' O* s; C( n. [) Q ]2 l
但是相比于之前的,需要更改一些设置,首先是DMA的设置9 Z9 a6 M5 t) ?) I( Z2 S5 v1 \
( I: Z U' s3 p
- ~4 p3 R+ x% e3 s0 }% I
. o8 k% A/ S6 l3 L4 V, ?$ s这里设置单词请求,而不是循环模式防止数据跑飞掉。4 b6 C5 V1 D, d9 r# o9 N
' K0 y5 @$ W# b2 }1 d+ s) I0 d- H! M6 B5 U! z* U6 f1 e9 c; J/ {" g
- MX_GPIO_Init();$ {# _$ Z; [% |, l9 w1 q+ L# o, F
- MX_DMA_Init();' T: N& Y4 \5 j; P! J5 R
- MX_ADC1_Init();8 c( C7 y% D5 v$ e/ O
- MX_DAC_Init();! d1 U5 I. q. v# J, [" k) R
- MX_USART1_UART_Init();" `" |0 H7 s5 K/ l
- MX_TIM1_Init();
2 F8 F! `8 N, X( T: E - MX_TIM2_Init();
- D0 y( x4 H+ {& q - /* USER CODE BEGIN 2 */' J) e$ m+ G* T/ a. N
- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //用来触发adc采样 ! X# W* a- E& P, U9 d
- HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC8 k7 B5 n( B4 ~+ E6 j1 X
- HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
9 Z: b+ [/ r0 h1 j' z - /* USER CODE END 2 */9 j1 o- y% X5 B* _& c/ Q8 K
, Q, P% U; l0 e1 f- /* Infinite loop */1 i! N9 N0 z$ F) S d7 t% {0 G4 V4 G
- /* USER CODE BEGIN WHILE */$ V1 |* L' k" d, `% F. [
- while (1)
+ ^' R( t) |% u0 o - {
$ ~/ e y6 T1 e2 ^ - /* USER CODE END WHILE */
8 o5 n; N& ^2 m2 Q; T
3 @( k; U1 n7 ?- /* USER CODE BEGIN 3 */# ]% U* o: D- @) |0 h2 q
- if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0))0 V+ B. O; Y+ g
- {! D" w W+ `0 U2 y7 Z
- HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC2 ~# p) u4 B k, [3 W& o
# y+ W; t8 f8 j/ h* K& v- HAL_Delay(20);% S a' G* c b }7 C
- ; ^' }: x, V) J- }4 b7 f
- while(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0));
" ~7 H# C# b4 y$ V+ e& j4 R% t' O4 I - HAL_Delay(1000);. L7 [ D0 ?. ^0 s
- for(int i = 0;i<ADLenth;i++)
* s4 r; a5 B# C7 C& n: Q: _ S2 q - {
+ N/ q4 v' T: p d f. k6 S1 D - printf("A:%d\r\n",AD_Value[i]);! P9 A( j2 ?& S& @
- }
- k7 t! |9 m; c3 p, P - , b$ p( R% w( Q! t3 z/ i
-
" I' K" M3 D) L5 d5 q$ G - }* r) j5 x9 R2 |/ c3 `! L" |! @0 U% a
- }8 F1 v; ~9 {. g: f
- /* USER CODE END 3 */
6 D: ]% S3 z% w1 w( Z! G3 Z/ R - }
复制代码
5 F; u5 }9 j6 x3 a& M
$ k$ j" b7 ]1 Z9 X) D# `+ a我们编写一段代码。
% Z7 _; _( @, Q& X" ^! a( n- ?) J. {9 S
按下按键的时候设置DAC的值,开启DMA传输,再加上ADC采样,之后输出结果。$ h; F, z% U' V i: a7 `
! @* c( u5 C. O( x0 R
' }5 f) i2 _7 w) t9 h3 c
* B1 R6 X. V- D! S) C2 g可以看到,我们按下按键之后,ADC的值会呈阶梯状上升。
% [' @' @0 S" ~. z% |7 d* X
3 M* p. v0 O/ h1 A% |: ^三角波发生器# P9 r# y$ K( C$ A, i: y( ~8 l4 o
1 N" d% e+ _, R; v7 ]
/ t4 F' \) P' q8 j, B
; g$ B- _3 t' b! N
在DAC配置中打开波形发生器,触发方式选择定时器2触发,三角波最大振幅511。 O$ f1 o. Y. M& s
6 x* P$ x5 W+ F4 w3 x+ \# r
) P6 K/ k. S3 Q
' ?& z* t4 D U& A/ ?+ t- y之后开启定时器2,由于ADC的采样率是1000HZ,因此根据奈奎斯特采样定律,信号的最大频率不能超过500HZ,因此我们使用100HZ的三角波。2 q2 D! ^% a$ ]8 t* W: l
( j+ ^! f$ x6 t9 a/ u) y6 T
( h! s1 @7 q7 M2 V, H) P4 t# \) l$ W& B+ N3 {; e, {8 g$ c
定时器设置好时间之后,设置触发事件。
2 {; I1 U, q; B R$ F0 G2 c# }8 h# j, ?2 ?2 h$ W
6 \+ W% H! S% ~( L6 x% _ J4 l1 E" @1 E9 ~' g+ \! Q; I& x" M
芯片手册中简单的介绍了一下如何计算三角波的频率。当触发信号发生后,内部计数器的值就会+1,所以频率可以用如下公式计算:
! Z4 W& ]" M: z" A
" W9 L: p6 J- X( ~定时器频率/分频系数+1/Period/三角波最大值/2
: N) A, P' n, ]- b, q
& P5 l# h3 T# B; g8 }9 Y- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //用来触发adc采样1 U4 ]: j5 y7 B
- HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //用来触发DAC输出3 J" T8 x' R: w/ F
- HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC
j) `) z& l! S' i6 Q - HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
* T3 J" j" I1 N$ _+ A - HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_L,0);//设置直流信号
复制代码 2 j. g; K5 O, e& J1 @3 U
9 l/ j1 n( R- G& k( @. K. i
0 m3 @7 {% F$ d/ k; k( [
正弦波发生器4 E! ?2 w" G5 I. J
7 w9 Y! p5 E" E! K6 [
9 G S1 r- d: E2 L; x- a9 t+ O
, [6 ]1 X1 o4 y% y6 q' y首先是定时器触发(方便控制频率)。但是关闭波形发生器。& w) i7 O3 y" Q) ?5 r
5 X1 x G7 V# V# K% U
# @- n; U9 I2 O# i( c1 \9 T
4 f3 |( D9 D- p. @9 O3 x' X% f
添加DMA,模式选择循环模式。# T8 R4 ?* \9 C# F( A# S
. ^, y4 c+ U2 r% V; P2 W9 _
还有改变一下定时器的频率!
. m& Q/ v, X6 X, P0 J
- t1 R h1 o* L1 k其他几乎不做改变。
# ~3 C6 i* h( V A% e5 R8 a! F: {4 ^/ d4 w
7 M S) n3 m' D" b- n) ?
- #define POINTS 256 $ z9 z3 n$ g( C7 L
- #define MIN_VALUE 50
7 k6 ]- z) a3 k: u( r - #define MAX_VALUE 650
3 V; Z0 m* I7 d: h. t - #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0) ' }# h4 p' q$ O! m
- #define OFFSET 50
7 P' s4 Y+ K. V! {' J, U% z$ \: } - #define M_PI 3.14159265
, J+ n0 P8 k/ b -
% d! c3 ?" C1 Q2 e - uint16_t SinWaveInt[POINTS];, A' s! X2 L/ D( n; Y6 Z P( W
- int SinWave[POINTS];
1 W, @2 f8 q' R! q - void SinInit(void)
5 M/ G' } v1 ?* ]* O& h/ h - { ( K5 T- _1 c: Q# {
- for (int i = 0; i < POINTS; i++) $ W6 Y9 \. }% V4 v3 f
- {
# ^9 f8 ] W2 ?* S! c! w - double x = ((double)i / (POINTS - 1)) * 2 * M_PI; 9 s5 T0 f" m" i1 V2 S
- double sin_value = sin(x); // 计算正弦值
H/ M8 m* v4 l. C) ` - SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET); % h7 H" s7 T! v- k3 s9 f
- SinWaveInt[i] = (uint16_t)SinWave[i]; ! d w2 w* p9 r/ r( F1 |+ ^- u
- }
; b2 d+ k. f2 h - }
复制代码 ! G( D; {, ^9 `. X
计算一个正弦表。4 }% A7 }; L9 |0 k, g1 P% U+ S
" i: m& ~+ Y& t- j3 U7 A4 L这里的Points决定了分辨率,结合定时器触发频率决定了正弦波的信号。9 G; M/ }5 T' t! f% X, ?8 Z
- ~1 N8 Y l& U: y }! w% Q
. L2 i; B5 b7 d2 M8 S
! ?! F- D# @! n9 C测试一下正弦表,输出的是正弦信号。8 { e/ Z. f- M7 N
' Y8 Y6 j4 ~- r4 N0 ^- }我们之后将正弦信号表导入DMA中。 I- E! n# ^: C2 v, {' o O; p/ ~! i
" J U" U+ N5 ^0 i- SinInit();/ `$ u9 D, [ t7 t1 Q# Z4 z; i- \
- HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)SinWave, POINTS, DAC_ALIGN_12B_R);
复制代码
9 U' O: C. o+ t) `正弦表初始化,之后启动DMA传输,导入正弦信号。5 n* [: q* a# \! @, I0 L: h3 e
/ m' S& j/ F! f1 H2 c: {
# Z: n/ V. O/ d% N
) O3 Z$ @- T' q8 |测试正弦信号成功。3 @+ J0 t- Z2 a4 R1 n
$ H4 e4 ~. p: E3 N, c5 {
FM调制- #define POINTS 1024
) l7 k, \! j* W+ i - #define MIN_VALUE 50
7 f: K5 X, u" [- ~' n - #define MAX_VALUE 650
- E" K9 \3 b: ?+ a( Y - #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0) $ Q9 M2 K0 T5 Z& s3 R- o+ W2 P, \
- #define OFFSET 50
2 e6 c& C7 s1 U8 u - #define M_PI 3.14159265) w" J0 S+ L0 r
- & m% Z$ K, b; ^" [( ?+ m$ q
- uint16_t SinWaveInt[POINTS];
! b9 U1 `! O9 S o. ]* H0 C( t - int SinWave[POINTS]; % t' _7 g; Q5 V3 ?% o
- void SinInit(void)
" i; ]/ W5 `$ S. P8 D( k3 O/ ? - { / [) V4 b. p- G3 E7 n8 ]2 f
- for (int i = 0; i < POINTS; i++) ?4 k v+ j/ j% _
- {
4 b9 m$ u! H; f9 D: {" ^ - double x = ((double)i / (POINTS/4 - 1)) * 2 * M_PI;
2 N6 w8 x5 f& o% [- U3 C7 L: K$ X# c3 v - double sin_val = sin(x)*sin(x/4); // 计算正弦值
; W" }8 e- E+ _+ P, X - SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET); ) q- C; q' Q+ Y- V0 j. y; I
- SinWaveInt[i] = (uint16_t)SinWave[i];
% d" h9 w" Y" g - }
& a8 m' e- L9 B6 a: P1 a4 g - }
复制代码
! a R. I) {5 w s
+ V5 y# r5 A1 ~拓宽点数,加上载波,即可构成FM调制信号。1 M9 o# V/ F) `8 a" ~5 N% _. Q
5 m& `3 u" I' [2 x; Z. b& v
) l& y _. ]* f* B; _' y
4 q6 A( A5 e, w1 J& i( L) L) ~( \" z' P7 q2 p$ H
转载自:电路小白4 g6 V% p2 p8 s! f
如有侵权请联系删除
7 N& N) b. L$ y, W8 Q! Q" @+ r) R5 {
7 i- C; e3 z Z3 z1 ^* D+ N
3 Y* ]: q* c7 {1 g4 ? \9 t* V% l$ _2 j
|
资料不错,值得参考学习。
dac+dma?