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

【经验分享】STM32 DAC详解

[复制链接]
STMCU小助手 发布时间:2022-4-17 21:24
既然有模拟转数字的ADC模块,那么就必然有数字转模拟的DAC模块。顾名思义,该模块仅具有ADC的补充功能。它将数字二进制值转换为模拟电压输出。DAC模块具有多种用途,包括音频生成,波形生成等。通常在大多数8位微控制器中,此模块不可用,并且通过脉宽调制(PWM)可以稍微满足其需求。部分原因是由于它们的硬件资源和运行速度相对较低。所有STM32单片机都具有PWM模块,但大容量STM32也具有DAC模块。STM32DAC模块不是很复杂,并且在工作原理方面与ADC模块相似。0 Q( E% }4 T7 {2 `# O1 A1 s( f; S
% w% G7 m! N2 ?/ @! v) R* h
01、DAC简介5 d9 n1 c4 _2 D) \( R/ C
从STM32F207数据手册看到,STM32F207具有两个DAC模块。; G) c- A- A- J' K1 I
# L2 P8 t# t' p+ i/ U9 b7 K
2801c6e10b7bc11769e781b0947a1a17.png : \4 u3 M! d2 _  `! W7 j. U

1 h' _2 u7 \& m8 P- b% q) t2 @每个DAC具有独立的通道,对应的GPIO分别为:PA4和PA5。对于GPIO的复用功能(Alternatefunctions)和附加功能(Additionalfunctions)。
: P2 O! @: d- X* v& f" A8 Y$ F( S  w8 z  d3 `& \7 E
除了DAC输出的管脚,还有其他相关引脚
1 q0 U  \! ~0 U& [
# m4 w2 ?$ z3 l, Z 128672eab617bb2f7c2901b13234d101.png * t; G  [. `5 c. r
- r7 k" i( l, u( K( d% M/ y
注意:使能DAC 通道x 后,相应GPIO 引脚(PA4 或PA5)将自动连接到模拟转换器输出(DAC_OUTx)。为了避免寄生电流消耗,应首先将PA4 或PA5 引脚配置为模拟模式(AIN)。
8 b' R5 b/ U+ n3 H" P) F. b0 {: O; S5 e0 [7 y" e! y3 x
下面的简化框图显示了STM32DAC模块的主要组件。1 N9 F' \( i% j( Y* I' q
% ^/ y3 o. }2 Q  L
947dae678a261d0fecef952dbec2b5f1.png
% [* @( B# @3 p& Z# \9 b# N( [/ U6 x* r6 I+ [
02、DAC转换3 \% [' e6 v* q; ?; ]3 V5 \0 M
由框图可以看出,DAC受DORx寄存器直接控制的,但是不能直接往DORx寄存器写入数据,而是通过DHRx间接地传给DORx寄存器,实现对DAC的输出控制。+ }& i; X! ]9 \+ Y  D
$ Z) D! ~( Y. r) x! N( a
不能直接对寄存器DAC_DORx写入数据,任何输出到DAC通道x的数据都必须写入DAC_DHRx寄存器(数据实际写入DAC_DHR8Rx、DAC_DHR12Lx、DAC_DHR12Rx、DAC_DHR8RD、DAC_DHR12LD、或者DAC_DHR12RD寄存器)。
* w& D3 o3 [  m" C, |8 L4 [# N1 Z% \  W/ `& c/ p
1.如果没有选中硬件触发(寄存器DAC_CR1的TENx位置0),存入寄存器DAC_DHRx的数据会在一个APB1时钟周期后自动传至寄存器DAC_DORx;
* Y" }) b1 M) O: M
8 O" Z/ g! i% u! V2.如果选中硬件触发(寄存器DAC_CR1的TENx位置1),数据传输在触发发生以后3个APB1时钟周期后完成。
$ A/ B3 [" u; Z. L; Z8 B2 v  O
" X) h1 {; s' D# ?4 Z; x一旦数据从DAC_DHRx寄存器装入DAC_DORx寄存器,在经过时间tSETTLING之后,输出即有效,这段时间的长短依电源电压和模拟输出负载的不同会有所变化。8 Q9 S+ A* o9 f7 C0 H% ~
! r: |6 c5 |; T3 P- R; L& J+ p" ?
e042f894972742c7683797281a85733f.png
7 I! l& t6 D, M' Y/ z  l, L+ z/ j) C3 `2 I$ ^+ A7 j5 u. M
DAC控制寄存器(DAC_CR)
& x4 U7 h7 r% C" k. ~, N) U8 L# m; d; t
8 f5 Q" D4 ]0 `7 E, ?" T1 i     DMAEN1:DAC通道1DMA使能(DAC channel1 DMA enable),我们不使用DMA,故设置为0* q6 A( L0 M  Z9 A3 W

) t8 D8 _$ K- V3 u, E( E* }& i/ L     MAMP1[3:0]:DAC通道1屏蔽/幅值选择器(DAC channel1 mask/amplitude selector)我们没有用到故这几位也设置为0
* ?9 }7 N% s$ V$ \; c: ]
- ?: @* g1 U/ w  s     WAVE1[1:0]:DAC通道1噪声/三角波生成使能(DAC channel1 noise/triangle wave generationenable)我们也没用到故也设置为01 E# h* w' V8 m- f$ t. g

4 m" U. ?1 Q! ^5 d9 v     TEN1:DAC通道1触发使能(DAC channel1 trigger enable)我们不用触发,所以设置为08 \% c3 _% q/ U
; I( U2 i3 P5 z# X& P, a1 ]
     TSEL1[2:0]:DAC通道1触发选择(DAC channel1 trigger selection)注意:该位只能在TEN1=1(DAC通道1触发使能)时设置。我们TEN1设为0,所以这几位就不用设置,默认为0! Y2 B0 ?! [5 l- P7 {7 b

# _: N8 A' J1 Y7 n+ |1 Z' `' O     BOFF1:关闭DAC通道1输出缓存(DAC channel1 output buffer disable)我们关闭输出缓冲故设置为1
$ U+ y  q7 H$ o4 c
" F/ G3 M0 w" q0 F" B' @     EN1:DAC通道1使能(DAC channel1 enable)我们要使能DAC通道、故设置为1。) n) ~2 j5 s! ^0 h! d8 o. C
1 [/ v/ Q5 X4 `( v6 t
03、功能说明3 _* y: i) j1 |: I9 @+ r9 O! e7 i
STM32的DAC等效电路如下
/ u8 b! e! O* H
1 Q4 J8 n% f( i/ |- v 30e013997f8b2c15012d9ffd7c519c8c.png
$ _8 Q  z3 w& t/ K/ u2 n4 k- ?! {; v0 P* p& i) W
该电路中显示的输出缓冲器在内部3.3V电源上运行。与大多数运放在单电源(而不是+/-双电源)上运行一样,输出摆幅永远不会真正达到目标。但是,如电路所示,有两个内部开关(S1和S2)可通过寄存器控制。将它们都打开将通过两个串联的电阻(Ra和Rb)将“DACINT”信号直接连接到“DACOUT”引脚。作为参考,Ra+ Rb约为15k。
7 i" c. A* n6 Q0 y, v( i
& @& w. N4 z1 G' v2 T根据选择的配置模式,数据按照下文所述写入指定的寄存器:
  T+ R! U4 @- X, J. R. i9 ]  J
* \; r. s9 j2 F( _, B/ E; T4 Y. x单DAC通道x,有3种情况:+ W; b: |, b+ G' v# Q. x4 a8 H

& F( P) |. e9 O1.8位数据右对齐:用户须将数据写入寄存器DAC_DHR8Rx[7:0]位(实际是存入寄存器DHRx[11:4]位);. D5 J% l. o& r+ r' m5 Y) ^) Y0 A# d

- M3 H3 c4 J2 c& l9 v% t4 L8 \2.12位数据左对齐:用户须将数据写入寄存器DAC_DHR12Lx[15:4]位(实际是存入寄存器DHRx[11:0]位);
6 e8 D  F0 H" p" ^; M' @! P/ L2 _4 e$ I, p, o. I
3.12位数据右对齐:用户须将数据写入寄存器DAC_DHR12Rx[11:0]位(实际是存入寄存器DHRx[11:0]位)。2 v' b' B0 x3 ], Y6 s; Q% H
6 ~0 r- \/ u/ Q. S: b. d
一般采用第三种方式:12位数据右对齐比较多。
& I7 l0 j8 Z% B+ i+ g4 N: `* ^( v; X# V% s; n& l! B
根据对DAC_DHRyyyx寄存器的操作,经过相应的移位后,写入的数据被转存到DHRx寄存器中(DHRx是内部的数据保存寄存器x)。随后,DHRx寄存器的内容或被自动地传送到DORx寄存器,或通过软件触发或外部事件触发被传送到DORx寄存器。4 c/ B" D' ~; P! ?5 y' T4 R

: F2 m" A# h& G: W b6fca6bf1d6da39d4be750e643e30949.png
0 X4 ~  ?: B+ E. ?8 \% K! `' Y8 T5 R' {" W
双DAC通道,有3种情况:" A$ J2 J* K0 q# r8 b

% O  B; J9 }: R. \: H/ N( a$ P1.8位数据右对齐:用户须将DAC通道1数据写入寄存器DAC_DHR8RD[7:0]位(实际是存入寄存器DHR1[11:4]位),将DAC通道2数据写入寄存器DAC_DHR8RD[15:8]位(实际是存入寄存器DHR2[11:4]位);- W$ f5 x3 x5 w) q5 g. r
1 E4 F: K. n; v0 j5 z- _
2.12位数据左对齐:用户须将DAC通道1数据写入寄存器DAC_DHR12LD[15:4]位(实际是存入寄存器DHR1[11:0]位),将DAC通道2数据写入寄存器DAC_DHR12LD[31:20]位(实际是存入寄存器DHR2[11:0]位);
" v! M4 k1 F2 D) X( b1 w4 K2 n. v1 \" g/ B) S/ Q9 G! V* z+ v
3.12位数据右对齐:用户须将DAC通道1数据写入寄存器DAC_DHR12RD[11:0]位(实际是存入寄存器DHR1[11:0]位),将DAC通道2数据写入寄存器DAC_DHR12RD[27:16]位(实际是存入寄存器DHR2[11:0]位)。3 C; x5 z( G  e3 G9 Y/ Q
  M7 v; a$ W/ f% A2 I$ H
a6794a43af583632c12727bc28837227.png
, b3 G1 z( g3 s
" T% b, ~- R' }$ O: L1 F8 X04、DAC输出电压
$ j0 D: {, |( a; M! J当DAC的参考电压位VREF+的时候,数字输入经过DAC被线性地转换为模拟电压输出,其范围为0到VREF+。* C9 F% X" f3 y7 ~5 q0 w' A4 Q( R

4 q- i' H/ o5 U4 h5 A: O任一DAC通道引脚上的输出电压满足下面的关系:1 G$ ?4 W+ a7 d9 I6 [# H; a

# t$ H8 f% A  ^DAC输出= VREF x (DOR / 4095)。
- m: D$ e9 t7 ~8 g( Y7 R8 j; R" g( n1 @6 O6 S7 ^: E8 R
注意:此时数据格式:应该选择12位数据右对齐。
% f  t2 l% S- z' f
$ d* _1 N& x  ^9 a) Y05、代码配置
% }. Y) K! E( U. HDAC配置1 Y/ Q, [! T. ]6 t
0 n6 i8 B& s+ \3 a$ I
  1. void DAC1_Config(void)7 I  a7 E" d* P8 N# e& O% E- c
  2. {4 Q5 ^2 l4 m- p: i. _! f
  3.   DAC_InitTypeDef  DAC_InitStructure;& a6 L$ n) ]1 s9 [! h1 J' U4 }
  4.   GPIO_InitTypeDef GPIO_InitStructure;: Z3 k  m% n6 H$ {4 L* ?8 A

  5. 5 r0 u0 n1 o, J0 f) f2 W
  6.   /* DMA1 clock and GPIOA clock enable (to be used with DAC) */3 g; M- }% x. O# I
  7.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);( K' ~1 o) N, h- M0 P
  8. , I1 P8 G8 }7 A) Z1 U
  9.   /* DAC Periph clock enable */
    % G" k3 z& i9 w- G0 ~( k
  10.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
    ( o1 T- o. o# W) M
  11. % s, Q( W) [5 U: q$ G. o
  12.   /* DAC channel 1 & 2 (DAC_OUT1 = PA.4)(DAC_OUT2 = PA.5) configuration */" x* T7 r+ s* D  S- m" y! g( K5 L
  13.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;# `( |$ a. ]; _9 Q% N* I9 L! C
  14.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;" g/ R+ z: _  `
  15.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;. Q0 I# t! ?0 V7 L" W; a
  16.   GPIO_Init(GPIOA, &GPIO_InitStructure);
    * Z. ]  `: o+ M* X# K

  17. $ s! w/ O9 w- d, [" A; |1 v
  18.    /* DAC channel2 Configuration */" D7 @6 s( ?7 h
  19.   DAC_InitStructure.DAC_Trigger = DAC_Trigger_None;$ d5 J$ U9 M, Z% P" @2 x; o% _0 i- y
  20.   DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
    , e: ?) e0 }+ V
  21.   DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0;1 V: w9 w; p- T7 T+ i) ^
  22.   DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
    4 V; h) P' ^, D0 f
  23.   DAC_Init(DAC_Channel_1, &DAC_InitStructure);( Y- ^! i7 M# s! T2 t4 d
  24. ) H6 `# m7 ^# B9 v' c' e
  25.   /* Enable DAC Channel2 */
    ! l% K- W( Y: X8 N& x4 ]
  26.   DAC_Cmd(DAC_Channel_1, ENABLE);  v0 ^- _" c- L% ~
  27. }
复制代码
+ s' \: Y7 F  R" m3 W) {  f
设置输出电压# s. L1 t7 L  t; D
% |2 C$ e. O$ I8 Z
  1. //设置通道1输出电压8 N: p5 Q0 L) e; }" x' e
  2. //vol:0~3300,代表0~3.3V
    8 J: P6 b- j$ O, B6 U1 N- a
  3. void Dac1_Set_Vol(uint16_t vol)
    0 G. c# F1 W) o$ I2 o: n1 A! L: v
  4. {4 N$ C1 L8 {  \) [  q
  5.   double temp=vol;$ x6 J5 O, p0 u' ?- W2 z7 b
  6.   temp/=1000;: l, K6 }) M; d/ `1 u/ b
  7.   temp=temp*4096/3.3;
    / p; A4 w% s5 A' I6 Y6 ^
  8.   DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值
    8 A; Z) c( [  D; X9 v! @8 w* U% M3 c
  9. }
复制代码

4 i$ L/ M! H. c: V6 L" _9 g7 s: i测试用例很简单,就是反复输出1.2V和3.0V电压
3 h7 E; L, m) u6 C! I7 ^7 B2 v6 x& Q. u
- F5 l3 T& E5 W6 ^; w
  1. while (1)
    " w+ F+ K7 h. g6 T6 }% t8 E
  2.   {' p4 D* W, m2 G$ ^( f
  3.     GPIO_SetBits(GPIOE,GPIO_Pin_4);  //熄灭LED灯. J$ a7 x& a, `2 k: B3 V
  4.     Dac1_Set_Vol(1200);
    , [: Y; Z. j2 b, R1 t
  5.     LCD_ShowString(0,0,"DAC OUT 1.2V");! B% Y# N; v& W$ l8 ]# g) j
  6.     Delay(500);                      //延时500ms4 X2 ~6 c; X' a/ l+ T) W* N
  7.     GPIO_ResetBits(GPIOE,GPIO_Pin_4);//点亮LED灯; l9 E' x/ e, U" x2 c
  8.     Dac1_Set_Vol(3000);. L7 h2 K% Q0 V% F
  9.     LCD_ShowString(0,0,"DAC OUT 3.0V");
    9 {' I9 l& K5 u  i6 Q! e) D. g
  10.     Delay(500);                      //延时500ms
    $ n% r% ]' m5 m; L' Y& O5 n! e
  11.   }
复制代码
- s7 e9 Z9 o: j
下载验证
  _! d  N) L2 i/ A4 F  Y' O8 \0 U3 r- {8 ]
f1dd10238818b89eab06440a5d2aa4c2.gif
9 L5 s7 v; X" ^7 L
% Z9 g) r' p+ s
5 q! [* {/ p4 s/ {( h5 f) \
) J" s1 U6 J' U, o* G: f/ h* ?" \$ q0 c6 ^8 g0 Q
赞 收藏 评论0 发布时间:2022-4-17 21:24

举报

0个回答

所属标签

相似技术帖

官网相关资源

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