DAC,即Digital to Analog Convertor,是数字到模拟转换器,也称为D/A转换器。其核心部分由R-2R电阻网络(也称倒T型电阻网络)、模拟开关和运算放大器组成。它可以将二进制码或BCD码表示的数字量转换为与其成正比的模拟量输出。% n7 |! ^: b8 p1 k) r# ?
0 d) R; O7 P; u$ W# hDAC的工作原理主要包括数字信号采样、量化、编码和模拟信号输出几个步骤。首先,将连续变化的模拟信号在一定的时间间隔内进行离散取样,即数字信号采样。接着,对采样后的数字信号进行量化,将其转换为离散的数值。然后,通过编码将量化后的数值进行转换,以便DAC能够识别和处理。最后,DAC将这些数字信号转换为模拟信号输出。4 k6 t4 ? X. H0 \0 n/ z g8 E4 I$ ^
8 ^6 ]# r; M+ ?* n: a, IDAC是数字系统和模拟系统之间的桥梁,具有广泛的应用领域。在音频处理中,DAC被用来将数字音频信号转换为模拟音频信号,以驱动扬声器和耳机,其性能对音频质量有着决定性的影响。在通信系统中,DAC用于将数字信号转换为模拟信号,以实现信号调制和解调。此外,在仪器仪表领域,DAC也被广泛应用于各种测量和控制设备中。
X9 M3 M" g, _7 ?# W
$ t% e, c3 }% H, f
: w3 ^0 U7 G! a8 _. M1 Y: i: }3 q
STM32中的DAC(视芯片而定例如F407ZGT6是2个DAC通道,有些芯片不支持DAC功能)支持12模式的数据输入,可以双通道同时转换。9 G+ B& r' j5 T$ u! \& B, [
$ E+ A; o6 k% y& ?' A/ c1 u! g( e5 M" O
本期我们将介绍如何使用STM32F407和CubeMX利用HAL库实现DAC的输出。(本来是想使用C8T6的,结果突然想起来C8T6)没有DAC。
7 d" S" s s3 i
" m9 P: \; V1 u( Q$ U, w) |+ RCubeMX配置
$ f: u4 V. s8 G# a# F8 l$ O6 t3 U) p; t$ h' X% \- g: y' D5 J
9 l" w! H7 w! B* |' W1 Y2 T$ ^; f8 ]$ n- i/ Y, z4 l
在DAC通道中开启DAC,在F407ZGT6中DAC1对应PA4,DAC2对应PA5。9 N$ `- ^0 ~4 q$ U e7 G. ^
' m8 Y4 o3 _- ]5 u" q0 b
4 z& A4 T# K. r5 d( r: s( H+ T; E! F& L" Z% p& b* N% e# B
OutputBuffer这里设置DAC的输出缓存使能,Trigger是DAC是触发方式,这里我们选择不触发(手动写入)。2 p+ U' ^1 _/ N( O$ |9 R
; a* W6 r, o9 `5 D @
如果选择触发的话是从缓存区写入数据。0 Y3 }' Z9 j3 \1 l9 y) a% c1 Y
$ T9 J, X. q" K! y/ h g1 j4 L: S
2 z$ e. Y: q! R+ g( m+ r4 a7 U
$ D8 F1 G n$ H6 `
这里顺带加一路ADC采样,因为手上没有示波器,所以使用ADC来进行查看。
$ P* z: G, j: d: M; k p3 r! s
; @: D9 x- D: O5 e0 @! ~: d这里使用DMA进行采样,具体可以参考公众号之前的关于DMA+ADC采样的内容。6 ?. V6 `1 F* \0 j/ J U- ^9 G
) @+ a" ]. i+ {) U! ySTM32的DMA采样+FFT时域分析(STM32F407)
* A8 h2 b, v. U4 k
! I2 @" j3 w/ |% A3 Z% @# {, e但是相比于之前的,需要更改一些设置,首先是DMA的设置
+ h# p1 J9 v0 G5 u9 |
- [9 n; V( _2 m7 Z. C" @
3 J9 C8 P1 A- G! l% }& v* M: e1 c$ B. _0 L2 ]) `( U
这里设置单词请求,而不是循环模式防止数据跑飞掉。
" S0 _ ]( f; v0 G+ z5 ?9 o( x, r6 c8 w9 Y4 a( `6 w0 `' H9 j
9 N) m( @1 |; H1 J( a a+ w* G- MX_GPIO_Init();4 H; C. r) k4 k) {- Z$ u
- MX_DMA_Init();
/ R( _: R3 s: @4 Z! m* S - MX_ADC1_Init();
$ m% ] H% A, c3 z4 ?2 ]& P - MX_DAC_Init();
! ]5 q4 b6 E. t - MX_USART1_UART_Init();# y+ F4 K9 R. ~5 l$ P' r4 |
- MX_TIM1_Init();' P/ w; \. I. r" B' D$ c4 b; ~5 j
- MX_TIM2_Init();
/ {, x& M) _ |3 d; m - /* USER CODE BEGIN 2 */. } Q. t2 ]' @# m/ \) X9 `
- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //用来触发adc采样
& l$ j3 y4 @& k1 q. H: E - HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC
9 y9 b4 x5 D4 t6 |3 v - HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
( A, L* M% l/ X' x - /* USER CODE END 2 */: | s8 A1 v$ L3 C- F
$ F& l' Q% g, c4 r3 F: C- /* Infinite loop */) \, s' @2 i8 {
- /* USER CODE BEGIN WHILE */2 h( N& x! r3 i. L
- while (1)
/ S, A; j6 Y, \+ y" c$ s - {4 c! D6 Z% e: Z$ H5 }
- /* USER CODE END WHILE */1 Q R+ i' O( j3 Y
7 V0 x0 w& l0 v- /* USER CODE BEGIN 3 */
8 f' r4 H7 P+ r; b4 P - if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0))$ n3 V, n1 ^4 K. M
- {
@$ S$ p4 W O- Q! |% Z - HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC9 R6 g- t; E* C0 z
- 2 C6 @# ^/ U" W
- HAL_Delay(20);: N; ~8 D! h3 S/ [; J
- 0 i& E [: `& h1 z! p" I# [
- while(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0));, H: `$ N9 e. [" D4 t( H
- HAL_Delay(1000);
, \. p, f3 A# w2 |; e - for(int i = 0;i<ADLenth;i++)0 b& ]( z5 P* c. p) R
- {+ G& e3 u$ A, d( S1 b, |8 ^
- printf("A:%d\r\n",AD_Value[i]);$ w! p' V1 I, Z$ _# P ~5 q& Z4 U
- }& E6 o$ J5 P+ w @; T
-
& d) G1 y& M' Y+ Z8 R+ |# M -
/ p& _+ Y5 V# _- x - }" a, ?2 F7 c, {9 \ F' ]
- }
* E) _3 b- S1 P3 g9 S - /* USER CODE END 3 */( k; g, e/ i+ } K9 M
- }
复制代码 : `% f% P: e1 W$ e+ `
; W( h$ q& T5 F0 ?% I我们编写一段代码。! a2 m. B" h7 d, U
7 Y$ I0 ^8 Z# H; j0 L; r按下按键的时候设置DAC的值,开启DMA传输,再加上ADC采样,之后输出结果。1 f# @4 U8 {' S0 c9 G3 N6 ~4 B1 Q
+ G% `; O0 {$ d" j
8 x$ F& g9 ]- Q
3 a' y) a4 ~9 A! Y) i可以看到,我们按下按键之后,ADC的值会呈阶梯状上升。
6 @; v7 O( e6 p b! c# U; I! l
- c3 B7 ]2 L. p8 a E( m7 c# Z三角波发生器/ f$ Y- ?* ], `6 T
1 M/ f) o) p8 x
. n" d0 E* i } _6 {! ?% Y6 ]
# Q9 ]5 F& d+ v1 P: D6 E8 k6 S在DAC配置中打开波形发生器,触发方式选择定时器2触发,三角波最大振幅511。
6 T) Z+ h- C% X* ]- C1 _ Z: ?1 O5 u* c0 g B, Z
/ a: i. U" N( w
+ ]* B( f4 t# p F) B7 \之后开启定时器2,由于ADC的采样率是1000HZ,因此根据奈奎斯特采样定律,信号的最大频率不能超过500HZ,因此我们使用100HZ的三角波。
: O4 J" U% Y9 i# [9 k7 Q5 n' u. N5 M0 v% {) L% ?" M" e; U
" L; ?& N8 g- R s' y( d4 B
+ K' U v) P9 g5 j3 O9 h( J定时器设置好时间之后,设置触发事件。
' B2 O/ e+ N% ~/ H8 d* k: y6 O# Q1 T. j3 W" {) \# h5 B
1 b0 h- L/ ]+ y" [! A
# e5 Z3 r1 y9 x3 o* q6 E芯片手册中简单的介绍了一下如何计算三角波的频率。当触发信号发生后,内部计数器的值就会+1,所以频率可以用如下公式计算:
/ p- x; ? M. _2 l0 K2 J6 l9 B$ f, ~9 [; Y, x6 t( \
定时器频率/分频系数+1/Period/三角波最大值/2# j- w# W* p B, \: `; Q
6 u# ^, J: v/ [
- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //用来触发adc采样
7 ]$ |1 }% O5 H - HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //用来触发DAC输出" _+ \: v; D; B/ n; n+ b3 t
- HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC
% d' ~: N7 y. w* Y - HAL_DAC_Start(&hdac,DAC_CHANNEL_1);4 }7 }* K1 C8 e( _* W, i
- HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_L,0);//设置直流信号
复制代码
2 y- U/ s7 Q; B* f( q/ \+ [# J
1 N2 E+ b2 U. Y
, m F4 U) c' r3 W正弦波发生器1 x, \. Z4 S" d: e( M
: ^' [1 E! z; }! R/ B& M H2 v
- z) P5 O" E3 n: z; p$ z+ }; i. b& H. s# l! K! } c: Y
首先是定时器触发(方便控制频率)。但是关闭波形发生器。! G* E- J! P: h: G
& b5 ~/ e$ a& C9 G% h
( w; t" ?- x2 Y4 ^9 |
2 m U5 y# p. F添加DMA,模式选择循环模式。
% n; y% V( i, J- E
+ Q, a# ]1 V h% M还有改变一下定时器的频率!/ s3 x, C% s6 V* R9 M, t$ ^
2 ~$ g1 G3 T) T- M* h! M$ v
其他几乎不做改变。
# G8 }, k/ c% I; ~8 ?- D% ?
! O+ d& `( ^" ~6 L. R+ b; e, ?
0 G* t1 C$ L! L8 Q, w% l* H- #define POINTS 256
7 Z- C: V! L2 T, c; g - #define MIN_VALUE 50
, q' ^, h3 M2 }) Z U - #define MAX_VALUE 650 + N* b7 K2 v, `3 M( D/ _3 S3 k9 u+ F
- #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0)
5 F9 c7 a4 ]6 W- t1 B* C! P1 z - #define OFFSET 50
' Q" C% H2 r, o9 E, m; V! k) ^ - #define M_PI 3.14159265
/ d* U( {) f, P8 ]8 x- w -
" J. a3 |9 c# r, O7 y - uint16_t SinWaveInt[POINTS];1 m6 A- r5 s* k8 s% t
- int SinWave[POINTS]; - A' V$ Z: r' b3 J" j9 s+ }
- void SinInit(void) ' I' f. M( D6 t) X! n: r7 e2 M9 }
- { 5 p1 m; N7 I9 U% s
- for (int i = 0; i < POINTS; i++) ' m, V" T; l3 w$ o$ `7 B' n8 X: i
- { # u, U- ~% S0 C0 b4 T9 W, [, ?( U: G" l
- double x = ((double)i / (POINTS - 1)) * 2 * M_PI; - l+ ?+ X V1 \/ I
- double sin_value = sin(x); // 计算正弦值 4 R# U$ ^8 d8 s# Z
- SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET);
2 {% b/ o- _) c7 K4 {9 }/ D% O - SinWaveInt[i] = (uint16_t)SinWave[i];
" I* c, e* M- z1 t: v - }- y4 @; U5 Y6 f; y/ x+ w. g6 r
- }
复制代码 + ^+ B5 H) q# o9 b: e" B
计算一个正弦表。
' {/ b$ {" m$ K/ L. ~* Z9 s7 C) [" T) g# N" r6 d& r
这里的Points决定了分辨率,结合定时器触发频率决定了正弦波的信号。
5 z8 y" R o% n6 K# b- Q0 Z, z& x( W: i: I% p7 z
& d& i w3 ^' B ?9 C) R/ z( H ~8 H& \& |6 `
测试一下正弦表,输出的是正弦信号。
# X x }9 u j0 ~. M; b
+ U4 v3 R: e& @2 v; k我们之后将正弦信号表导入DMA中。4 V4 x4 j! h9 `2 P l
, P% B3 |8 b$ F+ p$ w5 g; s2 E1 _- SinInit();
9 g/ x4 J) `4 O' A3 U - HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)SinWave, POINTS, DAC_ALIGN_12B_R);
复制代码 4 l0 d# W; I1 U
正弦表初始化,之后启动DMA传输,导入正弦信号。' }4 e+ {( ^3 s) _7 r5 F& i/ q+ n
8 w; k5 J6 Z/ L) A% D9 G% A
5 R$ w: w& O/ c; F; j) e6 D; g+ }
( ]5 p7 W% c4 c3 d! ^8 l
测试正弦信号成功。: ]' I& y4 z" ?. L. H
9 Q V/ l3 i w8 GFM调制- #define POINTS 1024 + C4 P7 A+ p4 N
- #define MIN_VALUE 50 # M: y/ ?" F/ l0 z
- #define MAX_VALUE 650
* n: K' S9 n% F8 C; J% u/ x4 V - #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0) ! N) l% q, D% A1 ^/ \5 r9 W6 {1 }
- #define OFFSET 50
o! V# c7 W6 B+ F - #define M_PI 3.14159265
( g; s) _& \$ H/ Y4 m - , a/ M& g" l% x& a
- uint16_t SinWaveInt[POINTS];4 [( K! c; z( K7 ^/ p" e; Z
- int SinWave[POINTS];
$ Q! e' J: G4 {0 v4 P) q) A. e - void SinInit(void) " V+ a5 {* O( G: S/ T1 c- f
- { * @2 l3 j3 k/ M# c" W
- for (int i = 0; i < POINTS; i++) ; H5 Q1 ?: r x& F3 w5 b0 ~5 G
- {
' i- f& g/ f1 W+ n" G - double x = ((double)i / (POINTS/4 - 1)) * 2 * M_PI; 9 W; _$ n: x; ]) }0 v% t
- double sin_val = sin(x)*sin(x/4); // 计算正弦值
: b5 b6 Q. G, X: R - SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET);
8 W, f* F7 b6 [! ], Y - SinWaveInt[i] = (uint16_t)SinWave[i];
! R+ ?3 k: a: E* g! n; ] - }0 x! @% x0 Q) D
- }
复制代码
% g8 ?7 E7 B# P$ i
0 T) g! _ d+ F) Y1 s& T拓宽点数,加上载波,即可构成FM调制信号。: r$ [; {1 O6 X+ P# ^
, ^ y- M1 A# ~+ x* f+ n g
7 [1 p$ H/ q% y! q7 b# n, j( _) P. T/ p N; N2 x# E" {6 p1 y4 _ T+ T8 U: G, w
- ]1 e9 b! v& Y/ n* F
转载自:电路小白$ M- w0 }. D W+ W
如有侵权请联系删除: d# }7 M8 |4 v; g! w j
' S, r* L5 v3 F+ r: \' J
{$ ]" i, B0 u; p- j0 w3 H) G
|
资料不错,值得参考学习。
dac+dma?