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

玩转STM32CubeMX | DAC数模转换

[复制链接]
STMCU小助手 发布时间:2020-12-11 09:36
1.DAC数模转换
DAC(digital to analog converter)即数模转换器,它可以将数字信号转换为模拟信号,它的功能与ADC相反。在常见的数字信号系统中,大部分传感器信号被转化成电压信号,而ADC把电压模拟信号转换成易于计算机存储、处理的数字编码,由计算机处理完成后,再由DAC输出电压模拟信号来驱动某些执行器件,使人类易于感知。如音频信号的采集和还原就是这样的一个过程( [+ D$ R. }* ^* q
STM32F1的DAC模块是12位数字输入,电压输出型的DAC。可以配置为8位或12位模式,也可以与DMA控制器配合使用,DAC工作在12位模式下时,数据可以设置为左对齐或右对齐。DAC模块有2个输出通道,每个通道都有单独的转换器。在双DAC模式下,2个通道可以独立地进行转换,也可以同时进行转换并同步地更新2个通道的输出。DAC可以通过引脚输入参考电压VREF+以获得更精确的转换结果。DAC结构框图如下示:
2.1.png
! J5 ?  T/ y, y0 `
2.2.png
) J$ D( d# p6 A: {8 T
  • VDDA和VSSA是DAC模块的供电引脚,VREF+是DAC模块的参考电压,DAC_OUTx是DAC的输出通道;当参考电压为VREF+时,DAC的输出电压是线性的(0~ VREF+),12位模式下DAC输出电压计算公式如下:
    DACx 输出电压 = VREF+ * ( DORx / 4095 )
  • DAC输出是受DORx 寄存器直接控制的,但是不能直接往DORx 寄存器写入数据,而是要通过DHRx间接的传给DORx 寄存器,实现对DAC输出的控制。如果未选择硬件触发,1个APB1时钟周期后,DHRx中存储的数据将自动转移到DORx 寄存器;如果选择硬件触发,将在3个APB1时钟周期后进行转移
  • 当DORx加载了DHRx内容时,模拟输出电压将在一端时间tSETTING后可用,具体取决于电源电压和模拟输出负载,可以从数据手册查到tSETTING的典型值为3us,最大值为4us,因此DAC的转换速度最快是250K左右
      s) `0 F% H6 }+ t4 G
. S2 }" d  J; G; m9 Z& C6 a

! h9 ?! E1 e( g. _1 v9 m# L
2.3.png
9 f, D3 L$ M5 ^

  j6 W# m$ q( M
   DAC可通过外部事件(定时器、外部中断线)触发转换,外部触发源列表如下示

& [" e! N! V0 [: v+ e
2.4.png

- M/ B' p8 [3 m+ s1 u+ R
# x: j$ i: A( Y- g* j4 j, q8 K6 n

: ?8 M5 n1 P8 p$ S% Y  z
2.硬件设计

* ?% B3 ~3 u; U) q7 f8 K; V' X1 j
本实验通过D1指示灯来提示系统运行状态,K_UP用来增加DAC输入值,K_DOWN用来减少DAC输入值,输入值的改变将控制DAC_OUT1的电压输出,通过USART1将输出的电压值打印出来
4 L/ i: X8 D4 R: p8 Y
  • 指示灯D1
  • USART1串口
  • DAC_OUT1(PA4)
  • K_UP和K_DOWN按键
    8 t2 J  x. D% G3 W

- [3 h' c6 e8 U5 D& ?* t

$ p7 C" b$ e% ?3 O8 v! L1 _, e
3.硬件设计

, o7 b2 K2 i: u' H
3.1  STM32CubeMX设置
# m1 ]  H1 X% T8 P, {4 m: k5 L! V

1 g- x5 [+ W  Z: Y3 f& J5 A( P* c; A% p, F
$ m% M  j. V. z! l9 ?
0 R- b. o0 f8 p9 f0 k/ _  v
  > RCC设置外接HSE,时钟设置为72M
  > PC0设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
  > USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位
  > PA0设置为GPIO输入模式、下拉模式;PE3设置为GPIO输入模式、上拉模式
  > 激活DAC_OUT1,关闭输出缓冲,不使用触发功能
; Q4 {  R7 {+ [
2.5.png
0 A  T) S& G, R, i0 Q8 R
  > 输入工程名,选择路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码

' ]. I% w' X+ [1 x# e! {" M
3.2  MDK-ARM软件编程
  >  在dac.c文件中可以看到DAC初始化相关函数
  1. void MX_DAC_Init(void){2 k. }6 F$ S, \0 q5 U( W5 {+ B
  2.   DAC_ChannelConfTypeDef sConfig = {0};1 u% r& r" U& c- `* ]; W0 v/ M  n
  3.   /** DAC Initialization */3 N/ ^" j( w1 f
  4.   hdac.Instance = DAC;
    3 F+ q1 {) B1 s
  5.   if (HAL_DAC_Init(&hdac) != HAL_OK){
    7 W/ i+ T) Z: h3 O
  6.     Error_Handler();% G2 [4 I/ ?$ |. `# y
  7.   }
    ) c" Z) c, |, D. j
  8.   /** DAC channel OUT1 config */
    ; h! j: t. s+ y6 b- G7 ~& [* i
  9.   sConfig.DAC_Trigger = DAC_TRIGGER_NONE;        //不使用触发功能' Q9 L. R( p: a) _) J
  10.   sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;        //输出缓冲关闭
    1 z  ^1 P  |1 T  A" M) F2 j) O
  11.   if (HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1) != HAL_OK){' D' I8 U2 q( l% Y8 Z0 i: _3 F5 l
  12.     Error_Handler();
    0 [3 _. X4 N  H/ ]+ ]
  13.   }* k% F+ s3 G/ k4 h" L
  14. }2 F- m1 Z9 @6 u5 g9 Z

  15. 0 H7 V5 M/ W  U$ l4 n
  16. void HAL_DAC_MspInit(DAC_HandleTypeDef* dacHandle){
    $ M, A7 v' j! X9 [, e
  17.   GPIO_InitTypeDef GPIO_InitStruct = {0};( h- G  V- y9 j
  18.   if(dacHandle->Instance==DAC)  {* k. {& W4 n! d. N6 S& H+ v
  19.   /* DAC clock enable *// ^) T3 t3 V9 i, C
  20.   __HAL_RCC_DAC_CLK_ENABLE();        //使能DAC时钟
    9 n/ {* C& o! t" \
  21.   __HAL_RCC_GPIOA_CLK_ENABLE();        % p) b: ~! i. T5 T& Q8 Z
  22.   GPIO_InitStruct.Pin = GPIO_PIN_4;
    ; [. n! l4 b( o  V* W( e6 s" J% ]$ |
  23.   GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;    //模拟
    % l/ s2 u5 m2 |9 P: ^" J3 k
  24.   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    + |( s* i6 p& U; ]
  25.   }
    - }9 r4 f8 O) C; U
  26. }
复制代码
  > 添加按键驱动文件key.c 和相关头文件key.h,参考按键输入例程

# u; b1 q- U# p( B. E; @* A
   > 在main.c文件下编写DAC测试代码
  1. int main(void){4 F$ {+ j+ j( D/ F0 R! A, r
  2.   /* USER CODE BEGIN 1 */
    0 k* n4 C& h5 i- \7 @" g
  3.   uint16_t dac_val;        //读取的DAC值
      s3 c, Z- Q  s( c5 a9 G
  4.   float dac_vol;        //转换后的电压值  U6 `# B1 r# x# s; ^
  5.   uint8_t t = 0;
    - p/ {% Q0 e/ v' i* ?! a( v
  6.   uint16_t dac_setval = 0; //DAC设置值
    . o" j2 n+ b# w1 e
  7.   uint8_t key;1 T  k9 M9 ~/ O) U
  8.   /* USER CODE END 1 */1 X3 x' d. C- g/ B' x, p+ T& w
  9.   HAL_Init();4 q) Q& r+ I5 i+ J0 `$ g* q
  10.   SystemClock_Config();
    ; z* J( v* H3 Z" f2 O1 W
  11.   MX_GPIO_Init();/ a9 ^4 u2 M5 F! E
  12.   MX_DAC_Init();* w, R+ u. A- T: S- }
  13.   MX_USART1_UART_Init();
    9 X. Q. j3 x/ ~0 @$ B
  14.   /* USER CODE BEGIN 2 */5 k+ z' `/ X' b4 z% o
  15.   HAL_DAC_Start(&hdac,DAC_CHANNEL_1);        //开启DAC通道1# y7 |$ {1 j9 D1 O5 ]% w
  16.   HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,0);//置初始值为0  e, u' C$ G3 W. x6 Z
  17.   /* USER CODE END 2 */
    - X! ]( B  H* [8 k; z3 K
  18.   while (1){
    " V2 d1 b' ^. v% q0 c
  19.     t++;
    & `8 W4 n3 N& C5 P
  20.     key = KEY_Scan(0);" T$ Z# c, G# ^1 ?: u
  21.     if(key == KEY_UP_PRES){
    ) l! T3 ?1 y0 E8 e4 E$ V
  22.       if(dac_setval < 4000)
    $ I6 K0 t" h0 \! \; A
  23.       dac_setval += 200;
    ) h% H. p5 i& y9 k
  24.       HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,dac_setval);
    / ], [3 r' ^. b! C
  25.     }- O/ U# t3 G" g: h4 h& p
  26.     else if(key == KEY_DOWN_PRES){
    ( P% g4 h: }. N1 X- Z
  27.       if(dac_setval > 200)
    " }& |: a- d! Y) i5 J$ R2 v# f
  28.         dac_setval -= 200;) ]7 t( h- c& h; \1 y% y
  29.       else7 _  J5 X( o; ?  x
  30.         dac_setval = 0;
    0 v+ G8 H6 B4 D0 D
  31.       HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,dac_setval);
    0 O& t0 j4 @$ {' D. X
  32.     }
    9 O7 ]9 T1 h7 v3 j! ^
  33.     /按键按下了或定时时间到
    ) l- O6 N3 T" u( w. \% v) o; b
  34.     if(t == 10 || key == KEY_UP_PRES || key == KEY_DOWN_PRES){        /
    5 f; G% Q1 V/ {8 z6 U
  35.       dac_val = HAL_DAC_GetValue(&hdac,DAC_CHANNEL_1);
    0 O1 b! S2 a2 i& y
  36.       printf("DAC_OUT1 DAC value: %d\r\n",dac_val);
    9 U0 I* r2 u' ^  _- f5 L. l, Q
  37.       dac_vol = dac_val * (3.3/4096);
    , Z6 Y' i0 Z* R9 H% d! V1 u
  38.       printf("DAC_OUT1 VOL value: %.2fV\r\n",dac_vol);+ U/ F3 \1 d' I! N9 y3 M
  39.       printf("\r\n");
    ! X* f7 m4 \$ y9 g' g
  40.       t = 0;
    2 Y( d% d4 [$ H. U
  41.     }
    " L- A4 n) g" L, A+ _: I8 }, f
  42.     HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
    . n7 r: J# Q, B4 q8 }
  43.     HAL_Delay(100);
    : `3 Z; R& l8 p' k5 I4 M( w9 m
  44.   }# c: ^  k$ d; ?% ^* E
  45. }
复制代码
: Y# G2 W7 v# h* a# q5 B
4.下载验证
编译无误后下载到开发板,可用看到D1指示灯不断闪烁,同时打印出DAC通道1的DAC值和电压值,当按下K_UP按键输出电压增大,按下K_DOWN按键输出电压减小
* Q! z9 p4 m, G* }, j2 E, Z
2.6.png
0 h# k: |" I" E* v* N& e) U
文章出处:嵌入式工程狮 安迪西

' |. F! z! h9 l

/ }% @8 d5 |  ~$ S# ~7 h

7 T! A7 x2 r7 H: ~6 a4 m6 e4 p

" E# N" V8 f% R/ y7 ~( j" x
赞 收藏 评论0 发布时间:2020-12-11 09:36

举报

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