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

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

[复制链接]
STMCU小助手 发布时间:2021-11-27 09:39
本章介绍STM32的DAC功能。本章利用按键(或者USMART)控制STM32内部DAC模块的通道1来输出模拟电压,通过ADC1的通道1采集DAC的输出电压,在LCD模块上面显示ADC获取到的电压值以及DAC的设定输出电压值等信息。
3 b$ L, Q' _$ \0 f) e9 k# F0 o" S, i
  s3 j4 P1 b; a, W( K, F% X0 x3 c5 HDAC本身是输出,但是为什么端口要设置为模拟输入模式呢?
% ^6 E# k- c8 K* |1 R因为一旦使能DACx通道之后,相应的GPIO引脚(PA4或者PA5)会自动与DAC的模拟输出相连,设置为输入,是为了避免额外的干扰。& T2 l. Y8 \' j1 Q  @( ~
: L' y+ q  J6 j' w* ]: T! x1 }
2020051417082468.png
$ w+ i( v' }' R( G; n1 @
20200514170851263.png

% g% H2 x' O1 Q9 R# y
20200514171026652.png

: s  ~0 i! K) ]+ F9 e; [. [7 P6 w1 Q" X
20200514171156709.png

3 j( f6 K- A8 L+ a1 h! @( u
2020051417141896.png

* F$ s$ ^+ j' o3 y
20200514171611130.png

8 ^, O: ]1 @* e5 |) e! b- z5 x# o
20200514171802467.png
# u: L' B2 c. S+ k5 u- m
20200514171858461.png

3 V5 Y+ R8 p2 z( F4 l( I
20200514171949521.png
6 ~- V6 p  F+ G3 x. Y
20200514172058766.png
. b( _  j5 x* c1 S) E
; s. W( [" U4 B2 V
# @5 `+ ]/ p- o
硬件设计
, v6 }; ?) j8 W9 H3 x9 g" z, ?! [' g; x" T2 q
20200514172217410.png
+ }8 d  ^: U) i1 l" _# H1 m1 F

8 y1 v; l! s5 ?' R/ _* P0 v; ?main函数
, o6 t+ Y, O4 I
  1. #include "led.h"' {4 u% s, D' V$ n! }" Y  w
  2. #include "delay.h") W" ?( U4 R& z( d
  3. #include "key.h"
      s7 H; L4 f5 M, ?/ J
  4. #include "sys.h"* c8 h, a! C# n1 Q; d* V
  5. #include "lcd.h"2 d( `; j+ R. k; b
  6. #include "usart.h"                  ; k+ B( T8 t+ @) d7 W; G
  7. #include "dac.h"
    : a% m3 r* V! _4 o. X6 t% f
  8. #include "adc.h"
    * L1 m% [) u/ r) b, u3 g
  9. #include "usmart.h"
    - n+ ]1 ]2 I: ~' S+ f

  10. - {% h1 C  Y% p0 T! R7 Q; J
  11. int main(void)
    - A" n" c; }& x
  12. {         
    9 S0 @1 `: ?5 E( ~% `$ ?% \  q
  13.         u16 adcx;
    ' ?, q5 H+ s% ~9 ~2 W" P1 o
  14.         float temp;% r7 t. h1 v- M" ]. I
  15.          u8 t=0;         
    ! d  A. @; N$ A) X
  16.         u16 dacval=0;  Z; w, y# m9 t
  17.         u8 key;' A6 T. e  E+ i2 j. ]" ]# y
  18.         
    7 P; ?* C) q8 V+ T5 W
  19.         delay_init();                     //延时函数初始化         
    % v/ r8 _: K6 P4 T$ [, l& X
  20.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级) [7 C0 B$ Z" p0 @1 E- O4 u
  21.         uart_init(115200);                 //串口初始化为1152009 O+ Q7 J$ a2 O, k  F
  22.         KEY_Init();                          //初始化按键程序% D2 [' _. E$ |6 o: R4 }: ^: ^) F
  23.          LED_Init();                             //LED端口初始化4 X7 Q0 L% _1 Q/ Z
  24.         LCD_Init();                                  //LCD初始化) S, q- l% i; \. t$ W( p/ Y) Y
  25.         usmart_dev.init(72);        //初始化USMART        
    3 w* c0 X3 G6 k+ S
  26.          Adc_Init();                                  //ADC初始化
    0 g8 x+ K8 [# {9 a1 ?0 l, X7 H
  27.         Dac1_Init();                        //DAC初始化! ]/ i: p/ X7 f) {4 n1 {4 `- W" M

  28. # j5 ]) Y9 Q! _; B9 S" E% t+ |, N: m
  29.         POINT_COLOR=RED;//设置字体为红色 * V, y" c. x& }2 e& r
  30.         LCD_ShowString(60,50,200,16,16,"WarShip STM32");        ) q7 m/ o9 `) r/ S- B
  31.         LCD_ShowString(60,70,200,16,16,"DAC TEST");        2 E' j5 r) W' {4 A
  32.         LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
    : t" ~( V, t- W& N
  33.         LCD_ShowString(60,110,200,16,16,"2015/1/15");        
    ; s1 e) ?4 l' I+ N" c
  34.         LCD_ShowString(60,130,200,16,16,"WK_UP:+  KEY1:-");        7 O' J$ p5 a8 t  P$ p; o7 I
  35.         //显示提示信息                                                                                             
    ( a  J# ~( ]7 A- b) j1 e9 I
  36.         POINT_COLOR=BLUE;//设置字体为蓝色
    . v0 u% [( z; J1 X2 g9 V
  37.         LCD_ShowString(60,150,200,16,16,"DAC VAL:");              
    . D; x, g/ N( _4 t
  38.         LCD_ShowString(60,170,200,16,16,"DAC VOL:0.000V");              ( a, z: L# L0 }: f- H
  39.         LCD_ShowString(60,190,200,16,16,"ADC VOL:0.000V");
    + a; @( x- S4 w5 j2 e: m( f0 S7 H
  40.         $ Q2 i1 s% M8 ^0 y% [! o) _" ?, s
  41.         DAC_SetChannel1Data(DAC_Align_12b_R, 0);//初始值为0                          , I1 Z! @8 K* Y
  42.         
    & c9 i7 v) h: Y2 G; e0 I
  43.         while(1)5 D( d/ A2 _1 x4 Y5 |, K- ~
  44.         {
    , @' t$ E1 p( u
  45.                 t++;
    * o3 L4 _/ K7 P: n
  46.                 key=KEY_Scan(0);                          
    9 l  E' O& S, N: W$ [& _
  47.                 if(key==WKUP_PRES)" V, Y( c/ ^/ P  ~! P+ I
  48.                 {                 & E5 s0 \* E9 {4 w
  49.                         if(dacval<4000)dacval+=200;  c4 o" m& |# U* D
  50.                  DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值        8 T% i5 {! Z3 r
  51.                 }else if(key==KEY1_PRES)        5 X* t& V. u/ ~- c
  52.                 {1 X/ A2 q) g: o# a* K3 G" c4 x
  53.                         if(dacval>200)dacval-=200;
    . T6 r8 {# Z6 f5 O; l
  54.                         else dacval=0;7 H) Z( L: N  C
  55.                   DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值
    9 K4 a  v$ {, X
  56.                 }         
    . J* g! I6 G/ U" ^0 {' |
  57.          9 c' a+ I' Z. Z9 I7 ?# ^" N. r
  58.                 if(t==10||key==KEY1_PRES||key==WKUP_PRES) //WKUP/KEY1按下了,或者定时时间到了
    ! D8 l/ h8 U2 o9 _5 C1 L
  59.                 {        
    * j- T' n0 |6 b8 h
  60.                         //获取DAC数据
    : ]3 V& T9 t+ Q- F
  61.                         adcx=DAC_GetDataOutputValue(DAC_Channel_1);//读取前面设置DAC的值
    6 X# c4 ?8 D. @- h/ @, _5 ^
  62.                         LCD_ShowxNum(124,150,adcx,4,16,0);             //显示DAC寄存器值
    4 `/ `! y: m, R2 B( _6 S
  63.                         temp=(float)adcx*(3.3/4096);                        //得到DAC电压值
    8 ?( {5 |3 `1 H$ X" x- S
  64.                         adcx=temp;3 A9 b6 ~) ~1 U" c% |/ J- E3 g
  65.                          LCD_ShowxNum(124,170,temp,1,16,0);             //显示电压值整数部分
    " a' r( U4 L) @& R( Q' k& }/ ^
  66.                          temp-=adcx;; V1 ^# f/ L" z8 j! s9 l0 K5 z5 a6 E
  67.                         temp*=1000;- B' k3 P8 |3 a7 h
  68.                         LCD_ShowxNum(140,170,temp,3,16,0X80);         //显示电压值的小数部分4 a: j' s8 I1 P3 Y# o' P" h" f
  69.                          & z- I; x4 f1 D  {: }
  70.                         //获取ADC数据
    ) v" d) J! {' ?3 S1 z+ o
  71.                         adcx=Get_Adc_Average(ADC_Channel_1,10);        //得到ADC转换值          7 n1 {. m1 R; w
  72.                         temp=(float)adcx*(3.3/4096);                        //得到ADC电压值
    * J, ?" C- x! U4 r8 y+ a
  73.                         adcx=temp;# m: m# ?8 I: x, Z
  74.                          LCD_ShowxNum(124,190,temp,1,16,0);             //显示电压值整数部分
    ) W7 e) P' B  ~+ B# b$ }& [
  75.                          temp-=adcx;
    0 Q, l' \" T+ Z6 Q+ z
  76.                         temp*=1000;
    ) E! w2 ^& i$ I7 D- u* E
  77.                         LCD_ShowxNum(140,190,temp,3,16,0X80);         //显示电压值的小数部分
    6 l' ?( ^. Q% K; k
  78.                         LED0=!LED0;           ; U2 o5 O# o* J) D- N% Y8 t
  79.                         t=0;9 \0 k# [0 d2 ^" p/ W
  80.                 }            
    : z) P9 s3 Z9 e- e7 `' Y7 n% Y" g
  81.                 delay_ms(10);        
    / |, X( h+ \, G' T% X
  82.         }
    " s6 s2 R+ z# C# U0 ]
  83. }
复制代码

: O, h0 c- K. Y1 C! p1 R! [. P2 J0 @dac.c函数
+ ^5 T: @+ T7 I1 A4 L. v/ W
  1. #include "dac.h"7 ~" L  s3 z- M% G; w
  2. & F6 S1 n% Z0 Y* G
  3. //DAC通道1输出初始化
    % [! h5 t8 P" A
  4. void Dac1_Init(void)
    ) F; v/ S5 u7 @9 |) s
  5. {
    + R! K, c; s" g% D5 w3 E
  6.         GPIO_InitTypeDef GPIO_InitStructure;
    " Y, B' q# E: x6 b" Q' O
  7.         DAC_InitTypeDef DAC_InitType;
    9 X0 [0 L1 t2 _9 w* [& j+ q
  8. 2 y/ L$ P# ?: }3 w9 L8 `
  9.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );          //使能PORTA通道时钟; B7 n8 ~4 s  z
  10.            RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE );          //使能DAC通道时钟 9 {  z3 X3 }, Q+ [: q0 }; `

  11. 5 v6 F+ p0 ~7 S: \
  12.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;                                  //端口配置
    3 o& Y0 b% ]: @$ C' I; l
  13.          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                            //模拟输入1 u5 D, y& d! s
  14.          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      j! A, i! N8 e8 `6 w4 W1 |8 @( r
  15.          GPIO_Init(GPIOA, &GPIO_InitStructure);
    2 ]4 b, F" g! O* F" u9 f+ @0 E
  16.         GPIO_SetBits(GPIOA,GPIO_Pin_4)        ;//PA.4 输出高2 i2 ]  ~2 I: A
  17.                                         . w. Q+ A4 G. X( D
  18.         DAC_InitType.DAC_Trigger=DAC_Trigger_None;        //不使用触发功能 TEN1=0
    # P; j/ i  Z" k0 Z  ^2 q
  19.         DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生4 {* V1 k8 y1 b6 [7 l0 [# f
  20.         DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置4 w) M9 _) w( E- T& H6 K3 G
  21.         DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;        //DAC1输出缓存关闭 BOFF1=1# V- b5 M0 y. O# n3 {0 n
  22.     DAC_Init(DAC_Channel_1,&DAC_InitType);         //初始化DAC通道1: J5 \, p+ ?0 |$ x

  23. , O0 B+ j, l! }+ w' ^7 g4 y
  24.         DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC1% z& k8 a3 n: }
  25. # n; I6 \* r. e- j3 ^
  26.     DAC_SetChannel1Data(DAC_Align_12b_R, 0);  //12位右对齐数据格式设置DAC值
    & d( I) T  V# x' K# u
  27. }
    ) F  R  E3 o* _$ o( t* ^
  28. 5 z5 R- I1 d" Z1 n2 s2 u
  29. //设置通道1输出电压
    * J0 R0 J7 C( r# Z( C* A" v
  30. //vol:0~3300,代表0~3.3V
    : f4 Y( O5 a; c
  31. void Dac1_Set_Vol(u16 vol)
    4 j7 l9 e8 W9 `) a
  32. {8 a- c: E9 G& j4 @5 ^
  33.         float temp=vol;/ P1 B# j4 f) r. y) |& j( }6 ?
  34.         temp/=1000;% q$ l4 B* n6 v  v0 ~
  35.         temp=temp*4096/3.3;$ o" @3 b" h. k4 k5 G
  36.         DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值
    3 t  V$ `- t6 M) }
  37. }) p( E9 `- A+ p/ Y
复制代码

+ E6 J. J& F- A) }" R; [adc.c函数
2 q+ g. N3 o" @' q  x- N. {
  1. #include "adc.h"0 @; P4 v+ r' n5 W1 A# R1 T
  2. #include "delay.h"# v! j' S6 A3 _
  3.                    " B) Y2 c  D) i; h& b& {
  4. //初始化ADC
    + U, s4 @# U. V: }) a' x( t/ z
  5. //这里我们仅以规则通道为例
    . q7 k' b. A& Z$ W
  6. //我们默认将开启通道0~3                                                                                                                                           5 O/ c% M- J8 @
  7. void  Adc_Init(void)( ~6 D4 Q5 E% T3 g
  8. {         
    ; \) s8 z0 p* U9 l. O  I8 y7 z( Y
  9.         ADC_InitTypeDef ADC_InitStructure; & h  E, @& w4 k! G6 w; W1 M- w. P
  10.         GPIO_InitTypeDef GPIO_InitStructure;6 I2 R) N$ q) d& q6 S
  11. & Z" j1 j  F" C! X7 C
  12.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );          //使能ADC1通道时钟% ^6 w: p7 H: R" i$ {2 n7 @0 K

  13. 5 m" y9 I# F3 t, F- u" Q
  14.         RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M) n, I5 M9 h) S% M
  15. , t" x. B% u. h: C" S( _9 A
  16.         //PA1 作为模拟通道输入引脚                         ' [1 F) c3 L6 r% f# A7 [5 m: [% X
  17.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;2 V# W4 @3 O( B0 k
  18.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
    ) I1 O: W- x! |7 e) L- G
  19.         GPIO_Init(GPIOA, &GPIO_InitStructure);        ) _$ @# p+ B: l/ a7 H/ w) y2 f

  20. 0 f$ W$ t6 T( L5 w/ U8 P! w
  21.         ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值
    ' }# O3 h# s* F  t6 v3 x0 c

  22. * t5 a2 _& |+ k1 `
  23.         ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式) I6 A- U$ a2 \: Q& ?
  24.         ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //模数转换工作在单通道模式
    6 Z, C1 a/ K/ a4 Q& B5 T
  25.         ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式* D3 T/ H+ _" t4 k, u; }
  26.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动
    ) m) B9 R) b" j/ S) _5 l' H
  27.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐
    1 q+ s% b  a# E+ Q5 j8 ~7 L
  28.         ADC_InitStructure.ADC_NbrOfChannel = 1;        //顺序进行规则转换的ADC通道的数目# e( b4 b' |* t( n( `
  29.         ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   + t9 f, e/ I/ i7 }0 A8 d
  30. ) H! ?5 g0 U( r9 f, @
  31.         ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1: L( d  u0 |: Z' T
  32.         
    7 N$ X+ z6 d7 {
  33.         ADC_ResetCalibration(ADC1);        //使能复位校准  
    - ^7 o6 X; ]" S0 |2 z  F
  34.          , z6 t# ^' H2 c2 o5 |
  35.         while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束
    ) u3 R7 I2 y1 U! P
  36.         
    9 O; O7 T' g- A' |; @% S" c7 X
  37.         ADC_StartCalibration(ADC1);         //开启AD校准
    0 {: u- G( e8 _- ?' ^2 Y

  38. ! y* W; m- r6 d5 s3 J$ \8 i
  39.         while(ADC_GetCalibrationStatus(ADC1));         //等待校准结束
    % `: J! N0 k8 k( |: S0 T3 T- l
  40. }        
    1 f/ l0 X# _$ I& q5 J5 g0 \+ ~$ m
  41. 1 ~- E9 ?' V: N  z7 r
  42. . ?* j# Q3 a! O( H4 j9 j0 o, T* ?
  43. //获得ADC值7 H( ^8 j! _! d" R
  44. //ch:通道值 0~3- D) V5 g7 D; ]$ y$ ?& q6 ~
  45. u16 Get_Adc(u8 ch)   % V4 h: P" h9 ^; Y
  46. {
    ' K9 X! R7 Y+ e( P3 {: _0 @0 G. y
  47.           //设置指定ADC的规则组通道,一个序列,采样时间
    * L7 t) Y* Z9 E) {& Z
  48.         ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期                                      
    ; T, e7 v* Q3 ^( x  m# H! h

  49. * ~/ n. a! @# L; I: a0 a
  50.         ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能        
    3 e' f, x% j( B, m2 m; U0 Q: b' {
  51.          
    & h* p! k& Y* |0 L
  52.         while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
    3 {) _! S6 I' [+ k4 I1 ^: [. v
  53. ; \* x* H  D; D$ \2 F6 A
  54.         return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果! G8 s% r) Y* w; z+ E! I2 e
  55. }
    / `) y9 w0 U+ e& w* {! S
  56. 2 i: s' M  s, X( f6 T7 w& K
  57. u16 Get_Adc_Average(u8 ch,u8 times)- u, _9 t( L! S, c7 f2 K
  58. {, P$ N4 ?) {2 J. N! d/ c
  59.         u32 temp_val=0;
    9 o0 C+ j' c7 f" R4 o7 f
  60.         u8 t;% X6 }) l0 J& a5 n: B+ V
  61.         for(t=0;t<times;t++)$ I, r: g/ S6 R; u
  62.         {
    ( ~0 q1 P$ M, e" c0 Z) x
  63.                 temp_val+=Get_Adc(ch);
    - c# G% a- i' m, A4 \4 P
  64.                 delay_ms(5);! ~! ?5 z1 U  N0 L
  65.         }/ {% @8 t$ a0 a, B
  66.         return temp_val/times;
    4 K1 \5 D8 s; r7 o0 G5 H
  67. }         
    4 b5 O1 j& F0 n
复制代码
  l! T2 t4 B# s# m' j) q( ?
从 main 函数代码可以看出,按键设置输出电压的时候,每次都是以 0.161V 递增或递减的,而通过 USMART 调用 Dac1_Set_Vol 函数,则可以实现任意电平输出控制(当然得在 DAC 可控范围内)。8 P- B% F% \( F- U6 T- e0 R
7 `# {. X' q# a) a/ K( G- T

. Y# F. |$ a1 R; h% F, q
赞 收藏 评论0 发布时间:2021-11-27 09:39

举报

0个回答

所属标签

相似技术帖

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