|
STM32-ADC模数转换内容概要: STM32-ADC模数转换概述 STM32-单通道采集实例 STM32-多通道采集实例 3 q+ M5 k. t0 f
STM32-ADC模数转换概述
( j6 B# [0 R6 v# i' s4 ]& o内容概要: ADC简介 STM32F0-ADC时钟 STM32F0-ADC转化模式 STM32F0-ADC转化时间 STM32F0-ADC模拟看门狗 + a2 f2 E- [ ^! p
- w8 E: [/ g+ i3 e& y- o' p
ADC简介: ADC的作用:采集传感器的数据,测量输入电压,检查电池电量剩余,监测温湿度等。 & c2 H: N8 E$ M' E5 \
ADC的性能指标: 量程:能测量的电压范围 分辨率:ADC的分辨率通常以输出二进制数的位数表示,位数越多,分辨率越高,一般来说分辨率越高,转化时间越长。 转化时间:模拟输入电压在允许的最大变化范围内,从转换开始到获得稳定的数字量输出所需要的时间称为转换时间 : i2 c9 n9 J# ?" U' j4 H
! [2 D T" X9 ]9 z
STM32F0-ADC特性:
% O! l; ]8 y9 x5 A/ ]3 D k6 Q3 b
3 O8 B% b9 z# e l3 u$ O. t12位精度下转换速度可高达1MHz : h* k; ~/ @' A7 y2 l# |0 t8 F
可配置的转换精度:6位,8位,10位,12位 转换电压范围:0 ~ 3.6V,V SSA ~ V DDA 供电范围:2.4V ~ 3.6V 19个转换通道: 16个外部通道、 3个内部通道 3 [. A% i) P$ U- D: {
采样时间可配置
' k {/ z. j+ h! }* }
ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中 2 Y! c+ L( }. d, ^! M( Q
STM32F0-ADC时钟:
. ^. s- Q! }, m6 U
APB时钟的2或4分频,最高14MHz 优点:不会有时钟域之间的同步带来的抖动,触发事件和转换的起始时刻之间的延迟是确定 的,从 而保证转换之间的时间间隔是固定的 缺点: ADC的转换时间和系统时钟频率相关,受系统频率的影响较大 : G9 K2 }! \% f& c: y
) H+ `, }+ I; v8 b% s9 D5 |/ r3 u
片上14MHZ HSI RC振荡器 优点:无论MCU的运行频率,都可以保证最高的ADC工作频率可以使用自动节电模式(自动开启或关闭14MHz的内部振荡器) 缺点:触发信号的同步会带来抖动,触发事件和转换的起始时刻之间的延迟不确定 9 z; h( g3 a. {9 X* v* e
& z; |7 x% t+ |
. I) B8 O9 p$ e6 P( e* c
STM32F0-ADC通道的选择:
% d' Q. p4 z# e5 n
4 U2 L, e$ U" B4 R- g19路复用通道: ●16 个从 GPIO 引脚引入的模拟输入 (ADC_IN0...ADC_IN15) ●3 个内部模拟输入 ( 温度传感、内部参考电压、 VBAT 通道 ) ADC 可以转换一个单一通道或自动扫描一个序列通道。被转换的通道序列必须在通道选择寄存器 ADC_CHSELR 中编程选择:每个模拟输入通道有专门的一位选择位 (CHSEL0...CHSEL18).
, `+ }; ^+ z) O5 X4 F/ P% V. }6 H
( H2 X, Y0 s7 G. l2 N7 m5 H3 z
STM32F0-ADC转化模式:
9 s1 Q. E& q8 B+ N$ z6 l; Q/ d& I/ F
注: ADC 通知应用每次转换结束 (EOC) 事件 ADC 通知应用每次序列转换结束 (EOS) 事件。 这些标志位都是在ADC 中断和状态寄存器(ADC_ISR)中 ADC_CFGR1可配置COUNT位 。 每次有一个通道在转化结束之后( (EOC) 事件),必须先读取出数据寄存器中采集的数据,然后才能采集下一个通道。 % I' ]5 J7 z* {2 s! ]8 t/ z, S3 T
! G/ r. D2 K! F# q0 j( w: ~5 D
! Z& Y! }. ?+ [ N4 H
[6 w' |* x- [2 ? A4 ~# e
: {( Y. g8 q& z3 k, V6 }1 v" |STM32F0-ADC转化时间: 可编程采样时间 (SMP): T Sampling 可配置: SMP[2:0]@ADC_SMPR 需要和外部电路的输入阻抗匹配,采样时间适用于所有通道 * N& E5 B% M$ ]; D: x
转化的时间: T conversion 取决于转换精度: RES[1:0]@ADC_CFGR1
. [/ c) d0 D! N: C% L: m- \) s S
9 [# D7 x6 D) q1 c
& X) k/ [1 W/ s
每个通道总的转换时间等于: T Sampling + T conversion (采样时间 + 转化时间) 转换时间快速预览表:不需要高转换精度的应用,可以通过降低精确度来提高转换速度 假设ADC模块工作在14MHz的最高工作频率下 / O( i; i4 Q! r
$ g2 ?* |7 u* s, m
5 Z' m/ t3 r8 J- c. l/ ~1 u4 C9 u6 N% ^. ~5 z& S1 p
STM32F0-ADC触发方式: 软件触发:软件设置ADC_CR的ADSTART=1 时,触发选择有效。 外部事件触发:外部事件 ( 例如:定时器TRGO、输入引脚 ) 触发,可以设置触发源以及触发极性
. a, W. ]. F; z5 \6 c8 D3 g& E$ i
' `9 X# U6 Q" x; d: s7 e2 H
! \& y8 |9 _, b6 x: d6 }; Z
+ ^! V. S1 p# d: u# K" Q
, q& ]; K: R1 [2 M/ M+ {- M
; L+ \' `6 h8 MSTM32F0-ADC模拟看门狗: ) P4 _5 p$ ^. H% z
% N2 Z( z: d+ m" L检测待转换的模拟电压:(简单的来说就是检测到电压值不在预设的范围之内,则产生中断,在中断中设置报警等处理措施) 电压超出检测范围就置位AWD@ADC_ISR,并条件性地产生中断 检测范围由上下门限寄存器指定、 12位的ADC_HTR和ADC_LTR有效值 ! K+ q5 J5 P' O |
模拟看门狗的使能控制: AWDEN@ADC_CFGR1 检测所有通道还是单个通道由AWDSEL@ADC_CFGR1决定 检测哪个单个通道由AWDCH[4:0]@ADC_CFGR1决定
" ]/ J6 s; z! I& R& @* k9 F2 ~
3 I! E' @5 A# w" U- z: _6 @( @
STM32-单通道采集实例
2 t. a' ]" ^ T- G实验要求:利用ADC采集光照传感器的数据,并在中断中获取采集的结果 9 Z) s; b0 B; R9 Q2 S* k2 e
- ]& Y& ?, W5 ~, g) G% H2 J1 G
2 Y" m4 ^2 b% u9 h
4 {6 C$ ?6 _, ^' c* E9 v/ m! s注:光敏电阻光强越强则阻值越小
X' y9 X! |- a0 O/ H4 ~( q
过程如下:
6 ^4 \) K# C1 X ]/ @/ j
- b. J+ B- s9 T c) a( G' w& m
1 [3 r i% L- B" N, }
y; U3 z, z; o6 c& w
5 d3 m$ c6 Y- o- P: m4 k
3 G( t: F+ V6 o0 r( u- o
0 d2 Z8 L& U3 w' p0 I, q5 Z9 O5 a4 B7 ] i" {" p1 N) _8 K
3 w: D& r3 c* \" U
( h3 h) h: h) ]; v
7 s" B- b5 W5 u7 L, W, F8 B
& q5 A, P. ] |2 G5 u$ y# s
! e% Q1 [8 x& f
- k5 ` y2 ?& i' X: }
9 U Y9 A( k, r* Z. }
- x( [' @) V8 Y1 }% W8 Y8 t2 K8 Y
# i9 n) Z: n' V$ P8 u: A+ ?
, i% G0 K; t. A, D
x- N- Y# y; X- v: Qmain.c中启动ADC并使能中断
9 E* J% @& M" D4 e; x' n0 n
( j% w2 X/ A) k! g3 ^4 NHAL_ADC_Start_IT(&hadc);//启动ADC转化并使能中断追加到回调函数(可以在向量表中开始追加,也可以在中断程序文件中(.._it.c表示的就是中断程序文件)追加) 

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

& S/ n; f9 T$ C" S7 R
0 {9 {! J7 Q7 m! A% C- int fputc(int ch,FILE *f){
; E: v9 U3 d, y - while((USART1->ISR&(1<<7)) == 0); ) O# ~3 u' ?7 m( F3 e
- USART1->TDR=(uint8_t)ch;1 @4 j {! `( }4 c) }
- return ch;: O& B, K# c" ^' c u! d1 L0 q/ p
- }
复制代码- void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)7 s1 i; E: w5 Z0 d" e* [
- {. O. V# ]3 s9 {6 y `; A
- uint32_t light_value;1 l7 I. y+ ?/ i" a c% `- j# }
- light_value = HAL_ADC_GetValue(hadc); //获取ADC中数据寄存器采集的值
7 P5 ~/ v$ ]2 w- B - printf("light_value = %d\n",light_value);8 @, G8 h# P$ H: _" O4 c
- }
复制代码
; x( s; t1 O! D: Y 测试结果: T8 V+ m# I' p! q+ O4 `' I8 r
. a6 k& i2 L9 w8 }! m9 X& t
# }6 q ^2 B, x
3 G; l5 e& n! b" Z2 R+ hSTM32-多通道采集实例实验要求:利用ADC采集按键以及光照传感器的数据,并在按键中断处理程序中打印采集的结果 原理图分析:
0 g) B: T: B* x4 Z9 B
' X: U# v8 e) \实验过程:
" V9 Q s% ~$ s, q4 l" z7 _7 \* V) ]0 _6 g
9 Q/ ^; I I1 e. u7 d* O8 Q3 u% n& _/ ^
% I9 Q7 T3 l8 t/ N3 Z
6 _! k2 _- l+ h8 m
配置ADC功能,因为是由按键中断进行采集,所以配置可以随便选择
* Z7 H' e/ ~4 e% ^; o$ X
打开按键中断:
' f: {5 c+ ~& l6 e* @+ _- K# a0 \
导出工程:
3 @6 O4 z) _$ e C5 Y
- j) d7 E( n4 D& b; H
, @/ g. o+ Y# ~$ T! U. ?3 V% x7 r# O" q
追加到按键中断回调函数
) k7 G0 o' P, g" V7 o
p, s) ^. l5 U; q$ O! c& m+ c4 ^4 s# r6 t; g. j/ H4 g
gpio.c中重新编写fputc 和 回调函数,添加必要的头文件:
$ |9 {+ [' O' @' u% y; ^
! ]+ D' U' q- B# c* W u6 Q. `7 T
4 r& M. d) ^$ S/ W
- #include "adc.h"
. F$ h. C% _+ O4 o3 d8 I6 q6 t - #include "usart.h"' G5 U& K# J/ N$ |9 f9 T9 \
-
% T, N* W3 A7 j. x& z" ^# y - int fputc(int ch,FILE *f){
1 Q. q2 a+ e: s' m - while((USART1->ISR&(1<<7)) == 0); ! `6 [- C. B, z
- USART1->TDR=(uint8_t)ch;
# h3 B( a, Y5 g& B& H+ l/ W+ b - return ch;
9 J0 D- Y; j; r% ] - } * w: \3 M: Y( n8 F
-
6 V8 Q( ^4 g" e7 V8 R" v; f2 s - void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
4 I6 l4 Z7 Y# f p+ T K' J8 Y+ N - {3 s4 j' Y l8 T8 Y
- uint32_t temp = 0;
; A3 k( r# x- t/ l - if(GPIO_Pin == GPIO_PIN_8)
8 \2 J5 ?, t' o) y6 T. O - {4 z E4 |" o3 o' f* H/ |
- HAL_ADC_Start(&hadc); //启动ADC- r( C- t+ a" [1 J9 K% Y3 S
- while(!(hadc.Instance->ISR & (1<<2)));//如果ADC的状态寄存器中的EOC置位,则表示当前通道转化结束, x0 e* j3 x# B7 `" g
- temp = HAL_ADC_GetValue(&hadc);
! ^! q/ X- h# T3 F4 s3 w) x - printf("key adc value = %d\n", temp);
& I. T) _) y- U, b6 ]. g7 Z - while(!(hadc.Instance->ISR & (1<<2)));//如果ADC的状态寄存器中的EOC置位,则表示当前通道转化结束
+ G+ W; e0 j6 @+ Q1 d - temp = HAL_ADC_GetValue(&hadc);
: y0 h6 s9 u8 j; b - printf("light adc value = %d\n", temp);
7 k5 Q: z* p+ \, b - HAL_ADC_Stop(&hadc); //关闭ADC# B$ v5 N1 D' R3 |# C
- }
_: U$ Q) @$ ~& _# ]9 }5 J( e o - }
复制代码
# [% i2 \* G* }/ F! P
9 d$ z: E2 [! E+ t; @
9 O x& u d7 u4 \3 r
' A& u! d! H! B( ~3 H. {测试结果: 
* S7 Y" z: D, G
* S/ o* l Z4 q3 r( P! s 利用中断和ADC识别五向键,即五向键任一按键拨动时能通过串口打印出是那个按键; M0 A* G; F3 a. ?, G4 P0 t- V* J& l
, O% E. @, S+ p' E
; B+ I, y1 t3 F1 X/ D
. t* Y6 Y/ _7 }
3 z' g* Z, k) D3 T: {: t1 @8 o
- o. _5 }2 p/ x/ J: x% k9 l- y( V: A# ^, M' M1 a; ^
8 G- X/ }- }0 R: U! k& H
/ V4 [9 ?8 S ^- L8 z s
( ~$ t; z0 _' t+ j( l2 _% {
! h+ T) Q8 N3 t
8 n) i& R" F6 C' R! K; G
* o( I1 j0 P2 @; j% G
' y/ |4 Q; }3 q7 V
- 2 Q- _% L+ m4 V) K+ U
- #include "adc.h"
6 L2 O9 O& [+ g2 D# s - #include "usart.h"
3 V: f: d3 e8 U- o7 j: W; E - ! i* k ^9 p) n. z0 m
- int fputc(int ch,FILE *f){ 1 J8 x8 Y& `$ N1 \
- while((USART1->ISR&(1<<7)) == 0); ( H4 l/ B+ @: ^) B
- USART1->TDR=(uint8_t)ch;$ d7 ]2 n) y' P }: `* T- z4 X
- return ch;; W) ~3 A& ]* u+ Y4 f% L
- }$ c- j9 _2 d5 L# i1 i% O; w4 t0 V
-
3 _. K4 r. p, Y - void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)% j: \/ u4 i9 T4 U* D: X5 c% q
- {
/ i: v8 Z) _: L/ o" j - if(GPIO_Pin == GPIO_PIN_8)# K3 e! b8 l% P5 m
- { a; t' a3 J; D9 L/ e! p+ [* a2 ]
- uint32_t data = 0;
0 @) w7 r8 e5 t$ I7 p' I$ S - HAL_ADC_Start(&hadc);
e" @$ M7 B1 i - while(!(hadc.Instance->ISR & (1<<2)));
+ L& q7 P" M& {1 {' z8 a& T, R& J9 c2 H - data = HAL_ADC_GetValue(&hadc);
1 S5 X: @2 _. r - printf("key value = %d ", data);
0 I' ~) p3 C$ {9 f, ? - if(data > 0 && data < 500) q( W8 T& C, i9 a# B
- {+ B7 ?0 w- ]& Z0 y# }! Z
- printf("下边的按键被按下\n");1 T7 w+ b% _# I2 o. g' f
- }
& {/ R1 A7 I. _4 s. b2 O6 } - else if(data < 1600)# ?' @4 p( {3 t/ d! x* K
- {6 Q# K( d, r( G
- printf("左边的按键被按下\n");
; X3 N4 Y3 `) ]# @7 h9 c, a - }
1 e) N- j$ J) i# _* } - else if(data < 2200)% {# g" T) p: t6 p4 W3 | A% @1 j; ?
- {! {8 r" d, N7 N. i
- printf("上边的按键被按下\n");
* f6 e$ h8 i% Z/ K4 v6 L% s - }5 x$ r- W6 t% o4 c3 B# V
- else if(data < 2700)
s7 t5 X' ]/ L% E4 e - {4 @0 o. _9 ?0 ?7 u5 v: f
- printf("中间的按键被按下\n");
9 }; d8 N3 _" m/ n$ k( U* L - }1 [$ j( G2 z+ C: {0 H) g9 `
- else if(data < 3100)
- Y- \$ ^! C. `( M( B; |7 q0 B - {
% D1 P# h' `. | |% n" P# \ - printf("右边的按键被按下\n");$ R. n- G3 z7 B) Y7 S F [: |& |
- }- @3 h( n, A2 T/ C7 Z
- HAL_ADC_Stop(&hadc);3 D; h( ^! E# @7 \3 H2 O1 l
- }5 U$ x& P4 ~ ~5 z
- }
复制代码 : b# S) Q% Q6 S! y' O0 [" Y
实验结果: % f6 I0 n3 r; _; A3 G9 G) I
7 l8 G1 R7 \( F' G- C3 i$ Y
& o$ Q% o0 j# P+ ^' a I |