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

物联网之STM32开发六(ADC模数转换)

[复制链接]
STMCU-管管 发布时间:2020-9-28 10:09
STM32-ADC模数转换内容概要:

STM32-ADC模数转换概述

STM32-单通道采集实例

STM32-多通道采集实例

9 p" `* y, L6 I3 n! q

STM32-ADC模数转换概述
4 R8 N; W- H2 J. a  b2 R' [

内容概要:

ADC简介

STM32F0-ADC时钟

STM32F0-ADC转化模式

STM32F0-ADC转化时间

STM32F0-ADC模拟看门狗

& r; A% }4 k( J. o) Z, v8 O# }


8 L9 w* Q3 t- }" O  i9 Q- Q; L' X

ADC简介:

ADC的作用:采集传感器的数据,测量输入电压,检查电池电量剩余,监测温湿度等。

% F6 l3 c4 \# ?3 t1 i

ADC的性能指标:

    量程:能测量的电压范围

    分辨率:ADC的分辨率通常以输出二进制数的位数表示,位数越多,分辨率越高,一般来说分辨率越高,转化时间越长。

    转化时间:模拟输入电压在允许的最大变化范围内,从转换开始到获得稳定的数字量输出所需要的时间称为转换时间


# v+ S; q7 l* j* n3 w, G! `

1_meitu_1.jpg

) E* A7 B8 O4 g  k0 d' Z$ r) h

STM32F0-ADC特性:

& ?+ W; A* n0 k1 W$ {

2_meitu_2.jpg


% l1 Q( [' f6 ?; G% n% J. t; d( h

12位精度下转换速度可高达1MHz


5 M  t" \: x( V9 g$ f; `

可配置的转换精度:6位,8位,10位,12位

转换电压范围:0 ~ 3.6V,V SSA ~ V DDA

供电范围:2.4V ~ 3.6V

19个转换通道: 16个外部通道、 3个内部通道


4 j: Q0 L- r5 ?1 O+ F

采样时间可配置

2 I: U& R% C% l' P( y

ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中

. ?3 [" c0 k4 z

STM32F0-ADC时钟:

1 x. H. g* b3 V

APB时钟的2或4分频,最高14MHz

优点:不会有时钟域之间的同步带来的抖动,触发事件和转换的起始时刻之间的延迟是确定 的,从 而保证转换之间的时间间隔是固定的

缺点: ADC的转换时间和系统时钟频率相关,受系统频率的影响较大


* W: u3 n9 h, t! J% ~


2 K' k: J/ B. `/ _( `: _

片上14MHZ HSI RC振荡器

优点:无论MCU的运行频率,都可以保证最高的ADC工作频率可以使用自动节电模式(自动开启或关闭14MHz的内部振荡器)

缺点:触发信号的同步会带来抖动,触发事件和转换的起始时刻之间的延迟不确定

2 w+ T0 H9 A4 n- E, M: |

( l' p1 Z/ q+ c+ q

3_meitu_1.jpg


8 w: D5 Q0 L$ q  Z

STM32F0-ADC通道的选择:

4_meitu_2.jpg


; G9 u7 l  Y- Y0 a5 r; P9 e
! i% Q: B1 Y0 {) E, ?/ Q

19路复用通道:

    ●16 个从 GPIO 引脚引入的模拟输入 (ADC_IN0...ADC_IN15)

    ●3 个内部模拟输入 ( 温度传感、内部参考电压、 VBAT 通道 )

ADC 可以转换一个单一通道或自动扫描一个序列通道。被转换的通道序列必须在通道选择寄存器 ADC_CHSELR 中编程选择:每个模拟输入通道有专门的一位选择位 (CHSEL0...CHSEL18).

3 k* l% X' Z% t8 n. y- \  U

: ^0 W4 @) ~1 K/ }% ^

STM32F0-ADC转化模式:

5_meitu_3.jpg


7 h1 ]1 }. ?" W; p0 v4 s$ U7 r  y6 `

注:  ADC 通知应用每次转换结束 (EOC) 事件

         ADC 通知应用每次序列转换结束 (EOS) 事件。

         这些标志位都是在ADC 中断和状态寄存器(ADC_ISR)中  ADC_CFGR1可配置COUNT位 。

         每次有一个通道在转化结束之后( (EOC) 事件),必须先读取出数据寄存器中采集的数据,然后才能采集下一个通道。


9 r5 B9 A8 u$ j' |8 \: k

+ h# Q5 F0 `4 r% R% c

6_meitu_4.jpg


1 K1 p: y4 s/ P& ^' f  Y2 f. e

7_meitu_5.jpg

; S6 K! v* V4 t7 R6 v) G% d

# t7 M; t4 R1 c2 r# E2 i

STM32F0-ADC转化时间:

可编程采样时间 (SMP):

      T Sampling 可配置:     SMP[2:0]@ADC_SMPR

      需要和外部电路的输入阻抗匹配,采样时间适用于所有通道

1 a9 o% y: i, H  T

转化的时间:

T conversion 取决于转换精度: RES[1:0]@ADC_CFGR1


* P" |2 z# c2 H3 s* @

8_meitu_6.jpg


' m) `5 @2 H) R, m6 V  y% d7 g- {4 i$ g# T+ z) M0 H. Y' e

每个通道总的转换时间等于:  T Sampling + T conversion (采样时间 + 转化时间)

转换时间快速预览表:不需要高转换精度的应用,可以通过降低精确度来提高转换速度    假设ADC模块工作在14MHz的最高工作频率下

; _# F; D) j, s) I

5 f. D0 q0 x9 V3 [, n9 M8 I5 {

9_meitu_7.jpg


" g7 W8 C& }4 b2 k. R6 Q7 Y( T* h. R/ A) Y2 m# H+ d

STM32F0-ADC触发方式:

软件触发:软件设置ADC_CR的ADSTART=1 时,触发选择有效。

外部事件触发:外部事件 ( 例如:定时器TRGO、输入引脚 ) 触发,可以设置触发源以及触发极性


' I) r+ W, O, S- k  R


" f0 A+ j% L- x! Z- S4 ~

10_meitu_8.jpg

1 [( U6 W8 d  l9 w; Q" D) Y  b
* w2 M7 C) u, ^; g  m

11_meitu_9.jpg


: g. R3 P" p7 ~, s: L
$ j  n6 i' `9 o

STM32F0-ADC模拟看门狗:


8 |3 l/ ~8 z3 U' }* S2 D

12_meitu_10.jpg


/ ?# |1 c) M5 q3 C9 O+ B8 j* Y

检测待转换的模拟电压:(简单的来说就是检测到电压值不在预设的范围之内,则产生中断,在中断中设置报警等处理措施)

    电压超出检测范围就置位AWD@ADC_ISR,并条件性地产生中断      

    检测范围由上下门限寄存器指定、 12位的ADC_HTR和ADC_LTR有效值


* p9 p7 k% L; M

模拟看门狗的使能控制:

    AWDEN@ADC_CFGR1      

    检测所有通道还是单个通道由AWDSEL@ADC_CFGR1决定      

    检测哪个单个通道由AWDCH[4:0]@ADC_CFGR1决定

, `$ p" {! `, y: V4 C

3 q: d* D4 O( l0 n9 r  F+ m

STM32-单通道采集实例
/ r& H# e7 o8 f* G

实验要求:利用ADC采集光照传感器的数据,并在中断中获取采集的结果


) d3 N" q1 x3 @) E

* B" f: m( D% ^4 H

13_meitu_11.jpg


0 Y$ b3 [( T( Q5 }& l: F4 s' Z) Q+ J/ ]4 T

注:光敏电阻光强越强则阻值越小

3 p, N/ x' {) r5 S6 ]4 K/ e

过程如下:


  R5 i$ ]* w/ X! T4 a+ {( r4 `


6 t2 G" \5 T2 K* o  R8 G8 u- ~

14_meitu_12.jpg

$ i9 ~# s+ ?9 [0 `. n9 ~
6 r# q# E& A& O0 y

15_meitu_13.jpg

0 `( I2 w9 i% X6 s3 n$ `# k- [: f
5 \% W! |7 n# n$ A  ?

16_meitu_14.jpg


* M' m- H- I2 c$ [
3 K  m8 s# v. t- p4 I

17_meitu_15.jpg


# m; ?, w/ y& f8 I+ P( a* J" v& H5 @" J, [; D4 k4 z

18_meitu_16.jpg


# c7 L# H1 O1 w5 J8 B' s, D: V6 O: r
! H. L6 d  E' Z; |- ^; q, Y

19_meitu_17.jpg


8 J$ e& @& V0 s3 S7 U5 z( m
; f3 t! [- H) |5 Q# k  p9 _

20_meitu_18.jpg


9 `2 e0 a+ T; S& [# s; t( c4 B9 e' _# b* y8 J& Q

21_meitu_19.jpg


& y* s8 }* P) [. }: Y5 P) b9 f# A

22_meitu_20.jpg


5 G0 }) k7 q; J4 x; N
/ |- h7 J2 F0 j, D

main.c中启动ADC并使能中断

23_meitu_21.jpg

- J$ B3 y+ s4 a1 M+ @9 ]& _+ r

6 c, Z+ C& g; `/ C) jHAL_ADC_Start_IT(&hadc);//启动ADC转化并使能中断

追加到回调函数(可以在向量表中开始追加,也可以在中断程序文件中(.._it.c表示的就是中断程序文件)追加)

main.c中重新编写fputc函数,adc.c中重新编写回调函数:

! _" E0 N& U- v& c


  1. & |) \$ f" Z1 j, V
  2. int fputc(int ch,FILE *f){       
    9 }9 e) E  S& m/ ]$ e, Z8 d
  3.     while((USART1->ISR&(1<<7)) == 0);        7 z0 j& `8 A6 ^' Z& o; l
  4.     USART1->TDR=(uint8_t)ch;
    ' k( I( d3 C$ @
  5.     return ch;$ g8 [, n7 K. z" T* A/ ?
  6. }
复制代码
  1. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
    , b5 ?$ h& ]+ w+ h& E9 @
  2. {
    - ~2 L  l$ W7 h7 w
  3.         uint32_t light_value;
    & i* B! @6 a' Q
  4.         light_value = HAL_ADC_GetValue(hadc);  //获取ADC中数据寄存器采集的值  P/ V' M3 M* M! Y% U, J
  5.         printf("light_value = %d\n",light_value);
    : O$ V" Y) N9 r4 C. N' K7 }
  6. }
复制代码

2 n% {2 Q7 J. Y: F9 B

测试结果:


2 [* m9 p7 l( o8 Y" b. {) h- C

; c, \- Q% m' F  _! b% b

28.png


) s2 g) V# z* ]  R, c9 x( l; J8 P  O9 Y9 I
STM32-多通道采集实例

实验要求:利用ADC采集按键以及光照传感器的数据,并在按键中断处理程序中打印采集的结果

原理图分析:

29_meitu_27.jpg


9 X9 w7 n" K4 O# B
. W% k7 n( I9 ~: a! ~' Q, f

实验过程:

30_meitu_28.jpg


; ^/ r4 q6 Z1 c: g; Q
+ x; J, ?4 ~1 v3 r0 `/ r

31_meitu_29.jpg


6 B- F" ^5 [8 D& ~- E5 l' j, M( G0 T# f* C, K8 x6 u! P

32_meitu_30.jpg


2 h/ O( }) |, ^) u- _0 S0 ]
6 A8 b4 H6 G( ?- Y' L

配置ADC功能,因为是由按键中断进行采集,所以配置可以随便选择

33_meitu_31.jpg

% l0 d0 J' u8 N: F- Z

打开按键中断:

34_meitu_32.jpg


: f' F8 \, @' y
1 Q* b) F5 ]$ D# q

导出工程:

35_meitu_33.jpg


6 k" d- ?$ ]7 B$ {9 D$ {- T; e* K; I8 Y. h; c6 S. k

36_meitu_34.jpg

0 ^/ s- W0 Z& Q7 q' ^1 V
& B9 T- W: z1 r9 S8 k! u$ g" J: `# x

追加到按键中断回调函数

37_meitu_35.jpg


: Q9 K1 G  ?0 q1 ^

38_meitu_36.jpg

1 [( z% }: e4 ]- p, ~

; d7 T% A; `7 }8 L! L# c3 F4 z

gpio.c中重新编写fputc 和 回调函数,添加必要的头文件:

. O; a% m4 R. r  C, W4 c' L

0 L) G) l/ N) t

39_meitu_37.jpg

/ b) V8 c7 G0 x2 n) }, G
  1. #include "adc.h"
    ; {% x8 u- X2 ^; k/ B5 b
  2. #include "usart.h"$ o. A0 B* Z* K4 U; P4 f4 u
  3. ( r1 z# @- \, i$ G8 D: T
  4. int fputc(int ch,FILE *f){       
      J8 Z9 l+ Y2 l, K6 N
  5.     while((USART1->ISR&(1<<7)) == 0);       
    / y" |4 Q; R( c! _6 I5 o8 L, R
  6.     USART1->TDR=(uint8_t)ch;
    : z9 V! P. @& ^/ S
  7.     return ch;! k% w. c8 q) O* I
  8. } $ }. l& C0 X' e8 \" Z9 U9 y! ~. a$ y

  9. ' z  U, @$ N, ?8 r8 _1 Y' l* |0 W
  10. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    : f' T8 E/ a3 W: e0 ]( C1 N
  11. {- f2 F# e# d. g1 W1 i+ Q
  12.         uint32_t temp = 0;% K- _$ _! L% F; z) i5 p. N
  13.         if(GPIO_Pin == GPIO_PIN_8)/ g3 c3 ]$ z2 `) p3 a' P
  14.         {& f' c- J# b% z' F% D+ V: G( e. U+ l. w
  15.                 HAL_ADC_Start(&hadc);   //启动ADC
    9 ^6 Y; f' }6 a, W# y+ Y
  16.                 while(!(hadc.Instance->ISR & (1<<2)));//如果ADC的状态寄存器中的EOC置位,则表示当前通道转化结束
    4 D% b2 l8 |- P0 c! o, O' T
  17.                 temp = HAL_ADC_GetValue(&hadc);) H5 G8 `9 w! r9 `
  18.                 printf("key adc value = %d\n", temp);6 [1 [( Q& B: J
  19.                 while(!(hadc.Instance->ISR & (1<<2)));//如果ADC的状态寄存器中的EOC置位,则表示当前通道转化结束
    . t$ E. k$ ^( O; S
  20.                 temp = HAL_ADC_GetValue(&hadc);
    8 i: c- T4 g0 j: l
  21.                 printf("light adc value = %d\n", temp);. i7 D: P: c, R% m: G7 M
  22.                 HAL_ADC_Stop(&hadc);  //关闭ADC7 t9 j9 K9 z1 J4 @: B9 M: g" q
  23.         }
    7 T, D, Z& a& |) o
  24. }
复制代码

7 n+ o' j0 _1 Z2 Z, Q3 q2 D  c& |  t3 N) G" U9 \, p

4 H$ ~$ @3 z5 Q% g8 |5 Q
0 P9 u) @- _3 G, z0 J7 i

测试结果:


0 ?! r4 ~1 g$ t

  H+ D& f+ ^, {! l  ~9 O

利用中断和ADC识别五向键,即五向键任一按键拨动时能通过串口打印出是那个按键
3 d8 p# j5 T5 b5 e+ F
( U+ }, ^6 J1 B1 \) C

41_meitu_39.jpg


. n6 r$ H! @( `+ l# R9 k" Q* b$ a3 G2 p$ o

42_meitu_40.jpg

* ]6 b& T8 h1 U$ C3 X6 V3 X5 L

2 g9 t. J4 O5 x( ?* R5 Z( b6 \! w1 n% c' o6 g( Q8 X

43_meitu_41.jpg


" o& Q1 N- \; M" C- n* g
+ I. \; A0 U! E7 J: A( M

44_meitu_1.jpg

+ d" t  Y4 b% ^
7 E4 F. x6 e0 [3 e! x

45_meitu_2.jpg

0 i  p3 _, ~/ H! d* ~' C0 g& ~
( t- R, o+ ~- @

46_meitu_3.jpg


2 l6 P% y9 j! w" f( u
  1. . ~0 P, U# h4 c) v
  2. #include "adc.h"8 t" Z; k7 J# b( j/ ^% o1 g
  3. #include "usart.h"
    ( D8 b& M7 a; L
  4. + ^# g6 M+ m4 k; p1 u4 q' t
  5. int fputc(int ch,FILE *f){        " s9 {8 p% [. A! ?, b
  6.     while((USART1->ISR&(1<<7)) == 0);        . \+ ?8 h1 D, @
  7.     USART1->TDR=(uint8_t)ch;
    2 H. X/ s" s& C
  8.     return ch;
    . t+ a, T0 \  N; w( a) k
  9. }+ G& V+ C) m& n: @0 e6 z, L

  10. 5 T: Q1 I( G! C% a# ?4 n6 ~+ E: h- a
  11. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    4 _& e. Q! _' j. v
  12. {) o; {* C* D* @7 h- A: B( g
  13.         if(GPIO_Pin == GPIO_PIN_8)9 x- O, ^5 i( L( t
  14.         {7 Q4 Y& R" y! f& |4 {+ ?1 h
  15.                 uint32_t data = 0;
    ) t0 F" m$ v- c  C
  16.                 HAL_ADC_Start(&hadc);
    & k7 S) Q/ _! w2 L3 y
  17.                 while(!(hadc.Instance->ISR & (1<<2)));% ]( K  K! l6 h* g
  18.                 data = HAL_ADC_GetValue(&hadc);- @3 |+ m$ M4 d# C( C9 T# N$ Q4 F" D
  19.                 printf("key value = %d    ", data);' d* ?" t7 h; N2 q" g) Q9 }' s) }0 j
  20.                 if(data > 0 && data < 500)+ n+ c% S( e2 G2 G
  21.                 {' i8 @. x9 ?7 y
  22.                         printf("下边的按键被按下\n");5 n+ P: a" O3 k
  23.                 }
    + N5 [4 V0 ^0 n" W
  24.                 else if(data < 1600)2 N9 Q; v2 ]0 N  |3 t
  25.                 {5 p. ~9 k) p: y6 s
  26.                         printf("左边的按键被按下\n");2 U! _+ Y$ {  r+ L
  27.                 }/ L# E# W' c/ o, \; s: V
  28.                 else if(data < 2200)9 D3 a4 e4 ~) d
  29.                 {
    " d* |2 L! M5 X& y3 x
  30.                         printf("上边的按键被按下\n");" T+ r1 Z( k% Z+ s; J
  31.                 }3 D7 K, G& c4 ~, T
  32.                 else if(data < 2700)
    5 E8 u, Z; ^# a% A- h, F
  33.                 {
    $ k) c! x, [2 \; X0 _
  34.                         printf("中间的按键被按下\n");, [- H3 E4 j) H- g! p  Z+ V
  35.                 }
    : d( w  I" y* U$ E4 |' g
  36.                 else if(data < 3100)% z* H4 i6 c7 x! T( }
  37.                 {
    3 F) p: O9 z( E: w! [& F" V4 j, \
  38.                         printf("右边的按键被按下\n");
    0 f& T3 D. Z  o; d7 \
  39.                 }
    $ E1 q4 u- l, @
  40.                 HAL_ADC_Stop(&hadc);; v% Q# @- d7 i) S9 L
  41.         }- {. ]' m/ L: J! P1 N  \
  42. }
复制代码

+ l* N3 _8 _$ A- n) ^( g' n

实验结果:

3 V$ i5 K! n5 h( w$ G0 [1 Z

47.png


: X) S* U0 z" ^. n
# U9 E! d: a# T1 L% S
24_meitu_22.jpg
25_meitu_23.jpg
26_meitu_24.jpg
27_meitu_25.jpg
40_meitu_38.jpg
赞 收藏 1 评论0 发布时间:2020-9-28 10:09

举报

0个回答

所属标签

相似技术帖

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