DAC,即Digital to Analog Convertor,是数字到模拟转换器,也称为D/A转换器。其核心部分由R-2R电阻网络(也称倒T型电阻网络)、模拟开关和运算放大器组成。它可以将二进制码或BCD码表示的数字量转换为与其成正比的模拟量输出。
7 F6 K+ \4 `9 Y& Y; y4 Z# M0 Z& w' ^8 E H8 F% b
DAC的工作原理主要包括数字信号采样、量化、编码和模拟信号输出几个步骤。首先,将连续变化的模拟信号在一定的时间间隔内进行离散取样,即数字信号采样。接着,对采样后的数字信号进行量化,将其转换为离散的数值。然后,通过编码将量化后的数值进行转换,以便DAC能够识别和处理。最后,DAC将这些数字信号转换为模拟信号输出。
. V* r) Y4 [3 ?" b3 B$ E6 @ p+ N) c" ~/ m
DAC是数字系统和模拟系统之间的桥梁,具有广泛的应用领域。在音频处理中,DAC被用来将数字音频信号转换为模拟音频信号,以驱动扬声器和耳机,其性能对音频质量有着决定性的影响。在通信系统中,DAC用于将数字信号转换为模拟信号,以实现信号调制和解调。此外,在仪器仪表领域,DAC也被广泛应用于各种测量和控制设备中。
3 F8 A4 W9 `9 j7 ~% Q' K
4 |. J% f* i6 k% w
1 E# {" n# y9 L
: {! v D ]6 M7 c3 Y& } a
STM32中的DAC(视芯片而定例如F407ZGT6是2个DAC通道,有些芯片不支持DAC功能)支持12模式的数据输入,可以双通道同时转换。
- f) T# X& J- M* t4 Z( K- _( p6 @6 Z9 `/ O$ v
本期我们将介绍如何使用STM32F407和CubeMX利用HAL库实现DAC的输出。(本来是想使用C8T6的,结果突然想起来C8T6)没有DAC。
. k, F0 [. _) z, B: G$ R. H3 Y; c1 F5 K% e# l
CubeMX配置
) d# C5 G. w c. X/ ?
) b2 U1 S+ R: e" b! y, S
) U. J5 A y/ N5 u9 E; o% o2 T. v+ m: D- f
在DAC通道中开启DAC,在F407ZGT6中DAC1对应PA4,DAC2对应PA5。7 U. B1 Z' p! f+ g! r" I
+ t! ^+ u' _# F. J4 L2 |& X& l& m
0 s9 I" x2 t! h* ^* S( G# K" o
# v6 |$ a# E. w% \ O0 xOutputBuffer这里设置DAC的输出缓存使能,Trigger是DAC是触发方式,这里我们选择不触发(手动写入)。9 ?- O- e( i3 f# E. a/ _
+ E% b" ?+ W& ~$ b+ Q: `
如果选择触发的话是从缓存区写入数据。
N/ i5 l5 i0 N% Q/ m. y- W" ]1 z, |5 S# o3 h9 c: h
. O/ M4 s ?5 W! u, Q* J3 a$ {
8 ]2 W; i* x6 e$ q: n5 u这里顺带加一路ADC采样,因为手上没有示波器,所以使用ADC来进行查看。+ w: V4 Q3 ^& }2 V9 @
9 I6 y$ {3 H2 h# M这里使用DMA进行采样,具体可以参考公众号之前的关于DMA+ADC采样的内容。
' B, O+ N8 A2 c( X% o" b0 V2 y2 x! {& J2 X
STM32的DMA采样+FFT时域分析(STM32F407)
9 b/ R& g7 V+ H0 H$ ~- t m: R
- h8 f4 f J- m( l W0 n9 z8 h但是相比于之前的,需要更改一些设置,首先是DMA的设置2 b# _6 o' j; T' @
" y3 K' b7 c! r8 c
( U0 l% [" D% _
: D: S- w2 y; n1 |6 D2 _% h
这里设置单词请求,而不是循环模式防止数据跑飞掉。
% c" |0 U6 _+ }0 f$ Y5 u. p1 f$ M5 u% [6 w' V }
O& Q& K) F6 C; ^$ r5 |- MX_GPIO_Init();
5 U) u$ V# L, k! I6 S1 B; E: z$ T - MX_DMA_Init();
6 j5 H3 g1 \$ ]) l: ^9 K7 ]. g0 \ - MX_ADC1_Init();7 R8 A& p: z7 `6 {/ d3 n
- MX_DAC_Init();
9 F' K& ^- y, C/ U; s* o. l - MX_USART1_UART_Init();
6 L; J3 R$ K! u3 I9 s0 D8 l - MX_TIM1_Init();
4 J/ N' R) W. X8 x5 [! D- n1 _0 s - MX_TIM2_Init();3 C% a5 Z! A4 e1 C
- /* USER CODE BEGIN 2 */) k: V3 n# n- B& I$ ]+ [2 [
- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //用来触发adc采样
2 S- Y( h, P6 S4 Q& J9 ~9 A - HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC3 e( h/ ~3 C' ^4 F
- HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
# |8 I+ M5 h+ x* |% |) p6 @ - /* USER CODE END 2 */8 |7 U; B; P3 l
$ r/ Y! R+ m/ M0 p' n( @4 K: Y- /* Infinite loop */
9 a# K; m8 c- r. v1 e$ d; v - /* USER CODE BEGIN WHILE */
7 r3 ]7 z; t# Z) X: F - while (1): V" g J/ h! Y; {7 ]
- {
7 I- u5 U6 v6 f/ F - /* USER CODE END WHILE */# z; M" K" L2 O# f( ~) Q
1 T9 b% @, [9 J+ m$ [; s3 b- /* USER CODE BEGIN 3 */
( b2 H; w5 \3 V( N5 e - if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0))
! J$ t c4 d! _) P# | - {# M3 T. m$ _. y0 F: Q3 T- z
- HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC6 n" `. M. M( @* A
5 ]9 Y" c0 m* Y- n) O- HAL_Delay(20);
( h; r& F1 O ^/ c5 e5 _( L. K -
, G9 E) G$ J3 f3 ~9 x9 J4 D4 M, r8 g - while(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0));
9 E c# [; W% U: b - HAL_Delay(1000);" S7 l% `1 w$ b
- for(int i = 0;i<ADLenth;i++)
) M: p" H2 e H - {
1 j& _/ w8 }1 z+ A - printf("A:%d\r\n",AD_Value[i]);8 X/ M7 O. A; p" G/ [! @
- }: U1 M: s" I% ]% b
- 9 c% D# @0 ~4 v- c! R! O$ [+ t
-
" `- n6 D6 v4 V3 F5 R, M, F3 V( e - }
# b9 y( {$ R! N - }5 r6 w2 h% N7 O1 O5 I" O
- /* USER CODE END 3 */
& q M2 I6 L& n6 Y( B5 E% y - }
复制代码
8 m; W; i+ A1 @0 N+ k; A0 [
4 W, ?' R& j7 x( [1 t我们编写一段代码。4 G$ z9 b1 M9 r# M7 R7 { A% X; i
. g; d! L+ T* o* W3 f( g8 O6 ~1 S
按下按键的时候设置DAC的值,开启DMA传输,再加上ADC采样,之后输出结果。
Y$ z- E7 h2 f& ~& ]/ L1 F9 e: i" k( B; X7 X$ P3 j _: }; Z8 w
/ a" J% s8 } s; g5 j _0 {$ g! U% o
( e, `: S8 E; L
可以看到,我们按下按键之后,ADC的值会呈阶梯状上升。
6 M- u$ }3 j$ l/ D! S! j! m' f8 E7 T7 J
( r" a. Y! s; K/ |/ r, S三角波发生器; s; O2 E1 s. _. i+ T) I
9 w$ `' G) }8 i$ f) s
1 n% V/ q8 }- \% T
& O, \( H& P0 M8 q/ `, s% g在DAC配置中打开波形发生器,触发方式选择定时器2触发,三角波最大振幅511。
S8 a: P0 h/ q, }+ Z
4 B0 E- K9 c0 R! \" J
' E! V9 e+ J/ c' G9 [/ `
) E9 d M2 H; N/ g" \之后开启定时器2,由于ADC的采样率是1000HZ,因此根据奈奎斯特采样定律,信号的最大频率不能超过500HZ,因此我们使用100HZ的三角波。- K, m2 F' w5 [
- G3 \" }7 d6 P
8 C" z1 |& H, b+ @1 r6 t; E" O; s2 E' W
定时器设置好时间之后,设置触发事件。8 D0 b6 g. f+ {& O/ r' U
- j8 \3 _7 _- D# }1 a
; x" T0 \; P, F. M$ k+ b
9 o" q/ m1 ^4 \2 F9 [! Y3 |芯片手册中简单的介绍了一下如何计算三角波的频率。当触发信号发生后,内部计数器的值就会+1,所以频率可以用如下公式计算:2 `1 G7 D# c6 h. L. K8 x8 @
5 p3 L* L/ w' {
定时器频率/分频系数+1/Period/三角波最大值/2
; Q; j+ H; F5 b; n8 ?% Z: T& X; M
) r0 n0 V% D F6 M2 C4 {- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //用来触发adc采样
% J$ ?, a: s0 J! {- B - HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //用来触发DAC输出
2 f- A2 M# P) a+ u) r* p5 s - HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC+ m3 n4 J! K: m( ]2 I7 G
- HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
- Q, T) e6 ?$ s4 P: X2 F - HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_L,0);//设置直流信号
复制代码 6 P" j" P& [) l+ s
7 e; C6 r% e1 M! n
' W2 p: e- U& o) F正弦波发生器! W5 T9 K# v- J" i. K
7 b6 y0 Y+ t- e; j; u+ F
/ v+ z: q: Y, Y6 g0 g# T
( o; W2 V# j7 T! J首先是定时器触发(方便控制频率)。但是关闭波形发生器。7 L# @& X( l- v$ B6 e5 s& l
2 t+ P. o9 H8 E
/ H5 o' k: J: s+ I. i$ U( D5 x6 T' y7 V, o, k
添加DMA,模式选择循环模式。; {3 {6 w% L+ k. k
/ K: \* V# _8 b$ N4 y还有改变一下定时器的频率!) j0 S# W0 L N1 G: E
1 q7 [- l, R6 H, m8 ^* {
其他几乎不做改变。2 U# E2 Y9 N; Z4 X s
9 G% \0 t5 x" m, Y
* ]+ U5 c6 a4 o- #define POINTS 256 6 F6 F# b8 n, ?' V( K
- #define MIN_VALUE 50 / X. e; z8 c5 a2 ?" n! z
- #define MAX_VALUE 650 1 S3 } `+ C$ C. Y( J5 o
- #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0) % N0 M! A' R6 ^1 w+ q7 d+ Q
- #define OFFSET 50 5 H( Y$ [# a. A8 q
- #define M_PI 3.14159265* {7 s5 O5 j# u- e3 C- D: ?
- . L) u: c* v# `$ E" X
- uint16_t SinWaveInt[POINTS];
4 R# Z' g9 g0 M6 q) x - int SinWave[POINTS];
+ J/ u. a$ [; A" e - void SinInit(void)
; b: Y- U" Q8 J - {
2 W+ R0 X/ {5 l1 c& e. ` - for (int i = 0; i < POINTS; i++) 9 Z) X; c7 e \, F/ _( _
- {
4 [' w6 \/ G5 K4 i& r9 A1 X - double x = ((double)i / (POINTS - 1)) * 2 * M_PI; 0 C( p( N, _# T% h
- double sin_value = sin(x); // 计算正弦值 7 v6 |8 Z5 H7 y% d: n6 b
- SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET); 1 ^% p8 C1 H# o
- SinWaveInt[i] = (uint16_t)SinWave[i];
' _2 H) |; q; D3 ~$ E( A6 J - }8 C$ E9 D& e: [* g/ W$ Z% L
- }
复制代码 $ r+ K" M7 `# i/ Y
计算一个正弦表。; Q9 h+ W7 R& G; }& Z+ F
5 f7 a7 G- Q9 n: p3 m% i- q6 k这里的Points决定了分辨率,结合定时器触发频率决定了正弦波的信号。9 b/ \& \/ ~6 U4 p' }6 r$ w
. d! M# p3 }/ s" Z& M8 s" B7 A
: b7 a4 y& y, ~2 |
( I7 v. k W- |1 J测试一下正弦表,输出的是正弦信号。$ s: g1 ]* x, J9 k7 R. n: ?
! R; V( @8 q) E/ J4 v6 D7 k我们之后将正弦信号表导入DMA中。3 q+ m& f8 H0 \7 z+ U
/ D* {4 K; S. I. p E3 J& H- SinInit();
E; E5 O( j# d! U8 e" s$ O - HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)SinWave, POINTS, DAC_ALIGN_12B_R);
复制代码
# u* t2 H' i9 e5 v8 x正弦表初始化,之后启动DMA传输,导入正弦信号。
. [7 e6 D8 i' \2 ?4 l
$ r4 N5 L; D4 V0 h1 \. ]( Y$ y
: V+ a! P4 o9 c# p5 O+ r
$ g" C2 Y( t W a2 y( b, @7 [
测试正弦信号成功。( A6 a' R: e4 G# Z
2 g# T0 H& L; ~. d; R8 s
FM调制- #define POINTS 1024
; [5 ~0 U- e! | Q+ `, ~5 L' s - #define MIN_VALUE 50
" I. U+ p' k j* ^8 o; ^% ]7 o! p - #define MAX_VALUE 650
# C; s! [. f% f; i# `& X; N - #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0) - w; d x) P5 S: w2 H ^& S
- #define OFFSET 50 . R2 F$ E7 b! s! l/ P( d" j
- #define M_PI 3.14159265
+ H; a6 n9 T; j7 P$ f, O ? - ) c8 _8 V f) |
- uint16_t SinWaveInt[POINTS];2 }3 z8 d" k& x1 y1 b# w" R
- int SinWave[POINTS]; 2 z0 J. j% s' j, l
- void SinInit(void) 3 ?' g' |/ }4 n
- {
8 P$ \) G6 U" b" n% k - for (int i = 0; i < POINTS; i++) 0 c: J2 P0 y# x( R: x
- { 3 ^. O0 I; x/ {- W3 q. G/ ?8 W
- double x = ((double)i / (POINTS/4 - 1)) * 2 * M_PI;
& h, v$ I7 A O/ l - double sin_val = sin(x)*sin(x/4); // 计算正弦值 ) V, j- ?" Q8 O6 Z- L- b: g
- SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET); 5 u! n2 g3 A3 {8 u* Y0 M( g1 M
- SinWaveInt[i] = (uint16_t)SinWave[i]; 7 J& e8 c2 c3 j" U3 i
- }
" n* C3 Y/ d5 D# D4 d4 X$ ` - }
复制代码
; M/ t, S, D! X( }4 ]. f$ j! i* F. k" c+ c' ]% I+ `
拓宽点数,加上载波,即可构成FM调制信号。
m$ g. e4 G+ J( c9 |! \1 ]5 c, \2 Q9 L5 E- y3 Y
3 c5 p7 A' ]8 Z# M' \8 ? z5 ]/ R+ {* ^$ U! v4 ?3 c0 ^+ r% M1 Y, g
8 c& ?) f. u% S, x
转载自:电路小白8 u3 t2 `' v; P* Z
如有侵权请联系删除. `& m- f! v( L0 s1 U
+ p( s C6 v4 o
4 D; K3 i4 M, Y7 O
! d4 y: b/ {7 c# @1 X; N9 y( b& w9 j
|
资料不错,值得参考学习。
dac+dma?