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

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

[复制链接]
STMCU小助手 发布时间:2021-11-27 09:39
本章介绍STM32的DAC功能。本章利用按键(或者USMART)控制STM32内部DAC模块的通道1来输出模拟电压,通过ADC1的通道1采集DAC的输出电压,在LCD模块上面显示ADC获取到的电压值以及DAC的设定输出电压值等信息。
6 K# e1 W; J( s8 w, m/ h, u! A7 V0 h
DAC本身是输出,但是为什么端口要设置为模拟输入模式呢?
3 M$ s+ F0 Z; B( K因为一旦使能DACx通道之后,相应的GPIO引脚(PA4或者PA5)会自动与DAC的模拟输出相连,设置为输入,是为了避免额外的干扰。
3 Q5 f% g9 U) U6 M) p
; F8 f! P+ \7 r
2020051417082468.png

1 k+ ]$ e  C# I, `
20200514170851263.png
5 h. Z& S2 g6 N/ C
20200514171026652.png

" ^  ~0 ~& W# v6 K( n
20200514171156709.png

; O  v" N* W. _' h1 x
2020051417141896.png

* Q) V7 E+ t8 k  C
20200514171611130.png

# R; I. m6 W, B4 F
20200514171802467.png
( x- @5 m# f) k2 G6 i# j8 ~! ^4 S
20200514171858461.png

1 j& ^( p; A8 p- O+ v
20200514171949521.png
$ Y7 |0 _% F$ ^9 \$ Q) a' U
20200514172058766.png

5 v6 M+ {( t) Z% I! {0 t  j0 `2 H; V. N' c5 }

* n( H3 B8 q# v$ N3 I1 G- u% C! r硬件设计
) T# N9 j0 l1 z# A) e) {0 S, R6 K- x% o/ N
20200514172217410.png
- A6 y, i$ y/ p7 q  O
, ~% ~6 R( C) y" `( d. p& m: m
main函数& |  N  i1 g8 b2 i: J7 N/ C
  1. #include "led.h"
    : e- A# A/ K. }, E
  2. #include "delay.h"
    2 @4 d6 N& Z# v* ?  }, d/ w  k
  3. #include "key.h"
    & {5 G3 @2 b3 s! }
  4. #include "sys.h"& s/ A! [; @7 b( o
  5. #include "lcd.h"
    " Z8 s# I: Q" R7 [
  6. #include "usart.h"                  ) r8 i: C1 R4 ]$ [
  7. #include "dac.h"
    . ?8 P! T0 s3 _: }, J  k
  8. #include "adc.h"! I  i* c3 @' }* X# U. x
  9. #include "usmart.h"
    . X' Q) z0 `7 q7 I8 J1 ~8 e8 r7 l
  10. - T# K" U: N$ G/ n; l4 ~# m( \
  11. int main(void)
    ; h4 F4 w$ V$ y( z1 C( p
  12. {         ! `0 {6 \1 H0 S' P8 ?
  13.         u16 adcx;6 u* ?, w8 f8 T5 O5 y
  14.         float temp;  G" c; x& X; i! V8 G4 G( J) R
  15.          u8 t=0;         
    & R& I; g, u& J' @  H7 b' V
  16.         u16 dacval=0;+ ]% O; u0 U2 F  U- v
  17.         u8 key;
    + a! t4 S/ T9 j8 w! A5 T' N3 L
  18.         7 I7 H- c7 x% m% w2 s. Y
  19.         delay_init();                     //延时函数初始化         
    / q7 g$ O, }* Z. G! C( B" C  ]
  20.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
    5 [2 V$ Z+ S: j! G( _* }- S# s
  21.         uart_init(115200);                 //串口初始化为115200/ B5 j6 K9 B# [+ c% ^/ @* F7 D
  22.         KEY_Init();                          //初始化按键程序" `; ~+ u# b( P& O$ F
  23.          LED_Init();                             //LED端口初始化  a" j+ \. T" k5 x2 v
  24.         LCD_Init();                                  //LCD初始化6 {7 L$ i6 j0 _: [  L
  25.         usmart_dev.init(72);        //初始化USMART        
    ; _) {# M! H# ?7 h7 T
  26.          Adc_Init();                                  //ADC初始化
    4 L6 n; {' R/ T
  27.         Dac1_Init();                        //DAC初始化! ^/ V3 @, P2 _+ x
  28. 7 f5 B) s8 R% t- ]. ~& Q: B# Y
  29.         POINT_COLOR=RED;//设置字体为红色   c; D, f8 w6 A
  30.         LCD_ShowString(60,50,200,16,16,"WarShip STM32");        
      f. P$ z) P0 W3 Z
  31.         LCD_ShowString(60,70,200,16,16,"DAC TEST");        ( R4 R" z: o" t& X1 R
  32.         LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
    # U, a& L( w' F$ Q% f8 V4 m  V7 j
  33.         LCD_ShowString(60,110,200,16,16,"2015/1/15");        
      C! h' p4 D- w- j' A
  34.         LCD_ShowString(60,130,200,16,16,"WK_UP:+  KEY1:-");        % x: U+ g# X! \" [# m2 B; s0 j2 |
  35.         //显示提示信息                                                                                             
    3 }/ k" p% h! v: ?* `# H- P
  36.         POINT_COLOR=BLUE;//设置字体为蓝色; ^9 ?/ P& D# o6 l$ L
  37.         LCD_ShowString(60,150,200,16,16,"DAC VAL:");              
    9 e: s8 g4 _5 E0 L
  38.         LCD_ShowString(60,170,200,16,16,"DAC VOL:0.000V");              ; R# Y. G* F5 y4 u/ w( ~  a* Z! J/ z
  39.         LCD_ShowString(60,190,200,16,16,"ADC VOL:0.000V");
    # @3 T+ r) }( t  _7 d
  40.         
    % {( M9 `4 }% x5 o0 ]& Q% w+ {
  41.         DAC_SetChannel1Data(DAC_Align_12b_R, 0);//初始值为0                          
    % R) [0 a2 x, Z; i
  42.         $ `9 \6 u& ~! B  U4 `
  43.         while(1)2 [! U7 Y1 z' u+ k
  44.         {7 s. D. ?6 v3 u! o6 t7 h- o
  45.                 t++;! R5 k, L) u1 l6 _5 H
  46.                 key=KEY_Scan(0);                          ! W% g/ K; y, K2 z' L' d) `! D6 }
  47.                 if(key==WKUP_PRES)+ V! _# x4 |. j! K% T6 w3 n7 R0 O
  48.                 {                 
    % w8 t+ s$ [- Y$ D- R, [! C8 _
  49.                         if(dacval<4000)dacval+=200;
    - b/ E9 E; m1 |$ ]' x5 u
  50.                  DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值        
    3 l2 b3 {) c! u0 ^1 z0 n) a* R
  51.                 }else if(key==KEY1_PRES)        % n9 O) `# S3 F  _  X! O" K
  52.                 {
    1 ?. q* D, f- ^
  53.                         if(dacval>200)dacval-=200;  ]( V* w# M; a8 [3 A2 P* a7 p
  54.                         else dacval=0;
    $ [- l/ Z- n" y
  55.                   DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值/ R* l& O0 l1 v" ]) d
  56.                 }         
    6 w7 d9 w  p! n1 c. I2 M5 h/ Q# G2 ^
  57.          
    2 P& `, m: _( J* k6 }
  58.                 if(t==10||key==KEY1_PRES||key==WKUP_PRES) //WKUP/KEY1按下了,或者定时时间到了
    9 o7 l9 A' b0 B) z
  59.                 {        ) A% A6 W. ?3 [& P$ q2 l
  60.                         //获取DAC数据7 L4 h% n; A& m, r. U& t0 _6 o
  61.                         adcx=DAC_GetDataOutputValue(DAC_Channel_1);//读取前面设置DAC的值% c/ M! D  h& K7 l8 R6 {; q
  62.                         LCD_ShowxNum(124,150,adcx,4,16,0);             //显示DAC寄存器值, q$ y' i1 ]; F! r
  63.                         temp=(float)adcx*(3.3/4096);                        //得到DAC电压值7 m3 A! p8 s. H9 @2 b
  64.                         adcx=temp;5 h6 Q: q. c# Z4 a
  65.                          LCD_ShowxNum(124,170,temp,1,16,0);             //显示电压值整数部分$ o0 @  K$ ]: j+ m/ l4 A5 q
  66.                          temp-=adcx;
    9 t$ O8 h9 J( G: d2 U6 T
  67.                         temp*=1000;2 |2 {& b1 `& h' o
  68.                         LCD_ShowxNum(140,170,temp,3,16,0X80);         //显示电压值的小数部分# ]# j; U  @& _5 b# I4 [5 g
  69.                         
    ' |# S% t$ i/ w& s/ C" g0 \
  70.                         //获取ADC数据
    ) g1 u0 P2 i8 N
  71.                         adcx=Get_Adc_Average(ADC_Channel_1,10);        //得到ADC转换值          $ R; Q/ Z; Q) v: i+ g
  72.                         temp=(float)adcx*(3.3/4096);                        //得到ADC电压值3 [, x$ Y2 a; R3 z3 ]" f/ G
  73.                         adcx=temp;0 e: x/ \# A: k9 H# J
  74.                          LCD_ShowxNum(124,190,temp,1,16,0);             //显示电压值整数部分
    . E' q" w& J6 Q. b6 U8 H/ a8 R; Y
  75.                          temp-=adcx;3 m5 x* H! E: {8 y" a3 L
  76.                         temp*=1000;
    8 V! q2 O2 Y' Y% M1 e
  77.                         LCD_ShowxNum(140,190,temp,3,16,0X80);         //显示电压值的小数部分
    0 h' _2 s2 z0 W: B; W2 p
  78.                         LED0=!LED0;           
    + b" c  u6 G! P$ t
  79.                         t=0;
    5 Z  J" [# f, ~' q
  80.                 }            
    4 _8 O) b1 p8 g6 S
  81.                 delay_ms(10);        0 b& |0 o/ Z( @6 a3 i- T6 c5 e# f
  82.         }( S* |% a2 E; L3 M
  83. }
复制代码

. `' P/ g" o- c- adac.c函数6 v7 ^9 H* Y" d/ @
  1. #include "dac.h"
    2 W# o1 @3 V% b9 R$ H& j
  2. 9 }2 d4 X" N/ W7 B5 h7 G! J9 T& t  e  ?
  3. //DAC通道1输出初始化
    % a7 |, ?7 i1 m) E/ m  B
  4. void Dac1_Init(void)
    $ Q( ~1 q* }  B
  5. {
    6 f6 ]4 V7 k5 m( }; v1 }  f4 B5 e
  6.         GPIO_InitTypeDef GPIO_InitStructure;
    2 z  Q3 f) v2 j
  7.         DAC_InitTypeDef DAC_InitType;
    - h* V9 I4 F* T1 L, ]/ I9 }
  8. ' E" a& s  K) B' o8 w0 A
  9.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );          //使能PORTA通道时钟
    5 K/ O9 e  _8 B$ K( T: d
  10.            RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE );          //使能DAC通道时钟 8 F- L$ E0 u- O1 \' j

  11. $ n5 _. {, E+ U
  12.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;                                  //端口配置1 X# b3 M+ x8 q) [% c
  13.          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                            //模拟输入" Y2 a$ S, Z6 y; Q
  14.          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;# H7 F1 a6 l3 K7 P
  15.          GPIO_Init(GPIOA, &GPIO_InitStructure);
    # w6 n1 k2 Z( K$ ^4 Z
  16.         GPIO_SetBits(GPIOA,GPIO_Pin_4)        ;//PA.4 输出高) Q! g4 R6 s0 ^  G/ X/ \+ ~
  17.                                         : J! w; A. j1 S- |* h
  18.         DAC_InitType.DAC_Trigger=DAC_Trigger_None;        //不使用触发功能 TEN1=0) g/ ^7 w' U3 \: q6 N- c
  19.         DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生  ^3 `7 [9 B) U% y/ D5 o
  20.         DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置
    * o0 M5 y& I7 _& r/ ]% m/ _
  21.         DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;        //DAC1输出缓存关闭 BOFF1=13 @! t* H% }0 V* `1 l; K
  22.     DAC_Init(DAC_Channel_1,&DAC_InitType);         //初始化DAC通道1
    ; L5 Y( w% w; u  n' m+ M0 c

  23. # a* T- O1 e2 C  [
  24.         DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC1- B7 f( R) C6 @1 s

  25. : b! W" k! Q( E( D4 J* e8 {
  26.     DAC_SetChannel1Data(DAC_Align_12b_R, 0);  //12位右对齐数据格式设置DAC值  H7 a5 b) x% ?
  27. }
    / `& Z8 q# o6 H5 z# G2 y' @

  28. & g/ R  ^* u$ q5 M  \& L
  29. //设置通道1输出电压; i. H7 l  p/ _2 U) a: m! k* ]# ]
  30. //vol:0~3300,代表0~3.3V2 f  ?- u0 N( ]! G
  31. void Dac1_Set_Vol(u16 vol)3 T4 k% m' K* I" k# V6 ?" x; C
  32. {
    / D+ r" G* d  F* q9 z7 ^) i
  33.         float temp=vol;
    * W/ K5 {/ S0 a3 a6 `1 T
  34.         temp/=1000;
    6 R; ^/ `: [, g. R! h
  35.         temp=temp*4096/3.3;. @/ V) E( \9 X1 e2 ?- F' @, J
  36.         DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值; `2 i" P) B3 Q0 d. v
  37. }
    - A. Q& [( Z/ a7 y
复制代码

: V+ r5 ^' S  L2 W. @8 Eadc.c函数
6 }6 s. o2 f) R3 Z/ w
  1. #include "adc.h"
    " b$ J; u0 G0 a$ _8 j
  2. #include "delay.h"
      T# s9 s/ F& `* Z
  3.                    9 {. |* A9 j3 U, T" e4 |; ~1 E
  4. //初始化ADC$ t6 \5 q' D6 T. Z
  5. //这里我们仅以规则通道为例
      F! f- F0 J7 M, U
  6. //我们默认将开启通道0~3                                                                                                                                          
    ; H' Q! d! w6 l( J$ V- S: g) }: B
  7. void  Adc_Init(void)
    3 K" i( A+ D3 r0 p% q# t" \
  8. {         3 A, j9 C/ z( C" l
  9.         ADC_InitTypeDef ADC_InitStructure; : C% }: G) B% T# x, ]; b; M. r! m4 _7 z
  10.         GPIO_InitTypeDef GPIO_InitStructure;
    - G$ I7 S; z6 l7 E$ |& v

  11. 8 [- N7 k" J! X- p
  12.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );          //使能ADC1通道时钟% a$ J* W' S2 E9 T" ^. Y$ Z( W4 r9 {

  13. 5 r& K$ T6 `& O. e. A1 Y
  14.         RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
    1 G! i8 }- Z+ R8 Z$ t' X  g4 H

  15. ) c3 L' g+ i" t6 r  G: r
  16.         //PA1 作为模拟通道输入引脚                         5 \5 u$ y5 U" v5 I% Y/ k
  17.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    ( R* }8 r' v: j3 w0 O4 q  x4 N
  18.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
    $ q  v( F8 @: c9 P* T- {
  19.         GPIO_Init(GPIOA, &GPIO_InitStructure);        . B( V! t% O! u9 c( R5 K7 d& u

  20. 6 h; ]" ^; r0 b
  21.         ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值" v3 V$ Q% |+ M# D

  22. . l' l3 ?% v+ h4 `
  23.         ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式
    1 V) s3 ~1 f: b5 d
  24.         ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //模数转换工作在单通道模式
    - F! r% S" V5 [- K
  25.         ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式6 b7 {' E' P& J: `- f# ]% A$ {
  26.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动: P0 v) T6 s1 B4 R
  27.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐7 k, W, w' ?7 D5 v
  28.         ADC_InitStructure.ADC_NbrOfChannel = 1;        //顺序进行规则转换的ADC通道的数目) w; }8 _4 U9 h( A, i" L0 |* \
  29.         ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   / x* ?" g& C8 W* `. \& N

  30. . ~! s! x: n. {" n. v9 c9 R
  31.         ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1$ z1 l" L, C7 h3 v
  32.         # e. r7 W. {, B# T/ U- F
  33.         ADC_ResetCalibration(ADC1);        //使能复位校准  ' E6 b. h; b1 y2 w5 F
  34.          
    4 @8 Q3 Z* G& c3 m
  35.         while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束
    ' s0 K' c- h$ Y% U- V2 I9 t
  36.         
    # b( x# w6 A* {0 B5 h
  37.         ADC_StartCalibration(ADC1);         //开启AD校准7 w( Q5 r; d+ g( |) |9 h

  38. . j7 Y5 H' |6 t  `
  39.         while(ADC_GetCalibrationStatus(ADC1));         //等待校准结束) `/ u7 f- \: @& T
  40. }        
    : B+ b* k, F9 d. n# C$ Q

  41. 4 o( n+ U) u! ~
  42. " f& n5 [# r$ T/ H+ i" j
  43. //获得ADC值$ V4 |, [9 U& \5 S7 e% l. h
  44. //ch:通道值 0~3
    6 S7 l' @- ]) x
  45. u16 Get_Adc(u8 ch)   
    9 S/ q* x# F9 q: r9 I" A* P7 d. y5 W
  46. {
    6 W7 N$ V, `( j0 ]# j( C9 p
  47.           //设置指定ADC的规则组通道,一个序列,采样时间
    8 U" c6 Y$ J& ]6 v: y" B' |
  48.         ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期                                      4 X# A6 s! Y% C0 s* b8 {* S

  49. " c7 s0 |# ?  V9 H: x* Q! J% @
  50.         ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能        / s9 y% j3 R3 ^" {( k
  51.          3 d. I2 B+ c7 G! G( `
  52.         while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
    # z- W/ z# F* Z
  53. 2 ^' y# W; [2 U  m! y4 S
  54.         return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果" f/ v7 `! w* w8 r7 p( G( @
  55. }
    5 f0 j- @& G* I/ v1 i
  56. ) k7 x4 Z8 e% n$ L6 N
  57. u16 Get_Adc_Average(u8 ch,u8 times)
    8 k  B( M" g6 T4 ^: b& N
  58. {, o, F  k6 N/ Z7 Y0 w  I2 f% F( Y
  59.         u32 temp_val=0;) v+ s% J8 s" W- G3 B2 ^
  60.         u8 t;0 D7 x8 ~6 m$ B$ x" ?+ K
  61.         for(t=0;t<times;t++)) P8 k1 {7 f, ?8 T
  62.         {7 }9 _6 J% }. }# f# }# Y/ D
  63.                 temp_val+=Get_Adc(ch);. D$ n. H' [( k8 E) j, L' S
  64.                 delay_ms(5);
    1 m" H  h" R" O4 r+ ]; @
  65.         }9 T$ S  k- T. i. J+ X/ q( S5 p+ t
  66.         return temp_val/times;
    ' @  x2 d! J$ N8 \6 r9 M9 d
  67. }         
    4 \  F4 o/ K" L: ~5 J
复制代码
) [% P0 n; s/ A5 A7 M& p3 @
从 main 函数代码可以看出,按键设置输出电压的时候,每次都是以 0.161V 递增或递减的,而通过 USMART 调用 Dac1_Set_Vol 函数,则可以实现任意电平输出控制(当然得在 DAC 可控范围内)。, Q+ J9 J. C! k( L0 u5 ]0 k+ P, s
% I) m4 B0 l0 {' }8 d  S" g' ?. [

  j3 B4 h8 b/ u* s  v
收藏 评论0 发布时间:2021-11-27 09:39

举报

0个回答

所属标签

相似技术帖

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