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

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

[复制链接]
STMCU小助手 发布时间:2021-11-27 09:39
本章介绍STM32的DAC功能。本章利用按键(或者USMART)控制STM32内部DAC模块的通道1来输出模拟电压,通过ADC1的通道1采集DAC的输出电压,在LCD模块上面显示ADC获取到的电压值以及DAC的设定输出电压值等信息。% D( y. }( N4 }* k) U( p) k
  g2 b/ y3 y5 Z( K: X& {
DAC本身是输出,但是为什么端口要设置为模拟输入模式呢?
" \- p3 P0 R# C' {  ?2 D  v$ |因为一旦使能DACx通道之后,相应的GPIO引脚(PA4或者PA5)会自动与DAC的模拟输出相连,设置为输入,是为了避免额外的干扰。, }5 R9 l! U, Y% @8 M, r
+ i1 x( o8 c6 p) t0 T* j7 M& x  a
2020051417082468.png
$ l/ i3 B3 N' s( T
20200514170851263.png

6 N! ]+ H! ^9 O/ h
20200514171026652.png

& C0 k1 p7 f6 |5 H( b1 s) ?
20200514171156709.png

) C7 @9 O% @3 E7 y( G6 c. [/ N
2020051417141896.png

9 w2 _) `  e6 h& h/ Z6 b
20200514171611130.png

5 |8 ?1 s- ^5 [; O/ n( p
20200514171802467.png
2 l0 j  m; \9 D* Z. I
20200514171858461.png

: r3 ~% U3 f! ~# j" E
20200514171949521.png
7 \# z) u' W( N# L  P) v0 a  N
20200514172058766.png

1 M0 X' b/ r, Y$ r0 h
7 r- m2 p. c  o. u( L! v3 I7 R* I# n9 c( v7 U7 Z* X1 u7 i
硬件设计# Q7 k, U& X5 S" U* G
$ D( a. I! m; T/ |  }
20200514172217410.png

# Q; U( ~  Q7 O% V0 O! |; y
- [0 s, d  m: qmain函数# a3 x" F% `7 i6 n5 ^" [& S8 H
  1. #include "led.h"! r+ _) F. U* T
  2. #include "delay.h"& c) i; [8 E& d- q9 j
  3. #include "key.h"
    * N* V) }7 _* s  P; Y; x
  4. #include "sys.h"
    1 H! P  ?& q# O3 u  j9 X
  5. #include "lcd.h"
    # B- M$ x+ z: E  G/ K; Z7 e" p
  6. #include "usart.h"                  ( o- H$ `% @: E& q2 D
  7. #include "dac.h"6 W0 O" Z. Z5 l9 W
  8. #include "adc.h"/ y3 ]4 @, z  z4 R5 y9 E- e
  9. #include "usmart.h"
    * J$ n" d& `+ w- Y  z

  10. % m9 V6 x! M+ a
  11. int main(void)0 A8 P8 u( E/ y+ Q: p: v) E
  12. {         
    7 L6 _6 O; X; H1 o! _+ }) [. {
  13.         u16 adcx;6 y0 m  ^/ b% s( D% I0 v
  14.         float temp;9 d: ^  U+ `6 b# M2 \3 E
  15.          u8 t=0;         
    / v. e9 j# _0 [
  16.         u16 dacval=0;+ I. j7 x2 v! Y1 r; L
  17.         u8 key;7 \- z+ F" H' ]% [. @
  18.         1 M; N( {$ x5 h- y9 y' C9 s5 {- ]  k
  19.         delay_init();                     //延时函数初始化         
    ( r  y  a. q2 W
  20.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
    0 C- a, v; O# T% E% Z5 v
  21.         uart_init(115200);                 //串口初始化为1152008 k. b% D0 T' s! K$ v
  22.         KEY_Init();                          //初始化按键程序
    ' w1 F7 H5 J- E* R9 n0 h' c
  23.          LED_Init();                             //LED端口初始化
    4 b0 D! @+ c+ e
  24.         LCD_Init();                                  //LCD初始化
    " q' C/ q# M4 E1 J7 a& Z# _% j6 w2 }
  25.         usmart_dev.init(72);        //初始化USMART        
    $ j) U  j* z: k' Y/ E# Q1 J- B
  26.          Adc_Init();                                  //ADC初始化
    & B! _: t! n8 R: w9 K  i2 G  {
  27.         Dac1_Init();                        //DAC初始化
    ' P& M, Y2 r! ?5 r8 l, _  y& Z
  28. 0 m# ]3 T: C: i
  29.         POINT_COLOR=RED;//设置字体为红色 4 h$ e4 S/ N1 K0 u5 \. Z0 l/ k) A" E
  30.         LCD_ShowString(60,50,200,16,16,"WarShip STM32");        " S- N5 V# Y2 y4 k# S$ g5 B4 g0 ~; M
  31.         LCD_ShowString(60,70,200,16,16,"DAC TEST");        
    : ^8 K& F% R: M$ p
  32.         LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");/ d4 T! r$ \, o2 G$ O5 m/ o, B( ^* v' L
  33.         LCD_ShowString(60,110,200,16,16,"2015/1/15");          y' W+ |/ _/ j8 R
  34.         LCD_ShowString(60,130,200,16,16,"WK_UP:+  KEY1:-");        " w3 T# w. {( l$ c: H" M
  35.         //显示提示信息                                                                                             
    ; Z# a  C; n6 o3 _$ s
  36.         POINT_COLOR=BLUE;//设置字体为蓝色0 C" |  W* `8 F, e/ x" w5 S
  37.         LCD_ShowString(60,150,200,16,16,"DAC VAL:");              ' ?# ]5 z4 _) t3 b2 m: `: ~* l. \
  38.         LCD_ShowString(60,170,200,16,16,"DAC VOL:0.000V");              
    * l( u4 `7 B3 q0 @- l# o
  39.         LCD_ShowString(60,190,200,16,16,"ADC VOL:0.000V");
    + Q* l' s; f7 W
  40.         ' f! n; s6 ]* H7 `9 u5 U
  41.         DAC_SetChannel1Data(DAC_Align_12b_R, 0);//初始值为0                          3 P% b( m; B+ C
  42.         
    ' u" ~) {' e! J  N# v+ }' A! m0 ~& \
  43.         while(1)
    : }0 b' [( @: h/ _
  44.         {& }8 v2 B  \- Y
  45.                 t++;# x8 @( M, E* n, n7 w7 l
  46.                 key=KEY_Scan(0);                          / V/ E1 B5 q* G4 a( j6 c
  47.                 if(key==WKUP_PRES)6 d7 Q: m6 S+ n3 h$ [# z2 m
  48.                 {                 
    ( O* J" ]2 F6 z4 R$ Z
  49.                         if(dacval<4000)dacval+=200;# \/ o" I. w9 N- x
  50.                  DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值        
    - Z) f: h* P6 D: {- J' o' z
  51.                 }else if(key==KEY1_PRES)        - r- x% ^; a! E. V' H
  52.                 {2 K. o2 B  f7 P* C  N- X
  53.                         if(dacval>200)dacval-=200;
    8 d8 L8 y& `4 F2 [8 X
  54.                         else dacval=0;" ]4 u0 Y! P. G4 m
  55.                   DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值
    5 L2 x$ q  B, B! v4 u
  56.                 }         + t2 ~1 b3 n+ t; ]
  57.          # [' S6 P$ _% {# G; [1 K
  58.                 if(t==10||key==KEY1_PRES||key==WKUP_PRES) //WKUP/KEY1按下了,或者定时时间到了% G9 }6 o' i* X
  59.                 {        $ t( V. y, V" {% Q4 h  i- y
  60.                         //获取DAC数据5 X; ^. o& n$ p: y! q
  61.                         adcx=DAC_GetDataOutputValue(DAC_Channel_1);//读取前面设置DAC的值
    ! b! f4 j$ l9 }1 l( m# H
  62.                         LCD_ShowxNum(124,150,adcx,4,16,0);             //显示DAC寄存器值
    & B# H# h) e% ?* g' c: P+ l; U# ?
  63.                         temp=(float)adcx*(3.3/4096);                        //得到DAC电压值0 W% B. z$ r7 @0 J
  64.                         adcx=temp;7 F5 f. j, p% R  D8 d$ u
  65.                          LCD_ShowxNum(124,170,temp,1,16,0);             //显示电压值整数部分5 R1 i3 D# R& h2 G! j  f, T
  66.                          temp-=adcx;0 S2 ~5 G' i1 O. x
  67.                         temp*=1000;
    - v3 p% c9 s( l) ~
  68.                         LCD_ShowxNum(140,170,temp,3,16,0X80);         //显示电压值的小数部分3 Y+ ~3 M7 c' W; b# s, m
  69.                         
    ' ?: W6 B( e( p# p4 v# l
  70.                         //获取ADC数据
      Z/ p8 P) q/ j+ g! `. ^( k, E
  71.                         adcx=Get_Adc_Average(ADC_Channel_1,10);        //得到ADC转换值         
    * _4 C* k" |! X6 H8 \) R
  72.                         temp=(float)adcx*(3.3/4096);                        //得到ADC电压值
    * C6 A# E1 G" E# _
  73.                         adcx=temp;
    ' x& z0 ~' A! U: \1 {2 @
  74.                          LCD_ShowxNum(124,190,temp,1,16,0);             //显示电压值整数部分
    - q1 z" B0 |% ~" r! D+ c( z
  75.                          temp-=adcx;
    ! }+ I8 e! G9 j" w
  76.                         temp*=1000;3 Y( E  l  j9 c5 ?' {
  77.                         LCD_ShowxNum(140,190,temp,3,16,0X80);         //显示电压值的小数部分
    ' y4 _+ v. s. M
  78.                         LED0=!LED0;           
      ~1 m+ E- ~  |9 H; d) U( H
  79.                         t=0;
    ) ~: c4 \/ S$ q+ w( s4 v/ Z4 E
  80.                 }            
    ) ~9 {6 D) }8 H7 _
  81.                 delay_ms(10);        
    $ s& T% `$ Y9 J9 M
  82.         }
    5 P6 h# t1 q' M0 Y
  83. }
复制代码
; r" f+ W4 N) [9 C
dac.c函数
7 ^. W6 F: ?3 y
  1. #include "dac.h"0 t# }# O- k0 C
  2. , z; ?: S) m: x
  3. //DAC通道1输出初始化
    $ u- B1 u: r* g, S! \; u
  4. void Dac1_Init(void)
    + T% W6 }3 ~" G4 j+ [
  5. { ( I! }6 ]1 w" v1 s% Y5 C
  6.         GPIO_InitTypeDef GPIO_InitStructure;
    . T8 ]' m4 f& R" }7 s6 _
  7.         DAC_InitTypeDef DAC_InitType;
    0 U2 {6 @9 U. R. ^) I0 b

  8. 3 T5 `# J. Y9 C3 I! m0 V
  9.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );          //使能PORTA通道时钟
    ' w, Z8 K$ Z9 J
  10.            RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE );          //使能DAC通道时钟
    , |) h3 j; c- C2 G- `) f- |
  11. & c! _( @% s* n  \
  12.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;                                  //端口配置5 y" C! M1 g" h/ c" _' }5 a7 c
  13.          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                            //模拟输入/ w- h: Q7 l" c  a/ \
  14.          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    2 Q- m8 G3 j1 `3 C5 }% h
  15.          GPIO_Init(GPIOA, &GPIO_InitStructure);
    ' }; j0 o3 W6 y+ G
  16.         GPIO_SetBits(GPIOA,GPIO_Pin_4)        ;//PA.4 输出高/ g: X8 E4 f% X9 V: G# A0 l
  17.                                         6 t7 T9 K3 e0 [& |, \
  18.         DAC_InitType.DAC_Trigger=DAC_Trigger_None;        //不使用触发功能 TEN1=0" E( i, g) |+ I6 J
  19.         DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生: l! R$ i! r/ Y' s% H4 M
  20.         DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置
    $ A! r+ k. G/ {$ s
  21.         DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;        //DAC1输出缓存关闭 BOFF1=15 T) {! g4 z( o* Y4 E
  22.     DAC_Init(DAC_Channel_1,&DAC_InitType);         //初始化DAC通道1
    ' u  q" F) m3 m9 f; L1 p$ a

  23. 3 Z  s3 H7 l+ U) l
  24.         DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC12 \3 E6 u1 _! p' o; J
  25. 1 u/ Q9 U; C5 Y5 {8 z4 ?! w
  26.     DAC_SetChannel1Data(DAC_Align_12b_R, 0);  //12位右对齐数据格式设置DAC值
    # P2 U! n7 Y- r; ^
  27. }
    , G  c' @5 k. a) v6 C- Y/ ?, r% X
  28. ! E5 v; R5 w1 e  Q
  29. //设置通道1输出电压
    ) H. [: B4 `' C# i( }( w
  30. //vol:0~3300,代表0~3.3V+ ?* K2 [+ S# m8 m& u9 ^
  31. void Dac1_Set_Vol(u16 vol)
    ' P. @) A; X. t& C0 |9 T# @
  32. {; m7 Z+ \! S5 u4 I6 s& L, A, U) p
  33.         float temp=vol;" `  ~6 K8 j  L6 R  A) b0 V
  34.         temp/=1000;9 t; Z& T" o" k* o$ D
  35.         temp=temp*4096/3.3;
    6 o$ u4 E1 g( G5 S5 `5 V; I
  36.         DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值4 ^: e, E0 s0 z: ~3 ^
  37. }4 b2 K1 {1 }# O2 b: H5 p
复制代码
  r- t- \0 U' Z. s' M+ P5 z
adc.c函数
) x) @0 m9 v. y0 W
  1. #include "adc.h"
    % f3 O# }! Q5 d: J" v$ O/ h
  2. #include "delay.h"% R1 K1 S: J  K
  3.                   
    - C8 k, n/ Z( a# b" R& [5 X
  4. //初始化ADC9 r. b$ \1 K# G$ r8 v9 S" T
  5. //这里我们仅以规则通道为例& u% w* G2 U# U. O4 e5 a
  6. //我们默认将开启通道0~3                                                                                                                                           & A5 i) P$ |. x3 y4 X$ N7 i
  7. void  Adc_Init(void)
    $ G5 }/ B( K+ P0 k: A
  8. {         
    + M8 t! o# l' ?5 n4 A+ x2 ^
  9.         ADC_InitTypeDef ADC_InitStructure; 5 {' K0 p# ~* F/ a  p
  10.         GPIO_InitTypeDef GPIO_InitStructure;
    4 M. k: H/ d  A3 }1 L% f# h/ {
  11.   t* n! Q3 m$ d
  12.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );          //使能ADC1通道时钟
    8 U* T' a6 E) o9 B2 y6 F

  13. $ j. W6 @$ k: J$ R% j2 N! I
  14.         RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M; p* W! S+ m6 E; z! G# n0 ^! S' z
  15. 8 J1 h# V7 U" q) g3 i! j
  16.         //PA1 作为模拟通道输入引脚                         + X- t# l5 V" C2 n) H/ K
  17.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    8 g) G& w$ M( H2 }" W6 X
  18.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
    & H2 }: u) j' v$ J# ?& n; C' V+ F
  19.         GPIO_Init(GPIOA, &GPIO_InitStructure);        
    ' K; d4 D' _$ C& @  q0 e0 H& }

  20. ! F* f& |* d! w" W4 |! t3 P1 n( a
  21.         ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值
    # Q1 e* P  V; i) ~- k
  22. $ t, R0 F/ g+ V  o6 u) a( [5 D
  23.         ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式4 J9 d  L; d4 z' s1 @& R
  24.         ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //模数转换工作在单通道模式8 A* ~, h. F( k7 @! g$ x4 D  Z
  25.         ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式
    ' f- X/ Z/ m3 ~( ^6 C& B1 t
  26.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动
    5 h3 \* E1 W. r
  27.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐; V5 ]# U" d$ W+ b5 R5 L
  28.         ADC_InitStructure.ADC_NbrOfChannel = 1;        //顺序进行规则转换的ADC通道的数目* l+ V. P* T. ^7 X  H
  29.         ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   . Z4 P% h" f4 r+ M" H- o8 L
  30. / }7 l# Z, t  C: ?
  31.         ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1
    / e0 w* W: H8 g% B6 S
  32.         ' Y4 {/ s6 i  w$ L7 B2 }
  33.         ADC_ResetCalibration(ADC1);        //使能复位校准  
    , f- M7 c  A8 n3 k
  34.          5 @/ Z) P2 ]( O6 A: |
  35.         while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束
    / g, u3 A! y8 K  t
  36.         
    ; w# v' d8 @) p9 N, k
  37.         ADC_StartCalibration(ADC1);         //开启AD校准- q. [( g9 S% q( [
  38. " j$ q3 e' A& ?( f# \6 u3 }* |
  39.         while(ADC_GetCalibrationStatus(ADC1));         //等待校准结束
    * h& ]" S& \# P' A
  40. }        ! B, y$ I  Y* H

  41. 6 A/ t( I" _( E. b0 T
  42. ( O8 x6 _. p4 R# q  J0 H8 b
  43. //获得ADC值) S3 s  F. M. ?: V* X! V3 V8 y
  44. //ch:通道值 0~3
    6 o" I; [8 ]$ \
  45. u16 Get_Adc(u8 ch)   
    % ]* _! W9 r9 `1 t( j, H7 J) Z' V4 Y
  46. {& T8 M' v% `  w6 e/ S8 \
  47.           //设置指定ADC的规则组通道,一个序列,采样时间
    # z$ M3 X9 L$ X" j
  48.         ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期                                      , X5 t2 n" P( o1 p2 B+ f

  49. / p% B" S+ L9 q1 D
  50.         ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能        2 u7 L! P( W: H) T
  51.          ' m$ T3 F8 w; r" K/ C/ C
  52.         while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束2 }/ c( q& |1 a, E* G
  53. * u4 d  M2 Z2 `0 m/ M+ f; e
  54.         return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果
    ( C' ]% Y! R; Z0 k; @+ ~) h/ v' h
  55. }+ H- S. g- Z  d8 t, S. k8 d
  56. ; G# a- k* I2 q9 C! W
  57. u16 Get_Adc_Average(u8 ch,u8 times)
    * c; ~% H9 c6 H0 p& v
  58. {
    6 z) I" ?! H3 O+ p) f& W
  59.         u32 temp_val=0;
    * T; v/ v. B4 z, L) H" F+ h3 R+ o
  60.         u8 t;2 d$ _( i$ Y4 w& B
  61.         for(t=0;t<times;t++)
    % u5 ]- H9 @/ V) g
  62.         {. D0 z6 D; X7 s
  63.                 temp_val+=Get_Adc(ch);1 W- A, x% y9 y* D8 X- v1 t
  64.                 delay_ms(5);4 u$ Y" i0 m0 @6 v$ [% R
  65.         }
    3 @6 V. L5 h8 s  ?5 t( W2 r
  66.         return temp_val/times;  m8 E9 Z4 w- E  w+ H' T( c* V
  67. }          * _3 X  l# G+ Y$ L* k4 ~0 V; b7 s
复制代码

6 g6 D. r1 I7 n3 L# S( k: G从 main 函数代码可以看出,按键设置输出电压的时候,每次都是以 0.161V 递增或递减的,而通过 USMART 调用 Dac1_Set_Vol 函数,则可以实现任意电平输出控制(当然得在 DAC 可控范围内)。
6 r) e! @( p9 v
3 i7 T* y; l7 J$ j9 X0 h  |& m& F+ |' `- q% q  C
收藏 评论0 发布时间:2021-11-27 09:39

举报

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