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

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

[复制链接]
STMCU小助手 发布时间:2021-11-27 09:39
本章介绍STM32的DAC功能。本章利用按键(或者USMART)控制STM32内部DAC模块的通道1来输出模拟电压,通过ADC1的通道1采集DAC的输出电压,在LCD模块上面显示ADC获取到的电压值以及DAC的设定输出电压值等信息。# `! R6 e- y# S4 I8 w4 x
/ W1 F) w, V4 p5 U
DAC本身是输出,但是为什么端口要设置为模拟输入模式呢?
1 M9 O. g1 S; e8 F因为一旦使能DACx通道之后,相应的GPIO引脚(PA4或者PA5)会自动与DAC的模拟输出相连,设置为输入,是为了避免额外的干扰。0 {2 d  G1 r0 n
, l2 n, O: h- I- {! Q- Z
2020051417082468.png

* {( J8 L2 L6 z5 L
20200514170851263.png

+ t: j0 f, D# c# o0 r- X/ O
20200514171026652.png

3 z: a/ Y9 Y& B+ o' P6 N
20200514171156709.png

# {  T6 }- j' Z% M
2020051417141896.png
. f) z6 {  j0 r+ t' p5 Z4 G8 A
20200514171611130.png
7 o5 F: _$ u2 [2 h
20200514171802467.png

# l& O/ t" w9 T, K
20200514171858461.png

  Z8 p; G1 k2 O/ L' n0 C+ M
20200514171949521.png

/ T0 u+ L* ~9 b  d% ?
20200514172058766.png
' m  L0 C2 a) O$ A& u& s4 f
3 I+ \. c9 ?0 [0 S: P4 M. K
2 x# ^  K) K+ L6 P; C  G0 M1 a0 P
硬件设计: [5 M4 Z0 ~3 T/ {5 N' H
" @: m' O$ T4 e
20200514172217410.png

& W6 A1 a) H' o) U4 O5 @
% Y$ h# f1 T# O, g* k4 Lmain函数, h% T0 }8 w( ]$ _2 E
  1. #include "led.h"
    3 i, }: N1 f  G9 `/ @
  2. #include "delay.h"7 U2 m3 Z7 _% S
  3. #include "key.h"/ D/ o/ E! ?% w/ b+ g/ B
  4. #include "sys.h"
    ! k' A' K8 D6 s4 q
  5. #include "lcd.h"9 L9 f- {' c" X- X: ?
  6. #include "usart.h"                  
    * e2 k- t" T' s- s0 ]2 \# I
  7. #include "dac.h"! B" f( C5 Y  r- L5 M
  8. #include "adc.h"# ]7 J7 s) ~1 E! M
  9. #include "usmart.h"( {# B+ M3 ]% t( ~( @7 j

  10. * |1 _0 w" z) Z1 u* f4 S3 B& J
  11. int main(void)& s1 I) b, _* a; [2 z# x7 Z2 T
  12. {         ; N+ {: H1 x7 b% B9 H( A" V; }2 E
  13.         u16 adcx;
    # i4 Y# |  f9 P2 E
  14.         float temp;
    7 M7 y8 o8 Q3 C  v8 L
  15.          u8 t=0;         9 s- x# U# R* j$ H/ w
  16.         u16 dacval=0;
    / @/ L. g9 Y, f4 f3 q: K
  17.         u8 key;: G( {5 ~$ k0 O: b) L; u
  18.         
    5 {% e. Z9 \# |) T; ^% ~  G
  19.         delay_init();                     //延时函数初始化         
    6 v4 {& P5 Z! N. E7 |( E- b
  20.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
    ; q0 H. S5 P3 @* u( @8 f
  21.         uart_init(115200);                 //串口初始化为115200; d9 ]- Y  L% C6 Y
  22.         KEY_Init();                          //初始化按键程序! |8 l! i9 O- ~% }$ i8 w
  23.          LED_Init();                             //LED端口初始化4 S, e) c0 |/ ~2 O4 x+ E" ?
  24.         LCD_Init();                                  //LCD初始化
    ) y6 m; `7 a8 Z
  25.         usmart_dev.init(72);        //初始化USMART        0 j0 ~* l3 z* `
  26.          Adc_Init();                                  //ADC初始化
    . o* }" f5 R$ n7 Q+ x$ j6 C6 n! H2 d
  27.         Dac1_Init();                        //DAC初始化# C7 E9 R% M+ }5 p! q
  28. " _" T( s* l1 ~! c9 |0 T  Y  r
  29.         POINT_COLOR=RED;//设置字体为红色
    9 {' x4 k- r$ v1 h
  30.         LCD_ShowString(60,50,200,16,16,"WarShip STM32");        
    , E3 W2 D- F, y2 d
  31.         LCD_ShowString(60,70,200,16,16,"DAC TEST");        
    8 q% `& c1 L' ^* y
  32.         LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
    ' p8 ]! ?0 I; m( T5 X- t1 t/ b
  33.         LCD_ShowString(60,110,200,16,16,"2015/1/15");        9 t2 b  `: s6 I( v: X
  34.         LCD_ShowString(60,130,200,16,16,"WK_UP:+  KEY1:-");        
    5 T5 }8 F8 A6 ^/ f
  35.         //显示提示信息                                                                                             
    ( H7 ^' v0 [! U3 K- P
  36.         POINT_COLOR=BLUE;//设置字体为蓝色
    ; M$ m0 t6 P* ?5 T% K. r
  37.         LCD_ShowString(60,150,200,16,16,"DAC VAL:");              
    5 p& _/ i; X5 R4 H0 C: r
  38.         LCD_ShowString(60,170,200,16,16,"DAC VOL:0.000V");              9 l. ^* z& L# ~- p1 m9 N
  39.         LCD_ShowString(60,190,200,16,16,"ADC VOL:0.000V");& x5 w: B1 Y" ?0 N$ ^
  40.         
    ( ^1 C0 E9 e, J) Z
  41.         DAC_SetChannel1Data(DAC_Align_12b_R, 0);//初始值为0                          
    " Z3 d" t! t3 k1 R4 ?* ~" y; a5 R
  42.         
    6 w( I( m/ R. ^8 i' A7 y& e+ _
  43.         while(1)
    2 o0 s( A& A! @- S- T
  44.         {. s1 V* Q' m/ ]1 I$ g0 `) M  B2 b
  45.                 t++;9 @* Z$ u3 ^$ o& Y' {/ _
  46.                 key=KEY_Scan(0);                          7 _# z; A! F: Z: n5 S% \7 J
  47.                 if(key==WKUP_PRES)
    , D8 u2 E3 o+ \. |3 q: l( s
  48.                 {                 
    ; W8 [" R) o5 L" z/ i/ c, @8 v
  49.                         if(dacval<4000)dacval+=200;% N1 j2 c7 \/ E; D
  50.                  DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值        
    5 q% I* U6 a1 r; p2 Q$ M! `  L
  51.                 }else if(key==KEY1_PRES)        
    7 ^  c8 F1 r7 X5 `8 Y
  52.                 {
    & P4 ~  P  K" ]; b0 u! g0 {0 u! }
  53.                         if(dacval>200)dacval-=200;
    9 b# u. O4 x; a, o3 r/ F1 m  T
  54.                         else dacval=0;
    . P. q4 \  }) c
  55.                   DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值
    , h  r4 G  P5 m! F1 T0 j, O% ~
  56.                 }         
    & L# \6 W* \. j! R# H, C
  57.          + @: [1 X- F0 n! z) x# ]9 o
  58.                 if(t==10||key==KEY1_PRES||key==WKUP_PRES) //WKUP/KEY1按下了,或者定时时间到了
    & Z  e5 |2 g+ ]8 d: S  C: U1 E
  59.                 {        
    1 T: X8 z' }, _' ^2 w- B0 Q9 v
  60.                         //获取DAC数据6 U/ `6 T1 A& R& d2 U3 i- b) g  J
  61.                         adcx=DAC_GetDataOutputValue(DAC_Channel_1);//读取前面设置DAC的值
    " s' N( @1 u. W  U& f$ B
  62.                         LCD_ShowxNum(124,150,adcx,4,16,0);             //显示DAC寄存器值2 f' O6 J# M% @. V. ]4 }' M0 H
  63.                         temp=(float)adcx*(3.3/4096);                        //得到DAC电压值
      ]- b! L1 L/ y% z$ l5 P1 G0 v' [
  64.                         adcx=temp;
    5 V" z- [( L3 S- E
  65.                          LCD_ShowxNum(124,170,temp,1,16,0);             //显示电压值整数部分
    3 r0 `* M+ n2 p
  66.                          temp-=adcx;
    ' [/ V6 P2 _  E+ A" @5 z1 ?( O
  67.                         temp*=1000;4 {; O6 c0 M; x4 y
  68.                         LCD_ShowxNum(140,170,temp,3,16,0X80);         //显示电压值的小数部分
      c& A; }5 x5 w2 A8 \7 F# S6 v
  69.                          ( W, H) J: [0 t
  70.                         //获取ADC数据
    2 Z' G  I' B( Z1 I/ _9 J! G& a; p
  71.                         adcx=Get_Adc_Average(ADC_Channel_1,10);        //得到ADC转换值          & R$ U2 r& Q+ X, ?5 c( r( F0 c; k
  72.                         temp=(float)adcx*(3.3/4096);                        //得到ADC电压值5 P0 ^" a$ l  S, x
  73.                         adcx=temp;9 k' W$ x& V- f1 `; C# _# @) N
  74.                          LCD_ShowxNum(124,190,temp,1,16,0);             //显示电压值整数部分
    4 o( h, ~( B9 d2 L$ ]
  75.                          temp-=adcx;0 y4 l2 T& \1 |, R9 M7 Z
  76.                         temp*=1000;' k; ~$ W  k6 C5 h. R# f
  77.                         LCD_ShowxNum(140,190,temp,3,16,0X80);         //显示电压值的小数部分
    1 K0 `9 J( G% B# L2 B3 b7 {1 ?
  78.                         LED0=!LED0;           
    % L$ s) x0 w4 {0 Y: P
  79.                         t=0;3 H4 g/ U  x) ~- V0 i0 }
  80.                 }            
    9 ^, i8 J' F  T. q8 U' x
  81.                 delay_ms(10);        
    7 k( Q- O6 Z3 w# g! P, _5 g8 P
  82.         }
    ) o% H, S  Q( M: E
  83. }
复制代码

. V6 Q* w- v6 p/ d+ z5 M: g' [9 g7 udac.c函数. z+ Q7 R: y" v7 t: O! p
  1. #include "dac.h"  o/ O0 x* v& s

  2. : @( v0 @4 E( p7 r) W- I
  3. //DAC通道1输出初始化
    ; o/ n5 }, d9 P, c/ L5 I- Z, `
  4. void Dac1_Init(void)' M4 K3 i/ ?! |" X
  5. {
    & Z3 U7 T- j: P, K
  6.         GPIO_InitTypeDef GPIO_InitStructure;
    : r' e+ @$ @1 Z# ^  W0 U
  7.         DAC_InitTypeDef DAC_InitType;5 H7 a: ~+ i: e" B/ A

  8. ' j% c# O, F" Y' \3 K
  9.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );          //使能PORTA通道时钟
    ( A4 n/ n0 v7 x
  10.            RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE );          //使能DAC通道时钟
    ( [% H! I, J  c* b1 |
  11. 4 s- L; _1 x8 x  @
  12.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;                                  //端口配置- t# @2 S" Y. h' B( H3 q
  13.          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                            //模拟输入
    : z- T% S. j0 R* U" i( L9 q9 X$ i
  14.          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;6 i7 ?' V! |- _- u
  15.          GPIO_Init(GPIOA, &GPIO_InitStructure);0 m6 f, n  W5 v; U( t
  16.         GPIO_SetBits(GPIOA,GPIO_Pin_4)        ;//PA.4 输出高* X2 I6 [3 n3 g" }. E
  17.                                        
    ! b% r. u" _: g; h: A9 v; g
  18.         DAC_InitType.DAC_Trigger=DAC_Trigger_None;        //不使用触发功能 TEN1=0
    ! I6 J  ?2 g' O' ^# ?8 R) z
  19.         DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生$ [" G7 k  Y( y
  20.         DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置+ y# t& X( y4 s8 H% f, J
  21.         DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;        //DAC1输出缓存关闭 BOFF1=1
    # C1 `" I" R8 K' X* w# R
  22.     DAC_Init(DAC_Channel_1,&DAC_InitType);         //初始化DAC通道1
    1 q9 @/ ]' ]  B. c; j8 U& ~0 [

  23. * L; A  z' s! p! K. i/ m( F, |
  24.         DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC1
    ; ~# Q* g: |# F& B9 I7 i, `* S% q3 W
  25. 6 y( h1 X8 r, G7 u6 S5 J
  26.     DAC_SetChannel1Data(DAC_Align_12b_R, 0);  //12位右对齐数据格式设置DAC值! W) W. s. t8 b, |
  27. }: w. l, }1 i' ^9 F2 \7 k* {
  28.   A) ]. D  i: Y, c! Z  c
  29. //设置通道1输出电压
    % V2 H- M0 K: _1 g% l
  30. //vol:0~3300,代表0~3.3V
    ' B) d- E0 G0 {0 `3 T
  31. void Dac1_Set_Vol(u16 vol)/ x, m. R+ b" R& r) N4 h
  32. {0 Z8 y# O: a; g- o
  33.         float temp=vol;
    : q, d. w* F; ]% V! o6 L% \
  34.         temp/=1000;9 |" e5 @, ~7 L" _
  35.         temp=temp*4096/3.3;/ Y6 `0 ^3 k: N( Z. r2 ^
  36.         DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值
    ; e7 s" V8 Y# J2 V7 c3 T
  37. }
    5 |5 H1 q) A/ l2 D
复制代码

- N2 N* n+ B& W( S. Oadc.c函数
' Y+ H, c, ^9 A% p: k( t: [
  1. #include "adc.h"
    , C8 w- [" c8 h- B6 n  R
  2. #include "delay.h"
    : t. s) N6 Q/ y+ C( y
  3.                   
    0 f9 B; C7 [( H6 A: t
  4. //初始化ADC
    ! l9 E$ Q( s" _! ~
  5. //这里我们仅以规则通道为例
    ! K% B  A% D/ O5 @( z7 R3 u0 F' ?
  6. //我们默认将开启通道0~3                                                                                                                                           4 Z" ]9 O- `2 |. T1 H
  7. void  Adc_Init(void): a3 q& d& h! x8 K. F7 ?$ {
  8. {         
    ( l8 x$ z/ s  _0 W. D) z
  9.         ADC_InitTypeDef ADC_InitStructure; % f  U* _7 s; Y4 t! o' S
  10.         GPIO_InitTypeDef GPIO_InitStructure;! T5 o, V# r  _- J! b# I) M6 ~& B0 l

  11. 6 K8 l! m( o6 q8 `4 L( y
  12.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );          //使能ADC1通道时钟& m7 o; {& B4 b" ?
  13. " t( J, n: ?& G- u& X3 @( M7 ~2 l
  14.         RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
    % h* P/ D4 y, |( ~
  15. # ]! \7 r5 }0 k& W/ r6 l) [
  16.         //PA1 作为模拟通道输入引脚                        
    % p, {- X# n( X& p5 D! U; m* {- e
  17.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;1 C( \8 Y7 I% d6 t( w- m. Q
  18.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
    2 ]5 {& N' d" Y4 o0 s
  19.         GPIO_Init(GPIOA, &GPIO_InitStructure);        
    7 ^1 L9 _, `, o/ C+ ]
  20. . ^2 p8 c& \% ?" w9 L
  21.         ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值
    0 Q& x6 r7 A* M+ \0 \  |4 @/ V
  22. 7 N. A/ _# p6 J3 h: P( R; E
  23.         ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式) M$ Q1 u+ Y* `; F; {- r
  24.         ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //模数转换工作在单通道模式# @! f8 l& u/ u2 ]5 h
  25.         ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式: d6 Z- W( v5 D
  26.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动1 b0 g& ?# \8 E! r5 Y* [% C5 V" D3 a
  27.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐. p/ ]& c1 S! ^* b) n
  28.         ADC_InitStructure.ADC_NbrOfChannel = 1;        //顺序进行规则转换的ADC通道的数目+ M6 P7 f/ v) P. t
  29.         ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   
    ; c8 y% c$ e( F4 _6 x0 R

  30. & s. z* K/ W7 E- U  w- I* v
  31.         ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1
    6 _% g6 r" G7 K
  32.         
    9 o/ U" r* m5 @6 x
  33.         ADC_ResetCalibration(ADC1);        //使能复位校准  
    6 U, }' g) b/ z8 g8 y# c1 @
  34.          
    9 q4 v4 }9 l- f% t; M
  35.         while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束
    # G* \" C2 H4 x: B+ O' B) U7 @
  36.         5 D9 v' N. m* u: v
  37.         ADC_StartCalibration(ADC1);         //开启AD校准
    2 O) a. }& a' V4 e. N$ ?' _- z  U
  38. 3 e4 n4 u" L8 Z* n" x1 ?; Z
  39.         while(ADC_GetCalibrationStatus(ADC1));         //等待校准结束
    , y5 x) i- `) |$ `3 t1 W
  40. }        
    7 r9 t+ k7 h# g2 z) S& q

  41. ' l( D/ w" h% B
  42. - a7 ^8 X* @) \4 l
  43. //获得ADC值
    1 \8 G1 Y0 h/ p$ p& B7 i
  44. //ch:通道值 0~39 T' D) }% C- `
  45. u16 Get_Adc(u8 ch)   
    : o3 g. A. c; W$ \  I* |9 {& X
  46. {7 I. D- L6 b8 `. t0 k# r
  47.           //设置指定ADC的规则组通道,一个序列,采样时间# ]) D! n7 g5 p# z* s0 K2 t' ^) \
  48.         ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期                                      
    % a$ ]3 f! O) t, }

  49. ) j( [& [7 {! v$ x& l
  50.         ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能        
    ( D$ \3 P) h+ c, u
  51.          4 b& z* r8 C2 I+ [: r
  52.         while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束; g# K4 Z! s& G8 e1 s2 }2 N6 T2 H& a2 j' \

  53. $ D" V& t% `/ y; i" b
  54.         return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果
    2 |5 b$ K: d9 O( P4 W
  55. }1 q4 j! k" D4 }. Z# w' t
  56. % q7 j' U# l$ S0 Q. I+ l
  57. u16 Get_Adc_Average(u8 ch,u8 times)# J4 E# @0 c9 ~
  58. {6 c. w0 a  g/ g4 M$ W
  59.         u32 temp_val=0;
    8 t1 j& u4 ~6 W5 G% ~# R2 L
  60.         u8 t;
    5 p, K7 L& S! s
  61.         for(t=0;t<times;t++)
    5 j, ]9 J  I+ q( x6 ?! F1 {' }
  62.         {9 @0 L" L( s7 B( w# l  W- F6 q
  63.                 temp_val+=Get_Adc(ch);# S& n8 c2 n$ _) ^/ D8 m
  64.                 delay_ms(5);
    / Z2 K; v8 v4 A& d! D: B
  65.         }
      t# a+ Y4 {' \- f- B, D
  66.         return temp_val/times;
    2 L( h& K  m& o- Q
  67. }         
    1 {' T- f& f" W. m
复制代码

$ ^& |; u7 ], ?$ H& o/ x从 main 函数代码可以看出,按键设置输出电压的时候,每次都是以 0.161V 递增或递减的,而通过 USMART 调用 Dac1_Set_Vol 函数,则可以实现任意电平输出控制(当然得在 DAC 可控范围内)。
( o: N: `8 z7 Z) X. [3 X: v1 p
- l6 \) G/ ^% N$ T# B: X; V4 [- `/ b1 }! x4 u9 T
收藏 评论0 发布时间:2021-11-27 09:39

举报

0个回答

所属标签

相似技术帖

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