|
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! `
) E* A7 B8 O4 g k0 d' Z$ r) h
STM32F0-ADC特性: & ?+ W; A* n0 k1 W$ {
% l1 Q( [' f6 ?; G% n% J. t; d( h12位精度下转换速度可高达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
8 w: D5 Q0 L$ q ZSTM32F0-ADC通道的选择:
; G9 u7 l Y- Y0 a5 r; P9 e
! i% Q: B1 Y0 {) E, ?/ Q19路复用通道: ●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转化模式:
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
1 K1 p: y4 s/ P& ^' f Y2 f. e
; S6 K! v* V4 t7 R6 v) G% d
# t7 M; t4 R1 c2 r# E2 iSTM32F0-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* @
' 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 {
" 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 ~
1 [( U6 W8 d l9 w; Q" D) Y b
* w2 M7 C) u, ^; g m
: g. R3 P" p7 ~, s: L
$ j n6 i' `9 oSTM32F0-ADC模拟看门狗:
8 |3 l/ ~8 z3 U' }* S2 D
/ ?# |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
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- ~
$ i9 ~# s+ ?9 [0 `. n9 ~
6 r# q# E& A& O0 y
0 `( I2 w9 i% X6 s3 n$ `# k- [: f
5 \% W! |7 n# n$ A ?
* M' m- H- I2 c$ [
3 K m8 s# v. t- p4 I
# m; ?, w/ y& f8 I+ P( a* J" v& H5 @" J, [; D4 k4 z
# c7 L# H1 O1 w5 J8 B' s, D: V6 O: r
! H. L6 d E' Z; |- ^; q, Y
8 J$ e& @& V0 s3 S7 U5 z( m
; f3 t! [- H) |5 Q# k p9 _
9 `2 e0 a+ T; S& [# s; t( c4 B9 e' _# b* y8 J& Q
& y* s8 }* P) [. }: Y5 P) b9 f# A
5 G0 }) k7 q; J4 x; N
/ |- h7 J2 F0 j, Dmain.c中启动ADC并使能中断
- 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
& |) \$ f" Z1 j, V- int fputc(int ch,FILE *f){
9 }9 e) E S& m/ ]$ e, Z8 d - while((USART1->ISR&(1<<7)) == 0); 7 z0 j& `8 A6 ^' Z& o; l
- USART1->TDR=(uint8_t)ch;
' k( I( d3 C$ @ - return ch;$ g8 [, n7 K. z" T* A/ ?
- }
复制代码- void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
, b5 ?$ h& ]+ w+ h& E9 @ - {
- ~2 L l$ W7 h7 w - uint32_t light_value;
& i* B! @6 a' Q - light_value = HAL_ADC_GetValue(hadc); //获取ADC中数据寄存器采集的值 P/ V' M3 M* M! Y% U, J
- printf("light_value = %d\n",light_value);
: O$ V" Y) N9 r4 C. N' K7 } - }
复制代码
2 n% {2 Q7 J. Y: F9 B 测试结果:
2 [* m9 p7 l( o8 Y" b. {) h- C
; c, \- Q% m' F _! b% b
) s2 g) V# z* ] R, c9 x( l; J8 P O9 Y9 I
STM32-多通道采集实例实验要求:利用ADC采集按键以及光照传感器的数据,并在按键中断处理程序中打印采集的结果 原理图分析:
9 X9 w7 n" K4 O# B
. W% k7 n( I9 ~: a! ~' Q, f实验过程:
; ^/ r4 q6 Z1 c: g; Q
+ x; J, ?4 ~1 v3 r0 `/ r
6 B- F" ^5 [8 D& ~- E5 l' j, M( G0 T# f* C, K8 x6 u! P
2 h/ O( }) |, ^) u- _0 S0 ]
6 A8 b4 H6 G( ?- Y' L配置ADC功能,因为是由按键中断进行采集,所以配置可以随便选择
% l0 d0 J' u8 N: F- Z
打开按键中断:
: f' F8 \, @' y
1 Q* b) F5 ]$ D# q导出工程:
6 k" d- ?$ ]7 B$ {9 D$ {- T; e* K; I8 Y. h; c6 S. k
0 ^/ s- W0 Z& Q7 q' ^1 V
& B9 T- W: z1 r9 S8 k! u$ g" J: `# x
追加到按键中断回调函数
: Q9 K1 G ?0 q1 ^
1 [( z% }: e4 ]- p, ~
; d7 T% A; `7 }8 L! L# c3 F4 zgpio.c中重新编写fputc 和 回调函数,添加必要的头文件: . O; a% m4 R. r C, W4 c' L
0 L) G) l/ N) t
/ b) V8 c7 G0 x2 n) }, G
- #include "adc.h"
; {% x8 u- X2 ^; k/ B5 b - #include "usart.h"$ o. A0 B* Z* K4 U; P4 f4 u
- ( r1 z# @- \, i$ G8 D: T
- int fputc(int ch,FILE *f){
J8 Z9 l+ Y2 l, K6 N - while((USART1->ISR&(1<<7)) == 0);
/ y" |4 Q; R( c! _6 I5 o8 L, R - USART1->TDR=(uint8_t)ch;
: z9 V! P. @& ^/ S - return ch;! k% w. c8 q) O* I
- } $ }. l& C0 X' e8 \" Z9 U9 y! ~. a$ y
-
' z U, @$ N, ?8 r8 _1 Y' l* |0 W - void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
: f' T8 E/ a3 W: e0 ]( C1 N - {- f2 F# e# d. g1 W1 i+ Q
- uint32_t temp = 0;% K- _$ _! L% F; z) i5 p. N
- if(GPIO_Pin == GPIO_PIN_8)/ g3 c3 ]$ z2 `) p3 a' P
- {& f' c- J# b% z' F% D+ V: G( e. U+ l. w
- HAL_ADC_Start(&hadc); //启动ADC
9 ^6 Y; f' }6 a, W# y+ Y - while(!(hadc.Instance->ISR & (1<<2)));//如果ADC的状态寄存器中的EOC置位,则表示当前通道转化结束
4 D% b2 l8 |- P0 c! o, O' T - temp = HAL_ADC_GetValue(&hadc);) H5 G8 `9 w! r9 `
- printf("key adc value = %d\n", temp);6 [1 [( Q& B: J
- while(!(hadc.Instance->ISR & (1<<2)));//如果ADC的状态寄存器中的EOC置位,则表示当前通道转化结束
. t$ E. k$ ^( O; S - temp = HAL_ADC_GetValue(&hadc);
8 i: c- T4 g0 j: l - printf("light adc value = %d\n", temp);. i7 D: P: c, R% m: G7 M
- HAL_ADC_Stop(&hadc); //关闭ADC7 t9 j9 K9 z1 J4 @: B9 M: g" q
- }
7 T, D, Z& a& |) o - }
复制代码
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
. n6 r$ H! @( `+ l# R9 k" Q* b$ a3 G2 p$ o
* ]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
" o& Q1 N- \; M" C- n* g
+ I. \; A0 U! E7 J: A( M
+ d" t Y4 b% ^
7 E4 F. x6 e0 [3 e! x
0 i p3 _, ~/ H! d* ~' C0 g& ~
( t- R, o+ ~- @
2 l6 P% y9 j! w" f( u- . ~0 P, U# h4 c) v
- #include "adc.h"8 t" Z; k7 J# b( j/ ^% o1 g
- #include "usart.h"
( D8 b& M7 a; L - + ^# g6 M+ m4 k; p1 u4 q' t
- int fputc(int ch,FILE *f){ " s9 {8 p% [. A! ?, b
- while((USART1->ISR&(1<<7)) == 0); . \+ ?8 h1 D, @
- USART1->TDR=(uint8_t)ch;
2 H. X/ s" s& C - return ch;
. t+ a, T0 \ N; w( a) k - }+ G& V+ C) m& n: @0 e6 z, L
-
5 T: Q1 I( G! C% a# ?4 n6 ~+ E: h- a - void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
4 _& e. Q! _' j. v - {) o; {* C* D* @7 h- A: B( g
- if(GPIO_Pin == GPIO_PIN_8)9 x- O, ^5 i( L( t
- {7 Q4 Y& R" y! f& |4 {+ ?1 h
- uint32_t data = 0;
) t0 F" m$ v- c C - HAL_ADC_Start(&hadc);
& k7 S) Q/ _! w2 L3 y - while(!(hadc.Instance->ISR & (1<<2)));% ]( K K! l6 h* g
- data = HAL_ADC_GetValue(&hadc);- @3 |+ m$ M4 d# C( C9 T# N$ Q4 F" D
- printf("key value = %d ", data);' d* ?" t7 h; N2 q" g) Q9 }' s) }0 j
- if(data > 0 && data < 500)+ n+ c% S( e2 G2 G
- {' i8 @. x9 ?7 y
- printf("下边的按键被按下\n");5 n+ P: a" O3 k
- }
+ N5 [4 V0 ^0 n" W - else if(data < 1600)2 N9 Q; v2 ]0 N |3 t
- {5 p. ~9 k) p: y6 s
- printf("左边的按键被按下\n");2 U! _+ Y$ { r+ L
- }/ L# E# W' c/ o, \; s: V
- else if(data < 2200)9 D3 a4 e4 ~) d
- {
" d* |2 L! M5 X& y3 x - printf("上边的按键被按下\n");" T+ r1 Z( k% Z+ s; J
- }3 D7 K, G& c4 ~, T
- else if(data < 2700)
5 E8 u, Z; ^# a% A- h, F - {
$ k) c! x, [2 \; X0 _ - printf("中间的按键被按下\n");, [- H3 E4 j) H- g! p Z+ V
- }
: d( w I" y* U$ E4 |' g - else if(data < 3100)% z* H4 i6 c7 x! T( }
- {
3 F) p: O9 z( E: w! [& F" V4 j, \ - printf("右边的按键被按下\n");
0 f& T3 D. Z o; d7 \ - }
$ E1 q4 u- l, @ - HAL_ADC_Stop(&hadc);; v% Q# @- d7 i) S9 L
- }- {. ]' m/ L: J! P1 N \
- }
复制代码
+ l* N3 _8 _$ A- n) ^( g' n实验结果: 3 V$ i5 K! n5 h( w$ G0 [1 Z
: X) S* U0 z" ^. n
# U9 E! d: a# T1 L% S |