59.1 初学者重要提示
8 o; n* @" ~* Z 注意STM32H7只有一个DAC,但有两个独立的通道,跟F4的略不同,F4是两个DAC。# E: i- S" A, H Z; E
如果仅使用STM32H7的一个通道,即PA4或者PA5引脚,另一个引脚没有做任何配置,这个引脚上会有波形效应。
6 i. M0 h) d: e$ ]" P. S STM32H7的DAC支持出厂校准和用户校准模式。特别注意一点,校准是建立在用户使能了输出缓冲的情况下才有效。
% ]# X. j5 y$ W STM32H7的DAC支持正常模式和采样保持模式,其中采样保持模式用于低功耗状态使用。
% X; B5 `. P% Z4 \ DAC的输出除了可以连接PA4或者PA5引脚,也可以连接到片上外设,比如运放,比较器。4 U4 G* i5 v: V* B
59.2 DAC基础知识# \- |4 {. }/ j$ O
对于STM32H7的DAC了解到以下几点即可:# ?) n4 j" m5 L5 y% |) ]% r
% Y& E' `% j B& J' o
STM32H7的DAC只有一个,但有两个独立的通道,跟F4的略不同,F4是两个DAC
$ T; g% \9 y6 j5 x- ]1 H 12位分辨率,双通道,支持独立或者同时使用。
8 {2 i9 t/ g" v/ @6 e: H1 X7 | 两个DAC通道均支持DMA。
0 I5 _% h) x2 D3 \0 ^! ^4 J 每路DAC输出均可与DAC_OUTx输出引脚断开连接,而且DAC 输出可与片上外设连接。
! k* }, i9 n( O: N& ~$ J 支持偏移校准,参考电压可以使用内部的VREFBUF,也可以使用VREF+引脚外接的电压基准。
0 w. K; |$ }! ?& D 支持噪声波和三角波生成。这两种方案不够灵活,所以基本都采用定时器触发+DMA方式生成任意波形。' A4 v% N) q0 u% u0 `: @5 c
59.2.1 DAC硬件框图
3 k0 o# J' Y/ |! H) Q0 M) E" s认识一个外设,最好的方式就是看它的框图,方便我们快速地了解DAC的基本功能,然后再看手册了解细节。框图如下所示:
0 s j2 W- w; _" f# \5 ], M/ ]/ ~' f, B- k
* _/ D; Z( b% x7 u
: C# m j( d7 M
通过这个框图,我们可以得到如下信息:
6 s8 m9 B. |$ N7 J4 H, A! z! ? l' N/ R5 A2 G+ J
VDDA
& _0 G0 `0 o8 p1 r9 X8 j) L用于ADC、DAC、运放、比较器和电压基准供电,这部分供电是独立的。6 l: e2 H! g) Q
7 `* ]" x* e* @# N" I( X( n
VREF+5 f+ P* h/ V' k$ _4 {
用于ADC和DAC的基准电压,当使能了STM32H7内部的电压基准,将使用内部基准供VREF+,VREF-。如果没有使能的话,通过外置电压基准提供。+ b; S8 g2 t m( Q$ v
8 N1 r% U$ t& m# \% l. u! m& |
VSSA
! H5 X. n7 R, T1 w L6 G7 r; ~所有电源和模拟稳压器的地端。
* N* \- O$ }0 H
|- ^2 k/ n4 g) R$ a9 Q G dac_ch1_dma
8 \& A+ T8 d9 _- KDAC通道1的DMA请求。" \! x2 }! p% I. Y; \) C# }* A
+ n: F9 j; i! J9 E' i, y: Y
dac_ch2_dma
9 m; g$ v+ G2 f8 s. pDAC通道2的DMA请求。
f+ z" Q. p2 C ]
3 `8 [& J/ K$ B1 e. S/ \; S dac_ch1_trg[0:15]# K9 a( n: q- X! [. L% j( N
DAC通道1的输入触发。; C/ r7 L, B2 v8 z' m
! s4 C" J; Q+ i: | dac_ch2_trg[0:15]
, P) `7 {9 l9 c! F9 B7 ^/ k2 B5 gDAC通道2的输入触发。- Q) {, G8 t8 c: c. Q7 O. n' f, K
- R* ]. [" s; m dac_unr_it
2 o5 J& W' {7 @% A2 q1 r6 `( T! o* _DAC输出的下溢中断信号。
- H9 A3 B! B) u8 ~- F7 c
3 k0 V$ ?- q9 x5 O4 V dac_pclk
7 ?' ?* L8 C# L7 `/ F0 g: `2 h. ADAC时钟输入
2 V B$ E* S2 Z" L4 I; N
: a- B5 @/ u3 z, ]0 K dac_out1
7 H% ?1 ^' ?/ U: k& l0 {DAC通道1输出。
8 F6 u _; @) s* f2 r8 K& I% Z! _
dac_out2% t- F4 g( `% ^# i" b
DAC通道2输出。
7 @! m1 \( ]' \, G+ x5 ]6 I+ {# a4 o5 e& a8 A/ U1 |- g5 D
lsi_ck$ @4 H% L! L4 m
使用LSI时钟源,可以让DAC在停止模式下运行。
* n; w& ]3 C, e. B6 y$ B, }3 D" e H% V' S
59.2.2 DAC数据格式和输出电压
* P8 u( V1 M; y- L) J3 ?DAC的数据寄存器设计比较灵活,每个通道都有一组单独的寄存器(下面是通道1的寄存器):
$ c6 r. ?8 i2 `& i0 @2 S! v% ~( k; A. t9 V5 ?* M; c$ R/ h% g
8位右对齐数据保持寄存器DACx_DHR8R1。% ]7 E l( y7 b3 k* ^* k4 U+ M5 C
12位右对齐数据保持寄存器DACx_DHR12R1。
?, ~! ]) l! F6 @0 K: q1 z1 t- X 12位左对齐数据保持寄存器DACx_DHR12L1。
% t, F. _; d) I' e* |0 H! r9 h, o% t
# S0 y- p5 b$ ?& P
除了这种单独寄存器,为了降低带宽,也支持两个通道公用一个寄存器。: o; w6 X9 L) [: l- T* P( M
% _4 j$ G% S! w- B0 C1 N" i
8 位右对齐数据保持寄存器DACx_DHR8RD。' T5 [) _! S3 B
12 位左对齐数据保持寄存器DACx_DHR12LD。( s9 } f- o" B/ s" s
12 位右对齐数据保持寄存器DACx_DHR12RD。" m8 ]9 V8 e4 U G
通道1和通道2共用的效果如下:7 d5 p# h1 h; O' n1 h
" A9 V! ?- o( w# J- T9 K# y- t
( i1 i3 j# d. O* F
4 y4 y6 O: o w7 |由于DAC是12bit的DAC,那么范围就是0-4095,对应的输出电压如下:% l: y1 e2 H* m1 m- @5 i% _5 f* x& n [' X
t2 c/ b- c4 Y3 F6 m
DAC Output = Vref *(DOR / 4095),其中Vref是参考电压,DOR是数据输出寄存器。
& [) X! v* \' y! C* }
1 {* f# j! y- F$ `: t: v比如需要DAC输出0.7V,那么假设VREF+ = 3.3V, DAC_OUT1 = (3.3 * 868) / 4095 = 0.7V。
9 n/ A; S; {$ H! i
& d2 q: ~ B" v6 h59.2.3 DAC支持的触发源3 [: n) ?7 A! F8 \
DAC支持软件触发和硬件触发,具体支持的触发源如下:! m' N3 s$ g. E
3 p) N5 \* Z/ l* ^; \6 [- #define DAC_TRIGGER_NONE ((uint32_t)0x00000000) i1 t6 }* W/ x- A
- #define DAC_TRIGGER_SOFTWARE ((uint32_t)(DAC_CR_TEN1))
: T& [- c, Z4 b2 e% a/ O - #define DAC_TRIGGER_T1_TRGO ((uint32_t)(DAC_CR_TSEL1_0 | DAC_CR_TEN1))
" |, A1 t, C! {" [9 J- K - #define DAC_TRIGGER_T2_TRGO ((uint32_t)(DAC_CR_TSEL1_1 | DAC_CR_TEN1)) / N/ K. }! a X, ~
- #define DAC_TRIGGER_T4_TRGO ((uint32_t)(DAC_CR_TSEL1_1 | DAC_CR_TSEL1_0 | DAC_CR_TEN1)
2 d' u8 N1 p Y$ l5 ]. T0 @ - #define DAC_TRIGGER_T5_TRGO ((uint32_t)(DAC_CR_TSEL1_2 |DAC_CR_TEN1)) 2 Z) U) c5 r. G
- #define DAC_TRIGGER_T6_TRGO ((uint32_t)(DAC_CR_TSEL1_2 | DAC_CR_TSEL1_0 | DAC_CR_TEN1)) % P& m6 W. P* E
- #define DAC_TRIGGER_T7_TRGO ((uint32_t)(DAC_CR_TSEL1_2 | DAC_CR_TSEL1_1 | DAC_CR_TEN1)) " b8 e8 W9 A' R% v9 E2 h* d, K# Y
- #define DAC_TRIGGER_T8_TRGO ((uint32_t)(DAC_CR_TSEL1_2 | DAC_CR_TSEL1_1 | DAC_CR_TSEL1_0 | DAC_CR_TEN1))
# D3 q0 ]) A2 f' y- t/ p" [ - #define DAC_TRIGGER_T15_TRGO ((uint32_t)(DAC_CR_TSEL1_3 | DAC_CR_TEN1))
2 Z" ~& l6 W/ ?. V - #define DAC_TRIGGER_HR1_TRGO1 ((uint32_t)(DAC_CR_TSEL1_3 | DAC_CR_TSEL1_0 | DAC_CR_TEN1))' g- B2 y' b3 X) l$ c, h
- #define DAC_TRIGGER_HR1_TRGO2 ((uint32_t)(DAC_CR_TSEL1_3 | DAC_CR_TSEL1_1 | DAC_CR_TEN1))
6 I7 i/ b( \- L - #define DAC_TRIGGER_LP1_OUT ((uint32_t)(DAC_CR_TSEL1_3 | DAC_CR_TSEL1_1 | DAC_CR_TSEL1_0 | DAC_CR_TEN1)) * H1 W+ O# e8 T5 i/ O# H9 B3 c
- #define DAC_TRIGGER_LP2_OUT ((uint32_t)(DAC_CR_TSEL1_3 | DAC_CR_TSEL1_2 | DAC_CR_TEN1))
# f+ ?) R9 a2 J; P, q - #define DAC_TRIGGER_EXT_IT9 ((uint32_t)(DAC_CR_TSEL1_3 | DAC_CR_TSEL1_2 | DAC_CR_TSEL1_0 | DAC_CR_TEN1))
; b& I9 \$ W# \/ T: ?3 Q {+ {
复制代码
& ~) d; m; q, |% n$ B0 B4 P0 j+ {: {; m: \! t7 O
59.2.4 DAC正常模式和采样保持模式
4 ~; J7 [3 K- ~7 w9 Y3 d关于正常模式和采样保持模式,注意以下几点:
8 v& P+ F( C* t/ d# E2 }: w! E1 d v! \9 q) w9 i/ }5 x
正常模式是平时最常用的方式,比较好理解。而采样保持模式用于低功耗方式。8 n( m! Z+ p# C6 _: z% ^: P' U8 R
在采样保持模式下,DAC内核转换数据,然后保持电容上的电压。不转换时,DAC内核和样本之间的缓冲器完全关闭,DAC输出为三态,因此降低了整体功耗,但每次新转换前都需要一段稳定期。
4 p2 m; C1 r1 { 采样保持模式可修改内部或者外部参考电压。7 d4 P3 h F6 t% Y
采样保持部分可以用LSI时钟,也可以运行在几种低功耗模式下,如RUN模式, SLEEP& STOP模式。( \, g; q4 Q3 p
59.2.5 DAC的出厂校准和用户校准' i2 F0 s6 A% F1 u
一般情况下,使用出厂校准即可,芯片上电后自动完成出厂校准。而用户校准略麻烦,暂不做研究。这里特别注意一点,校准是建立在用户使能了输出缓冲的情况下才有效。
2 K* q7 h4 j: ^$ j$ o5 O2 W$ p3 Z9 K( o9 l
59.3 DAC的HAL库用法
" U) S( k% U8 B+ KDAC的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断和DMA。下面我们逐一展开为大家做个说明。
6 m8 h" |- g3 p9 a: y. n6 V8 H+ @; K+ c& P) o" a7 ] J
59.3.1 DAC寄存器结构体DAC_TypeDef
+ ?9 k2 H& j8 ~1 m W* B7 X) CDAC相关的寄存器是通过HAL库中的结构体DAC_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:/ ]* q+ K8 N T) j5 M
9 c4 ^* w* O7 @! D$ { a
- typedef struct
3 P& b F+ Q# {( W2 n" e) I - {. l* V7 U1 F( q* W$ u' ~& J& z4 [* ^8 ?
- __IO uint32_t CR; 3 H" A' I' _3 r; P: B; I k7 t; |
- __IO uint32_t SWTRIGR;
. n; R4 t( Y+ L: \3 h - __IO uint32_t DHR12R1;: Y+ g' K; Z/ O" X4 {/ l
- __IO uint32_t DHR12L1; + j7 I1 Z- a2 O5 @& ]
- __IO uint32_t DHR8R1; : G: z1 @, X4 d3 ]" T/ H
- __IO uint32_t DHR12R2; + N$ R: a# I6 ]+ H1 G9 I2 e& I, S
- __IO uint32_t DHR12L2;
$ i: c+ P+ W/ {/ ]+ O - __IO uint32_t DHR8R2; % C9 a: y$ F3 W4 w
- __IO uint32_t DHR12RD; # A6 V( x* p: Z, u
- __IO uint32_t DHR12LD;
3 X5 @# ?2 G, s1 A& s% y - __IO uint32_t DHR8RD;
8 ^' l6 Z& r* ?6 I: i2 X - __IO uint32_t DOR1;
7 B( l* ]0 ~) }9 K9 P2 j - __IO uint32_t DOR2; ) @0 U" d d( {3 o6 T+ a
- __IO uint32_t SR;
" P/ S# B7 d8 H) f# E& c& m% i - __IO uint32_t CCR;
/ _9 G0 K7 T! N6 E/ i5 G+ g% t - __IO uint32_t MCR; 2 u/ L6 |5 K6 T+ Y' V/ e) P
- __IO uint32_t SHSR1; / ~+ h8 W9 K' U3 |4 ]8 Z. o
- __IO uint32_t SHSR2;
8 R$ P6 @! T3 j- [5 A. L - __IO uint32_t SHHR; . B0 h/ z* }) o* Y) ~
- __IO uint32_t SHRR;
3 O. I0 c: `% ?" M. ^$ ~ - } DAC_TypeDef;
复制代码
, O4 q4 w) m) q2 q+ x, N; a# d__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:% S9 S4 b# \! |) _% q. j
2 |( @% |$ }* B8 g
- #define __O volatile /*!< Defines 'write only' permissions */, A* e9 E/ Y* d; \" k, ]
- #define __IO volatile /*!< Defines 'read / write' permissions */
复制代码 3 f8 k5 v, M7 \( V* w/ v8 W
下面我们再看DAC的定义,在stm32h743xx.h文件。
& h. Y# F n* [1 W6 `' k- }
' F0 o% ^; `# }) S+ l* u- #define PERIPH_BASE ((uint32_t)0x40000000) 6 U. v5 P7 W' i7 |) M5 d# n
- #define D2_APB1PERIPH_BASE PERIPH_BASE
, M: g% {1 C# z1 }" X, N) q4 b7 t9 K1 Q - #define DAC1_BASE (D2_APB1PERIPH_BASE + 0x7400)
& L j/ g* U3 B, s* d/ ? - #define DAC1 ((DAC_TypeDef *) DAC1_BASE) <----- 展开这个宏,(DAC_TypeDef *) 0x40007400
复制代码
4 f; P# m: @ A我们访问DAC1的CR寄存器可以采用这种形式:DAC1->CR = 0。4 Q8 u( R* C) z7 b. _6 I
" P. I1 S, b: p9 x# v" e% o) H
59.3.2 DAC的采样保持DAC_SampleAndHoldConfTypeDef' }8 ]- g/ m1 @; ]' w
此结构体用于DAC的采样保持参数,具体定义如下:, ^" I9 X, M( t, C9 H, J+ m
+ C# [0 @: Z {# ^$ s
- typedef struct2 [6 Z6 M% N8 {) a/ m
- {7 Z; s7 j2 j, I/ r% B5 {
- uint32_t DAC_SampleTime ;
" W* r S; r5 u) x7 ?' A( d) B - uint32_t DAC_HoldTime ;
+ R$ `7 P U9 M3 c) ~6 b! V - uint32_t DAC_RefreshTime ; }
2 b+ c5 z/ |. ~3 N3 H% K6 d, V - DAC_SampleAndHoldConfTypeDef;
复制代码 8 g( h d$ ^+ u! F& _9 \7 h
下面将这几个参数逐一为大家做个说明:
4 ?% `& k8 G! w* e S' g$ E5 ~$ s6 \: R$ G4 v9 h1 _
uint32_t DAC_SampleTime* h7 @+ Q9 Q- e+ r, {0 }6 t3 \* f' ]
此参数用于设置DAC的采样时间,范围0 - 1023。& r; {! A3 l4 U/ `- B+ ^3 Z9 v. P
4 C$ u: U; g- o% K8 E9 H
uint32_t DAC_HoldTime' h1 H: w' G7 i2 }
此参数用于设置DAC的保持时间,范围0 – 1023。% p" K0 i# Z- D/ J
& i9 d9 _, v; {) {1 a uint32_t DAC_RefreshTime, V' D- p/ l9 t8 P" A9 A
此参数用于设置DAC的刷新时间,范围0 – 255。1 `3 j1 ~7 g$ g3 Z% @" c" S1 \
/ |3 b- ]2 _5 `& T6 h/ ?1 V* k
59.3.3 DAC的通道参数结构体DAC_ChannelConfTypeDef
) ]* [" [6 N" {! F. U9 C O此结构体用于DAC的通道参数配置,具体定义如下:
2 ?# V) m' Q- S/ A4 H
- J+ {( O8 e0 x% T7 r' ^3 w' C- typedef struct1 F b4 y3 g7 B# h! W) ~5 v
- {1 A3 w: \0 K* u0 ]- \- n( X
- uint32_t DAC_SampleAndHold; " @3 R3 U D/ k
- uint32_t DAC_Trigger; " @8 {- C, x! V1 e
- uint32_t DAC_OutputBuffer;
+ K% B9 n! [0 Q& x* q6 u. o - uint32_t DAC_ConnectOnChipPeripheral ;7 F. O2 u+ z, j7 E$ ?( `
- uint32_t DAC_UserTrimming;
2 W, r; D6 u# P! g2 O - uint32_t DAC_TrimmingValue;
) h8 L R, J/ {6 L' J/ ^4 H - DAC_SampleAndHoldConfTypeDef DAC_SampleAndHoldConfig; , k& R# @# P b& B
- }DAC_ChannelConfTypeDef;9 P [& g+ Z9 M2 n6 M. i6 V
复制代码 8 w, C$ ]( R8 J2 ?$ X4 O
下面将这几个参数逐一为大家做个说明: j) x* \" |& [" K" W
( x( i( t s) `' T& h6 e uint32_t DAC_SampleAndHold$ o$ {/ Y: y. T2 x! Y f
此参数用于使能采样保持模式,具体支持的参数如下:
9 @' G% k4 ?$ N2 e9 U( ]! H" |6 X; c1 ^& V: [
- #define DAC_SAMPLEANDHOLD_DISABLE ((uint32_t)0x00000000)4 m" \0 E2 K4 {! |$ b# I$ n7 a$ l d
- #define DAC_SAMPLEANDHOLD_ENABLE ((uint32_t)DAC_MCR_MODE1_2)
复制代码 " E! q! R. p; |2 u& `
uint32_t DAC_Trigger6 b7 Q4 N9 D4 m( }
此参数用于DAC触发源的选择,具体支持的参数如下:
) E1 p: h* s+ K- #define DAC_TRIGGER_NONE
2 [1 @3 i/ G4 C1 s8 H) Z- J8 K5 S9 ? - #define DAC_TRIGGER_SOFTWARE
1 G. d. F- r; C; R7 L T2 k8 J - #define DAC_TRIGGER_T1_TRGO $ w4 v% ]$ ]( |, I/ Z: x( l0 ^/ D
- #define DAC_TRIGGER_T2_TRGO ; g6 u" ?* P' P G
- #define DAC_TRIGGER_T5_TRGO * m& x& L7 z3 y
- #define DAC_TRIGGER_T6_TRGO 7 D' S1 `7 b* ]# n# u0 f0 m% m/ \
- #define DAC_TRIGGER_T7_TRGO
! s; P) a) N1 B. c% p4 o6 V2 b - #define DAC_TRIGGER_T8_TRGO
- {7 z6 H1 Z; r8 P+ T - #define DAC_TRIGGER_T15_TRGO " ]; t* A+ N, a" H6 H$ g. T
- #define DAC_TRIGGER_HR1_TRGO1 $ K$ H% |: n+ k5 B0 x# T. G
- #define DAC_TRIGGER_HR1_TRGO2 & p5 Z+ o* N2 I( R) r/ u" m; R; t7 }
- #define DAC_TRIGGER_LP1_OUT - s) d8 B7 T, a4 \5 _
- #define DAC_TRIGGER_LP2_OUT 1 Y5 a# U& _1 m$ `
- #define DAC_TRIGGER_EXT_IT9
复制代码
% g/ w: L4 }' D5 ~7 ], p uint32_t DAC_OutputBuffer& W( M4 o) s; s0 U
此参数用于使能或者关闭DAC的输出缓冲,使能输出缓冲后,可以增加DAC的驱动能力,具体支持的参数如下:
/ @! b4 b) a8 k- }% g- G3 A) ^% G% N7 c. ^7 T
- #define DAC_OUTPUTBUFFER_ENABLE ((uint32_t)0x00000000)! W2 T' ?3 o/ u+ S* x9 H2 D$ | B
- #define DAC_OUTPUTBUFFER_DISABLE ((uint32_t)DAC_MCR_MODE1_1)
复制代码 ( S0 s3 ]: s5 I' b# @$ h* _
uint32_t DAC_ConnectOnChipPeripheral/ A# _2 F Y' k
此参数用于DAC是否连接片上外设(运放,比较器等),具体支持的参数如下:
/ o% e' U; q% d$ J; |& e4 N# Y
5 _- s3 h" M$ @) h5 P+ [- #define DAC_CHIPCONNECT_DISABLE ((uint32_t)0x00000000)3 {1 s" d8 e- w7 T* a5 E
- #define DAC_CHIPCONNECT_ENABLE ((uint32_t)DAC_MCR_MODE1_0)
复制代码 ; D5 T5 B7 |. j6 j3 ] c+ s
uint32_t DAC_UserTrimming: w" `6 z% W0 z; X) W! c: H$ U( ^
此参数用于设置DAC的校准方式,采用出厂模式还是用户模式,具体支持的参数如下:) \( W5 q5 p( U5 f" |
/ T1 x, d6 K, ?4 P- U' `: n
- #define DAC_TRIMMING_FACTORY ((uint32_t)0x00000000)
! B% j- U5 Z, i4 H, b - #define DAC_TRIMMING_USER ((uint32_t)0x00000001)
复制代码
4 w3 U# W1 y4 W4 @& f3 w5 ]7 k uint32_t DAC_TrimmingValue$ w3 G4 d( O/ ? f9 @$ ?6 v# M
此参数用于设置用户校准模式的偏移值,参数范围1-31。 : H6 @1 K9 K2 M! z+ R5 E) ?; g$ a
7 E O F4 s8 C1 K" s DAC_SampleAndHoldConfTypeDef DAC_SampleAndHoldConfig
3 R, u3 P9 A) T3 ^& V! M此参数用于采样保持具体参数设置,详解本章3.2小节的说明。2 q. w2 I$ @5 P6 h: |8 o2 o
% l! L/ ?5 v6 F+ g59.3.4 DAC结构体句柄DAC_HandleTypeDef2 _- }$ {) ^% y" t r
HAL库在DAC_TypeDef的基础上封装了一个结构体DAC_HandleTypeDef,定义如下:. e3 n0 t( Q2 L! _3 [
$ p) M- r0 w) K5 p! I- typedef struct
: I+ z' N( e- ], ]5 y' | - {7 N) S8 z, E4 F) Z
- DAC_TypeDef *Instance;
$ V) D# Y- s7 P% ]/ |+ U9 g4 z0 |8 U) }( E - __IO HAL_DAC_StateTypeDef State;
& ?* b+ s" ^9 s/ i" \5 p* s* J - HAL_LockTypeDef Lock;
: E. [; y8 l+ U - DMA_HandleTypeDef *DMA_Handle1; . j6 m( r- g: N6 r* Z& w
- DMA_HandleTypeDef *DMA_Handle2;
2 u# T, N# n& \* n/ g7 y4 p) R - __IO uint32_t ErrorCode; " N) W, H, f# `
- }DAC_HandleTypeDef;
复制代码 下面将这几个参数逐一做个说明。4 }- u5 ?5 t/ W; H
3 f) q: U O2 u5 p8 M* r
DAC_TypeDef *Instance2 Y' H# v# k! C( Z+ B! J; r5 H: Y* N
这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。8 Q/ e8 n8 r. R! g* n1 f
5 G* S8 z+ c8 q# G6 U4 ?- {6 ?4 p DMA_HandleTypeDef *DMA_Handle1" N4 i3 T( ?0 K' P- b) j
DMA_HandleTypeDef *DMA_Handle28 @9 H" {/ |# ?7 V" c
DMA句柄结构体指针变量,用于关联DAC句柄,方便调用。 ; |9 m. Y9 S$ ^- t
) I- i& c# g0 l
HAL_LockTypeDef Lock 5 J/ k% f" i! ^
__IO HAL_DAC_STATETypeDef State
$ v, c! [ }( M5 j __IO uint32_t ErrorCode ' c, G3 [; C3 J" |
这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置DAC状态,而ErrorCode用于配置代码错误。
6 _3 e) d0 V1 Y6 b$ C P; }; D$ n/ N5 o0 B j
59.3.5 DAC初始化流程总结9 e. h7 b# X, }! a5 g
使用方法由HAL库提供:
7 I0 F: _+ A( t( s& Q3 v* M9 R, `5 r6 c7 ~! u, C
第1步:基本的初始化。# x c& q. j ]* L6 G( q
9 \6 e+ W( X) n9 b 函数HAL_DAC_Init初始化。
2 V2 s6 W% r$ s) K: x6 Y0 q; i 配置DAC_OUT1: PA4, DAC_OUT2: PA5引脚为模拟模式。
+ B8 i1 ] a; Y" D4 v 函数HAL_DAC_ConfigChannel配置通道参数。
: U' T/ y6 g, h7 ^% W1 v, `; T 函数HAL_DAC_Start() or HAL_DAC_Start_DMA()使能DAC。
3 ] V, s \# v7 ?" D# g% M- e) v
& q. r/ W/ B+ ^
第2步:DAC校准。
' w5 L& r* w1 ?; C2 K5 `) k t1 H2 d) u4 [
出厂校准比较简单,芯片上电后自动完成,而用户校准需要依次调用函数HAL_DACEx_GetTrimOffset,HAL_DACEx_SelfCalibrate和HAL_DACEx_SetUserTrimming。
' F* y/ _: k" p& }6 K* e3 D$ k+ F7 W: U5 E: p! w
- d0 \9 k, ~" f& o4 Q& s+ r
第3步:查询模式。2 A( x" {; F% G! I
, `; B* E: a! o6 g 函数HAL_DAC_Start() 启动。' W$ E2 B) b9 H( J- X8 V5 m
函数HAL_DAC_GetValue()可以读取输出值。; E; c& R- n1 O, T' M6 b# r. |& | S
函数HAL_DAC_Stop可以停止DAC。3 L" Q8 P. u8 a- F/ ^* p
5 P) \5 t5 w) Q; F- J6 b3 |9 }
3 ]" T2 ^$ {$ y6 l$ x1 b3 g( t 第4步:DMA方式。% V3 [' i9 Y" t/ Y& i
& { r: ^. E0 l' ~/ r$ l
函数HAL_DAC_Start_DMA()启动DMA方式转换。
0 {. H0 x3 k+ c3 M. C: ?4 E# _ DAC的数据传输一半的时候, HAL_DAC_ConvHalfCpltCallbackCh1() 或者 HAL_DACEx_ConvHalfCpltCallbackCh2() 会被调用。
' p3 J" O+ T0 N" L- S3 @. n( Z DAC的数据传输完成的时候,HAL_DAC_ConvCpltCallbackCh1() 或者 HAL_DACEx_ConvHalfCpltCallbackCh2() 会被调用。2 s2 P+ Y+ B$ P3 M7 f
传输错误时,函数HAL_DAC_ErrorCallbackCh1会被调用。' y5 W, R; Z4 {/ {
DMA下溢错误,会调用函数HAL_DAC_DMAUnderrunCallbackCh1()或者HAL_DACEx_DMAUnderrunCallbackCh2()。
+ U8 x+ c4 G1 B; X$ x, Q 停止DAC的DMA方式,可以调用函数HAL_DAC_Stop_DMA& m0 S7 X/ y: a+ R! B7 u
59.4 源文件stm32h7xx_hal_dac.c
3 i4 f7 [/ w1 P: B: `. H( k这里把我们把如下几个常用到的函数做个说明:% l* w( {6 n5 ], s( e
# K0 c" Q/ {1 B$ C5 c+ ~+ L$ M q8 c- _1 H HAL_DAC_Init9 Q- t: D9 n" e/ {" N, ?: p' G
HAL_DAC_ConfigChannel1 Y' L( U5 `4 V. }' m5 ?% e
HAL_DAC_Start_DMA
4 _ _$ ~7 a8 T% R. C% }! K% n59.4.1 函数HAL_DAC_Init+ }- s, b, s2 ~/ {
函数原型:
: S f! K+ d' k2 A- & b, ~ J+ u; V& C1 M
- HAL_StatusTypeDef HAL_DAC_Init(DAC_HandleTypeDef* hdac)
/ J- d, g; _4 k3 o; u: A - {
7 h0 M% w1 `- m1 m - /* 检测DAC句柄 */
6 P3 o0 U' x9 {1 F2 _* c - if(hdac == NULL)+ P/ L9 B' j$ P# i7 T
- {. m. `" ?' z: o3 Q" O+ f W
- return HAL_ERROR;' o# b |: N2 a9 Z
- } y# j& Y% ^5 ^
- assert_param(IS_DAC_ALL_INSTANCE(hdac->Instance));% h) M& R2 k5 u8 Z8 b8 E6 W
* g0 s. j* M/ d5 C- if(hdac->State == HAL_DAC_STATE_RESET)
. N R4 H+ M b5 L9 D - { , p/ T# Q& ~' u% @
- hdac->Lock = HAL_UNLOCKED;6 B( _6 F( i$ {8 w/ H: R1 y# o
- /* 初始化GPIO,NVIC等 */
8 f! P+ i, ^# v" r$ J8 ] A/ _: m) h2 d; I - HAL_DAC_MspInit(hdac);
1 n- \6 \) V5 {' ` - }1 H" k2 F4 o3 _$ u
3 M& \% h9 S: t7 p# s- /* 设置DAC状态忙 */
! N& r( L& y5 r$ o - hdac->State = HAL_DAC_STATE_BUSY;7 A* K# O, r5 y
- & f1 A) b6 u2 Q" Q4 R
- /* 设置DAC无错误 */
. \( p1 A! J F% `- j - hdac->ErrorCode = HAL_DAC_ERROR_NONE;' S* z5 N& W5 f; o* c# F- x
- " V/ }0 p m' f
- /* 设置DAC就绪 */
0 O, w) d# N' D, N4 `3 T - hdac->State = HAL_DAC_STATE_READY;
8 f. d# s( {& ~* q- B
- y8 g Z9 Z5 j, U2 F- /* 返回HAL_OK */
' d) Q( b% H% h4 ?( t+ H" B - return HAL_OK;7 d8 f0 b+ _& y( o. F" h: |
- }
复制代码
$ G' a5 ]" I% e$ D0 r: z( U函数描述:; q7 ]# l Q9 `( t& z' d0 h# K
9 \% x' ?( i+ L9 E0 V
此函数用于初始化DAC。/ F: U+ h9 a, L" N
3 C" t( X0 L9 f3 m4 i* {/ ~6 }函数参数:9 B, r/ Q6 e( v" t
- a/ E, v- W. q, k8 N a% b) e
第1个参数是DAC_HandleTypeDef类型结构体指针变量,结构体变量成员的详细介绍看本章3.4小节。
3 O! D( V- K% F9 M1 l& | 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
- r( N- {3 c5 g0 l注意事项:
9 B# f4 E0 Q# G9 M! m. ~# F! g, J
+ \5 Z K* Y" y- |4 P函数HAL_DAC_MspInit用于初始化DAC的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。3 R' r$ b( X; a+ ]5 k" `% \, H% M8 ?
如果形参hdac的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量DAC_HandleTypeDef DacHandle。* K/ s( `5 Q3 B9 T( p
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_DAC_STATE_RESET = 0x00U。: n7 ?) r& u6 q
r+ _$ o6 t' t/ \- u6 r& \
解决办法有三
9 L! P) T8 |) b7 P$ n
7 k$ H- v/ ], p0 o) G$ z) Q- F1 F方法1:用户自己初始DAC底层。4 e) O& o0 d; g: _' I3 Y
% U) h) K5 `3 ~方法2:定义DAC_HandleTypeDef DacHandle为全局变量。
# r3 l; m0 Y* V; j/ o7 |: v" V0 u4 g' \' J. n j! @/ q8 U+ x, ]% k" Z
方法3:下面的方法( {3 h8 h h" L
6 \+ `: O5 L( ]+ U
- if(HAL_DAC_DeInit(&DacHandle) != HAL_OK)# Y; U- s/ l( d8 d. I1 r5 v# }
- {- H2 f6 l$ z3 g2 S) F9 {6 u
- Error_Handler();7 p/ s/ \; L8 q8 P. R
- } % t# W2 O, |) }
- if(HAL_DAC_Init(&DacHandle) != HAL_OK)
5 {+ f; [& r9 w+ i& k& e6 X& ? I - {
: {% Q" L2 m% | y) }% F6 u( o% n' S - Error_Handler();$ j6 ?3 P" b7 ^3 O. @% h* z. @+ {
- }
复制代码
7 E( z9 [) `: V( h- y使用举例:1 `2 x7 C# _; B. V
9 W v! \- P7 A$ w, K* Y* Q4 u
- DAC_HandleTypeDef DAC_Handle;# S6 ]7 j7 j2 l& s0 ?& N# ]
- DacHandle.Instance = DAC1;
t; E* a; Q7 s [7 B0 t) T6 N - if (HAL_DAC_Init(&DacHandle) != HAL_OK)
9 H) P0 g$ z% y - {
$ K% k) s6 J/ B+ L7 ^9 x - Error_Handler(__FILE__, __LINE__);9 R/ N0 p0 l* ?' x2 H: u
- }
复制代码
- f6 ?4 R4 k1 R$ e' m* m* j5 q3 b59.4.2 函数HAL_DAC_ConfigChannel
# v: |: y. l% {3 {函数原型:- p" W7 Y7 r- }* U6 w
) A0 @4 ~# D' D. E
- HAL_StatusTypeDef HAL_DAC_ConfigChannel(DAC_HandleTypeDef* hdac, DAC_ChannelConfTypeDef* sConfig, uint32_t Channel), j7 F" d' E$ B
- {
! ~7 U: E3 |5 ?4 B, E- f* ? - uint32_t tmpreg1 = 0, tmpreg2 = 0;
[% x$ x0 F+ T* \7 v+ u% b - uint32_t tickstart = 0;
! w0 k5 a! P+ {4 a3 \7 H* M
) t! N) o* H, J6 t4 A- /* 部分省略,未贴出 */
6 X" @2 l% [9 P, S1 P6 N& [6 D0 {
! V: O8 i# ]3 Q7 {% ]: _0 x: ]- /* 上锁 */$ n% w, `& h# i6 A; W
- __HAL_LOCK(hdac);
* T4 F1 ?2 s; I9 J. c7 J7 L
! Z F) ]$ R! P, G5 @- /* 设置DAC忙 */5 ]$ n8 G: Q' H. U# n* L; R! }; {/ @
- hdac->State = HAL_DAC_STATE_BUSY;& P$ L) K/ |! J- [6 J+ c
/ B& _5 }2 z* c1 c7 |6 v- if(sConfig->DAC_SampleAndHold == DAC_SAMPLEANDHOLD_ENABLE)
8 W/ I# n2 c e A5 D. h. @ - {
7 ?" C; ~! k/ ` - /* 通道1设置 */
! f! P! ]" B0 [5 W - if (Channel == DAC_CHANNEL_1)
9 E s0 b$ U4 z& z# X5 n f; Z" s - {
/ M/ W- @# s- U. D! T - + b. Y' M# L# k2 Z- k, K
$ f) Z, F$ m: \: R4 y- }
9 T6 z1 C6 Z8 C" }2 O* h! g8 a - else /* 通道2设置 */% |5 W6 D3 g5 J2 K
- {" J8 D. H M9 C W+ q; K
- }" l% [6 n4 j# Q7 w5 e
- }) ^ C- P: s2 ^+ l9 ^ |
- ; i. l' z- g9 j9 o- _+ w `- m* V
- if(sConfig->DAC_UserTrimming == DAC_TRIMMING_USER)+ k8 l" i; W Z' S% h, l5 o
- /* 用户校准配置 */
0 z+ g- e& m# L - {" j" ^1 j4 _- J" ^ p% ~) a' o
- . f! g/ R# q1 L$ H
; j8 e& U) ~- g- }
0 k8 F4 n5 p6 n) U' \7 b) j4 ^% P - /* 出厂模式无需配置,复位后自动设置 */
0 e! a) W7 m8 Q6 b - - v7 g# d. @( P+ e" a
- /* 获取DAC MCR数值 */
$ z) ?* I4 r/ ~: R3 ^9 f - tmpreg1 = hdac->Instance->MCR;
9 z1 v! {4 ]1 l5 B0 w. p' V - /* 清除DAC_MCR_MODE2_0, DAC_MCR_MODE2_1 和 DAC_MCR_MODE2_2 位 */1 k4 b( r% M* \" i
- tmpreg1 &= ~(((uint32_t)(DAC_MCR_MODE1)) << Channel); * W+ h5 F7 }' ]5 W
- /* 配置DAC通道 */+ N9 }0 @4 D) N# [# k- e
- tmpreg2 = (sConfig->DAC_SampleAndHold | sConfig->DAC_OutputBuffer | sConfig->DAC_ConnectOnChipPeripheral);
- W0 A; S7 \# ~* v/ c& E) R" }: \ - tmpreg1 |= tmpreg2 << Channel;
- d% S1 F. L# J3 h - /* 设置MCR数值 */7 g3 E/ g: }0 m
- hdac->Instance->MCR = tmpreg1;
$ ^0 b) W! k6 [. Q) }
1 X! Z: n, [# L3 U! I- /* DAC工作在正常模式 */: N1 ~" t% h7 S: i
- CLEAR_BIT (hdac->Instance->CR, DAC_CR_CEN1 << Channel);* P" U, U7 e1 v1 X
- . m0 C9 d% ]) U4 m( y" c5 h
- /* 获取DAC CR值 */
: ?$ k$ q! {3 P5 H/ n) @ - tmpreg1 = hdac->Instance->CR;* q' p% |; i" B+ s! c9 r, f- Z
- tmpreg1 &= ~(((uint32_t)(DAC_CR_MAMP1 | DAC_CR_WAVE1 | DAC_CR_TSEL1 | DAC_CR_TEN1)) << Channel); 0 \5 i5 y* r. ^" ~9 ]
- tmpreg2 = (sConfig->DAC_Trigger);
' _) h8 `4 z& `6 f0 I9 d. s - tmpreg1 |= tmpreg2 << Channel;! k1 K4 I2 P* S4 z6 a
3 W/ T$ V! R2 Y( a9 v3 ^- /* 写DAC CR值 */+ L9 O' h. I, ?7 L1 Y8 R; U
- hdac->Instance->CR = tmpreg1;
+ ~+ \: Z: e0 P7 Z- e F7 _ - 8 v2 O- \% G# `0 t2 ]
- /* 禁止波形生成 */
! ~! r6 h! h% ~& O7 I- W - hdac->Instance->CR &= ~(DAC_CR_WAVE1 << Channel);5 g+ {( f( U7 v- o. L6 u
- - A; D+ m) f: ~" G: b
- /* 设置DAC就绪 */
, e* ^! G3 Y3 ^* ?2 e- }' E - hdac->State = HAL_DAC_STATE_READY;3 E$ Y2 ]: B+ \$ J- \1 }
- ; k. T- t4 J& N7 ^
- /* 解锁 */
; a+ ]6 {+ V0 a8 X8 B - __HAL_UNLOCK(hdac);& y8 C0 Y( ~- L' p' T2 O' q
- ) K" {5 N& Y( ] m# i
- /* 返回HAL_OK */; Q6 H+ ? s- ^& P+ E" [$ U. s! l
- return HAL_OK;) n+ w, O' {4 c! [4 J8 v- E I, u8 h
- }
复制代码 * E+ M8 e& @& i! T+ i$ `% ^$ |3 Y3 b
. q: b' I$ M) D0 {: U7 V4 O% |函数描述:1 F4 P2 s p/ t& {/ o. ]. ]- H7 b
7 T% M+ A! e; t0 v+ C, u, {& Q S; C
此函数主要用于配置DAC的通道参数。& j6 X7 X. d2 X3 z1 y) V) l
7 t9 \! U5 _& i, X T% A函数参数:2 K: F1 w6 i7 Q5 j" q
% m7 R1 v I# {6 J7 _8 s- O1 \7 R% g
第1个参数是DAC_HandleTypeDef类型结构体指针变量,结构体变量成员的详细介绍看本章3.4小节。3 j$ x* n; {% P1 W( A
第2个参数是DAC_ChannelConfTypeDef类型结构体指针变量,用于DAC的通道参数配置,结构体变量成员的详细介绍看本章3.3小7 x" o* L1 j5 x; G
第3个参数用于选择要配置那个通道,DAC_CHANNEL_1表示配置通道1,DAC_CHANNEL_2表示配置通道2。
8 {( l1 z; e/ G8 ? 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
- f) ?( n3 w+ _2 i使用举例:
, }( F: i8 ^, Q, _
# }* n, _- M4 k( I; f- static DAC_ChannelConfTypeDef sConfig;
& D* V8 G9 P* G# z+ ~ - static DAC_HandleTypeDef DacHandle;, E: d% Z G+ l/ ?6 J0 l
6 z+ L7 \" ~# I6 t; m: S c- sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE; /* 关闭采样保持模式,这个模式主要用于低功耗 */4 U: q3 V5 F4 f! d. @2 S' o
- sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO; /* 采用定时器6触发 */9 t/ H& A/ ^! t8 L# j
- sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; /* 使能输出缓冲 */
1 m! P- Y: M2 j; x; a% w - sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_DISABLE;/* 不将DAC连接到片上外设 */( b, U5 [+ O! [/ G) s; R! c
- sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY; /* 使用出厂校准 */* g9 c U4 U5 U1 {
4 `# Z5 b' ~' p* B3 X% F- if (HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DAC_CHANNEL_1) != HAL_OK)" \- j/ i+ s( y2 x) Y2 @% ?; r$ e6 \4 R
- {9 |# f8 k. l' q
- Error_Handler(__FILE__, __LINE__);
7 I) [) B/ o1 A% x- N1 n - }
复制代码
# @" r0 Z$ I* b, [3 A: c p# N6 J
: X. k7 e6 B# ?. P7 q7 @) ~9 M. A& e# b4 f9 n' ^
59.4.3 函数HAL_DAC_Start_DMA
9 o% u A4 R" K6 M8 H函数原型:2 Y6 ?) C$ ?( I4 w, A' |
5 u1 K# `2 V9 j& x5 G; W: W
- HAL_StatusTypeDef HAL_DAC_Start_DMA(DAC_HandleTypeDef* hdac, uint32_t Channel, uint32_t* pData, uint32_t Length, uint32_t Alignment)* e7 U0 L' q2 @
- {
% ^3 Q2 }6 Z0 ^ - uint32_t tmpreg = 0;4 j6 A+ f& Q7 r$ R$ ~
- % M6 w6 Q: F+ _, u! A
- /* 部分省略,未贴出 */
3 o4 P% N3 \+ X8 O9 H7 ]
4 \8 ]/ W( e. E$ t. G3 b8 W# e- /* 检测参数 Check the parameters *// l& { n1 `: O
- assert_param(IS_DAC_CHANNEL(Channel));
F7 k% k1 ?4 @& K; G" u& ] - assert_param(IS_DAC_ALIGN(Alignment));
5 J7 }2 q$ P9 ]& Y. o
/ w3 o$ Z" g4 N- /* 上锁 Process locked */
* [6 A8 C' }" H$ ]3 _0 t/ p( F# ~ - __HAL_LOCK(hdac);
) I, N$ ^, _9 b4 N, Q0 D- o$ | - ) i; s) z3 D- {/ F8 V% _( J- R
- /* 设置DAC忙 Change DAC state */8 E! ]) r* A. r: S. @2 c
- hdac->State = HAL_DAC_STATE_BUSY;/ A; V* S# ` K" H) p0 D2 L% u
- / j% x7 c7 I3 f: ]4 r6 H4 f6 v
- /* 配置通道1 */
8 M2 b$ I* m. B8 a" m" }0 `4 d& v - if(Channel == DAC_CHANNEL_1)# s/ Y* |8 T6 s( \* u( G
- {
- f- n' h; l1 i( s s. { - /* DMA传输完成回调 */
6 A5 a6 @& t$ V# a - hdac->DMA_Handle1->XferCpltCallback = DAC_DMAConvCpltCh1;- ~4 k; |$ K8 [1 \, l: p
- 6 S. A+ g `/ C
- /* DMA半传输完成回调 */2 t/ j# y9 l, [# _
- hdac->DMA_Handle1->XferHalfCpltCallback = DAC_DMAHalfConvCpltCh1;
0 a6 c7 Z5 q- G" h - 0 N5 j8 `1 _. w6 {3 A7 A2 X
- /* DMA传输错误回调 */- b3 @" `. i5 M% u& C/ b
- hdac->DMA_Handle1->XferErrorCallback = DAC_DMAErrorCh1;. F6 p0 y7 Z+ ] U5 I
" O! t+ n6 L* r" A4 o4 e, W- /* 使能DAC DMA */
4 E, Z! D% v, [# p) v. x% k - SET_BIT(hdac->Instance->CR, DAC_CR_DMAEN1);
& s# [9 k$ D4 n: ?1 e! S1 E2 E' D E0 f - 3 u; F1 z2 ], A: U
- /* 数据对齐方式设置 */
- Y, X6 ~% E; E* W# S9 I - switch(Alignment)
' K6 |2 Z# x& G - {) ]& P8 t2 c8 c9 @; z
- case DAC_ALIGN_12B_R:! M3 e+ w# q* I( \) n
- tmpreg = (uint32_t)&hdac->Instance->DHR12R1;8 r( w( k/ x, T3 L: v$ g- h
- break;% j# I" ^/ J+ L! S' K- t
- case DAC_ALIGN_12B_L:3 _! b7 x% Q6 f# e& l* }
- tmpreg = (uint32_t)&hdac->Instance->DHR12L1;; k- m+ _. s4 M
- break;: L: |# h5 o. w( E" g6 m
- case DAC_ALIGN_8B_R:
6 H6 b2 M" ^# G9 i& O - tmpreg = (uint32_t)&hdac->Instance->DHR8R1;
# m7 H" w! A1 ^' Q; `1 z - break;
6 j w+ Q/ O) }; m7 a% \ - default:
+ ?/ I" o6 q- p - break;
! M' M4 r0 d$ p1 [9 A" | - }0 r6 x6 s( q$ n6 X: A8 R/ o
- }
! K7 m4 R5 ?% d" I$ r8 E - else3 {, e n3 a) |; ]* o) Z" U
- {2 U( u7 O \6 f) D7 N( s, z
3 R' {3 t. f* Q. g n* d- }
; Q1 _7 K# X& e6 E/ {) R - }
) O4 L$ |1 F! _
. ]# b! `# N# _) S9 J( U$ u. k3 T- /* 使能DMA Stream */% \0 F; q* ^' {7 ^( j: d8 h; b
- if(Channel == DAC_CHANNEL_1)
4 h5 V/ _4 X; Y) U# s8 u- a - {
! l8 {2 m# g0 e1 _- s% W - /* 使能DAC DMA下溢中断 */
; B7 v( e$ A- N - __HAL_DAC_ENABLE_IT(hdac, DAC_IT_DMAUDR1);
+ C% U' G" y J: \2 V" C - 0 \; i) d3 E& q; v# s
- /* 启动传输 */# l* |! g' u5 x* R
- HAL_DMA_Start_IT(hdac->DMA_Handle1, (uint32_t)pData, tmpreg, Length);
5 P9 u4 E4 r) A9 D - } - X; B+ u0 q3 i+ y/ s3 D$ \
- else* j. \' J" Y5 K, F; c4 }
- {
5 K2 m( H% C- U/ H1 ?( G9 e# ` - __HAL_DAC_ENABLE_IT(hdac, DAC_IT_DMAUDR2);7 D5 _, O$ A4 g' _" `5 n$ e
- HAL_DMA_Start_IT(hdac->DMA_Handle2, (uint32_t)pData, tmpreg, Length);; @- d( Z1 V' ]- q% s M
- }) ?5 x8 |8 z! n- f- d
; A1 R7 ^& v& k5 Z+ `) w5 G- /* 解锁 */( J; V7 `, f) I& H
- __HAL_UNLOCK(hdac);
4 f! D) ^9 V( |% {! D3 m - /* 使能DAC通道 */
6 u" J) a9 }; ~ - __HAL_DAC_ENABLE(hdac, Channel);; ^1 \" E1 G3 s5 O2 A
: }: w+ \8 G* [& c- /* 返回HAL_OK */
: X: w" G/ A( J6 C& b: {/ y1 s - return HAL_OK;
/ ]8 J/ ~! X" J9 V0 ?5 j - }
复制代码
! L8 r- n! Y3 Q- M2 X函数描述:8 K2 G9 h" z) q7 p
5 a: U% W6 z! b1 f8 F1 \3 w此函数用于启动DAC的DMA方式
$ K9 m( }. U6 Q' E3 R2 B2 E2 a' H# ]% Q) W$ T
函数参数:
M* }# a6 h4 U. J2 g2 `% f2 J
$ P/ F4 o9 e9 |; \$ H% b 第1个参数是DAC_HandleTypeDef类型结构体指针变量,结构体变量成员的详细介绍看本章3.4小节。
. U- O' O/ F, n: U% P& A. P9 D5 G 第2个参数用于选择要配置那个通道,DAC_CHANNEL_1表示配置通道1,DAC_CHANNEL_2表示配置通道2。
% Q: M# p& t5 }4 Y, n* ~# t 第3个参数是波形数据地址。, t9 P) W5 e, n6 Q
第4个参数是传输的数据长度。& Q. x9 g7 L! E$ {8 j+ w3 {6 H( s
第5个参数是数据对齐方式设置。
, ~- [5 n: k/ o2 t DAC_ALIGN_8B_R 表示8bit右对齐。& b. q! X! `* y. P* e0 |
DAC_ALIGN_12B_L 表示12bit左对齐。; _* q/ q& ?/ M" M& u+ H# S$ Z
DAC_ALIGN_12B_R 表示12bit右对齐。
3 X3 d' @% x5 T1 G& a 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。1 ~) M& O5 ]. h" e/ F
使用举例:
, P2 x! k3 l/ Y8 L" b8 J: T$ G- X
( h& B& d5 |# Y1 D5 A1 S2 ~ I- static DAC_HandleTypeDef DacHandle;
8 `& k: G9 T4 ?4 R# _. I - 6 ]1 \3 C" U# \9 t3 g" o
- /* 启动DAC DMA */
/ n. }+ j' Z @. ?, x5 f% a, y - if (HAL_DAC_Start_DMA(&DacHandle, DAC_CHANNEL_2, (uint32_t *)g_usWaveBuff, 64, DAC_ALIGN_12B_R) != HAL_OK)
( c* \* s b* l; z' h - {8 Z+ H5 U" t0 @" I
- Error_Handler(__FILE__, __LINE__);
3 w9 P6 [) B6 [; y! ~. x3 e - }
复制代码
) ?/ d; Q$ \- s, e
/ F6 V+ n: B% t# {; O, t* U# @% r9 v
59.5 总结
0 p! z8 n8 C$ H7 g: i本章节就为大家讲解这么多,DAC功能用到的地方还是比较多的,建议熟练使用。
8 Q* }9 s2 ?& F6 |3 z% _ W2 E* v' r
' q, G, N) `3 q3 w: O4 x
|