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

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

[复制链接]
STMCU小助手 发布时间:2021-11-27 09:39
本章介绍STM32的DAC功能。本章利用按键(或者USMART)控制STM32内部DAC模块的通道1来输出模拟电压,通过ADC1的通道1采集DAC的输出电压,在LCD模块上面显示ADC获取到的电压值以及DAC的设定输出电压值等信息。
4 ~) S5 ?/ `4 \9 X; `. j+ I# f- _$ f2 X8 _7 `, t+ a# `
DAC本身是输出,但是为什么端口要设置为模拟输入模式呢?
3 C9 l1 L9 Y* v- C. g! n1 a% k因为一旦使能DACx通道之后,相应的GPIO引脚(PA4或者PA5)会自动与DAC的模拟输出相连,设置为输入,是为了避免额外的干扰。
4 [& w2 X* J3 E0 `2 J5 {) G
0 W" P* O4 ^7 `
2020051417082468.png
8 N. b  ]0 A# v; B9 x! L7 g
20200514170851263.png
6 g/ N8 ?, o' R1 ~" A4 ^" E
20200514171026652.png

( f& z: ]0 ?; I0 R' B/ X, |0 a3 w8 U
20200514171156709.png
- ?5 j6 _! u9 J. G5 z5 u
2020051417141896.png

- v) H" c0 Q8 e  y
20200514171611130.png

$ e8 K8 ]& s4 Q3 [/ Q
20200514171802467.png
! [* K, v' I" S# O' a$ E! k8 L
20200514171858461.png
& n# x6 m. ]+ q5 _5 H) h! a* a8 E: t
20200514171949521.png

+ P- p' f- u2 K2 X5 O% ^
20200514172058766.png

% S& ~. T, v' P$ V7 c2 ~, |2 Y) R

  a: [5 h, q- V硬件设计
3 f4 D; [4 b0 u8 [* X; x# Q" c( y0 R
20200514172217410.png

* L- q$ O8 M4 n  f4 P; Z6 W: U# u: Z9 s- p
main函数( U% T  c" r7 `* J2 W# J1 C
  1. #include "led.h"
    + n6 m; y6 `% G- X: v- K. z
  2. #include "delay.h"
    0 l* |+ q! ^" m' z" w$ o
  3. #include "key.h", D  |8 D. V% ?8 L! p
  4. #include "sys.h"
    6 e( ]7 ^# v! U! N. C
  5. #include "lcd.h"; N3 J$ b$ V( x
  6. #include "usart.h"                  
    * d( |# [* O7 F. `8 X8 w/ r
  7. #include "dac.h": M9 |: A" Y% A$ O8 V0 d* m
  8. #include "adc.h"
    % D+ ]! `/ `" A- E
  9. #include "usmart.h"% Z7 n) M: k  U3 q* n* Q; m

  10. * X5 c' I+ g2 X0 I5 s7 w
  11. int main(void)
    1 m" Q+ e- ~' X/ T
  12. {         + w# o  Z2 E: _$ S6 {# x( e
  13.         u16 adcx;& S" D& A% \! M* I6 s5 z2 u
  14.         float temp;2 H3 k8 T+ R, c9 ?6 t% b' W
  15.          u8 t=0;         $ W, o( x9 S0 \" H- D$ n
  16.         u16 dacval=0;
    ; T4 b9 G5 P. t5 f1 i3 T+ i0 P
  17.         u8 key;8 y' k" A6 k1 G3 `$ t, E
  18.         
    & l+ V$ C  w$ j- Y" x5 `
  19.         delay_init();                     //延时函数初始化         
    ' i: f, O' U! y! t' {9 I
  20.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级. N! t$ I. N' B
  21.         uart_init(115200);                 //串口初始化为115200# Z% ~% |% B* t* V& d  F
  22.         KEY_Init();                          //初始化按键程序* b5 F; _* l$ C* T7 X3 V
  23.          LED_Init();                             //LED端口初始化
    ) Y5 F# z; l/ n# G0 @0 Y. d
  24.         LCD_Init();                                  //LCD初始化
    6 i) u5 F1 M: m% G
  25.         usmart_dev.init(72);        //初始化USMART        , H5 W" w+ L9 S
  26.          Adc_Init();                                  //ADC初始化
    # [0 l. _' ?4 V9 E+ z/ J5 r" G
  27.         Dac1_Init();                        //DAC初始化7 S7 x' M3 u1 H. Y+ d

  28. ' `  ?- i; R7 D" r5 d7 \
  29.         POINT_COLOR=RED;//设置字体为红色
    6 V! k* ~8 H: x4 X) X6 J
  30.         LCD_ShowString(60,50,200,16,16,"WarShip STM32");        
    1 _) B4 Y$ f9 j& S& u
  31.         LCD_ShowString(60,70,200,16,16,"DAC TEST");        " r3 P: n5 Z: M" R, X) L
  32.         LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");9 U8 H2 e. ~6 L1 C4 ?
  33.         LCD_ShowString(60,110,200,16,16,"2015/1/15");        , p( c# y1 d$ a- g5 t
  34.         LCD_ShowString(60,130,200,16,16,"WK_UP:+  KEY1:-");        $ |7 f2 H+ w, r% ]. k& n# @+ Q6 J
  35.         //显示提示信息                                                                                              6 Q8 ^9 W$ [# o1 P4 k
  36.         POINT_COLOR=BLUE;//设置字体为蓝色. L3 T4 R* {/ Q' H, r
  37.         LCD_ShowString(60,150,200,16,16,"DAC VAL:");              
      f4 i: f4 z' v3 v. @. b$ @) v
  38.         LCD_ShowString(60,170,200,16,16,"DAC VOL:0.000V");              
    / @! j2 Z2 A  R, G& h& f$ E
  39.         LCD_ShowString(60,190,200,16,16,"ADC VOL:0.000V");
    4 X9 S% ]" [0 `' ^! R- W% z3 e
  40.         / C0 f7 p- k4 h5 k0 P
  41.         DAC_SetChannel1Data(DAC_Align_12b_R, 0);//初始值为0                          * ]( W1 M3 Q2 I- a, o
  42.         
    6 Y4 b% [! ?7 V6 b+ d
  43.         while(1)
    7 c. u- ?/ P2 x$ m
  44.         {
    * t/ Z- V+ Y# q5 d! S3 Q( M2 q2 g
  45.                 t++;& u7 z& S, F! J6 m0 k/ N
  46.                 key=KEY_Scan(0);                          
    1 `+ V& ]$ t( E8 L' I- g
  47.                 if(key==WKUP_PRES)
    / p# W, v/ L# Q* G
  48.                 {                 
    ! O6 c: x1 ?% m0 B
  49.                         if(dacval<4000)dacval+=200;8 L( ~1 L& }* v' ]1 k# `( r& o7 H
  50.                  DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值        1 n$ k. Q) W$ h, K) a: I: m
  51.                 }else if(key==KEY1_PRES)        
    8 i8 d4 C* `1 _/ s" @3 P/ R
  52.                 {" A& u6 Z+ o) V3 j5 U# f
  53.                         if(dacval>200)dacval-=200;/ `  k7 O* E  U" O5 w
  54.                         else dacval=0;
    6 |1 B3 i! e6 n6 Y
  55.                   DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值/ B, J4 |* k4 T& Z
  56.                 }         
    + ?; N5 T9 J9 ?
  57.          
    0 p+ P2 V8 k' X5 G& C
  58.                 if(t==10||key==KEY1_PRES||key==WKUP_PRES) //WKUP/KEY1按下了,或者定时时间到了- [" C* C0 p+ H  E
  59.                 {        ( |+ m; Q4 B3 w: S  i% x/ R! t
  60.                         //获取DAC数据, o, G  ]0 o5 y
  61.                         adcx=DAC_GetDataOutputValue(DAC_Channel_1);//读取前面设置DAC的值
    / n. R1 t1 g: ?* e
  62.                         LCD_ShowxNum(124,150,adcx,4,16,0);             //显示DAC寄存器值, }3 ?7 d+ I) n; x9 N5 ]
  63.                         temp=(float)adcx*(3.3/4096);                        //得到DAC电压值
    ; |# w9 T) _4 a) m4 C  M/ s" \
  64.                         adcx=temp;# j" m6 o  m1 e
  65.                          LCD_ShowxNum(124,170,temp,1,16,0);             //显示电压值整数部分4 ~/ ]5 s! f8 g/ v3 X
  66.                          temp-=adcx;# n) K, B5 F2 ^* y* h8 ?
  67.                         temp*=1000;0 g- G/ A& e" |
  68.                         LCD_ShowxNum(140,170,temp,3,16,0X80);         //显示电压值的小数部分8 s4 n% N0 y# I$ g' L0 I) {
  69.                         
    0 z/ q) Z% e/ W7 [& H1 M
  70.                         //获取ADC数据+ v' _9 M- i  m" K' u! }8 H4 i. ~
  71.                         adcx=Get_Adc_Average(ADC_Channel_1,10);        //得到ADC转换值         
    & R/ m& i+ M* r8 v" s' L
  72.                         temp=(float)adcx*(3.3/4096);                        //得到ADC电压值. A2 y) ]6 N. ^- n& [( P8 `' H2 A
  73.                         adcx=temp;
    2 U) s( p' {# e. g0 X
  74.                          LCD_ShowxNum(124,190,temp,1,16,0);             //显示电压值整数部分4 M* [' n9 _& H7 _% O8 B3 N
  75.                          temp-=adcx;
    3 n9 f: |# Z' I/ Q2 L
  76.                         temp*=1000;
    7 F! m& d. d/ Q: D$ M  n
  77.                         LCD_ShowxNum(140,190,temp,3,16,0X80);         //显示电压值的小数部分
    6 Q# X/ h, o, p) Z, Y& o9 m1 Y
  78.                         LED0=!LED0;           
    2 l8 w' @. y# z$ Q7 e
  79.                         t=0;5 k1 V' \& S4 F! @3 A2 l) J0 D
  80.                 }            % {- d5 e+ E0 _! v( P: ?1 v
  81.                 delay_ms(10);        " T4 L- u& I% B) \. Q2 I
  82.         }8 q8 X. a2 t9 N
  83. }
复制代码
9 U* u1 s1 B6 M" v0 d
dac.c函数9 @( S& d/ D; i% T3 `
  1. #include "dac.h"
    0 D; g% o  T" e, L# W) I
  2. 0 x9 T% F# w: c: B. d
  3. //DAC通道1输出初始化" g8 V( v: Q& I1 G; g, }
  4. void Dac1_Init(void)1 e, j) h; q8 v  t: {/ |# Y
  5. {
    : V* t# e! M2 i2 P9 T
  6.         GPIO_InitTypeDef GPIO_InitStructure;& ]! C9 Y2 ~# H' Z4 ~( t+ f
  7.         DAC_InitTypeDef DAC_InitType;% j# o( o# T, F- O
  8. ! S4 F& [$ c  |" H, v
  9.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );          //使能PORTA通道时钟7 C4 M0 U. f# F, t2 Y# c
  10.            RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE );          //使能DAC通道时钟
    & l! O3 `' P6 o( \4 r  ~. s$ p
  11. " K0 k( u6 Z1 U
  12.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;                                  //端口配置
    4 I3 y: w, `) ^3 O2 o1 B; C
  13.          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                            //模拟输入
    + n! @) q  D8 s( a4 ]
  14.          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;4 ~6 p$ g% Q0 C; g4 \( N  a! l# M
  15.          GPIO_Init(GPIOA, &GPIO_InitStructure);
    & c* b5 N0 j# s. ~8 ]+ i
  16.         GPIO_SetBits(GPIOA,GPIO_Pin_4)        ;//PA.4 输出高$ u1 m0 V) g3 L5 d
  17.                                        
    : z$ d1 O1 u* v# ]- ]" h( f
  18.         DAC_InitType.DAC_Trigger=DAC_Trigger_None;        //不使用触发功能 TEN1=0# Y+ P) m7 Q- v% J0 e+ H5 V
  19.         DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生
    ( S1 z' W3 w6 @
  20.         DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置  z; H* J5 g) R/ }. O! g! Y9 B- j
  21.         DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;        //DAC1输出缓存关闭 BOFF1=1
    ; {" {: R$ k: u
  22.     DAC_Init(DAC_Channel_1,&DAC_InitType);         //初始化DAC通道1$ c: U& j' r# `5 X
  23. ! ^' b# k. B4 o% p# y7 A
  24.         DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC1
    * E2 K, B9 v' v5 \
  25. 4 ~) e+ w5 O' x0 R3 ^$ o: Z
  26.     DAC_SetChannel1Data(DAC_Align_12b_R, 0);  //12位右对齐数据格式设置DAC值1 I6 e( }# J6 m; U- J% i
  27. }3 A; Y. s3 y* N, Q$ _
  28. 3 r; A7 a5 ~* _& a
  29. //设置通道1输出电压
    / `* J# K$ [) i  M
  30. //vol:0~3300,代表0~3.3V
    % K% f: E7 W3 _
  31. void Dac1_Set_Vol(u16 vol)4 C1 m4 @6 A1 ?% X$ N
  32. {+ n7 H% W6 \. y  e
  33.         float temp=vol;" ], J9 ]$ ?# @: j& w7 J: d
  34.         temp/=1000;
    ) E) f' [4 t( d+ a; \
  35.         temp=temp*4096/3.3;
    . G1 H* ]0 \% q& D4 L! y7 J
  36.         DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值
      d, A3 K5 v; A( m
  37. }
    % e$ O& B! {% u( c' Q
复制代码
: c/ y. c7 H- V6 i3 B+ R6 w: x( W
adc.c函数
4 X! h9 l, X# {0 w3 N
  1. #include "adc.h"
    ' b( C) S8 v5 q( Q8 N! V
  2. #include "delay.h"# C  b7 U. m8 B7 p, R, G( I
  3.                    , ^- I- h5 Q& B2 _% x$ t5 S' E. R
  4. //初始化ADC- R( C# U# |* x7 [) M$ }4 U
  5. //这里我们仅以规则通道为例, g5 h# Y2 D# k
  6. //我们默认将开启通道0~3                                                                                                                                           2 F6 `6 V8 s5 r. a, V+ t0 }9 e
  7. void  Adc_Init(void): A# B$ E7 f3 n0 I. j. `
  8. {         % B0 u& g4 }/ G3 F% J5 w; v
  9.         ADC_InitTypeDef ADC_InitStructure;
    " d6 J* O( T5 E: S: i+ k
  10.         GPIO_InitTypeDef GPIO_InitStructure;
    6 D( z6 O( l% h, F8 K: p: j+ x

  11. # C  l! {3 P; o) t0 {% |
  12.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );          //使能ADC1通道时钟( l: t" ?8 c# ~7 k

  13. * J9 S/ R( b- z% j: _
  14.         RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M, ^2 t. s2 X/ P6 {1 Y! p: g

  15. : z2 p" D4 k* z9 y- d: |
  16.         //PA1 作为模拟通道输入引脚                         , J% D, O+ f+ ^: A% u1 C
  17.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;1 N+ {/ c( O" m- k, \( @* d6 i
  18.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
    9 g( l8 N0 e$ L, i7 t9 z
  19.         GPIO_Init(GPIOA, &GPIO_InitStructure);        9 N  C5 l4 J3 G9 _* [9 U' Q# \% r
  20. ' W- D2 c7 x5 h- n2 ]4 J  W
  21.         ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值
    + ?" a1 j3 k) e4 w9 _

  22. / I# B4 d9 Z* \. [/ O3 ?
  23.         ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式
    2 E4 K$ ?( F8 W
  24.         ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //模数转换工作在单通道模式
    1 s' o6 x& a1 ~$ P
  25.         ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式
    2 a! `' T5 e, a! X: h4 C' H
  26.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动
    , G2 J- u* l! z/ e# D% b5 e& W8 ?
  27.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐
    5 \  M  V; C: a& Q. O
  28.         ADC_InitStructure.ADC_NbrOfChannel = 1;        //顺序进行规则转换的ADC通道的数目7 H- n0 F$ c9 n, I8 W
  29.         ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   - l+ m7 P* ~3 a- f; B: ^+ Q: Y2 M

  30. 9 p. P6 X8 e1 _' C# @' w
  31.         ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1
    4 |% C# O. Q9 H* ]$ m( G
  32.           h$ ]3 A8 y, g+ N$ `7 }
  33.         ADC_ResetCalibration(ADC1);        //使能复位校准  
    ; H5 V  e* P+ T# R4 Q
  34.          
    + w# j( ?1 v9 {( F1 y' X5 {
  35.         while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束: U# M; }% H5 I  ]" D
  36.         5 T& h* W  f: s
  37.         ADC_StartCalibration(ADC1);         //开启AD校准
    1 \. O& {1 y( u& c
  38. 5 `1 a. ]" e' y
  39.         while(ADC_GetCalibrationStatus(ADC1));         //等待校准结束% A8 m$ H! Q: v; ]
  40. }        
    : H: g$ l2 e1 g  T+ k( A5 D
  41. 8 r0 u1 T$ Q7 F6 \6 b& T) k, }  B
  42. . j8 a* d0 j$ R- g0 F' L
  43. //获得ADC值
    ) P8 A$ M3 w% a
  44. //ch:通道值 0~3
    9 \- Y3 W2 }0 p' S
  45. u16 Get_Adc(u8 ch)   
    ! |3 h2 l* Z9 I( j% [5 J8 h
  46. {
    9 C: q$ F( _1 J& w
  47.           //设置指定ADC的规则组通道,一个序列,采样时间
    3 e3 g& D9 T  m
  48.         ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期                                      
    + _/ j$ x6 M4 L1 B/ i& V$ ?/ j
  49. 0 n& W! b# E7 V3 y
  50.         ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能        
    & L, l' Y$ w2 h6 r: i2 W5 e
  51.          
    & b& t$ h) f) I" Z
  52.         while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
    5 X+ L9 ^( b) ]* f7 V( v
  53. 1 D) z% d9 i4 y+ {5 K
  54.         return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果
    5 T2 ^3 t7 }& [2 W) `
  55. }
    , b# z  }: f+ g2 V( f

  56. : j: E# a& J# v& ^
  57. u16 Get_Adc_Average(u8 ch,u8 times)
    2 W. S0 a! Y0 W' q6 B  m; h4 T. n
  58. {3 h4 E" D; R6 @' m! ?" l
  59.         u32 temp_val=0;
    " Q9 j8 L8 W% J1 K/ d
  60.         u8 t;
    ; F) V: i* y; l$ F9 Q+ o
  61.         for(t=0;t<times;t++)
    4 N4 d* G  f3 h9 D9 s
  62.         {" N  w! P  L2 `6 ?2 X8 y
  63.                 temp_val+=Get_Adc(ch);
    : {& ]1 x: [( c! O! N
  64.                 delay_ms(5);' j, E8 @0 P! {7 r1 I. X2 ]0 e
  65.         }
    # r2 `" h6 X' t4 q8 @& D; @
  66.         return temp_val/times;: U% K. ~7 i5 Q4 j
  67. }         
    ; v( D! V7 \$ j/ ^
复制代码

; n% G3 X+ M- `( ~6 B& V' a' N5 t从 main 函数代码可以看出,按键设置输出电压的时候,每次都是以 0.161V 递增或递减的,而通过 USMART 调用 Dac1_Set_Vol 函数,则可以实现任意电平输出控制(当然得在 DAC 可控范围内)。
( H. O) H& I& z5 }" W8 a  Y% x( a8 O; G- R4 M/ S
, g. {* v  B: O) J2 g" I
赞 收藏 评论0 发布时间:2021-11-27 09:39

举报

0个回答

所属标签

相似技术帖

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