在DAC的主要特征中可以看出,DAC内部带有波形发生器。
# j# O- ?* h' E# f% e
' U/ v8 N5 j. S6 P7 `3 QDAC 主要特征
! F! m+ {, o% e- Q* F- p6 u2个DAC转换器:每个转换器对应1个输出通道- X, @& E2 S0 k, K% A. p0 w
8位或者12位单调输出$ G+ N* p9 Z% P8 Y
12位模式下数据左对齐或者右对齐 f/ ^7 X- |! w* r6 }- k
同步更新功能
* c8 x/ X9 X( \: k! V( J. Q0 s噪声波形生成
% {9 G4 Q) E0 y- H0 H9 [三角波形生成
! S. D; F0 _* O! B9 e双DAC通道同时或者分别转换. v: V: |, ]6 s( E F) T
每个通道都有DMA功能
+ I3 W0 o) A0 R1 L" w# n外部触发转换$ G8 e( _. C+ V" `( `- b1 X
输入参考电压V REF+& e5 _4 e' e2 x2 p& ~4 r, e
但是这里面只有三角波和噪声波,那么正弦波要如何生成呢?6 m$ H6 e+ H0 D
" E4 O! ^3 S% y8 y& W虽然DAC没有自带正弦波的功能,但是我们可以先生成一个符合正弦规律的数组,然后通过定时器,将正弦数组中的值依次发送出去,这样输出的电压值也就会成正弦规律变化了。; h( ]" d' N- B
7 M. h7 F7 \& q 下面直接通过代码来演示如何输出正弦波# f# D l ? e: E
, n8 |8 w1 G- B& S
- #include "dac_sin.h"4 P+ n* X: Y3 p8 Y
7 B" T- @( m( h- #define DAC_DHR12RD_Address 0x40007420
- x3 @6 L5 j( D! b
) [4 S( [8 Z6 ?2 K0 C0 b7 b8 Y
) _7 n. Q4 l, z1 R& H: w- uc16 Sine12bit[32] = {2047, 2447, 2831, 3185, 3498, 3750, 3939, 4056, 4095, 4056,
" B3 h$ a2 ], ?/ s - 3939, 3750, 3495, 3185, 2831, 2447, 2047, 1647, 1263, 909,
6 I# ~( A" s5 G5 O! V$ R9 T - 599, 344, 155, 38, 0, 38, 155, 344, 599, 909, 1263, 1647
1 r. k. a t6 Z, ^5 N1 w2 K - };
$ P8 d9 c4 h z- H
2 D) k) s G. p- u32 DualSine12bit[32];
" p. w& {+ I5 L' m3 o; u - u8 Idx = 0;
: f' N! B$ y4 _6 z1 x - }* H( ~5 e8 j4 I
- //用DMA在PA4、PA5上产生正弦波
& K, E5 k6 J. I4 \+ r% Z U( J - void DAC_SIN_Init(void)$ J0 w8 N0 @) s% u# Q# J( O
- {
/ r, O3 p U9 Y) V - GPIO_InitTypeDef GPIO_InitStructure;9 [' T1 l/ l9 ?/ `4 h7 O* f
- DAC_InitTypeDef DAC_InitStructure;
, A& e. ]) G! ?* B0 n - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;8 s( X% F* C/ {$ M
- DMA_InitTypeDef DMA_InitStructure;0 }7 X# @( @ R2 P: M O
- //时钟设置3 e% F) T$ F% d- {# }/ u# v6 D
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);2 {! b: D @7 d+ z# |0 R& G6 I
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA, ENABLE);
) H- p* }1 \# l1 a - RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);. y# R X( L6 L# f2 X$ k& x
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);: b9 c; E8 F/ `8 e( w
- //GPIO设置# a1 F! M3 b% y
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
& J3 i# L9 o# [$ m; K - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;; W5 h7 T( J O0 C0 {7 k3 {
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
( V( X4 g2 }' I# o0 O6 k/ R2 b( y( z - GPIO_Init(GPIOA, &GPIO_InitStructure);
, |# E0 h5 t3 j+ j - //高级定时器设置' x$ X4 |% a) }! i+ z% p9 ]# ?! G
- TIM_TimeBaseStructure.TIM_Period = 0x19;
0 V% P$ X7 S- K* F. H% B+ H - TIM_TimeBaseStructure.TIM_Prescaler = 0x00;& ]) e! N, q" j4 _* G& [/ ^# o* S. |
- TIM_TimeBaseStructure.TIM_ClockDivision = 0x00;
& ]6 D3 D2 ?2 N/ {7 V - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
0 n( g( N4 z' ]- p - TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x00;
: V2 A9 v4 u t n6 r# T - TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);
/ N8 j2 t g6 w) u& F' N2 s0 ?8 c - ! J9 t# V7 d* Z# f; a0 n
- TIM_SelectOutputTrigger(TIM8, TIM_TRGOSource_Update);" a9 r+ A, W8 W2 C
- //DAC设置1 I- `5 |9 K; k
- DAC_InitStructure.DAC_Trigger = DAC_Trigger_T8_TRGO; //TIM8触发
) P3 V% l8 a+ H: b7 ~ - DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;: D# X* ~3 ?/ U% `- L
- DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
, l! o' A1 S# z5 F - DAC_Init(DAC_Channel_1, &DAC_InitStructure);$ }2 e) @- T1 q+ m; G3 J
8 A' o( n" v4 ]3 W/ {- DAC_Init(DAC_Channel_2, &DAC_InitStructure);
9 H! Q* {7 R7 o) x- V0 H0 C - 7 W. _8 N9 `3 {" K) O
- for(Idx = 0; Idx < 32; Idx++)
; b) O' s$ o: i - {1 \1 T% k4 R. _; Z2 i
- DualSine12bit[Idx] = (Sine12bit[Idx] << 16) + (Sine12bit[Idx]);
# J# [# l4 p2 g4 y - }- _& L4 R$ j Z u
- //DMA设置/ H: b# k; B' Q o3 R3 _% _; p7 G
- DMA_DeInit(DMA2_Channel4);
% z7 z) K( L2 E - % J; J B$ g. d
- DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12RD_Address; //DMA外设基地址
4 p& H$ F& e1 ]5 R7 {0 k& ] ^ - DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&DualSine12bit; //DMA内存基地址
- o6 m/ g( z/ g4 m E- P' l5 V - DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向,从存储器读( t9 Z9 n- X( R3 L' g: I. Z% z. @# J2 K
- DMA_InitStructure.DMA_BufferSize = 32; //DMA通道的DMA缓存的大小
3 H( I) c6 B5 P/ A ~$ P0 o5 r - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
4 Q* E% @6 Q8 N: z) n - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
/ a4 a5 x3 Z T$ p0 d - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //数据宽度为32位
8 }8 p4 \8 s7 G9 x2 ^ - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //数据宽度为32位* S( }1 `- J; m
- DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作模式为循环模式
2 X& e/ X5 L/ f7 R - DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道 x拥有高优先级
1 q0 j+ ]7 U6 k" A2 x% T# N - DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x 非存储器到存储器模式
7 [2 j0 E: q; l - DMA_Init(DMA2_Channel4, &DMA_InitStructure);
+ M. w: j2 C: B( ` - . c6 P5 F1 W7 A+ w3 V
- DMA_Cmd(DMA2_Channel4, ENABLE); //使能DMA2通道4, A4 f' e+ [2 D& l1 @; S
- ) j: K E$ X8 V& c; W
- DAC_Cmd(DAC_Channel_1, ENABLE); //使能DAC通道1+ m* l" N' ~6 B( T" v, f4 j7 U
- DAC_Cmd(DAC_Channel_2, ENABLE); //使能DAC通道2
W4 c# i& J) j - 6 ]# B& W* {( j! I) L
- DAC_DMACmd(DAC_Channel_2, ENABLE); //使能DAC的DMA功能8 c, D8 }5 ]1 j# `) B; B4 C" O
4 W/ V) o: `) t- TIM_Cmd(TIM8, ENABLE); //使能定时器
6 r9 _6 G3 m: V) Z5 N H; s* Z - }
复制代码
' c- ^1 E/ ]7 W3 aSine12bit数组中存放的数据就是按照正弦规律变化了,可以将数组中的数据复制到表格中,观察一下。
8 E6 l$ Y% R( B5 g$ B- d! F- K: P5 X$ I
* V, A: X" D( a3 |; ]
1 J- n" q. E# c) w8 D
可以看出数组中的数据组成了一个标准的正弦波。' _/ I* {* l+ B5 d; D
! e- T- p. r/ x% W' A& r 数据有了之后开始初始化DAC,这里DAC依然使用定时器触发,使用定时8触发,波形的产生方式设置为无,因为这里不使用内部的波形发生器。
4 l8 l* g9 a) @$ ^# |3 `$ _8 |+ O/ t- D }
接下来数据的传输选择使用DMA模式,当然也可是通过程序设置一个循环来依次将数据中的值放到DAC寄存器中去,但是这样比较占用单片机的资源,为了节省资源,可以让单片机自己来实现这个功能。
0 [) h9 w# e1 X% K- q
7 {7 n* j5 ]4 @3 u
; K- f3 U* [% {1 E' v0 J- S/ ~& k+ ~* R2 j0 }) D
将DMA的外设地址设置为DAC寄存器的地址,将DMA的内存地址设置为存储正弦波数据的数组,这样每次定时器8的中断发生之后,DMA就会自动从数组中拿出一个数据设置到DAC的寄存器中。通过DMA功能就可以实现数组中的数据依次被放到DAC的数据保持寄存器中。; Q( x+ z5 `" u, g+ \5 {+ C
* N9 v; X+ p: v# F2 e
最后使能定时器,DAC,DMA功能后,DAC的两个输出端口PA4和PA5就会自动输出成正弦规律变化的波形了。6 y' h9 O2 u2 y3 x- O
: U5 z. l, i3 _6 p W. Q+ z. V, C$ g- E( q# f
|