你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32H7的DAC基础知识和HAL库API

[复制链接]
STMCU小助手 发布时间:2021-10-31 20:23
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
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
* _/ 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
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

( 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 [
  1. #define DAC_TRIGGER_NONE        ((uint32_t)0x00000000)         i1 t6 }* W/ x- A
  2. #define DAC_TRIGGER_SOFTWARE    ((uint32_t)(DAC_CR_TEN1))     
    : T& [- c, Z4 b2 e% a/ O
  3. #define DAC_TRIGGER_T1_TRGO     ((uint32_t)(DAC_CR_TSEL1_0 | DAC_CR_TEN1))
    " |, A1 t, C! {" [9 J- K
  4. #define DAC_TRIGGER_T2_TRGO     ((uint32_t)(DAC_CR_TSEL1_1 | DAC_CR_TEN1)) / N/ K. }! a  X, ~
  5. #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 @
  6. #define DAC_TRIGGER_T5_TRGO     ((uint32_t)(DAC_CR_TSEL1_2 |DAC_CR_TEN1))  2 Z) U) c5 r. G
  7. #define DAC_TRIGGER_T6_TRGO     ((uint32_t)(DAC_CR_TSEL1_2 | DAC_CR_TSEL1_0 | DAC_CR_TEN1)) % P& m6 W. P* E
  8. #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
  9. #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" [
  10. #define DAC_TRIGGER_T15_TRGO    ((uint32_t)(DAC_CR_TSEL1_3 | DAC_CR_TEN1))
    2 Z" ~& l6 W/ ?. V
  11. #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
  12. #define DAC_TRIGGER_HR1_TRGO2   ((uint32_t)(DAC_CR_TSEL1_3 | DAC_CR_TSEL1_1 | DAC_CR_TEN1))
    6 I7 i/ b( \- L
  13. #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
  14. #define DAC_TRIGGER_LP2_OUT     ((uint32_t)(DAC_CR_TSEL1_3 | DAC_CR_TSEL1_2 | DAC_CR_TEN1))
    # f+ ?) R9 a2 J; P, q
  15. #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
  1. typedef struct
    3 P& b  F+ Q# {( W2 n" e) I
  2. {. l* V7 U1 F( q* W$ u' ~& J& z4 [* ^8 ?
  3.   __IO uint32_t CR;       3 H" A' I' _3 r; P: B; I  k7 t; |
  4.   __IO uint32_t SWTRIGR;  
    . n; R4 t( Y+ L: \3 h
  5.   __IO uint32_t DHR12R1;: Y+ g' K; Z/ O" X4 {/ l
  6.   __IO uint32_t DHR12L1;  + j7 I1 Z- a2 O5 @& ]
  7.   __IO uint32_t DHR8R1;   : G: z1 @, X4 d3 ]" T/ H
  8.   __IO uint32_t DHR12R2;  + N$ R: a# I6 ]+ H1 G9 I2 e& I, S
  9.   __IO uint32_t DHR12L2;  
    $ i: c+ P+ W/ {/ ]+ O
  10.   __IO uint32_t DHR8R2;   % C9 a: y$ F3 W4 w
  11.   __IO uint32_t DHR12RD;  # A6 V( x* p: Z, u
  12.   __IO uint32_t DHR12LD;  
    3 X5 @# ?2 G, s1 A& s% y
  13.   __IO uint32_t DHR8RD;  
    8 ^' l6 Z& r* ?6 I: i2 X
  14.   __IO uint32_t DOR1;     
    7 B( l* ]0 ~) }9 K9 P2 j
  15.   __IO uint32_t DOR2;    ) @0 U" d  d( {3 o6 T+ a
  16.   __IO uint32_t SR;      
    " P/ S# B7 d8 H) f# E& c& m% i
  17.   __IO uint32_t CCR;      
    / _9 G0 K7 T! N6 E/ i5 G+ g% t
  18.   __IO uint32_t MCR;      2 u/ L6 |5 K6 T+ Y' V/ e) P
  19.   __IO uint32_t SHSR1;   / ~+ h8 W9 K' U3 |4 ]8 Z. o
  20.   __IO uint32_t SHSR2;   
    8 R$ P6 @! T3 j- [5 A. L
  21.   __IO uint32_t SHHR;     . B0 h/ z* }) o* Y) ~
  22.   __IO uint32_t SHRR;     
    3 O. I0 c: `% ?" M. ^$ ~
  23. } 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
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */, A* e9 E/ Y* d; \" k, ]
  2. #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
  1. #define PERIPH_BASE         ((uint32_t)0x40000000) 6 U. v5 P7 W' i7 |) M5 d# n
  2. #define D2_APB1PERIPH_BASE  PERIPH_BASE
    , M: g% {1 C# z1 }" X, N) q4 b7 t9 K1 Q
  3. #define DAC1_BASE           (D2_APB1PERIPH_BASE + 0x7400)
    & L  j/ g* U3 B, s* d/ ?
  4. #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
  1. typedef struct2 [6 Z6 M% N8 {) a/ m
  2. {7 Z; s7 j2 j, I/ r% B5 {
  3.   uint32_t DAC_SampleTime ;         
    " W* r  S; r5 u) x7 ?' A( d) B
  4.   uint32_t DAC_HoldTime ;            
    + R$ `7 P  U9 M3 c) ~6 b! V
  5.   uint32_t DAC_RefreshTime ;        }
    2 b+ c5 z/ |. ~3 N3 H% K6 d, V
  6. 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
  1. typedef struct1 F  b4 y3 g7 B# h! W) ~5 v
  2. {1 A3 w: \0 K* u0 ]- \- n( X
  3.   uint32_t DAC_SampleAndHold;          " @3 R3 U  D/ k
  4.   uint32_t DAC_Trigger;                  " @8 {- C, x! V1 e
  5.   uint32_t DAC_OutputBuffer;            
    + K% B9 n! [0 Q& x* q6 u. o
  6.   uint32_t DAC_ConnectOnChipPeripheral ;7 F. O2 u+ z, j7 E$ ?( `
  7.   uint32_t DAC_UserTrimming;            
    2 W, r; D6 u# P! g2 O
  8.   uint32_t DAC_TrimmingValue;         
    ) h8 L  R, J/ {6 L' J/ ^4 H
  9.   DAC_SampleAndHoldConfTypeDef  DAC_SampleAndHoldConfig;      , k& R# @# P  b& B
  10. }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: [
  1. #define DAC_SAMPLEANDHOLD_DISABLE     ((uint32_t)0x00000000)4 m" \0 E2 K4 {! |$ b# I$ n7 a$ l  d
  2. #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
  1. #define DAC_TRIGGER_NONE                                       
    2 [1 @3 i/ G4 C1 s8 H) Z- J8 K5 S9 ?
  2. #define DAC_TRIGGER_SOFTWARE               
    1 G. d. F- r; C; R7 L  T2 k8 J
  3. #define DAC_TRIGGER_T1_TRGO              $ w4 v% ]$ ]( |, I/ Z: x( l0 ^/ D
  4. #define DAC_TRIGGER_T2_TRGO             ; g6 u" ?* P' P  G
  5. #define DAC_TRIGGER_T5_TRGO                * m& x& L7 z3 y
  6. #define DAC_TRIGGER_T6_TRGO               7 D' S1 `7 b* ]# n# u0 f0 m% m/ \
  7. #define DAC_TRIGGER_T7_TRGO            
    ! s; P) a) N1 B. c% p4 o6 V2 b
  8. #define DAC_TRIGGER_T8_TRGO              
    - {7 z6 H1 Z; r8 P+ T
  9. #define DAC_TRIGGER_T15_TRGO              " ]; t* A+ N, a" H6 H$ g. T
  10. #define DAC_TRIGGER_HR1_TRGO1            $ K$ H% |: n+ k5 B0 x# T. G
  11. #define DAC_TRIGGER_HR1_TRGO2         & p5 Z+ o* N2 I( R) r/ u" m; R; t7 }
  12. #define DAC_TRIGGER_LP1_OUT              - s) d8 B7 T, a4 \5 _
  13. #define DAC_TRIGGER_LP2_OUT               1 Y5 a# U& _1 m$ `
  14. #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
  1. #define DAC_OUTPUTBUFFER_ENABLE            ((uint32_t)0x00000000)! W2 T' ?3 o/ u+ S* x9 H2 D$ |  B
  2. #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+ [
  1. #define DAC_CHIPCONNECT_DISABLE      ((uint32_t)0x00000000)3 {1 s" d8 e- w7 T* a5 E
  2. #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
  1. #define DAC_TRIMMING_FACTORY        ((uint32_t)0x00000000)         
    ! B% j- U5 Z, i4 H, b
  2. #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
  1. typedef struct
    : I+ z' N( e- ], ]5 y' |
  2. {7 N) S8 z, E4 F) Z
  3.   DAC_TypeDef                 *Instance;     
    $ V) D# Y- s7 P% ]/ |+ U9 g4 z0 |8 U) }( E
  4.   __IO HAL_DAC_StateTypeDef   State;        
    & ?* b+ s" ^9 s/ i" \5 p* s* J
  5.   HAL_LockTypeDef             Lock;         
    : E. [; y8 l+ U
  6.   DMA_HandleTypeDef           *DMA_Handle1;  . j6 m( r- g: N6 r* Z& w
  7.   DMA_HandleTypeDef           *DMA_Handle2;
    2 u# T, N# n& \* n/ g7 y4 p) R
  8.   __IO uint32_t               ErrorCode;     " N) W, H, f# `
  9. }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
  1. & b, ~  J+ u; V& C1 M
  2. HAL_StatusTypeDef HAL_DAC_Init(DAC_HandleTypeDef* hdac)
    / J- d, g; _4 k3 o; u: A
  3. {
    7 h0 M% w1 `- m1 m
  4.   /* 检测DAC句柄 */
    6 P3 o0 U' x9 {1 F2 _* c
  5.   if(hdac == NULL)+ P/ L9 B' j$ P# i7 T
  6.   {. m. `" ?' z: o3 Q" O+ f  W
  7.      return HAL_ERROR;' o# b  |: N2 a9 Z
  8.   }  y# j& Y% ^5 ^
  9.   assert_param(IS_DAC_ALL_INSTANCE(hdac->Instance));% h) M& R2 k5 u8 Z8 b8 E6 W

  10. * g0 s. j* M/ d5 C
  11.   if(hdac->State == HAL_DAC_STATE_RESET)
    . N  R4 H+ M  b5 L9 D
  12.   {  , p/ T# Q& ~' u% @
  13.     hdac->Lock = HAL_UNLOCKED;6 B( _6 F( i$ {8 w/ H: R1 y# o
  14.      /* 初始化GPIO,NVIC等 */
    8 f! P+ i, ^# v" r$ J8 ]  A/ _: m) h2 d; I
  15.     HAL_DAC_MspInit(hdac);
    1 n- \6 \) V5 {' `
  16.   }1 H" k2 F4 o3 _$ u

  17. 3 M& \% h9 S: t7 p# s
  18.   /* 设置DAC状态忙 */
    ! N& r( L& y5 r$ o
  19.   hdac->State = HAL_DAC_STATE_BUSY;7 A* K# O, r5 y
  20. & f1 A) b6 u2 Q" Q4 R
  21.   /* 设置DAC无错误 */
    . \( p1 A! J  F% `- j
  22.   hdac->ErrorCode = HAL_DAC_ERROR_NONE;' S* z5 N& W5 f; o* c# F- x
  23. " V/ }0 p  m' f
  24.   /* 设置DAC就绪 */
    0 O, w) d# N' D, N4 `3 T
  25.   hdac->State = HAL_DAC_STATE_READY;
    8 f. d# s( {& ~* q- B

  26. - y8 g  Z9 Z5 j, U2 F
  27.   /* 返回HAL_OK */
    ' d) Q( b% H% h4 ?( t+ H" B
  28.   return HAL_OK;7 d8 f0 b+ _& y( o. F" h: |
  29. }
复制代码

$ 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
  1. if(HAL_DAC_DeInit(&DacHandle) != HAL_OK)# Y; U- s/ l( d8 d. I1 r5 v# }
  2. {- H2 f6 l$ z3 g2 S) F9 {6 u
  3.     Error_Handler();7 p/ s/ \; L8 q8 P. R
  4. }  % t# W2 O, |) }
  5. if(HAL_DAC_Init(&DacHandle) != HAL_OK)
    5 {+ f; [& r9 w+ i& k& e6 X& ?  I
  6. {
    : {% Q" L2 m% |  y) }% F6 u( o% n' S
  7.     Error_Handler();$ j6 ?3 P" b7 ^3 O. @% h* z. @+ {
  8. }
复制代码

7 E( z9 [) `: V( h- y使用举例:1 `2 x7 C# _; B. V
9 W  v! \- P7 A$ w, K* Y* Q4 u
  1. DAC_HandleTypeDef   DAC_Handle;# S6 ]7 j7 j2 l& s0 ?& N# ]
  2. DacHandle.Instance = DAC1;
      t; E* a; Q7 s  [7 B0 t) T6 N
  3. if (HAL_DAC_Init(&DacHandle) != HAL_OK)
    9 H) P0 g$ z% y
  4. {
    $ K% k) s6 J/ B+ L7 ^9 x
  5.     Error_Handler(__FILE__, __LINE__);9 R/ N0 p0 l* ?' x2 H: u
  6. }
复制代码

- 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
  1. HAL_StatusTypeDef HAL_DAC_ConfigChannel(DAC_HandleTypeDef* hdac, DAC_ChannelConfTypeDef* sConfig, uint32_t Channel), j7 F" d' E$ B
  2. {
    ! ~7 U: E3 |5 ?4 B, E- f* ?
  3.   uint32_t tmpreg1 = 0, tmpreg2 = 0;
      [% x$ x0 F+ T* \7 v+ u% b
  4.   uint32_t tickstart = 0;
    ! w0 k5 a! P+ {4 a3 \7 H* M

  5. ) t! N) o* H, J6 t4 A
  6.   /* 部分省略,未贴出 */
    6 X" @2 l% [9 P, S1 P6 N& [6 D0 {

  7. ! V: O8 i# ]3 Q7 {% ]: _0 x: ]
  8.   /* 上锁 */$ n% w, `& h# i6 A; W
  9.   __HAL_LOCK(hdac);
    * T4 F1 ?2 s; I9 J. c7 J7 L

  10. ! Z  F) ]$ R! P, G5 @
  11.   /* 设置DAC忙 */5 ]$ n8 G: Q' H. U# n* L; R! }; {/ @
  12.   hdac->State = HAL_DAC_STATE_BUSY;& P$ L) K/ |! J- [6 J+ c

  13. / B& _5 }2 z* c1 c7 |6 v
  14.   if(sConfig->DAC_SampleAndHold == DAC_SAMPLEANDHOLD_ENABLE)
    8 W/ I# n2 c  e  A5 D. h. @
  15.   {
    7 ?" C; ~! k/ `
  16.     /* 通道1设置 */
    ! f! P! ]" B0 [5 W
  17.     if (Channel == DAC_CHANNEL_1)
    9 E  s0 b$ U4 z& z# X5 n  f; Z" s
  18.     {
    / M/ W- @# s- U. D! T
  19. + b. Y' M# L# k2 Z- k, K

  20. $ f) Z, F$ m: \: R4 y
  21.     }
    9 T6 z1 C6 Z8 C" }2 O* h! g8 a
  22.     else /* 通道2设置 */% |5 W6 D3 g5 J2 K
  23.     {" J8 D. H  M9 C  W+ q; K
  24.     }" l% [6 n4 j# Q7 w5 e
  25.   }) ^  C- P: s2 ^+ l9 ^  |
  26. ; i. l' z- g9 j9 o- _+ w  `- m* V
  27.   if(sConfig->DAC_UserTrimming == DAC_TRIMMING_USER)+ k8 l" i; W  Z' S% h, l5 o
  28.   /* 用户校准配置 */
    0 z+ g- e& m# L
  29.   {" j" ^1 j4 _- J" ^  p% ~) a' o
  30. . f! g/ R# q1 L$ H

  31. ; j8 e& U) ~- g
  32.   }
    0 k8 F4 n5 p6 n) U' \7 b) j4 ^% P
  33.   /* 出厂模式无需配置,复位后自动设置 */
    0 e! a) W7 m8 Q6 b
  34. - v7 g# d. @( P+ e" a
  35.   /* 获取DAC MCR数值 */
    $ z) ?* I4 r/ ~: R3 ^9 f
  36.   tmpreg1 = hdac->Instance->MCR;
    9 z1 v! {4 ]1 l5 B0 w. p' V
  37.   /* 清除DAC_MCR_MODE2_0, DAC_MCR_MODE2_1 和  DAC_MCR_MODE2_2 位 */1 k4 b( r% M* \" i
  38.   tmpreg1 &= ~(((uint32_t)(DAC_MCR_MODE1)) << Channel); * W+ h5 F7 }' ]5 W
  39.   /* 配置DAC通道 */+ N9 }0 @4 D) N# [# k- e
  40.   tmpreg2 = (sConfig->DAC_SampleAndHold | sConfig->DAC_OutputBuffer | sConfig->DAC_ConnectOnChipPeripheral);
    - W0 A; S7 \# ~* v/ c& E) R" }: \
  41.   tmpreg1 |= tmpreg2 << Channel;
    - d% S1 F. L# J3 h
  42.   /* 设置MCR数值 */7 g3 E/ g: }0 m
  43.   hdac->Instance->MCR = tmpreg1;
    $ ^0 b) W! k6 [. Q) }

  44. 1 X! Z: n, [# L3 U! I
  45.   /* DAC工作在正常模式 */: N1 ~" t% h7 S: i
  46.   CLEAR_BIT (hdac->Instance->CR, DAC_CR_CEN1 << Channel);* P" U, U7 e1 v1 X
  47. . m0 C9 d% ]) U4 m( y" c5 h
  48.   /* 获取DAC CR值 */
    : ?$ k$ q! {3 P5 H/ n) @
  49.   tmpreg1 = hdac->Instance->CR;* q' p% |; i" B+ s! c9 r, f- Z
  50.   tmpreg1 &= ~(((uint32_t)(DAC_CR_MAMP1 | DAC_CR_WAVE1 | DAC_CR_TSEL1 | DAC_CR_TEN1)) << Channel); 0 \5 i5 y* r. ^" ~9 ]
  51.   tmpreg2 = (sConfig->DAC_Trigger);
    ' _) h8 `4 z& `6 f0 I9 d. s
  52.   tmpreg1 |= tmpreg2 << Channel;! k1 K4 I2 P* S4 z6 a

  53. 3 W/ T$ V! R2 Y( a9 v3 ^
  54.   /* 写DAC CR值 */+ L9 O' h. I, ?7 L1 Y8 R; U
  55.   hdac->Instance->CR = tmpreg1;
    + ~+ \: Z: e0 P7 Z- e  F7 _
  56. 8 v2 O- \% G# `0 t2 ]
  57.   /* 禁止波形生成 */
    ! ~! r6 h! h% ~& O7 I- W
  58.   hdac->Instance->CR &= ~(DAC_CR_WAVE1 << Channel);5 g+ {( f( U7 v- o. L6 u
  59. - A; D+ m) f: ~" G: b
  60.   /* 设置DAC就绪 */
    , e* ^! G3 Y3 ^* ?2 e- }' E
  61.   hdac->State = HAL_DAC_STATE_READY;3 E$ Y2 ]: B+ \$ J- \1 }
  62. ; k. T- t4 J& N7 ^
  63.   /* 解锁 */
    ; a+ ]6 {+ V0 a8 X8 B
  64.   __HAL_UNLOCK(hdac);& y8 C0 Y( ~- L' p' T2 O' q
  65. ) K" {5 N& Y( ]  m# i
  66.   /* 返回HAL_OK */; Q6 H+ ?  s- ^& P+ E" [$ U. s! l
  67.   return HAL_OK;) n+ w, O' {4 c! [4 J8 v- E  I, u8 h
  68. }
复制代码
* 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
  1. static DAC_ChannelConfTypeDef sConfig;
    & D* V8 G9 P* G# z+ ~
  2. static DAC_HandleTypeDef      DacHandle;, E: d% Z  G+ l/ ?6 J0 l

  3. 6 z+ L7 \" ~# I6 t; m: S  c
  4. sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;        /* 关闭采样保持模式,这个模式主要用于低功耗 */4 U: q3 V5 F4 f! d. @2 S' o
  5. sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;                    /* 采用定时器6触发 */9 t/ H& A/ ^! t8 L# j
  6. sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;           /* 使能输出缓冲 */
    1 m! P- Y: M2 j; x; a% w
  7. sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_DISABLE;/* 不将DAC连接到片上外设 */( b, U5 [+ O! [/ G) s; R! c
  8. sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;              /* 使用出厂校准 */* g9 c  U4 U5 U1 {

  9. 4 `# Z5 b' ~' p* B3 X% F
  10. if (HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DAC_CHANNEL_1) != HAL_OK)" \- j/ i+ s( y2 x) Y2 @% ?; r$ e6 \4 R
  11. {9 |# f8 k. l' q
  12.     Error_Handler(__FILE__, __LINE__);
    7 I) [) B/ o1 A% x- N1 n
  13. }
复制代码

# @" 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
  1. 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 @
  2. {
    % ^3 Q2 }6 Z0 ^
  3.   uint32_t tmpreg = 0;4 j6 A+ f& Q7 r$ R$ ~
  4. % M6 w6 Q: F+ _, u! A
  5.   /* 部分省略,未贴出 */
    3 o4 P% N3 \+ X8 O9 H7 ]

  6. 4 \8 ]/ W( e. E$ t. G3 b8 W# e
  7.   /* 检测参数 Check the parameters *// l& {  n1 `: O
  8.   assert_param(IS_DAC_CHANNEL(Channel));
      F7 k% k1 ?4 @& K; G" u& ]
  9.   assert_param(IS_DAC_ALIGN(Alignment));
    5 J7 }2 q$ P9 ]& Y. o

  10. / w3 o$ Z" g4 N
  11.   /* 上锁 Process locked */
    * [6 A8 C' }" H$ ]3 _0 t/ p( F# ~
  12.   __HAL_LOCK(hdac);
    ) I, N$ ^, _9 b4 N, Q0 D- o$ |
  13. ) i; s) z3 D- {/ F8 V% _( J- R
  14.   /* 设置DAC忙 Change DAC state */8 E! ]) r* A. r: S. @2 c
  15.   hdac->State = HAL_DAC_STATE_BUSY;/ A; V* S# `  K" H) p0 D2 L% u
  16. / j% x7 c7 I3 f: ]4 r6 H4 f6 v
  17.   /* 配置通道1 */
    8 M2 b$ I* m. B8 a" m" }0 `4 d& v
  18.   if(Channel == DAC_CHANNEL_1)# s/ Y* |8 T6 s( \* u( G
  19.   {
    - f- n' h; l1 i( s  s. {
  20.     /* DMA传输完成回调 */
    6 A5 a6 @& t$ V# a
  21.     hdac->DMA_Handle1->XferCpltCallback = DAC_DMAConvCpltCh1;- ~4 k; |$ K8 [1 \, l: p
  22. 6 S. A+ g  `/ C
  23.     /* DMA半传输完成回调 */2 t/ j# y9 l, [# _
  24.     hdac->DMA_Handle1->XferHalfCpltCallback = DAC_DMAHalfConvCpltCh1;
    0 a6 c7 Z5 q- G" h
  25. 0 N5 j8 `1 _. w6 {3 A7 A2 X
  26.     /* DMA传输错误回调 */- b3 @" `. i5 M% u& C/ b
  27.     hdac->DMA_Handle1->XferErrorCallback = DAC_DMAErrorCh1;. F6 p0 y7 Z+ ]  U5 I

  28. " O! t+ n6 L* r" A4 o4 e, W
  29.     /* 使能DAC DMA */
    4 E, Z! D% v, [# p) v. x% k
  30.     SET_BIT(hdac->Instance->CR, DAC_CR_DMAEN1);
    & s# [9 k$ D4 n: ?1 e! S1 E2 E' D  E0 f
  31. 3 u; F1 z2 ], A: U
  32.     /* 数据对齐方式设置 */
    - Y, X6 ~% E; E* W# S9 I
  33.     switch(Alignment)
    ' K6 |2 Z# x& G
  34.     {) ]& P8 t2 c8 c9 @; z
  35.       case DAC_ALIGN_12B_R:! M3 e+ w# q* I( \) n
  36.         tmpreg = (uint32_t)&hdac->Instance->DHR12R1;8 r( w( k/ x, T3 L: v$ g- h
  37.         break;% j# I" ^/ J+ L! S' K- t
  38.       case DAC_ALIGN_12B_L:3 _! b7 x% Q6 f# e& l* }
  39.         tmpreg = (uint32_t)&hdac->Instance->DHR12L1;; k- m+ _. s4 M
  40.         break;: L: |# h5 o. w( E" g6 m
  41.       case DAC_ALIGN_8B_R:
    6 H6 b2 M" ^# G9 i& O
  42.         tmpreg = (uint32_t)&hdac->Instance->DHR8R1;
    # m7 H" w! A1 ^' Q; `1 z
  43.         break;
    6 j  w+ Q/ O) }; m7 a% \
  44.       default:
    + ?/ I" o6 q- p
  45.         break;
    ! M' M4 r0 d$ p1 [9 A" |
  46.     }0 r6 x6 s( q$ n6 X: A8 R/ o
  47.   }
    ! K7 m4 R5 ?% d" I$ r8 E
  48.   else3 {, e  n3 a) |; ]* o) Z" U
  49.   {2 U( u7 O  \6 f) D7 N( s, z

  50. 3 R' {3 t. f* Q. g  n* d
  51.     }
    ; Q1 _7 K# X& e6 E/ {) R
  52.   }
    ) O4 L$ |1 F! _

  53. . ]# b! `# N# _) S9 J( U$ u. k3 T
  54.   /* 使能DMA Stream  */% \0 F; q* ^' {7 ^( j: d8 h; b
  55.   if(Channel == DAC_CHANNEL_1)
    4 h5 V/ _4 X; Y) U# s8 u- a
  56.   {
    ! l8 {2 m# g0 e1 _- s% W
  57.     /* 使能DAC DMA下溢中断 */
    ; B7 v( e$ A- N
  58.     __HAL_DAC_ENABLE_IT(hdac, DAC_IT_DMAUDR1);
    + C% U' G" y  J: \2 V" C
  59. 0 \; i) d3 E& q; v# s
  60.     /* 启动传输 */# l* |! g' u5 x* R
  61.     HAL_DMA_Start_IT(hdac->DMA_Handle1, (uint32_t)pData, tmpreg, Length);
    5 P9 u4 E4 r) A9 D
  62.   } - X; B+ u0 q3 i+ y/ s3 D$ \
  63.   else* j. \' J" Y5 K, F; c4 }
  64.   {
    5 K2 m( H% C- U/ H1 ?( G9 e# `
  65.     __HAL_DAC_ENABLE_IT(hdac, DAC_IT_DMAUDR2);7 D5 _, O$ A4 g' _" `5 n$ e
  66.     HAL_DMA_Start_IT(hdac->DMA_Handle2, (uint32_t)pData, tmpreg, Length);; @- d( Z1 V' ]- q% s  M
  67.   }) ?5 x8 |8 z! n- f- d

  68. ; A1 R7 ^& v& k5 Z+ `) w5 G
  69.   /* 解锁 */( J; V7 `, f) I& H
  70.   __HAL_UNLOCK(hdac);
    4 f! D) ^9 V( |% {! D3 m
  71.   /* 使能DAC通道 */
    6 u" J) a9 }; ~
  72.   __HAL_DAC_ENABLE(hdac, Channel);; ^1 \" E1 G3 s5 O2 A

  73. : }: w+ \8 G* [& c
  74.   /* 返回HAL_OK */
    : X: w" G/ A( J6 C& b: {/ y1 s
  75.   return HAL_OK;
    / ]8 J/ ~! X" J9 V0 ?5 j
  76. }
复制代码

! 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
  1. static DAC_HandleTypeDef      DacHandle;
    8 `& k: G9 T4 ?4 R# _. I
  2. 6 ]1 \3 C" U# \9 t3 g" o
  3. /* 启动DAC DMA */   
    / n. }+ j' Z  @. ?, x5 f% a, y
  4. 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
  5. {8 Z+ H5 U" t0 @" I
  6.     Error_Handler(__FILE__, __LINE__);
    3 w9 P6 [) B6 [; y! ~. x3 e
  7. }
复制代码

) ?/ 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
赞 收藏 评论0 发布时间:2021-10-31 20:23

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版