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

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

[复制链接]
STMCU小助手 发布时间:2021-11-27 09:39
本章介绍STM32的DAC功能。本章利用按键(或者USMART)控制STM32内部DAC模块的通道1来输出模拟电压,通过ADC1的通道1采集DAC的输出电压,在LCD模块上面显示ADC获取到的电压值以及DAC的设定输出电压值等信息。
# `" |; n: G9 ~
+ l( w/ \$ s1 a8 }+ w* ~* kDAC本身是输出,但是为什么端口要设置为模拟输入模式呢?
! `$ b! ^. @* D# N( m% H9 v因为一旦使能DACx通道之后,相应的GPIO引脚(PA4或者PA5)会自动与DAC的模拟输出相连,设置为输入,是为了避免额外的干扰。
- c( H: O0 ^3 P, C4 w2 T2 \! Q% R- d. y* ?5 z
2020051417082468.png

/ O5 U* t& k1 j, Y
20200514170851263.png
& C; w7 {7 x8 j$ u: S( \
20200514171026652.png
0 Y: O" R3 @# H5 r5 L; L
20200514171156709.png
/ ?* @! u. m3 A. X( X% S% [
2020051417141896.png

0 a2 n! V2 R1 G4 D* r
20200514171611130.png

/ P8 w1 }5 {8 q7 R5 S2 u- V
20200514171802467.png
0 u7 J/ O3 y3 N/ N9 T, I
20200514171858461.png

/ ]" t. @) ?! ?4 Q; N' p
20200514171949521.png
& `& `# g" R. Y  y' @2 Z* i
20200514172058766.png
& h3 C) a& H. D' H
' f2 ~5 w& L# d+ v6 s4 k

4 B) M# A/ R& N- T6 o1 D6 s0 O- S硬件设计
. n" x% V( H" c% c
2 S  D( x9 ]; q1 `
20200514172217410.png
$ G: u3 q4 U+ ]: v& }" |
) D6 E1 t* |" d
main函数% P/ M9 e' M! r6 S- b
  1. #include "led.h"
    5 U3 L1 h$ Q( _1 O4 g
  2. #include "delay.h"
    : O: [) S% C$ O. ?1 K, a7 [) @- u
  3. #include "key.h"
    6 g" x4 C' G% r; B
  4. #include "sys.h", K4 F- l3 v, _# r4 `# [
  5. #include "lcd.h"
    # _: N+ v8 F7 Q& F' o0 Q
  6. #include "usart.h"                  
    + @- a3 r& G; ~/ @" U; S/ o+ Z
  7. #include "dac.h"
    6 @# r" w; w  M; u% a
  8. #include "adc.h"  R" ?$ W) d& K! @/ j5 d7 Y
  9. #include "usmart.h"
    8 l3 W7 h, D/ ~6 C2 E

  10. 4 O0 |2 h% R% r9 L) h. P6 s4 a
  11. int main(void)
    # H2 }( S$ D" W2 {, x
  12. {         
    2 w7 a8 |3 F! H
  13.         u16 adcx;( L# W6 H$ C9 m5 a
  14.         float temp;
    ( Z. h$ m" V  `. W* L
  15.          u8 t=0;         
    : E# ~$ n0 q( _: J2 [# o' o
  16.         u16 dacval=0;
    0 |" b% [* O9 D$ X' z
  17.         u8 key;$ r) l) x; n, c
  18.         ! R: ~  i; n, t4 Z- ^  z/ C
  19.         delay_init();                     //延时函数初始化         
    % i8 j7 N' j0 U8 p; |; K
  20.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
    $ m0 \: `% u/ s  {6 P
  21.         uart_init(115200);                 //串口初始化为1152005 i2 b6 ]& K: h$ O5 H/ |$ l. Y! u. r
  22.         KEY_Init();                          //初始化按键程序& K# u0 o5 R6 b
  23.          LED_Init();                             //LED端口初始化# Q" {+ A. B- r; U# m) D' n
  24.         LCD_Init();                                  //LCD初始化. @' v1 k3 P# a1 [. }; B. Z6 ~  W% `
  25.         usmart_dev.init(72);        //初始化USMART        
    ( }: ]7 z8 A0 F- D' Q
  26.          Adc_Init();                                  //ADC初始化
    ' Z3 f6 N% i: I
  27.         Dac1_Init();                        //DAC初始化
    , E3 F: N4 w- t3 E
  28. 7 O% t$ q8 n' r1 j& B' `% r+ k
  29.         POINT_COLOR=RED;//设置字体为红色 6 Q+ \  t# y4 c$ {  p! A9 x& S% X
  30.         LCD_ShowString(60,50,200,16,16,"WarShip STM32");        
    5 E" E* T" f" ^. Z8 [2 x: g
  31.         LCD_ShowString(60,70,200,16,16,"DAC TEST");        
    8 e7 v/ c: I- u4 C! u# z) @3 t
  32.         LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
    7 w; u- w% ^! R7 X: G0 n
  33.         LCD_ShowString(60,110,200,16,16,"2015/1/15");        % H1 O/ L6 t  j8 M4 g
  34.         LCD_ShowString(60,130,200,16,16,"WK_UP:+  KEY1:-");        
    6 k& y3 u7 m/ J2 V0 y; W
  35.         //显示提示信息                                                                                              & B+ B2 d  ]. y
  36.         POINT_COLOR=BLUE;//设置字体为蓝色
    1 ?0 G( q. ~+ B8 I+ z8 V
  37.         LCD_ShowString(60,150,200,16,16,"DAC VAL:");              2 K& n( Z4 _9 X, Z2 L
  38.         LCD_ShowString(60,170,200,16,16,"DAC VOL:0.000V");              ' T; Y. V& T1 ~+ b! c# ^6 p
  39.         LCD_ShowString(60,190,200,16,16,"ADC VOL:0.000V");- h* l- T+ l+ J* i& p0 @
  40.         # i. r8 n. W5 e+ h( x
  41.         DAC_SetChannel1Data(DAC_Align_12b_R, 0);//初始值为0                          
    ! T4 p7 J2 I4 b# h, ]$ y6 p& j, m
  42.         ; l+ k/ Z0 e$ s( i  J
  43.         while(1)9 _  U' N% ?! F$ A4 e; [9 \2 \; W% `
  44.         {' m- z8 E4 K: }' c- ?, q
  45.                 t++;
    2 L, i/ ^- ^0 L- N9 D
  46.                 key=KEY_Scan(0);                          
    ' y2 ]+ W0 t& [2 R: z
  47.                 if(key==WKUP_PRES)
    0 P7 |3 F6 d, d- e
  48.                 {                 
    9 {& U2 K7 A7 H' \7 V3 y
  49.                         if(dacval<4000)dacval+=200;- N: J+ P' D% q9 h& U
  50.                  DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值        / N4 z$ h8 {' X9 Q; r' U: W8 C8 i
  51.                 }else if(key==KEY1_PRES)        6 d. F) i. G- {) S8 I9 D, B1 [
  52.                 {5 l9 L$ ?/ ]/ W& e
  53.                         if(dacval>200)dacval-=200;, g' v9 y. g" n% I1 ]/ D
  54.                         else dacval=0;4 @* b5 C8 z: c, a" Y0 E9 g
  55.                   DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值* L/ q+ V6 E* }( i7 i
  56.                 }         + v0 n& ^8 g/ A9 O9 A0 M
  57.          
    ; b+ [5 S  m9 G
  58.                 if(t==10||key==KEY1_PRES||key==WKUP_PRES) //WKUP/KEY1按下了,或者定时时间到了0 u8 ]' h0 W# h) }4 N- ~
  59.                 {        
    2 R# k" c& T. i
  60.                         //获取DAC数据( F  C/ q! B4 x- i% b( ^
  61.                         adcx=DAC_GetDataOutputValue(DAC_Channel_1);//读取前面设置DAC的值$ {% v1 x! v. z
  62.                         LCD_ShowxNum(124,150,adcx,4,16,0);             //显示DAC寄存器值
    ) H1 q$ P, n. c2 }* D5 j; f
  63.                         temp=(float)adcx*(3.3/4096);                        //得到DAC电压值
    5 U4 ]6 v- ~0 {' e8 F
  64.                         adcx=temp;
    - B% e4 S' g# a4 Y2 c
  65.                          LCD_ShowxNum(124,170,temp,1,16,0);             //显示电压值整数部分
    6 x, A$ o1 T% G4 f% ^# d! y
  66.                          temp-=adcx;5 o* S' y2 O: u* e1 g( N- b3 Q
  67.                         temp*=1000;
    ! M, B' b& ^8 x% ^' s% S/ e: p
  68.                         LCD_ShowxNum(140,170,temp,3,16,0X80);         //显示电压值的小数部分4 d3 {5 U% g9 `; V$ z0 ?
  69.                         
    $ b  O3 F$ ?# j- p$ `+ X% Y- u
  70.                         //获取ADC数据8 g6 T- N' o8 o
  71.                         adcx=Get_Adc_Average(ADC_Channel_1,10);        //得到ADC转换值          ) t5 r' Q8 D2 ~2 t$ g2 S9 T# i8 [
  72.                         temp=(float)adcx*(3.3/4096);                        //得到ADC电压值
    ; {' j+ s* Z3 Q7 j' r) v% ]
  73.                         adcx=temp;/ z) m3 k9 Z' |
  74.                          LCD_ShowxNum(124,190,temp,1,16,0);             //显示电压值整数部分
    $ Q  l4 ^! Q- r7 u$ }
  75.                          temp-=adcx;) @7 E3 N( X( E% R' d5 e8 c1 g- E
  76.                         temp*=1000;7 F8 |* B% Y, h4 x& G4 @
  77.                         LCD_ShowxNum(140,190,temp,3,16,0X80);         //显示电压值的小数部分
    * a6 t# w1 b$ l1 ~: o2 Y
  78.                         LED0=!LED0;           
    3 Q' y! L7 y3 t
  79.                         t=0;
    * j( v$ P3 G; c2 G  a# o
  80.                 }            
    1 P* s! ^/ s6 P- Z* a! S- @
  81.                 delay_ms(10);        2 C9 O1 `0 N- l  h4 y
  82.         }
    6 p+ M. b9 t# d1 e' Z
  83. }
复制代码
1 C1 I- |# t: Z$ B: Z% ~5 s
dac.c函数
6 d% z3 i$ u2 H8 b
  1. #include "dac.h"
    . Q) y1 T; U( _2 _1 i2 G2 f9 M6 J! f: Y' K

  2. 1 K, u9 a5 I9 c
  3. //DAC通道1输出初始化% ~( R% E! Q: c, c3 U' z
  4. void Dac1_Init(void)
    0 j* ^7 w) U" ?( K
  5. { 8 Z9 o- f- J3 ]9 B
  6.         GPIO_InitTypeDef GPIO_InitStructure;
    * H( H, W! G3 V& a+ P* V
  7.         DAC_InitTypeDef DAC_InitType;
    + @2 T2 Q' o6 N# L6 N, u& k1 S0 t
  8. : I( X: z) k% ?, f. a
  9.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );          //使能PORTA通道时钟
    ' W; q+ k% d5 \+ B5 @' Z
  10.            RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE );          //使能DAC通道时钟
    & H2 N: _0 {, ^- ?( I: M

  11. . Z$ B0 I3 T4 A/ C2 w9 ]! X
  12.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;                                  //端口配置' c% m! v4 V% j; G6 ]
  13.          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                            //模拟输入; o( K/ Q8 j) l* g, Y
  14.          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;9 X4 r7 d: m; a, E4 M0 I3 g
  15.          GPIO_Init(GPIOA, &GPIO_InitStructure);
    " H3 B$ U; j) X2 z" ?; h
  16.         GPIO_SetBits(GPIOA,GPIO_Pin_4)        ;//PA.4 输出高: c: G; _8 \3 C
  17.                                        
    * J- ^% {( L8 D5 d' z5 _$ _
  18.         DAC_InitType.DAC_Trigger=DAC_Trigger_None;        //不使用触发功能 TEN1=05 e; P8 s1 I' a) V, {& r0 V" L4 b
  19.         DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生
    " j$ z2 I1 @0 A) f% Y3 P9 l7 p; P% I
  20.         DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置
    " V7 ?5 l# R  _; m$ o! Y/ S
  21.         DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;        //DAC1输出缓存关闭 BOFF1=1! U# k0 d7 k  T/ F: }
  22.     DAC_Init(DAC_Channel_1,&DAC_InitType);         //初始化DAC通道1! a+ U9 d  \7 ?1 s) U  S
  23. ! M; K0 \( G1 e7 z! E
  24.         DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC1
    & J3 a: y8 u$ S8 p' d+ h4 w

  25.   x& X( z- K5 h
  26.     DAC_SetChannel1Data(DAC_Align_12b_R, 0);  //12位右对齐数据格式设置DAC值( s) H( x+ a; z5 L$ b
  27. }
    * ?" g9 i5 r1 h5 u  U
  28. 3 d2 C- I; [# Y# _! y
  29. //设置通道1输出电压. V* c* U0 @8 q  B; T$ {
  30. //vol:0~3300,代表0~3.3V
      l- ~$ V' _2 j6 r( q$ b
  31. void Dac1_Set_Vol(u16 vol)
    3 n4 s* f  j% Q
  32. {1 F, j4 N5 L" Z5 z1 J
  33.         float temp=vol;/ K# s0 [$ Q6 b( I
  34.         temp/=1000;* O) ^& x1 i% }6 X2 k
  35.         temp=temp*4096/3.3;
    , P7 Z7 P) ~. a: S
  36.         DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值# m3 C8 w9 c0 Q1 {- K
  37. }
    ; t% o# G5 R, a. H2 q3 G
复制代码
# A- S& y; N/ q( s$ A: _
adc.c函数
" R( O/ C7 S. l4 R" O
  1. #include "adc.h"( s0 I0 E9 ], Y- c3 c, W! ~
  2. #include "delay.h"
    $ _& J- e7 k# c
  3.                    8 c% b* m  m( X6 W9 Z/ W0 H4 N; ?
  4. //初始化ADC8 k- O6 x! B8 f4 |
  5. //这里我们仅以规则通道为例9 S. P: k8 H& i7 M) ~
  6. //我们默认将开启通道0~3                                                                                                                                           6 R' B' X: W+ w7 G. e; H
  7. void  Adc_Init(void)
    , E4 O+ p! B0 a# f# C$ H; e
  8. {         
    * r+ J8 w; s9 X! u+ e0 l
  9.         ADC_InitTypeDef ADC_InitStructure;
    / A* b+ w2 A, y" J/ O" b) ^" V
  10.         GPIO_InitTypeDef GPIO_InitStructure;# {6 u) G4 S3 b( y: r* K

  11. - F. T2 Y& T- l* G0 f+ _( d
  12.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );          //使能ADC1通道时钟
    1 J5 x% u$ B9 U' q
  13. 2 ]+ n7 I" Y! q/ \! V
  14.         RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M1 Z3 x. n) [, f

  15. + \5 C" P- M4 ^
  16.         //PA1 作为模拟通道输入引脚                        
    , y, _$ F; |& |! }9 [
  17.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    ( [' f6 P+ K. o9 p* V# Z* E
  18.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚) @  w1 F2 U+ E) j0 p
  19.         GPIO_Init(GPIOA, &GPIO_InitStructure);        
    * q  T/ f- Z* j9 ~

  20. 6 \, l! Z* o9 b( u6 y& i
  21.         ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值
    4 L# }! a7 F1 d( i/ Z' o
  22. . ^0 \% ~7 i: ^: F
  23.         ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式
    4 _6 c# e+ P* o9 K" Z& c; v* B6 T* \
  24.         ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //模数转换工作在单通道模式& D. u  |; C9 m' V+ c  l6 K& v2 i* K
  25.         ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式5 J  {$ W$ b$ g$ k+ b
  26.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动
    , k& y# D- U8 z6 [; N+ w
  27.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐3 M; }8 u. V* q
  28.         ADC_InitStructure.ADC_NbrOfChannel = 1;        //顺序进行规则转换的ADC通道的数目
    ) B1 O6 e+ r- M
  29.         ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   # ~9 o; y0 ^# @
  30. ( T, z9 A# H# Z  k% p9 r4 m
  31.         ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC17 C8 C% M) ]) J% i. {
  32.         
    ! q% \% C) ]+ i0 g3 w$ T8 T) M
  33.         ADC_ResetCalibration(ADC1);        //使能复位校准  - E2 T, W! f2 m1 Y2 d
  34.          # I6 B3 B3 \+ ~2 a- x$ A5 ?. ?
  35.         while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束
    : |7 a5 [! O) N+ Z% [
  36.         + ~0 l+ q+ D6 {3 @. z! S8 h: {
  37.         ADC_StartCalibration(ADC1);         //开启AD校准. p5 H/ [7 q" [' J3 J% N" e

  38. 8 d/ s1 ^0 T! R
  39.         while(ADC_GetCalibrationStatus(ADC1));         //等待校准结束- L& Q) x! S) S2 [
  40. }        
    0 q8 t: R) }  q. }. |9 o5 S

  41. 3 \$ a8 v3 ]8 r! A% C
  42. ( d( l) m4 t" L
  43. //获得ADC值; |3 d, i4 h4 x  w& a9 P! N! c# Z" ]
  44. //ch:通道值 0~3( Z6 g2 g1 L# O: z9 q: t& g+ _
  45. u16 Get_Adc(u8 ch)   $ X# i5 K, ~) G8 e
  46. {
    % ~$ u% \1 N% j
  47.           //设置指定ADC的规则组通道,一个序列,采样时间1 M: I( L0 Y2 S) H
  48.         ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期                                      
    - E& A/ e- B; g. K' T* |2 \+ O
  49. ( `3 q) S) \0 }& ~, D: V6 |* b. l
  50.         ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能        & r# b2 I3 M: K- X( D  u, M
  51.          2 d6 R1 a( s+ F1 Z7 }4 U
  52.         while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束. ]9 Y9 D( W/ `2 c

  53. % }: }( y; |% G$ a: F: S8 S& A, e7 U
  54.         return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果1 Y  f: X7 ]/ u: Q8 I3 l
  55. }0 u( x. l- f1 i/ {- ^& n; }

  56. - r: U, b4 h8 {: z. G
  57. u16 Get_Adc_Average(u8 ch,u8 times)* J9 V3 j) C1 r2 _
  58. {" Q5 V, _+ M7 V
  59.         u32 temp_val=0;
    # ~  O2 ~7 E; I& l$ e# k, F
  60.         u8 t;5 l3 x' t6 A1 G- M+ z
  61.         for(t=0;t<times;t++)9 f# p0 ^$ C+ l- T" J
  62.         {8 X$ u7 a9 Z$ {4 i, w
  63.                 temp_val+=Get_Adc(ch);- I: c% \- ]* r
  64.                 delay_ms(5);  f2 h0 i2 z# }. t
  65.         }
    . _2 V6 g. \2 B) Q3 o; j! N
  66.         return temp_val/times;1 I- `4 \# o) m: U: I$ {2 R
  67. }         
    ; ]4 d* ^3 ~, y; r
复制代码

7 y' n) @* z0 x3 t8 V* f8 V* H从 main 函数代码可以看出,按键设置输出电压的时候,每次都是以 0.161V 递增或递减的,而通过 USMART 调用 Dac1_Set_Vol 函数,则可以实现任意电平输出控制(当然得在 DAC 可控范围内)。
1 h5 l. U1 v, u1 `! v
0 |' ~  l! G0 v; T. s7 [
. r8 H" j! }) \. L' r& V
收藏 评论0 发布时间:2021-11-27 09:39

举报

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