|
STM32-ADC模数转换内容概要: STM32-ADC模数转换概述 STM32-单通道采集实例 STM32-多通道采集实例
6 g" [- L8 N+ s/ [, X% S STM32-ADC模数转换概述3 X2 Z$ r* p2 ^2 n' c4 Q' B9 E! a
内容概要: ADC简介 STM32F0-ADC时钟 STM32F0-ADC转化模式 STM32F0-ADC转化时间 STM32F0-ADC模拟看门狗 ) [0 k# M6 g: o- G& y5 k
& B# K. Q( i8 c
ADC简介: ADC的作用:采集传感器的数据,测量输入电压,检查电池电量剩余,监测温湿度等。
3 E% |, |3 M" Y
ADC的性能指标: 量程:能测量的电压范围 分辨率:ADC的分辨率通常以输出二进制数的位数表示,位数越多,分辨率越高,一般来说分辨率越高,转化时间越长。 转化时间:模拟输入电压在允许的最大变化范围内,从转换开始到获得稳定的数字量输出所需要的时间称为转换时间
! d$ Y( ]: `$ s; A( y4 C( t
' T; i$ C6 N k; d6 p3 W" X
STM32F0-ADC特性: 5 ^+ Z3 j% M4 {) ?1 ~& ]/ ]9 W
( Z% ^/ }' P- S( F$ m
12位精度下转换速度可高达1MHz
/ p& P8 k+ n7 ^0 C* _6 L* T
可配置的转换精度:6位,8位,10位,12位 转换电压范围:0 ~ 3.6V,V SSA ~ V DDA 供电范围:2.4V ~ 3.6V 19个转换通道: 16个外部通道、 3个内部通道 8 \/ V- l1 K1 w" B& X
采样时间可配置
1 |" x& Q9 O- M2 C* ~# D
ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中 5 v; B" D4 |6 `/ G( `
STM32F0-ADC时钟: & U" m! Y. |1 Q7 u, V
APB时钟的2或4分频,最高14MHz 优点:不会有时钟域之间的同步带来的抖动,触发事件和转换的起始时刻之间的延迟是确定 的,从 而保证转换之间的时间间隔是固定的 缺点: ADC的转换时间和系统时钟频率相关,受系统频率的影响较大
) s+ B) M4 A! |8 C9 c
+ W( t; Y+ {2 U! T
片上14MHZ HSI RC振荡器 优点:无论MCU的运行频率,都可以保证最高的ADC工作频率可以使用自动节电模式(自动开启或关闭14MHz的内部振荡器) 缺点:触发信号的同步会带来抖动,触发事件和转换的起始时刻之间的延迟不确定
, r3 Q/ O% Z6 E2 ^. s
# H/ E9 l0 L- V7 q$ _' j
: y- ?9 p+ Z0 y2 E2 R% ~
STM32F0-ADC通道的选择:
& S1 y3 M$ T: N* \; T/ G9 a* m8 W8 P6 X
19路复用通道: ●16 个从 GPIO 引脚引入的模拟输入 (ADC_IN0...ADC_IN15) ●3 个内部模拟输入 ( 温度传感、内部参考电压、 VBAT 通道 ) ADC 可以转换一个单一通道或自动扫描一个序列通道。被转换的通道序列必须在通道选择寄存器 ADC_CHSELR 中编程选择:每个模拟输入通道有专门的一位选择位 (CHSEL0...CHSEL18).
+ E4 I" T0 V; g
5 E9 ~' H( [) d1 t8 w5 B- N
STM32F0-ADC转化模式:
! j( }" e/ o9 `6 T, H& c
- z: C9 X" G+ ~( Z注: ADC 通知应用每次转换结束 (EOC) 事件 ADC 通知应用每次序列转换结束 (EOS) 事件。 这些标志位都是在ADC 中断和状态寄存器(ADC_ISR)中 ADC_CFGR1可配置COUNT位 。 每次有一个通道在转化结束之后( (EOC) 事件),必须先读取出数据寄存器中采集的数据,然后才能采集下一个通道。
3 i2 a, \& C; D5 ^) S3 X! }7 @
6 G0 r8 i* M% r
9 | v6 q8 c. i3 ~* i
4 q. ~; \2 T4 v. w* [3 E9 D7 a: ]5 ?, P+ k
STM32F0-ADC转化时间: 可编程采样时间 (SMP): T Sampling 可配置: SMP[2:0]@ADC_SMPR 需要和外部电路的输入阻抗匹配,采样时间适用于所有通道
4 z" O I. P9 P0 M+ m9 E$ X
转化的时间: T conversion 取决于转换精度: RES[1:0]@ADC_CFGR1 : E* w7 F9 y' J7 S4 e: b8 Q7 v
1 O# u1 I6 S7 \( u
$ c3 x' k/ o0 i _每个通道总的转换时间等于: T Sampling + T conversion (采样时间 + 转化时间) 转换时间快速预览表:不需要高转换精度的应用,可以通过降低精确度来提高转换速度 假设ADC模块工作在14MHz的最高工作频率下
6 r& X) ]. Z0 Y# J7 k
& x# v6 [! ?( p4 |" i( E, N6 i3 H5 j: ^
% ]: R: l% ^. E; B
# {3 T# T r& w
STM32F0-ADC触发方式: 软件触发:软件设置ADC_CR的ADSTART=1 时,触发选择有效。 外部事件触发:外部事件 ( 例如:定时器TRGO、输入引脚 ) 触发,可以设置触发源以及触发极性
1 {, j# F" N4 f# o4 u, r9 A
7 b" v2 W" ~+ t* h) A
" w! e: l( U7 v2 E0 I
( {! w- N& M4 ~2 I' ]: c; q
7 M9 j0 m/ `4 a0 L* `: @5 d' ^1 o6 D! \
STM32F0-ADC模拟看门狗: / g" P% e& [3 ]4 z' P0 y
1 m9 x8 H' Z( J6 |# D0 `! K8 D
检测待转换的模拟电压:(简单的来说就是检测到电压值不在预设的范围之内,则产生中断,在中断中设置报警等处理措施) 电压超出检测范围就置位AWD@ADC_ISR,并条件性地产生中断 检测范围由上下门限寄存器指定、 12位的ADC_HTR和ADC_LTR有效值
) Q- ]5 ]) k a3 p* V) o: g& v
模拟看门狗的使能控制: AWDEN@ADC_CFGR1 检测所有通道还是单个通道由AWDSEL@ADC_CFGR1决定 检测哪个单个通道由AWDCH[4:0]@ADC_CFGR1决定
/ l' O; ]- `: @( C7 h9 [/ z3 _ q
% l3 w s7 o& A' J l' {
STM32-单通道采集实例
# T) C/ m* P+ s3 m/ D实验要求:利用ADC采集光照传感器的数据,并在中断中获取采集的结果
7 Z. [( ~" Y% D$ b, u6 W: I- v% W
: U' N) V, j' H
2 n) k$ v0 Y2 F2 ^
% T7 D1 J' `0 q% k注:光敏电阻光强越强则阻值越小 # w+ ~' ?* B# w0 o
过程如下: + f4 C, y- f3 d" W
* c( X% C4 i0 f
3 e: n- q! {. E, h& Y
, D; j+ Q6 W& I% t- Z% I1 F
& C) G1 U3 c( H- v* T6 a# a o; ?5 B% ^3 Y- N8 t5 Z- n
1 z9 _" f9 G0 h$ w1 \
0 y0 ?) a$ b0 W. K: {2 u/ o- ^# t
$ [7 n, W6 z8 k( s2 w+ a
$ p* N. R2 ?0 B7 U
; ^1 H% o, X& n/ i$ }. k6 K
5 F" R% f) x u' p
. S$ S' k8 E' o- h
& s- r: M3 g" |7 S5 A
! h; {" ^9 y6 f: I1 |5 r ]) }4 W# h8 M* x
7 t5 t# B4 @! c% ]- I
. t" O& Y1 h" ^+ D& e
: |2 o) R# h% _8 y0 M4 K& V
main.c中启动ADC并使能中断
) F1 _4 t9 R M; [5 t
/ z$ Z$ i5 Y6 Z8 ]( O5 QHAL_ADC_Start_IT(&hadc);//启动ADC转化并使能中断追加到回调函数(可以在向量表中开始追加,也可以在中断程序文件中(.._it.c表示的就是中断程序文件)追加) 

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

5 a+ A# S7 h' z# K7 _# Z
4 z; N: l4 K; k- int fputc(int ch,FILE *f){
, w, }0 ~: G6 I- i) G1 o$ Q# h - while((USART1->ISR&(1<<7)) == 0); - u( u) b6 {8 A! z1 _5 C7 [ c
- USART1->TDR=(uint8_t)ch;$ u1 H) E2 X' @3 j t9 {" r: b9 n
- return ch;
5 F1 I6 b+ i6 f# I9 s9 \ - }
复制代码- void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
" w! H& l* [# K! K! f/ m( f, I - {
" e' T0 W: }0 D - uint32_t light_value;7 p1 B' E1 _+ L- v
- light_value = HAL_ADC_GetValue(hadc); //获取ADC中数据寄存器采集的值0 B$ k3 g1 M5 N9 I8 W5 O
- printf("light_value = %d\n",light_value);9 d8 P$ l6 U2 K1 g, R/ e
- }
复制代码 * e9 Y! n4 K: \9 f* o8 L% N
测试结果: ( V" [( p- r7 B3 w8 ~3 \
& D9 l- J- l" O$ m* _" M
$ N+ A B; K0 t/ w. c3 X
. N, k$ ?$ U/ ~" q! l
STM32-多通道采集实例实验要求:利用ADC采集按键以及光照传感器的数据,并在按键中断处理程序中打印采集的结果 原理图分析:
+ z( e1 z8 K( ]+ G
$ h* p1 e7 E. j7 M; h
实验过程:
1 Y! Y1 h& O8 x1 f) |, c1 |: w; h
4 E! c$ d+ Q1 R$ Y6 N
1 I/ j0 o# r+ Z4 |- Y" x' n
* D' N& C- ~1 w( r" B2 o
% S4 u6 ]6 u2 d1 P$ Q
1 E( [) X! F5 I" Q' K. z- a0 W) l配置ADC功能,因为是由按键中断进行采集,所以配置可以随便选择
9 m$ z9 Q* P7 U$ G d9 X
打开按键中断:
2 Y8 W9 f% i9 Q" V
; ^2 Z3 ~1 N, A, G& d. V
导出工程:
5 ?( h; n- V5 r: k
% p" l7 F$ u' H
6 A& |4 ~ j! d1 G+ A4 }. l F h% _; C2 V b: Q: q& [: j
追加到按键中断回调函数
' u+ }3 z( F+ a1 t7 w
}2 K1 B+ w& L
8 Q" `+ h/ X" d- K- Q
gpio.c中重新编写fputc 和 回调函数,添加必要的头文件:
8 Y% w7 w Q! L
* ~# z; y7 M2 d4 s* D( o) Q
. I6 |. v8 z. x) V' [4 ^+ r6 M- #include "adc.h"
" X* k* e) C, _& L& } - #include "usart.h"
7 m# s: Y4 v/ { -
, ?( \6 M9 I5 _# Z9 N - int fputc(int ch,FILE *f){ 1 k( ]% X% D- i( O# D. N0 L
- while((USART1->ISR&(1<<7)) == 0); 6 Y, b; ]# ]) ^; T+ c
- USART1->TDR=(uint8_t)ch;9 N6 [9 L6 l0 u, [/ A8 c
- return ch;2 c1 H$ R6 y4 ^* F1 a4 P& p* n( Z
- } - M) S, G; N3 r
- 0 c7 }& x5 C* Q f) W! u% _
- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
5 q0 w" k7 k h9 m5 t" P2 X - {1 _' K' @8 H# W/ T, K
- uint32_t temp = 0;- m6 h( Z6 Z2 N! I7 r N
- if(GPIO_Pin == GPIO_PIN_8), F/ N4 E# O6 q* v0 i
- {
8 u) X6 Y/ P1 I0 p$ G - HAL_ADC_Start(&hadc); //启动ADC
3 M, ?! ?" D9 P7 `+ J0 u - while(!(hadc.Instance->ISR & (1<<2)));//如果ADC的状态寄存器中的EOC置位,则表示当前通道转化结束2 }+ S* q) c& D5 u- d0 k
- temp = HAL_ADC_GetValue(&hadc);; ^6 O% k7 p. A% U3 u7 t
- printf("key adc value = %d\n", temp);8 }0 B, e- V. {" l6 C/ K
- while(!(hadc.Instance->ISR & (1<<2)));//如果ADC的状态寄存器中的EOC置位,则表示当前通道转化结束
- E5 I+ T7 U5 p - temp = HAL_ADC_GetValue(&hadc);3 e) S1 H# b& V; X, k. J5 T
- printf("light adc value = %d\n", temp);+ B' K1 _! `& f
- HAL_ADC_Stop(&hadc); //关闭ADC7 D+ g9 U( N' h+ O8 Y: R+ k: q8 X
- }
/ o6 r$ `2 X6 e - }
复制代码
2 ~" i% {6 Q2 g8 m4 q0 w4 }+ Z1 R8 E7 S& W0 ^: j% [% K
4 [& h, s/ x6 G2 ^" T/ V% C* Q1 ]* ^4 j0 c6 H
测试结果: 
7 V/ G$ `% Y- V( r6 h
/ \' D" [; A; u 利用中断和ADC识别五向键,即五向键任一按键拨动时能通过串口打印出是那个按键, F `6 X6 b+ a8 A2 w; F
2 [: x* Z; x) I. M
- F/ ]- b/ T2 P( L; t; C
" j+ K2 K, s" }- a; R# y4 w
8 _, y2 g! F; w" B" x' w
k4 J+ a% v6 o/ i* _; x
9 j( Z. U" P" W& @. j; s3 P( h
8 X- O, b7 U/ d! ?, E* [/ `; Y8 E8 H, N
% g: O1 x J# V) s1 G( @
/ T1 p8 H' [+ D$ u4 e' h
g1 ^9 w8 @) u% b& g3 i' I
" ]3 T8 g7 W0 ]) l6 a
' I+ d+ B/ S3 B! y; s- w
4 y0 x% ]+ ]3 b7 Q; x- #include "adc.h"+ b) ]4 @5 @& b
- #include "usart.h"8 g( }9 g0 w4 S
-
: _& g, S/ Y9 f! H4 u - int fputc(int ch,FILE *f){ ! `. `# t9 |2 t) Z1 ~
- while((USART1->ISR&(1<<7)) == 0);
, z A7 w+ n7 j+ \& I$ h3 G& s - USART1->TDR=(uint8_t)ch;- U$ a; E, a, ^2 {
- return ch;, M b8 e Y9 Q' F# ?% ?/ _
- }- c) r: D, Z' r$ u2 z0 ?
- 4 u$ z: G4 B! d# B$ I
- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
6 E2 r9 {7 Z. O$ P1 M1 t1 A$ [ - {
0 v# ]" l* g9 ~ - if(GPIO_Pin == GPIO_PIN_8); e$ V' ~3 ?( X5 \* Z: w" I) ~4 i- g
- {
- M6 s) n/ H* |. V - uint32_t data = 0;, q6 g% z9 _% H. g
- HAL_ADC_Start(&hadc);
3 q1 U6 ~2 l. p$ F) ?' e0 s7 f - while(!(hadc.Instance->ISR & (1<<2)));
* e+ n7 Q! e! e, Z" ~: U - data = HAL_ADC_GetValue(&hadc);* L! ^) o' l7 a: [
- printf("key value = %d ", data);. n7 ]( ~: Z6 z# t
- if(data > 0 && data < 500)- e% ?9 @0 r, f' T% i: B, H
- {3 D; i' U& M) v0 [' x
- printf("下边的按键被按下\n");3 S% l& M* W5 X K! J" ]
- }' i' V, P1 ^3 M- O: G+ N/ l
- else if(data < 1600)
& a) N& v' \2 H$ [9 D - {2 L# O9 H# B- r7 G) y0 ?4 d
- printf("左边的按键被按下\n");
! W5 W+ J& \& P9 k9 c - }
" k% m8 |7 R' N- Z+ C% O2 O. S - else if(data < 2200)
! b/ v8 r' y, N; p8 W - {1 J1 b: ?: G1 {
- printf("上边的按键被按下\n");. B9 m1 q0 s3 u4 s! d2 I6 {
- }
* R/ u4 I# J* s* ?6 M1 t - else if(data < 2700)' H! x" Q! i8 s% C! f
- {
2 L! E# h- ^( \ - printf("中间的按键被按下\n");
6 ?( ]+ B; i9 l0 r1 U# ]' H2 E3 s - }) E G& A. _3 X! ~6 i( r
- else if(data < 3100)$ L$ d: [8 F- f) a2 o% t3 D9 {9 b
- {$ F9 ~( j8 d; \7 G5 ~' k6 p
- printf("右边的按键被按下\n");
/ N& s7 e h, `; A9 R' c% w - }
! N$ H N1 m1 ?& i7 D) U - HAL_ADC_Stop(&hadc);
' C% h* U c4 q+ ] - }
) U$ R( ~6 p& j2 i - }
复制代码 # K+ u7 X8 \/ m
实验结果:
2 L( w6 k2 _" R
6 h# f7 ]' b& s4 e' C: K) b% o
1 Q" `7 {0 o1 D# u9 ` |