STM32-ADC模数转换内容概要: STM32-ADC模数转换概述 STM32-单通道采集实例 STM32-多通道采集实例 2 _$ n6 q- j% i6 X# u; J4 t" s! i
STM32-ADC模数转换概述
M: v- S" w' ~* n. Z1 y内容概要: ADC简介 STM32F0-ADC时钟 STM32F0-ADC转化模式 STM32F0-ADC转化时间 STM32F0-ADC模拟看门狗 + w" y% ^" r6 z8 v' L, P- x3 ?5 H! l
. g W8 d' N7 `! R' ^$ Q
ADC简介: ADC的作用:采集传感器的数据,测量输入电压,检查电池电量剩余,监测温湿度等。 8 Q& T; F2 t8 T: `$ s( h
ADC的性能指标: 量程:能测量的电压范围 分辨率:ADC的分辨率通常以输出二进制数的位数表示,位数越多,分辨率越高,一般来说分辨率越高,转化时间越长。 转化时间:模拟输入电压在允许的最大变化范围内,从转换开始到获得稳定的数字量输出所需要的时间称为转换时间 - N+ Q( }5 D6 h+ a+ `
9 o7 |. S5 [: G! k3 }STM32F0-ADC特性: 9 ?( n5 N, V' D1 _+ M2 R) H
: r" o! W0 i. g a12位精度下转换速度可高达1MHz 3 v8 q7 A: x. {' h4 Y4 F9 j$ V
可配置的转换精度:6位,8位,10位,12位 转换电压范围:0 ~ 3.6V,V SSA ~ V DDA 供电范围:2.4V ~ 3.6V 19个转换通道: 16个外部通道、 3个内部通道 ! T# R- h1 X& F) h
采样时间可配置 ' X6 e# J* @3 j. ^9 G
ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中
2 _6 g) M* t, y2 X/ s
STM32F0-ADC时钟: % ~1 K8 Z) E% C5 a! M
APB时钟的2或4分频,最高14MHz 优点:不会有时钟域之间的同步带来的抖动,触发事件和转换的起始时刻之间的延迟是确定 的,从 而保证转换之间的时间间隔是固定的 缺点: ADC的转换时间和系统时钟频率相关,受系统频率的影响较大 ; l3 u5 D# m% k. S3 w" k
; b" R4 ~. U) m v" s& L
片上14MHZ HSI RC振荡器 优点:无论MCU的运行频率,都可以保证最高的ADC工作频率可以使用自动节电模式(自动开启或关闭14MHz的内部振荡器) 缺点:触发信号的同步会带来抖动,触发事件和转换的起始时刻之间的延迟不确定 / w! H) O, Y3 g; p
7 S) m, l# y5 {# ^! x. t6 A
2 O2 a$ |7 K& ]% Z
STM32F0-ADC通道的选择:
# n5 o7 T( {% X z3 S0 \& Q, Z) Y2 P5 j6 |
19路复用通道: ●16 个从 GPIO 引脚引入的模拟输入 (ADC_IN0...ADC_IN15) ●3 个内部模拟输入 ( 温度传感、内部参考电压、 VBAT 通道 ) ADC 可以转换一个单一通道或自动扫描一个序列通道。被转换的通道序列必须在通道选择寄存器 ADC_CHSELR 中编程选择:每个模拟输入通道有专门的一位选择位 (CHSEL0...CHSEL18).
3 K/ f0 K$ a x$ e$ I/ ?1 ~" R
5 F0 `& E8 O, P" x
STM32F0-ADC转化模式:
, D, A4 @- j3 v: [, |# [! _& C: B. {- @6 o+ z3 R+ j: W* V! W- F' {, N
注: ADC 通知应用每次转换结束 (EOC) 事件 ADC 通知应用每次序列转换结束 (EOS) 事件。 这些标志位都是在ADC 中断和状态寄存器(ADC_ISR)中 ADC_CFGR1可配置COUNT位 。 每次有一个通道在转化结束之后( (EOC) 事件),必须先读取出数据寄存器中采集的数据,然后才能采集下一个通道。 9 Z; C0 c' v. }/ F
0 Z/ Y+ z0 J- A; k9 F
& a' a3 j2 f; Q$ Y, x# F# K
) G0 A( g L" V$ V- G
M9 e1 c, J% x, g/ XSTM32F0-ADC转化时间: 可编程采样时间 (SMP): T Sampling 可配置: SMP[2:0]@ADC_SMPR 需要和外部电路的输入阻抗匹配,采样时间适用于所有通道 . W1 q; w O& ~- e4 {% }4 ]
转化的时间: T conversion 取决于转换精度: RES[1:0]@ADC_CFGR1 2 C3 W* p, ?# F- _' k; ?4 m X% x
" r0 B0 `" g. M8 f( j
9 L3 l) g. _& f E, {; Q每个通道总的转换时间等于: T Sampling + T conversion (采样时间 + 转化时间) 转换时间快速预览表:不需要高转换精度的应用,可以通过降低精确度来提高转换速度 假设ADC模块工作在14MHz的最高工作频率下 7 o5 B, M- t3 e% {6 L @
4 E5 e; l2 U% e' \8 v0 t8 ]
: w4 ^6 w# I7 {: }: Y
. A: [7 L. I2 |6 I2 k
STM32F0-ADC触发方式: 软件触发:软件设置ADC_CR的ADSTART=1 时,触发选择有效。 外部事件触发:外部事件 ( 例如:定时器TRGO、输入引脚 ) 触发,可以设置触发源以及触发极性 / t3 d+ M, b1 Y8 U4 v, J, w3 O, V3 r
" ~1 w& L& O* ]" H
9 u4 e2 h- C, `, J7 m. x Z
5 C3 @: K& ^/ B7 {1 d, ]" o# ]
) H& V( {& J, l1 `- o
p. h& Q, ~5 ~; k+ f
STM32F0-ADC模拟看门狗:
% E7 p V( C0 M7 H" H$ h$ ]
3 ] Q7 [( k' ~' }. _
检测待转换的模拟电压:(简单的来说就是检测到电压值不在预设的范围之内,则产生中断,在中断中设置报警等处理措施) 电压超出检测范围就置位AWD@ADC_ISR,并条件性地产生中断 检测范围由上下门限寄存器指定、 12位的ADC_HTR和ADC_LTR有效值 9 L6 @0 p9 d$ s' J' c& Y# F
模拟看门狗的使能控制: AWDEN@ADC_CFGR1 检测所有通道还是单个通道由AWDSEL@ADC_CFGR1决定 检测哪个单个通道由AWDCH[4:0]@ADC_CFGR1决定
: I; D9 E! @6 I
A( k1 B! t' x2 O# x+ m STM32-单通道采集实例2 Z! E) h6 q4 {- W5 l0 a3 d
实验要求:利用ADC采集光照传感器的数据,并在中断中获取采集的结果
4 e, D: D" h) u. ?, i
0 [7 E3 p8 I/ \! w
; g' a- s y% J% b4 A+ b( e# b2 J5 m: `
注:光敏电阻光强越强则阻值越小
1 X8 O: j% k, A+ C" U: W
过程如下: 8 F" l8 B' G: k; ~$ l: |! _ m
3 z! O5 b2 q# G3 }7 W' C5 U
3 t! u% j# l" o9 F, ~7 b: [) [
7 m4 j, [! E$ G2 d, ]9 }
3 S& {6 Q. Z' |+ G" U+ O4 z8 W0 \# ?' | [
3 X( C/ j/ c0 u0 a k( K/ r) W2 P& O% ?; i* {% o9 O+ s
% s6 A3 @8 X% S7 ~5 H" B2 O7 i( `7 }- ^8 w- D) L
4 }/ |5 Z1 j0 ]8 N8 k6 b5 _/ c( C! B/ I; e+ \* B
$ W* A _5 o2 ?8 E- l$ k6 t
+ N- w% c7 {0 O, r" B6 b0 G
( e; i- V8 }' L! b/ m
7 B) G3 x# F8 I+ [7 L
. |: i% s& F( ^
; E+ j2 p! ~# P5 j) ?. X' I9 @8 E0 w" D: g& F* x; a# N9 g
main.c中启动ADC并使能中断
9 ]$ n8 O) |) L, ]1 I" l9 Z A) J0 y
$ Y2 r- F0 J, R
HAL_ADC_Start_IT(&hadc);//启动ADC转化并使能中断追加到回调函数(可以在向量表中开始追加,也可以在中断程序文件中(.._it.c表示的就是中断程序文件)追加) 

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

6 ^5 h( `, a) U; ]4 _
+ g, ?# F/ L8 _- int fputc(int ch,FILE *f){
: a& o( V" z. H4 @6 v# d3 p" b - while((USART1->ISR&(1<<7)) == 0);
3 T4 I/ M* C! ~4 } - USART1->TDR=(uint8_t)ch;
6 T+ u6 {0 p- H) Y - return ch;
; P& t% {( K2 g( X - }
复制代码- void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
: H* Z0 x7 Q* p/ ]2 h: \ - {" L8 {' R0 E- c2 O5 h
- uint32_t light_value;3 j9 J9 m0 m7 c6 q* a: ]. ]- B* h
- light_value = HAL_ADC_GetValue(hadc); //获取ADC中数据寄存器采集的值
$ m: M! X0 r5 j U - printf("light_value = %d\n",light_value);; ~7 y+ E" |& G
- }
复制代码
& x. \2 g% J- _8 l! F% |; ~0 x 测试结果:
$ r- |# E! x D6 ~
: N% Q" U, O: N
# [% T! l7 q+ X7 Q: c
6 b8 l1 }3 A2 [3 [STM32-多通道采集实例实验要求:利用ADC采集按键以及光照传感器的数据,并在按键中断处理程序中打印采集的结果 原理图分析:
2 {: ^7 q; M' W
9 Z8 R) u1 T3 Q9 g
实验过程:
5 Q3 s: t' h P- j: E9 e8 ]9 {# Q+ F, l+ \
" \) y! ~" X7 D7 \$ T* t# F9 I0 t
# R+ B0 D: ^$ B8 ?6 O' S
) L" {9 n& k& w: z. \! C8 }
+ Z8 Y+ F/ P0 d8 F配置ADC功能,因为是由按键中断进行采集,所以配置可以随便选择
. s0 J) {; x; ^* g7 n. d; N' V
打开按键中断:
# n8 J8 z! v3 b( }; D% s' R$ @. ?
# w5 z( r6 K; b" H0 X- ~1 @7 E, P, a
导出工程:
: t# `. t# h* @% e2 u H# M! S
( F; e4 Y/ U9 z7 ?
! h0 u( f- K; p1 F
7 ~6 L/ W3 E3 M8 Q6 _2 |4 ^" m追加到按键中断回调函数
' S7 J" Z; L! e8 j, V
3 B8 ]+ Y' N; o$ h" l. Y
- Q" M" `; t* T+ E, k
gpio.c中重新编写fputc 和 回调函数,添加必要的头文件: * F' m. v* Q4 D$ w( D
/ t; W& M6 \: O, z
/ u* b% s0 o' S7 M' E
- #include "adc.h"
0 a1 J2 E) n }' v4 g9 H - #include "usart.h"
1 m! K2 {+ G, } -
. ]( J: U% B0 z3 _/ S - int fputc(int ch,FILE *f){
( _& k- d. f2 J# | - while((USART1->ISR&(1<<7)) == 0); 0 F) N0 j5 h+ N' l" x
- USART1->TDR=(uint8_t)ch;' c8 c Z3 ^, E) a
- return ch;
; y$ C: q0 N$ }/ g4 } - }
5 n5 Z$ Q1 ?/ R$ Y4 k1 b - W7 B& s9 [' K
- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
' T4 s! }2 a7 m5 E& \ - {8 h D2 e5 ^# H$ F
- uint32_t temp = 0;
$ n2 c3 Q3 e9 N" J' ~ s - if(GPIO_Pin == GPIO_PIN_8)7 W* i1 Z* q5 d" H- _. Y
- {
% [; `2 E( e( V% ^* y - HAL_ADC_Start(&hadc); //启动ADC5 G. i# B5 \' u1 t, n5 Q; \
- while(!(hadc.Instance->ISR & (1<<2)));//如果ADC的状态寄存器中的EOC置位,则表示当前通道转化结束
! w% v. X# Q8 I4 Z/ O7 G - temp = HAL_ADC_GetValue(&hadc);
) j5 k4 J, s6 l& q - printf("key adc value = %d\n", temp);
2 K' [+ c" J+ G$ u, l, b - while(!(hadc.Instance->ISR & (1<<2)));//如果ADC的状态寄存器中的EOC置位,则表示当前通道转化结束
3 Y. i: I; }+ N& ~- y, F - temp = HAL_ADC_GetValue(&hadc);
# @: \/ c+ y* u$ m8 l - printf("light adc value = %d\n", temp);) o- j- V: ?: L9 o7 ~
- HAL_ADC_Stop(&hadc); //关闭ADC- }3 C- s6 o( y) U
- }
1 r. c) m' f. |4 C/ _6 M# ] - }
复制代码
0 e; W3 A% @! m9 i2 m# t/ }5 ~% W6 f5 E; A8 a2 s8 m
8 S' z; Q9 |6 T$ `0 n
+ X8 p% {0 A. I
测试结果: 
' D6 o9 w( U( j( B. S. N
& h. J9 F2 |: k; U
利用中断和ADC识别五向键,即五向键任一按键拨动时能通过串口打印出是那个按键& d9 |5 f- }) ^' a) i" h
( R3 Y1 C# C9 D" l+ q) \
* K9 D: _" E2 l: R5 g
, g/ q4 T. Q9 n
" l1 p5 ]9 s/ i" e
; D0 M9 U9 ]1 } g# b
8 `, N% K8 ?" Y1 U. ]7 m
; l4 D, y0 h x1 G& v3 ]* q' `) B% W
6 z- }+ `( y4 }+ q
( z7 ~9 {$ G8 d3 F4 N6 T' }
% h S/ _# r5 Z5 u3 }9 U7 h" ?, q% _
8 e; ~1 o+ r/ {7 m
) E+ H- F$ I9 I4 n1 u0 m3 l- #include "adc.h"* b* a5 H5 K' g
- #include "usart.h"5 w! ?! k7 }* o% v7 n" h
- ' _, k' m+ W7 h
- int fputc(int ch,FILE *f){
% y5 f; a( q* c3 M1 F/ J1 W' i - while((USART1->ISR&(1<<7)) == 0); $ n4 h; S7 A& O6 Z
- USART1->TDR=(uint8_t)ch;* d* k, P1 L: |- B
- return ch;
; Y* O6 \9 q+ f! J5 ]9 i - }9 x! D9 v4 X' Z+ b
- , i8 j8 v+ u9 ]: d' w
- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)+ q: r4 [0 I6 y& Q. M! x* W3 D6 O
- {
/ O- |: g4 B& L- r* t* _5 a - if(GPIO_Pin == GPIO_PIN_8)
$ N% P4 a; d f5 ~% o$ _3 P - {
# K. p, o4 M. T! O - uint32_t data = 0;
4 k- m5 ?- _ x. f7 G/ f: P9 P3 { - HAL_ADC_Start(&hadc);
3 y/ }( e8 d8 R& { - while(!(hadc.Instance->ISR & (1<<2)));' d3 M; q# t6 i( X0 e
- data = HAL_ADC_GetValue(&hadc);
" m5 w. s# \7 N9 h; o( Z6 t L* Y; z9 @ - printf("key value = %d ", data);- j& W9 G$ W; U; x% r
- if(data > 0 && data < 500)) T& G$ I C0 q, Z3 @
- {2 }8 t: s5 i% I. T; p4 ^
- printf("下边的按键被按下\n");* ~5 o1 i1 r: _" M& U, e
- }
5 N5 V0 l1 T) A - else if(data < 1600); l: Z% [0 v5 V! C' d3 x0 R! `' I) h
- {
) B8 r5 t" w" r0 ]; }9 q - printf("左边的按键被按下\n");, o' x6 u& N4 q7 j
- }
. {& z5 M# w7 G3 w% Q( `; s - else if(data < 2200)
! ?# ~6 ~5 |$ y l- w% O* v - {" h: {% v) Y6 q7 p! f
- printf("上边的按键被按下\n");+ a. x$ v% W' H( I/ J+ V
- }* z8 t/ |+ i y: L/ H
- else if(data < 2700)
9 U8 A" q S5 x9 h - {3 j( W1 D# m6 W: n0 z6 ^/ ^5 E
- printf("中间的按键被按下\n");! I+ z1 @7 W( W' k/ k L2 c
- }
. H& }% Y& w% e- s/ {: A0 k - else if(data < 3100)
$ ~0 w5 g& h1 H8 j1 w; v6 k$ h - {3 Z& V8 ^; x* ^( }" M0 ^
- printf("右边的按键被按下\n");
5 v2 p B2 p3 h* E, |3 ?$ P) i - } v. s& G5 Q, f) V; O- x9 }0 I
- HAL_ADC_Stop(&hadc);) W! O3 K- v8 ]- K1 J+ j# C4 Y9 q( Q
- }
% `7 y2 u+ R; g0 ?- b. p - }
复制代码
( \, ^9 ^ z- |$ K$ k实验结果:
: H. @- I2 e+ F+ l2 @( u3 K+ a
* i' I. L" Z8 Z: A' | h
+ U5 Z& g) X$ p) X+ d2 Z
|