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

【经验分享】STM32F1开发指南笔记30----DAC实验

[复制链接]
STMCU小助手 发布时间:2021-11-27 09:39
本章介绍STM32的DAC功能。本章利用按键(或者USMART)控制STM32内部DAC模块的通道1来输出模拟电压,通过ADC1的通道1采集DAC的输出电压,在LCD模块上面显示ADC获取到的电压值以及DAC的设定输出电压值等信息。: x* g8 ]% }, \  p1 ?8 |% a7 L
) \3 }' A* b- Q* J( {4 U
DAC本身是输出,但是为什么端口要设置为模拟输入模式呢?8 v# M; Q$ W& N+ ?& s
因为一旦使能DACx通道之后,相应的GPIO引脚(PA4或者PA5)会自动与DAC的模拟输出相连,设置为输入,是为了避免额外的干扰。/ U  G& L% [; a% M

; ~* y. z; M9 ^
2020051417082468.png
3 G$ Z6 l( y- Z
20200514170851263.png

4 z% N( j3 ]+ a7 d$ r2 Q+ I9 }8 j' c
20200514171026652.png
/ l$ a% ~8 Z9 _. V" \8 N+ g
20200514171156709.png

" x+ c. D/ u, ?* a
2020051417141896.png

& t  e2 v; W- M- x( Y- A; Q3 R
20200514171611130.png
9 I7 S. D; e- r7 E& `+ z- j
20200514171802467.png
. ~! Y1 }% K* B  n- H/ O% L# H/ a& \
20200514171858461.png
5 `- q  [: U7 |6 n6 {
20200514171949521.png
. A0 M! c( `1 o
20200514172058766.png
% ~8 I/ V+ X8 H- Q; |

& Z. y0 s) @3 x; O) _2 y; B, G) J, {" J
硬件设计  _8 A$ O2 j# j

, o- Y8 y9 h' n+ B; O
20200514172217410.png
8 c5 R# i/ b) T& }! ]0 d
5 F' V7 j1 A$ ^! }; C( ?# k
main函数6 S( n1 x. A/ y$ _4 L3 b6 k5 d
  1. #include "led.h"
    2 |3 z! e* d7 B2 ?! j: m: x, \" \
  2. #include "delay.h"
    $ d# o+ ]' `6 Q
  3. #include "key.h"6 u9 f3 V% O# n( F0 h
  4. #include "sys.h"
    / @) F0 o; h/ x9 t
  5. #include "lcd.h"$ S; S1 h1 s- }# w# A) Y* R' N
  6. #include "usart.h"                  ! W* h9 q, W6 l
  7. #include "dac.h") h, k& b+ `. K: K/ N0 G9 s
  8. #include "adc.h"
    7 w" L, Z* f% k" K3 ]" |( m
  9. #include "usmart.h"
    $ }- \+ l. I. v, Q( S# U) q1 t: L) u

  10. ) Z: Y& g/ u. s4 J: n( n( X
  11. int main(void)) `( b# a2 N3 f3 }
  12. {         " R% N2 L8 Q% S/ N: C
  13.         u16 adcx;
    - Z4 C- I2 y2 y/ E# g+ L5 x
  14.         float temp;8 @! G' C# Q/ ?; B! b5 p
  15.          u8 t=0;         ! {  E; m% a( J$ R* }  T/ o
  16.         u16 dacval=0;9 r3 S: s  w+ M. o% ^
  17.         u8 key;0 [$ R5 @3 i% U  V# C5 Y
  18.         & l. c0 C# ~  J- ?& f
  19.         delay_init();                     //延时函数初始化          / O1 Q/ U& {/ @6 {+ [
  20.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级5 J2 C# u7 M6 _) ?) p4 X
  21.         uart_init(115200);                 //串口初始化为115200
    ; ^: N! p$ @5 L. A
  22.         KEY_Init();                          //初始化按键程序
    ) Z* i, Q1 L2 O- p9 F0 `7 p( B
  23.          LED_Init();                             //LED端口初始化
    2 V- ~! c, ^% B7 ^' n  B0 a$ i+ p
  24.         LCD_Init();                                  //LCD初始化
    7 F7 T5 R. @( ^- k/ n3 G+ M
  25.         usmart_dev.init(72);        //初始化USMART        2 T& Q" s9 ^- S6 A4 r. s
  26.          Adc_Init();                                  //ADC初始化) [- T% e- E$ o7 S7 K" n
  27.         Dac1_Init();                        //DAC初始化0 U1 c0 G) h7 t$ v
  28. , u4 t- [  k  ^9 I' y7 p
  29.         POINT_COLOR=RED;//设置字体为红色
    / `  R. B4 [3 `2 K: s
  30.         LCD_ShowString(60,50,200,16,16,"WarShip STM32");        
    8 i$ e, S0 e3 {7 K2 @& H7 N$ |
  31.         LCD_ShowString(60,70,200,16,16,"DAC TEST");        * \8 F  f( N: z8 @: e
  32.         LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");: v# H6 ]( k' A
  33.         LCD_ShowString(60,110,200,16,16,"2015/1/15");        
    1 D$ Z: w: P8 R
  34.         LCD_ShowString(60,130,200,16,16,"WK_UP:+  KEY1:-");        
    2 \5 j8 K$ ]. o! G
  35.         //显示提示信息                                                                                              ' O# n6 [! G1 w
  36.         POINT_COLOR=BLUE;//设置字体为蓝色2 W& ]! O5 K! i
  37.         LCD_ShowString(60,150,200,16,16,"DAC VAL:");              
    $ ~) t, T# X0 X2 a! R
  38.         LCD_ShowString(60,170,200,16,16,"DAC VOL:0.000V");              
    5 {" D, ^/ l+ d8 j( X' R
  39.         LCD_ShowString(60,190,200,16,16,"ADC VOL:0.000V");* P1 E& g/ b0 I
  40.         ( M; ^& W: S' S
  41.         DAC_SetChannel1Data(DAC_Align_12b_R, 0);//初始值为0                          2 a" [/ V* m! `  y) M8 V; a
  42.         ( t7 I* a6 Y: e. F/ g# z
  43.         while(1)
    - Y4 D3 ^, ?1 l2 u  @' R7 J
  44.         {' m# P1 x7 ]1 q1 E# S7 |
  45.                 t++;
    5 L$ y$ v( G- s; h: j
  46.                 key=KEY_Scan(0);                          
    ' |" C6 b2 t: `
  47.                 if(key==WKUP_PRES)" r3 W( [/ ]+ v7 w+ v) J3 u- @3 Z! m
  48.                 {                 - h4 z3 y, G! _
  49.                         if(dacval<4000)dacval+=200;
    9 r$ `1 T, }1 t8 u# k6 Y
  50.                  DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值        
    2 b$ L. h+ Q. d2 w! }& \/ g3 B
  51.                 }else if(key==KEY1_PRES)        7 |% Z8 x0 V9 L" e" K6 Q
  52.                 {
    - ?9 m! q; V1 s6 z% B) V% o
  53.                         if(dacval>200)dacval-=200;
    6 u/ G  D! C; w6 d
  54.                         else dacval=0;
      T2 _5 G9 M" k# e/ U; c
  55.                   DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值- M. S* o  P1 C
  56.                 }         
    * `: T0 w8 d# u) J3 |
  57.          : ^& w: h4 }7 H4 I0 o/ R3 y8 W4 ^6 K
  58.                 if(t==10||key==KEY1_PRES||key==WKUP_PRES) //WKUP/KEY1按下了,或者定时时间到了
    : P  X% R, Y9 p
  59.                 {        8 L/ ~$ t) ^; D2 e3 r; K5 `9 ?
  60.                         //获取DAC数据# f% U. ]# p# O( |; N
  61.                         adcx=DAC_GetDataOutputValue(DAC_Channel_1);//读取前面设置DAC的值
    $ C& L; D- f5 ]: v
  62.                         LCD_ShowxNum(124,150,adcx,4,16,0);             //显示DAC寄存器值$ _4 i& s5 V, x2 f, Z" {; f& Y
  63.                         temp=(float)adcx*(3.3/4096);                        //得到DAC电压值4 |( F9 W+ v8 @: n, @9 \
  64.                         adcx=temp;
    : o/ {& \& B7 O: D1 J0 K
  65.                          LCD_ShowxNum(124,170,temp,1,16,0);             //显示电压值整数部分
    : W2 K( z2 ]" w" I
  66.                          temp-=adcx;
      t, T1 |. d% _% c" e6 J1 i9 r
  67.                         temp*=1000;4 k, h$ S0 n; {9 K9 l6 w- T) f9 D8 ~
  68.                         LCD_ShowxNum(140,170,temp,3,16,0X80);         //显示电压值的小数部分
    3 |% [) t/ _! q) E! m* E
  69.                         
    % U, P4 I0 w0 T+ K& f
  70.                         //获取ADC数据7 J! n  g4 j2 e5 H* `6 ~
  71.                         adcx=Get_Adc_Average(ADC_Channel_1,10);        //得到ADC转换值         
    # D) Y. ?( Y) k
  72.                         temp=(float)adcx*(3.3/4096);                        //得到ADC电压值
    + q2 J8 f2 o' }: \1 g* R1 k% E& U
  73.                         adcx=temp;
    , w- i- L. G4 c3 g
  74.                          LCD_ShowxNum(124,190,temp,1,16,0);             //显示电压值整数部分$ E  f$ p' e! R2 }* P
  75.                          temp-=adcx;
      C) z9 L& Y# V+ V' \
  76.                         temp*=1000;# j: ]) r: J% Z* U
  77.                         LCD_ShowxNum(140,190,temp,3,16,0X80);         //显示电压值的小数部分* i! X6 r& H; C# z* ^
  78.                         LED0=!LED0;           & i  }, r- r  L' T- H- r
  79.                         t=0;2 X, [" `/ o( u5 o( _0 S6 a. q
  80.                 }            3 A3 m  o# U' W9 T4 M
  81.                 delay_ms(10);        
    9 U6 H; t* P/ r4 D% n/ |
  82.         }) E+ s. s; Q. X; V# o( G
  83. }
复制代码

: }& f' o6 l4 Udac.c函数
  _6 }9 x& S7 Y1 L; b& W
  1. #include "dac.h"- }" g' R- x7 J4 d# `9 j% \) F( L$ W

  2. 1 Z* e7 F/ h( V  u7 G2 a; R
  3. //DAC通道1输出初始化/ i- C. V( h3 s" |. w* Q6 Q
  4. void Dac1_Init(void)2 d0 J* O2 Z/ W2 ?, K; Q
  5. { ! B# m9 O' V! b  r& P
  6.         GPIO_InitTypeDef GPIO_InitStructure;! H- _3 l0 _6 w) W
  7.         DAC_InitTypeDef DAC_InitType;9 {# s+ t# ^( A2 ~$ e2 {% q) Y4 R5 V
  8. 6 G" ~* ~  A: n/ `
  9.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );          //使能PORTA通道时钟* y3 |+ {9 J- n) Q6 p
  10.            RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE );          //使能DAC通道时钟
    - S0 r& q; B, J/ y! x# S3 z
  11. ( J2 t- o% a6 q) p: G  [
  12.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;                                  //端口配置3 ^: v4 s' v/ K- m9 x
  13.          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                            //模拟输入
    ' K, e% p2 t$ z# t% X# o0 J+ Z
  14.          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;: B3 K* `. E! A
  15.          GPIO_Init(GPIOA, &GPIO_InitStructure);
    ( u; E1 s& F3 b$ ~: K
  16.         GPIO_SetBits(GPIOA,GPIO_Pin_4)        ;//PA.4 输出高
    : k  Q; }. S4 b7 }* k8 G
  17.                                        
    + u$ |$ `* V* Z/ W- R
  18.         DAC_InitType.DAC_Trigger=DAC_Trigger_None;        //不使用触发功能 TEN1=0
    6 ]1 x" G0 T7 F0 p: {  e% [
  19.         DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生: ^) i* H0 v9 k2 E) p% L9 J( e
  20.         DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置
    * n- _5 Q+ e# E- k5 j5 d# t7 I( y
  21.         DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;        //DAC1输出缓存关闭 BOFF1=1; m, _" k2 h! ]! e8 z# D1 n* k
  22.     DAC_Init(DAC_Channel_1,&DAC_InitType);         //初始化DAC通道1
    ( k9 a8 e  s0 m- n$ n2 ~
  23. : X& i! M8 s9 M# R9 f
  24.         DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC1* H( L7 ^6 m: U8 \5 K
  25. . D1 d- b" w' x$ V
  26.     DAC_SetChannel1Data(DAC_Align_12b_R, 0);  //12位右对齐数据格式设置DAC值$ ]) O8 E9 q7 g+ T9 P3 ^) F0 I& ]" ]9 b
  27. }/ P5 S8 g- S2 |8 z2 S& U

  28. 7 ]5 p4 d% l; b: N% x! a; Z( J! c* K
  29. //设置通道1输出电压' \3 B( e0 D7 C" `
  30. //vol:0~3300,代表0~3.3V
    3 W; h6 Z* q& H. s! C+ `# [) L6 ]
  31. void Dac1_Set_Vol(u16 vol)
    6 h" A$ p) Z/ I4 t
  32. {
    + W+ J' |! Y7 {! I
  33.         float temp=vol;, J4 q2 L8 |% }0 @
  34.         temp/=1000;
    / w" [- j% g( B' Y4 _8 j7 q
  35.         temp=temp*4096/3.3;
    * h/ A$ {# e; F
  36.         DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值; W5 \7 A  n0 p- q' E
  37. }7 h! M5 X9 @% B0 s/ ^0 l
复制代码
4 M- y7 B3 B5 m' Q3 b4 g
adc.c函数9 Q: u$ \- b" [0 k$ b
  1. #include "adc.h"( r, V  A7 S8 }$ e; K0 ~
  2. #include "delay.h"3 W4 B. ~7 D1 m* Y8 C+ o% A
  3.                   
    # y2 _# W5 r& J
  4. //初始化ADC
    ) K7 t7 i1 L: D
  5. //这里我们仅以规则通道为例
    , {( X0 F: D/ F2 O7 C* }
  6. //我们默认将开启通道0~3                                                                                                                                           $ \+ X9 D  z* _% V4 A8 y$ m
  7. void  Adc_Init(void)+ U, E8 N3 ]: G8 y6 o) f! y' Q
  8. {         + Z( D: g- G- r8 X  c$ o
  9.         ADC_InitTypeDef ADC_InitStructure;   h, V' p! I! Q8 H, W
  10.         GPIO_InitTypeDef GPIO_InitStructure;
    - [) `7 p- z! B/ c$ E7 S

  11. 6 g# ?2 f2 l9 s4 y
  12.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );          //使能ADC1通道时钟
    & a1 e8 X4 y9 U3 N6 l

  13. 3 n+ T/ M0 z6 G9 v) y. a) }. S
  14.         RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M) S: K) b0 ?6 e, ]/ V3 L
  15. 0 M" i4 N" P# X/ W
  16.         //PA1 作为模拟通道输入引脚                         ! h& b; P( N- T  U5 Y+ I$ g( ~
  17.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    " b9 H9 M0 x- o, k7 n
  18.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
    # r/ D/ Y& `4 }  x) W
  19.         GPIO_Init(GPIOA, &GPIO_InitStructure);        
    7 h0 y) L( p5 M

  20. , _$ P: x1 g: ^: D& V
  21.         ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值
    5 I% z4 L1 |1 i8 \2 @8 U
  22. * i# \$ g) h5 k# q4 x
  23.         ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式3 v" W1 R% s0 n. |3 [
  24.         ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //模数转换工作在单通道模式+ }  [/ y! y" H+ X0 x  E) C4 M
  25.         ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式
    / d% ?( ]& k& `5 o" z1 C
  26.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动
    ) q/ J  x& t! H: x) G2 g
  27.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐
    3 ?% U( d" f& g8 R+ h# J# B% R
  28.         ADC_InitStructure.ADC_NbrOfChannel = 1;        //顺序进行规则转换的ADC通道的数目
    ! y' c1 |# D) w) _# [
  29.         ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   . Y+ j& x8 P# O3 O. g) ~% E& S5 I
  30. " R7 H% F! A' h4 }, s+ \5 Q+ U/ B( V" o
  31.         ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1
    % C2 ~: Q  v* r( T9 k
  32.         
    ; _! v' T1 l8 I; _8 g
  33.         ADC_ResetCalibration(ADC1);        //使能复位校准  
    / ?# t0 P4 x0 g1 w0 O
  34.          1 ^! @- I8 \. U. T+ L3 u
  35.         while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束
    2 B# T: Z  c  }/ W7 n
  36.         & @8 p/ b4 z) A5 f7 f7 \6 v7 p
  37.         ADC_StartCalibration(ADC1);         //开启AD校准
    & n/ n( S% E( Y5 f- e8 ?/ ~* g
  38. $ @5 _& g5 ~2 L2 Y2 ?
  39.         while(ADC_GetCalibrationStatus(ADC1));         //等待校准结束7 _. n9 P9 T$ Y3 O0 U9 n1 |
  40. }        # R1 D3 {: [; `/ g
  41. " B0 t' q* \* _. U
  42. ( |" O$ [- r0 f4 g4 @9 F
  43. //获得ADC值
    - f+ g9 t9 B5 Z% q' B/ S
  44. //ch:通道值 0~3- l1 T& S( [& C9 E; B8 R, A
  45. u16 Get_Adc(u8 ch)   ' S( l+ t1 U) O; K0 l
  46. {
    6 Z, j% p' u: T6 o2 ?0 W9 ?$ }0 S
  47.           //设置指定ADC的规则组通道,一个序列,采样时间& r' `% f* N- G% b( |
  48.         ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期                                      & r. j6 ?; @( b0 K6 I' W( Q% `

  49. ; \  n+ J! o. W: H
  50.         ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能        
    4 q6 m9 s2 X8 I( f6 o% w
  51.          * u/ a/ D- l2 m' K" U2 k/ k
  52.         while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
    8 a# W9 ]0 r% u" ?' i
  53. 2 R% V" ^8 E. a- E4 B) Z- j6 Q+ d
  54.         return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果
    5 @* U3 O1 ~2 m4 d
  55. }$ v2 K/ r% B; \- G" ]6 `
  56. 9 v8 G9 ^1 Y8 D; [
  57. u16 Get_Adc_Average(u8 ch,u8 times)
    9 m6 \* W. h- x" ?1 D: N
  58. {
    : q7 j% v; w& L% S
  59.         u32 temp_val=0;9 e/ m' N' B9 w9 w
  60.         u8 t;
    ! u' {" p- A& o# m* x5 M
  61.         for(t=0;t<times;t++)
    8 `2 g% K$ {+ i9 i
  62.         {- N6 k7 l! p/ u1 P- v& H+ }
  63.                 temp_val+=Get_Adc(ch);* |! d& n: I/ w: a; i- H
  64.                 delay_ms(5);
      _, u" k" w1 V$ S" h2 ~9 a
  65.         }2 i" t# |1 F% i& L) B
  66.         return temp_val/times;/ S. f# C: ]" W. U: {7 r) S- P
  67. }          / v4 c' `5 n' I# s: V  w
复制代码

0 G$ X. W+ y0 C/ d  Y4 [7 G) w从 main 函数代码可以看出,按键设置输出电压的时候,每次都是以 0.161V 递增或递减的,而通过 USMART 调用 Dac1_Set_Vol 函数,则可以实现任意电平输出控制(当然得在 DAC 可控范围内)。2 R3 x- `1 c0 D" C* `
4 h# b: T. ]  M2 X

. ?3 V5 h, N( V2 e5 Z1 W
收藏 评论0 发布时间:2021-11-27 09:39

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版