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

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

[复制链接]
STMCU小助手 发布时间:2021-11-27 09:39
本章介绍STM32的DAC功能。本章利用按键(或者USMART)控制STM32内部DAC模块的通道1来输出模拟电压,通过ADC1的通道1采集DAC的输出电压,在LCD模块上面显示ADC获取到的电压值以及DAC的设定输出电压值等信息。
3 a/ E4 ~# q( t" t! f' p4 u) h& O; z8 j5 I+ k
DAC本身是输出,但是为什么端口要设置为模拟输入模式呢?
1 Z* p5 _% H& k$ s8 x. K+ ?) ?6 ^因为一旦使能DACx通道之后,相应的GPIO引脚(PA4或者PA5)会自动与DAC的模拟输出相连,设置为输入,是为了避免额外的干扰。
/ ^) \5 c9 H# U! V: M: O& @& t( V3 Y9 |6 m
2020051417082468.png
1 R3 J0 Y  Y# k) R* {+ i
20200514170851263.png
) I4 R/ p1 `' ]2 e3 s
20200514171026652.png
, m$ u* W' g: s! a" d
20200514171156709.png
* U7 ?1 S5 C* y, Q
2020051417141896.png
" R  K/ |/ l2 `. h* H4 W% l; s" B
20200514171611130.png

# ^0 Z3 t2 y4 O/ b4 B2 c
20200514171802467.png
' U3 C, Y; r5 |  J
20200514171858461.png

* A- l) ~- ~8 H$ ]3 `4 P
20200514171949521.png
5 e- m7 f  E- c- N
20200514172058766.png
. A4 L% Y6 P! ?! d1 }0 y# a) ~
5 z7 C) ]& V$ O6 r4 B1 |
2 B7 ]8 H& ?  j3 S+ [
硬件设计2 r8 N# y( O. s  ?: f

: |4 d8 v" _7 A! ?$ e5 J9 v
20200514172217410.png

3 s3 D4 G* h5 |; o+ V
, p1 ?* |# A3 `% Q; t+ x" mmain函数7 k  H, p/ C& B% Q
  1. #include "led.h"4 t# a  s3 f& g
  2. #include "delay.h"
    7 ~$ L8 j1 a7 c9 l
  3. #include "key.h"
    " g6 r% x9 D: [7 J
  4. #include "sys.h"
    # l0 h' Q1 m. I- d0 }! t
  5. #include "lcd.h"
    4 g3 |5 o+ c) N1 c) F
  6. #include "usart.h"                  
    , S3 B* U' s3 ~# `! A; D3 Q, u
  7. #include "dac.h"0 p3 g5 }( s# \! W6 P9 s: g3 I- C
  8. #include "adc.h"
    3 d. e8 O2 @) p, N, J( m
  9. #include "usmart.h"* |! |4 O% E0 p* C" v
  10. + Z) F% G7 s* \3 M
  11. int main(void)! w5 X* d2 N: ^2 @1 N
  12. {         3 T8 O% n/ d  U" y! F$ Z- d, c; S
  13.         u16 adcx;3 v1 d1 p) D# J
  14.         float temp;
    ' W8 Z% F" e" x" _
  15.          u8 t=0;         
    5 T( h8 x& O! t+ J! L+ i+ L7 I/ Z* Z
  16.         u16 dacval=0;! |7 k6 N- n/ s) }9 q" X( B2 r) c
  17.         u8 key;- y" n4 K! G' D: p  K, }6 D: \- p
  18.         
    5 B. S9 J8 G3 s7 l
  19.         delay_init();                     //延时函数初始化          & I- V$ ^0 O# B( y8 o5 x
  20.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
    - [% V- A0 o0 w3 S' E0 ^+ a) i- ?
  21.         uart_init(115200);                 //串口初始化为115200% D0 N4 }: r. Z& m- n
  22.         KEY_Init();                          //初始化按键程序6 j) V) a. ], y* h0 M
  23.          LED_Init();                             //LED端口初始化
    : _! X/ a, J0 c2 h' c; x9 o/ D8 P
  24.         LCD_Init();                                  //LCD初始化8 _- I& Y+ S* X- g7 a  u
  25.         usmart_dev.init(72);        //初始化USMART        6 J. ~4 C' F. y# }1 n; O
  26.          Adc_Init();                                  //ADC初始化
    4 k7 p' F; L( x" r5 `
  27.         Dac1_Init();                        //DAC初始化* X% A; E( ~5 @& p' ?! T" I) m
  28. 1 o& O1 t& b& |2 M% U0 W
  29.         POINT_COLOR=RED;//设置字体为红色 # ]3 ~( e4 Z& D% A
  30.         LCD_ShowString(60,50,200,16,16,"WarShip STM32");        
    8 c& G- F. D* C0 @. z3 u4 y4 D0 g
  31.         LCD_ShowString(60,70,200,16,16,"DAC TEST");        4 F) T8 Y0 B+ D* L$ B- Z
  32.         LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
    " ^0 H( G, w$ ?( d
  33.         LCD_ShowString(60,110,200,16,16,"2015/1/15");        
    , C' N7 b3 [+ A1 T! ^
  34.         LCD_ShowString(60,130,200,16,16,"WK_UP:+  KEY1:-");        & Y* V1 Q$ B0 N' x  H
  35.         //显示提示信息                                                                                              # M' x. p4 i: U
  36.         POINT_COLOR=BLUE;//设置字体为蓝色
    ' \5 t% L3 n4 o
  37.         LCD_ShowString(60,150,200,16,16,"DAC VAL:");              - E* V( d0 M4 K$ E; W
  38.         LCD_ShowString(60,170,200,16,16,"DAC VOL:0.000V");              
    : I" Q# s* x3 S% s4 d9 e7 a  p6 U
  39.         LCD_ShowString(60,190,200,16,16,"ADC VOL:0.000V");
    % g: Z" T2 ?0 j. H! q
  40.         
    # V3 j. f- ?! m$ o) ]" O
  41.         DAC_SetChannel1Data(DAC_Align_12b_R, 0);//初始值为0                          3 |, U! g+ d1 k% R& s$ u
  42.         ( z2 H/ n) S6 l6 Q# C# n: ?
  43.         while(1)
    " p1 _9 |# U# I: J5 B2 v
  44.         {( d' e* f# E# W& E8 J4 i
  45.                 t++;
    6 n+ r) ^" S" ]3 D
  46.                 key=KEY_Scan(0);                          
    5 N& i* w- i( Y$ ^$ T! L
  47.                 if(key==WKUP_PRES)
      H' y9 ]% c: x+ H. N' B
  48.                 {                 
    ) w+ W' v/ ^+ U  D' {
  49.                         if(dacval<4000)dacval+=200;
    # X* ?7 r; c- J6 ?+ s2 ]0 X( I
  50.                  DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值        : U3 a& r3 l  {+ p! m7 ]7 W
  51.                 }else if(key==KEY1_PRES)        
    / ~" g5 t1 M; I6 d
  52.                 {
    ) a* a; {) M( h- g
  53.                         if(dacval>200)dacval-=200;
    ( R) g" [7 [9 M4 K
  54.                         else dacval=0;
    # s' G5 O* [4 V6 L. s  g. g
  55.                   DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值; O1 A& e. U- V( U
  56.                 }         - l( \, ^& K, v! I6 Y
  57.          " ~1 m, }0 H1 N9 Y) C( F- f3 {
  58.                 if(t==10||key==KEY1_PRES||key==WKUP_PRES) //WKUP/KEY1按下了,或者定时时间到了
    # u( {# S( c. e
  59.                 {        $ {$ P9 A$ ^  I- R2 H# {
  60.                         //获取DAC数据1 I* t9 L7 @0 e5 r  E( N+ w9 l
  61.                         adcx=DAC_GetDataOutputValue(DAC_Channel_1);//读取前面设置DAC的值
    , e- K8 O9 @7 N$ _5 k: X! }6 {
  62.                         LCD_ShowxNum(124,150,adcx,4,16,0);             //显示DAC寄存器值: U$ u( o9 ]3 r
  63.                         temp=(float)adcx*(3.3/4096);                        //得到DAC电压值
    0 _. a5 e0 N! X$ m
  64.                         adcx=temp;
    6 {  C; S6 c/ K1 {( l6 N
  65.                          LCD_ShowxNum(124,170,temp,1,16,0);             //显示电压值整数部分
      m( {& }% G$ F$ g* S  x1 v
  66.                          temp-=adcx;7 f9 E6 m1 ]3 S& T5 w& y: c) G
  67.                         temp*=1000;
    * H8 z3 X9 S6 V; ^; H* {
  68.                         LCD_ShowxNum(140,170,temp,3,16,0X80);         //显示电压值的小数部分
    * X, U0 V( p: s4 O0 x$ f
  69.                          ) b; Q+ @$ s8 w2 z2 ?
  70.                         //获取ADC数据
    1 ?& M# I/ H3 f' S; t
  71.                         adcx=Get_Adc_Average(ADC_Channel_1,10);        //得到ADC转换值         
    & G: I% p" Y4 r4 a( O% a  ^
  72.                         temp=(float)adcx*(3.3/4096);                        //得到ADC电压值
    ; U! v8 L9 }2 M, x; T
  73.                         adcx=temp;' k' O7 j- a+ @, b- V6 x5 }6 }
  74.                          LCD_ShowxNum(124,190,temp,1,16,0);             //显示电压值整数部分+ z% l; {9 Q, i$ B# j1 t
  75.                          temp-=adcx;
    2 k2 |# r# s  v  _: y; R
  76.                         temp*=1000;
    0 x6 F5 B: `. U) d1 ^% w( D% y
  77.                         LCD_ShowxNum(140,190,temp,3,16,0X80);         //显示电压值的小数部分
    2 E, q$ V( q8 M! Q, f5 Y1 L
  78.                         LED0=!LED0;           
    7 G* _  T2 Z8 V4 N8 m* j
  79.                         t=0;. ^0 \+ K) J" l( [+ I' L) k* o8 X
  80.                 }            
    $ q( n0 c# A2 D7 j$ ~
  81.                 delay_ms(10);        + x" A- e% R$ x) v) H- o
  82.         }4 J% Q% D6 B. i; f9 G; {% \# q
  83. }
复制代码
+ }. e* F2 w! l; r/ n
dac.c函数; z+ R/ {* ^4 M5 Q5 k, ]" H
  1. #include "dac.h"9 l! _0 _! i( ~6 b3 W7 a) k
  2. ( Q' l8 I& w4 g' e- ~8 }
  3. //DAC通道1输出初始化
    + \2 w* [1 Y' E& v( d
  4. void Dac1_Init(void)6 S9 I! w! s1 K' @$ o
  5. { 5 Y* n# u  v3 l/ k4 B
  6.         GPIO_InitTypeDef GPIO_InitStructure;/ ^5 ?$ [, ^# B
  7.         DAC_InitTypeDef DAC_InitType;
      I( I+ O# x7 y2 G
  8. ) ]0 X7 W$ w2 s' K( L+ u
  9.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );          //使能PORTA通道时钟
    ' n$ q6 S2 b$ c3 k
  10.            RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE );          //使能DAC通道时钟
    , |0 B5 z6 B  x( ~
  11. 9 c5 q$ @: X7 f  y: m; m
  12.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;                                  //端口配置
    * `1 Z( t9 Q  C
  13.          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                            //模拟输入
    " W; L. e* m+ G8 f7 x0 S
  14.          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    * ^5 \5 k( _5 |6 f' o- y! A
  15.          GPIO_Init(GPIOA, &GPIO_InitStructure);# E  E& ~+ f4 z# `
  16.         GPIO_SetBits(GPIOA,GPIO_Pin_4)        ;//PA.4 输出高
    $ m) M4 R: Y  x
  17.                                        
    : U3 g6 ?/ A7 E# i3 C
  18.         DAC_InitType.DAC_Trigger=DAC_Trigger_None;        //不使用触发功能 TEN1=0) u+ j' E: {" R( v9 G* @$ s* {- y
  19.         DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生
    4 T4 h/ y6 f& h# H
  20.         DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置
    5 l# Z4 T! I1 _( P9 l  @% ]$ D
  21.         DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;        //DAC1输出缓存关闭 BOFF1=1
    9 x  H0 M5 K) Y5 I; O
  22.     DAC_Init(DAC_Channel_1,&DAC_InitType);         //初始化DAC通道1+ ^1 m) t+ n5 h* L' Q4 t. @

  23. - G; z# A$ n0 N0 D! n
  24.         DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC17 D  m$ g5 m. o( n2 n% t

  25. 1 H( m5 X" X. i7 i. a
  26.     DAC_SetChannel1Data(DAC_Align_12b_R, 0);  //12位右对齐数据格式设置DAC值) D- ^; y4 c. z* m" I+ _
  27. }) |( Q6 d9 b5 u1 U+ j7 G) v5 }  j

  28. / Y  I3 ]: a( d8 ^
  29. //设置通道1输出电压! D  c  s: f, n7 N" p# n
  30. //vol:0~3300,代表0~3.3V" a. }1 C9 D% p( K5 k, }$ |
  31. void Dac1_Set_Vol(u16 vol)8 J- e5 @1 I7 {3 P' d
  32. {
    4 j& C% H1 \) ~7 O* z
  33.         float temp=vol;0 r1 V! L9 \% O0 E8 H: s' P
  34.         temp/=1000;9 }# a9 S* a% `0 r
  35.         temp=temp*4096/3.3;
    7 A/ u! m% _* r5 @) o
  36.         DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值6 @  `( D" e* U6 e3 l% o
  37. }
    ; H& a" o5 w; |+ i: I- I0 @
复制代码
- M" S+ m0 J5 `  n" r: B0 }8 k
adc.c函数
7 K9 Y% u5 n. @& |
  1. #include "adc.h"
    ; w; G  O, k2 c4 ]' Q/ P. k( b
  2. #include "delay.h") W3 j3 K# D7 d, a2 D9 |& W
  3.                    " t# X2 S2 i) j0 n/ ?
  4. //初始化ADC
    0 c: D% n7 x4 R& f
  5. //这里我们仅以规则通道为例, B& h) V2 X3 F, H: d/ L% h
  6. //我们默认将开启通道0~3                                                                                                                                           % k- [; n0 o0 z# ^- S0 m
  7. void  Adc_Init(void)
    8 N2 o6 o3 _8 J# @
  8. {         ; _$ J' Z( ~# W
  9.         ADC_InitTypeDef ADC_InitStructure;
    " u4 |, C& ]! V+ _
  10.         GPIO_InitTypeDef GPIO_InitStructure;% G. R3 M0 `3 |+ T

  11. : F& C# w( c8 }- Q5 v1 K7 D( x
  12.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );          //使能ADC1通道时钟
    1 v0 a. v8 `# f& H

  13. 1 D/ S! ~4 @+ v& Z& N
  14.         RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M6 e7 s5 j, h8 H# p4 n7 }/ D0 S
  15. , J, w/ L  M' ^! s& a- y% [1 n/ q
  16.         //PA1 作为模拟通道输入引脚                         1 t+ g# H( V% D6 p. R/ [
  17.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    ) `+ r/ J3 K3 X, a6 B! s( e
  18.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
    " g. q) \) x) ~% C' c/ ~
  19.         GPIO_Init(GPIOA, &GPIO_InitStructure);        
    7 t) t2 j$ W3 P/ F
  20. 4 s, }3 J: X8 b8 P. x, X
  21.         ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值" c# x/ p  ^9 J

  22. 7 ?; I; d% }- T9 _
  23.         ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式9 x0 Q! Z# T3 F3 O8 t/ o
  24.         ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //模数转换工作在单通道模式$ X* ~7 d6 Y6 D1 y
  25.         ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式
    9 F/ Q' M+ _6 b; i8 Y
  26.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动
    . }, h: I3 F8 T
  27.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐
    5 g! z  o' S% E9 ^8 _
  28.         ADC_InitStructure.ADC_NbrOfChannel = 1;        //顺序进行规则转换的ADC通道的数目5 d; Q7 @% g8 d: ~0 V9 m3 y& O
  29.         ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   
    9 I6 n" r' h2 \/ Q' S7 ~

  30. + v  f* r* \+ T
  31.         ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC13 b3 w! u- E) F4 @( |7 x9 V' K
  32.         
    1 i0 z: g5 |* w
  33.         ADC_ResetCalibration(ADC1);        //使能复位校准  
    4 R9 j9 O' B2 _
  34.          
    # x% B5 q9 P' h+ t# O
  35.         while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束$ U# H0 f( Q. |* k% Q
  36.         . K. O2 N- ?; y' Y# T+ F/ p- o
  37.         ADC_StartCalibration(ADC1);         //开启AD校准
    ! `( W& Y% u' h' y" X# u! r  S" ]. F
  38. : j1 H7 t' f9 N1 s9 U0 [* o
  39.         while(ADC_GetCalibrationStatus(ADC1));         //等待校准结束
    + u, P" M' A+ r7 v
  40. }        
    * P: M: N# k) A6 R
  41. - Y) {) f( a- _' h& e9 Z

  42. # t- S: H+ S* z! C9 b0 Q3 ?
  43. //获得ADC值
    # g  {! c* I! J  ^7 O
  44. //ch:通道值 0~39 c. T  H5 j0 n  Q
  45. u16 Get_Adc(u8 ch)   
    # o7 q8 H+ _, J0 e+ f
  46. {! t2 I" Q6 c4 F" k8 R
  47.           //设置指定ADC的规则组通道,一个序列,采样时间
    0 q; L% ~+ H7 S1 t# i
  48.         ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期                                      $ B3 A3 j0 c! U* E, c+ p! W
  49. 5 u9 Y/ H  R' O" s5 C% B3 p
  50.         ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能        
    4 @) _+ R( w6 ]  e) n
  51.          
    2 b9 U3 w" q2 Z1 L7 _( Q
  52.         while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束/ K7 s& h$ H5 Z5 e* ~7 i$ j

  53. 3 v* z% p7 B; g; P6 s
  54.         return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果7 B& V) K/ z" A2 t
  55. }% a" g7 q7 }9 P/ T

  56. 0 U) f) a8 W( n$ Z/ ]% L
  57. u16 Get_Adc_Average(u8 ch,u8 times)
    3 U( I# J0 c. _  K7 n' [& z
  58. {
    ( W5 Q- j( @& ]  \* ?
  59.         u32 temp_val=0;! Q6 |6 K2 Q0 o: N# w6 y, ~
  60.         u8 t;4 [' f9 D' V& o% a4 c
  61.         for(t=0;t<times;t++)7 ?  T% R  v8 r7 C
  62.         {1 [1 R  W0 t% }$ v
  63.                 temp_val+=Get_Adc(ch);
    0 n; x4 m# r$ t1 |" o' n6 {* H
  64.                 delay_ms(5);
      \* R1 H: `: r
  65.         }/ r$ l: c2 i+ s! P* Q
  66.         return temp_val/times;5 G: S" G3 Z9 I* \; L7 U. W) v7 E8 V
  67. }         
    + c# ~5 Z! }( L4 z2 O
复制代码
  }: R, `0 A5 o6 D6 i+ }+ n/ S+ f4 q
从 main 函数代码可以看出,按键设置输出电压的时候,每次都是以 0.161V 递增或递减的,而通过 USMART 调用 Dac1_Set_Vol 函数,则可以实现任意电平输出控制(当然得在 DAC 可控范围内)。
, X3 r$ P) n  r4 P; d7 Z" ]+ F$ f( Z; R" d5 p; x7 l2 d- p# f

  l0 @3 \0 x: ~& z6 H4 Q3 b/ I- \8 Y4 P
收藏 评论0 发布时间:2021-11-27 09:39

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版