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

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

[复制链接]
STMCU小助手 发布时间:2021-11-27 09:39
本章介绍STM32的DAC功能。本章利用按键(或者USMART)控制STM32内部DAC模块的通道1来输出模拟电压,通过ADC1的通道1采集DAC的输出电压,在LCD模块上面显示ADC获取到的电压值以及DAC的设定输出电压值等信息。
  D3 K5 x/ d: @0 x. X
7 X' r$ G6 L5 d3 t. v& m" n) p  ZDAC本身是输出,但是为什么端口要设置为模拟输入模式呢?7 R) b' O, {* M& t3 Y/ N
因为一旦使能DACx通道之后,相应的GPIO引脚(PA4或者PA5)会自动与DAC的模拟输出相连,设置为输入,是为了避免额外的干扰。
6 z# c/ Z8 K9 q1 K) ^0 O0 Q5 k* G: K2 |  N+ t/ Q
2020051417082468.png
1 B' B" s7 c4 x, j3 w" {8 I
20200514170851263.png

; U5 ~& I$ @' b7 q) c
20200514171026652.png
5 {; z: F, u5 h7 J& E0 O  c
20200514171156709.png

* K) V- ~8 I! w0 u. y
2020051417141896.png

1 n+ W. @! `5 M- [. e
20200514171611130.png

9 u# I% g% Z1 Y8 k' [0 e' m/ C) q0 V
20200514171802467.png

# L  M8 e' \. W; S5 L' G
20200514171858461.png
) U8 K% b+ h7 g& H1 ~
20200514171949521.png
, _$ i  N, m0 q1 J" V( Q
20200514172058766.png

; v/ W9 S; s9 J* ~9 P6 R1 z3 ?" b

0 _! B/ A6 [8 G1 Y6 `5 X0 c! k/ U  H硬件设计- U3 I0 v& W; K, s: B

* q7 j7 d& `  ^- O" Y
20200514172217410.png
/ J7 A. ]5 z/ W5 l
  q& g+ l0 h8 h* Z8 h
main函数( Q( R4 q8 \' E9 a- ~1 ~+ t& D, S
  1. #include "led.h"
    - W6 m4 \# t8 E* h9 [' }- P6 I
  2. #include "delay.h"
    5 {, }; B4 ^9 {/ k
  3. #include "key.h"5 S( B3 @" E6 |/ K( Q
  4. #include "sys.h"
    1 \  ~6 T3 C, `- J' t  ~8 \, J
  5. #include "lcd.h"
    9 `, z1 }1 ]. p* u* u
  6. #include "usart.h"                  + U  Z  P3 z6 O2 O
  7. #include "dac.h"' Q0 J- D" R2 r+ G5 f' h
  8. #include "adc.h"
    5 ~% Y  O7 q6 i7 q
  9. #include "usmart.h"! o# R# N: x6 q) m
  10. 3 {8 J+ A  K/ H( W2 \
  11. int main(void)# ^/ n6 H! o5 {
  12. {         
    / m% |# S! x6 Q9 x1 t2 ]- h, M
  13.         u16 adcx;2 Q( s' T: k! I+ A
  14.         float temp;
      b( S- M8 t6 s, x( N! X
  15.          u8 t=0;         
    + e$ H4 F3 U3 P
  16.         u16 dacval=0;
      S0 E2 o' x* H3 \/ Y6 t
  17.         u8 key;
    ; }" J3 R. \/ l% z: I* K. u
  18.         
    * U2 I& Q( S# Z  |5 [; b5 f! m; b: [
  19.         delay_init();                     //延时函数初始化         
    3 l# y) {6 ~6 q( y
  20.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级% u/ P, i- z: v
  21.         uart_init(115200);                 //串口初始化为115200
    . @& p- F; W: B) d: H; T0 a
  22.         KEY_Init();                          //初始化按键程序
    ; l9 H" |4 k2 A1 Z: i5 M
  23.          LED_Init();                             //LED端口初始化
    * T) s9 Y8 N5 E" `, c0 @% i
  24.         LCD_Init();                                  //LCD初始化5 x4 w: v* @* q$ o+ x8 I
  25.         usmart_dev.init(72);        //初始化USMART        * _  |4 k& R7 v6 c% J% A
  26.          Adc_Init();                                  //ADC初始化
    1 j/ e' P# t. K7 \
  27.         Dac1_Init();                        //DAC初始化
    7 r$ h/ g! [) `7 u! A( @
  28. 7 y; j9 l* U* Z6 K# _$ s4 k, M$ m
  29.         POINT_COLOR=RED;//设置字体为红色
    $ G& W9 X- `/ w. Q- A
  30.         LCD_ShowString(60,50,200,16,16,"WarShip STM32");        
    9 j0 D$ v; ^$ o# \
  31.         LCD_ShowString(60,70,200,16,16,"DAC TEST");        
    . h' g- m+ m; L+ J% R1 r; k" P6 w
  32.         LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
    ! v$ N) ^' ?$ B/ m, w2 @1 a
  33.         LCD_ShowString(60,110,200,16,16,"2015/1/15");        
    2 i6 O- w, c) ]7 I- K
  34.         LCD_ShowString(60,130,200,16,16,"WK_UP:+  KEY1:-");          q2 q3 x7 _, j) v- T+ B
  35.         //显示提示信息                                                                                             
    2 G, j' [! G* ?
  36.         POINT_COLOR=BLUE;//设置字体为蓝色
    2 l( F# H( D) g" n
  37.         LCD_ShowString(60,150,200,16,16,"DAC VAL:");              
    6 |# D! K, k9 A8 [; c2 m' m
  38.         LCD_ShowString(60,170,200,16,16,"DAC VOL:0.000V");              
    + r6 p: @( S6 h
  39.         LCD_ShowString(60,190,200,16,16,"ADC VOL:0.000V");0 G3 i) U" R; `% W4 h6 w5 P
  40.         ! |5 r( V/ X6 J
  41.         DAC_SetChannel1Data(DAC_Align_12b_R, 0);//初始值为0                          ! u' f( G! F% P( b* n
  42.         
    1 v" b+ x6 y9 r! a6 x, K" F
  43.         while(1)
    9 R, s. [, _, {: y9 z( L7 s- C
  44.         {5 \1 A2 V% o; f* J: y2 w2 X: Z
  45.                 t++;
    4 D4 i$ a/ W5 P1 X& s" ]6 w
  46.                 key=KEY_Scan(0);                          
    ' h& x. b  N$ [$ b2 T2 R
  47.                 if(key==WKUP_PRES)( e. v" f! O0 Q+ P2 f# H
  48.                 {                 ) `! F6 N1 B% Q+ w: b4 V7 g- P$ H
  49.                         if(dacval<4000)dacval+=200;
    , U5 y* s" v4 M- _" @$ B
  50.                  DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值        $ _" I  [/ O5 @5 p. w( F) C4 D, R
  51.                 }else if(key==KEY1_PRES)        5 d0 [0 w# e- @* J# i0 j8 d
  52.                 {" k6 W' Q: n) o, K* F) Z% D
  53.                         if(dacval>200)dacval-=200;  T, w, ]0 B( p4 w
  54.                         else dacval=0;
    # o0 P+ ]. B/ s5 q8 L: D' H2 g& ?
  55.                   DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值% f$ t; x6 J$ U% l' G
  56.                 }           t3 w) U  Y' }, e" O
  57.          
    + c; L. O, s" S( {/ ~
  58.                 if(t==10||key==KEY1_PRES||key==WKUP_PRES) //WKUP/KEY1按下了,或者定时时间到了) B: J6 Q) ?. L# U4 F
  59.                 {        
    7 |9 w* _* s6 j1 G7 V4 M1 a1 N# L
  60.                         //获取DAC数据9 {. J7 j2 A3 M" ]' L+ j
  61.                         adcx=DAC_GetDataOutputValue(DAC_Channel_1);//读取前面设置DAC的值
    9 W! q8 H" p3 ~3 ~  K9 C
  62.                         LCD_ShowxNum(124,150,adcx,4,16,0);             //显示DAC寄存器值
    ) D* Q$ s+ d8 @* o8 ~
  63.                         temp=(float)adcx*(3.3/4096);                        //得到DAC电压值0 G8 S$ ^8 i  E
  64.                         adcx=temp;
    & ^0 o3 f' C( f8 I+ N) Q& s1 o
  65.                          LCD_ShowxNum(124,170,temp,1,16,0);             //显示电压值整数部分8 s9 f) ^' R4 O6 C6 w4 q) o
  66.                          temp-=adcx;
    4 A$ n- I. m2 H- F- G  p7 _6 Y. A
  67.                         temp*=1000;
    ( p3 Y. F3 ^+ L3 ?) g
  68.                         LCD_ShowxNum(140,170,temp,3,16,0X80);         //显示电压值的小数部分* @8 v" R3 N1 F, H5 ?; }
  69.                          ' Z( d) [+ @2 k: g- y2 H& ]
  70.                         //获取ADC数据3 F1 @! z! V* `0 f
  71.                         adcx=Get_Adc_Average(ADC_Channel_1,10);        //得到ADC转换值          * _; e/ F/ |% u. Y2 h+ Q2 j( s3 @
  72.                         temp=(float)adcx*(3.3/4096);                        //得到ADC电压值
    & P( H6 g6 R% K: y+ b+ `9 R9 A. h
  73.                         adcx=temp;
    6 E: n* D. ]3 c% Y# Y2 c
  74.                          LCD_ShowxNum(124,190,temp,1,16,0);             //显示电压值整数部分
    ; K" M% S  g( ^
  75.                          temp-=adcx;0 m7 e1 M5 _3 ^2 n
  76.                         temp*=1000;
    6 z2 M4 C  O/ d( g
  77.                         LCD_ShowxNum(140,190,temp,3,16,0X80);         //显示电压值的小数部分
    1 i5 x: t1 c3 f7 q0 @
  78.                         LED0=!LED0;           
    . h% t" h, c1 K4 P  n# `0 m/ U
  79.                         t=0;
    " }' t0 X! e4 \5 q* @
  80.                 }            $ \, S8 h! k3 i9 Z
  81.                 delay_ms(10);        
    3 [% \3 w4 w. W' l6 v
  82.         }
    . f. n7 K5 y& |7 q4 z; `, c. N
  83. }
复制代码
: L6 c( B7 L4 ~  ~' T, o3 b; G
dac.c函数
- Q$ T, n, y2 W8 d1 |% ~) @* m' |, u
  1. #include "dac.h"4 b8 X6 v) ~% o, R: W* f
  2. 8 J* z6 N5 g4 E% |& U3 Q7 T0 j$ o0 F
  3. //DAC通道1输出初始化
    9 e+ o! g8 i6 U. w0 H: {. L
  4. void Dac1_Init(void)
    & A8 i+ S' l6 N# x
  5. { ( R& l/ R' V1 M1 j! S# ]9 _
  6.         GPIO_InitTypeDef GPIO_InitStructure;
    ' p2 v; f7 }* i3 n  L9 ?
  7.         DAC_InitTypeDef DAC_InitType;
    * V% _+ W, U$ U+ u

  8. ( p- M2 E+ }# F
  9.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );          //使能PORTA通道时钟; w8 C# R. z9 n) m
  10.            RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE );          //使能DAC通道时钟 ! |! E; E( }8 w; P4 m( U
  11. 4 O' t/ t* r* h- I; x, `
  12.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;                                  //端口配置
    / H/ `7 o% I' |  v" u3 V( C
  13.          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                            //模拟输入
      ~2 d+ A6 P2 h& b* j+ H: t6 P
  14.          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;4 G9 V, L; R, Y; U
  15.          GPIO_Init(GPIOA, &GPIO_InitStructure);
    " k& q5 O; K2 _# E  J. z6 P( M5 }1 R! O
  16.         GPIO_SetBits(GPIOA,GPIO_Pin_4)        ;//PA.4 输出高, R/ W! B  @  g" Y& K5 x
  17.                                        
    % F" K: ^' g$ [
  18.         DAC_InitType.DAC_Trigger=DAC_Trigger_None;        //不使用触发功能 TEN1=09 w& U& I$ V) O4 `5 f+ v
  19.         DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生. B# P% c. J  g. Z
  20.         DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置
    , e9 L/ g2 d+ u; w' t
  21.         DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;        //DAC1输出缓存关闭 BOFF1=1
    4 _! f$ U" x6 a- a% [
  22.     DAC_Init(DAC_Channel_1,&DAC_InitType);         //初始化DAC通道11 @8 O+ h4 W9 h: p5 s# X
  23. 7 X+ S9 D6 z% X, a% p% ~' Z
  24.         DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC1
    ' x) b+ {3 w4 G+ s1 M

  25. 9 \& B4 y/ r) M' {( c. \$ g6 |
  26.     DAC_SetChannel1Data(DAC_Align_12b_R, 0);  //12位右对齐数据格式设置DAC值
    3 U7 f: u7 |2 k2 a3 [0 \& U
  27. }" X' C5 {+ G  m- N3 ?: E

  28. ( v; _& \$ X! ?$ r; H5 s1 p
  29. //设置通道1输出电压% O4 k( d9 z- v% y7 e
  30. //vol:0~3300,代表0~3.3V3 }& t1 Y6 }8 \) `
  31. void Dac1_Set_Vol(u16 vol)9 A7 J$ Q( {* n% ^% B+ F
  32. {9 P; q$ U# y* `/ S, E) T( h2 h# ^) v
  33.         float temp=vol;
    % F: X4 ^  J4 r8 v! I6 B2 l$ b
  34.         temp/=1000;( M- V1 a3 w. f' e$ f/ U7 ~
  35.         temp=temp*4096/3.3;
    4 U7 A3 n; H! M) j% W, O
  36.         DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值, l& S- l& G: x, T* g8 y
  37. }
    ( z! z& n( R. Z; i- \4 n2 }! N+ I
复制代码

3 y) M4 H* ~; }! g- y& P* m% dadc.c函数# |1 f9 @6 z" V" a* X3 C$ P
  1. #include "adc.h"1 g: D2 M0 i2 \6 o0 B
  2. #include "delay.h"7 e6 m, n; R$ [0 w& q
  3.                    ) J9 S, N, ^8 q. Q5 C
  4. //初始化ADC9 N3 {0 s( K0 G# ~, H- o
  5. //这里我们仅以规则通道为例1 Z2 ?  X' e! m2 ?8 ~
  6. //我们默认将开启通道0~3                                                                                                                                           * K' @0 P- d+ U% ?4 M
  7. void  Adc_Init(void)% O( t! ~$ A* {: m8 n
  8. {         ! S0 @$ m% M/ ]; d9 F# s
  9.         ADC_InitTypeDef ADC_InitStructure;
    0 b! O8 q8 r5 _' `$ W/ c. y
  10.         GPIO_InitTypeDef GPIO_InitStructure;
    + Y* L* _1 s- U" T8 J/ S  n0 m

  11.   `4 [0 b( T# a) i& C! J- Y+ \
  12.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );          //使能ADC1通道时钟
    . u4 f. C3 ^4 }6 B. F. d
  13. # d8 ~" I6 W0 V9 O
  14.         RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
    2 F& m, I3 J" E

  15. 0 N0 ~9 E9 R6 C) |% |
  16.         //PA1 作为模拟通道输入引脚                         - y- W& U* s9 x* r7 V
  17.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;9 J" W( w/ x% b) r( _, n6 {
  18.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
    8 ?* z( R3 I' n: ?  C- l0 T) O
  19.         GPIO_Init(GPIOA, &GPIO_InitStructure);        3 l/ P+ N8 H. w" X% I- S

  20. - \& b1 L, l5 ?2 |8 r# O
  21.         ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值, q% d2 L: f4 A. a9 m1 G; y

  22. 0 p* ?2 J5 E5 s" o9 C4 M. Q
  23.         ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式( y* H, a2 z! L/ p" N: e- w
  24.         ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //模数转换工作在单通道模式, G7 v( H; ^. n1 {! i1 m
  25.         ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式" Z4 z' S; E2 \+ F7 {3 o
  26.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动
    ) ^3 e, c" M# p0 V/ V
  27.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐) _# w6 k( i: i: j% Y4 Q% ^7 q
  28.         ADC_InitStructure.ADC_NbrOfChannel = 1;        //顺序进行规则转换的ADC通道的数目
    ) I: o" h% `8 O: a6 i
  29.         ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   
    % Z- k+ X' ?& l
  30.   d1 u) C! o: q  O
  31.         ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1% B4 u4 G  i4 B) a  O
  32.         
    + d# y+ q5 U& O- c2 T
  33.         ADC_ResetCalibration(ADC1);        //使能复位校准  + Z3 j8 D. E2 H7 C5 |
  34.          0 w  t  p' P8 \" U9 Q5 ~( f& n5 ?
  35.         while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束: f( p- d/ ]7 Q. b; |( t
  36.         
    " M$ L' l; p2 o
  37.         ADC_StartCalibration(ADC1);         //开启AD校准$ t" v3 w7 D& o+ P
  38. 8 r' r. E* V+ K. a5 N
  39.         while(ADC_GetCalibrationStatus(ADC1));         //等待校准结束
    " y* N$ R3 i# t! c7 J, h7 P' {
  40. }        
    ; s2 ]4 h! [3 P2 S; ?
  41. ! |% m, O, q6 _* M. P0 C2 t- [
  42. % L. p. @! Z3 g! \: r/ @: }8 w; B
  43. //获得ADC值
    # x8 w2 F2 T( f" R7 D$ Q. F2 u
  44. //ch:通道值 0~3
    ) Y$ a; _8 ~% C1 l$ k& b
  45. u16 Get_Adc(u8 ch)   
    7 E; n9 q: k" d4 C& g
  46. {
    & X& x' O$ C; c* e6 i
  47.           //设置指定ADC的规则组通道,一个序列,采样时间8 }, F& h- M; G
  48.         ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期                                      
    - u9 u  ]1 b% j1 K& z, J; @
  49. # M0 `) @6 ~" k
  50.         ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能        
    * `) v* J/ n' V6 a- G
  51.          
    ( b: _; v( Y3 [$ u
  52.         while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束8 |- l+ k0 x0 t  T7 n" O* w) J
  53. ; ^) z0 @$ J7 u0 Z1 N* R
  54.         return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果3 s  n0 S$ F9 ^
  55. }% S, S3 y0 I7 p2 U" _8 B% g
  56.   w* D" G' |& y6 e. y
  57. u16 Get_Adc_Average(u8 ch,u8 times)
    1 w; j* j6 j- k% y/ |
  58. {
    : d& j5 Q3 B7 K1 D8 o! V( W7 o
  59.         u32 temp_val=0;; e( q2 `- S- B2 t% H0 h
  60.         u8 t;
    5 D+ v; w  d/ P9 D. M
  61.         for(t=0;t<times;t++)
    / m; D- c. R1 h+ P1 ^
  62.         {
    " `& g* i/ g( Q5 l1 J: J( b( Z
  63.                 temp_val+=Get_Adc(ch);- U$ h* y! L" h+ r- t- b% X
  64.                 delay_ms(5);- L6 P; _/ w8 \) V) m
  65.         }" X0 X9 r# r" D6 O
  66.         return temp_val/times;
    6 d% m3 [2 E9 @- f3 ?! v
  67. }         
    4 b2 [+ P" \2 F9 e1 |8 z
复制代码
: H7 K4 M1 W, [1 C
从 main 函数代码可以看出,按键设置输出电压的时候,每次都是以 0.161V 递增或递减的,而通过 USMART 调用 Dac1_Set_Vol 函数,则可以实现任意电平输出控制(当然得在 DAC 可控范围内)。
, u! r% @2 U- c  u0 n9 @' e8 }% v2 ?* v' N2 b

1 O  ^3 t  h4 _. q3 P- G
收藏 评论0 发布时间:2021-11-27 09:39

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版