01. ADC简介# `$ p! j+ k5 C0 L5 z3 m
STM32F4xx 系列一般都有 3 个 ADC,这些 ADC 可以独立使用,也可以使用双重/三重模式(提高采样率)。STM32F4 的 ADC 是 12 位逐次逼近型的模拟数字转换器。它有 19 个通道,可测量 16 个外部源、2 个内部源和 Vbat 通道的信号。这些通道的 A/D 转换可以单次、连续、扫描或间断模式执行。ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。 模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
- Q: Q" z- @9 t" q" n( s0 S3 \; T( ?& d; Y; p. j. |* i4 o$ f# q. O9 |+ ^. W
STM32F407ZGT6 包含有 3 个 ADC。STM32F4 的 ADC 最大的转换速率为 2.4Mhz,也就是转换时间为 0.41us(在 ADCCLK=36M,采样周期为 3 个 ADC 时钟下得到),不要让 ADC 的时钟超过 36M,否则将导致结果准确度下降。
, n+ I, |* D& F1 A' M
7 A7 Y; _: L! S9 _5 p' pSTM32F4 将 ADC 的转换分为 2 个通道组:规则通道组和注入通道组。规则通道相当于你正常运行的程序,而注入通道呢,就相当于中断。在你程序正常执行的时候,中断是可以打断你的执行的。同这个类似,注入通道的转换可以打断规则通道的转换, 在注入通道被转换完成之后,规则通道才得以继续转换。
! N! o4 w: l8 E% R3 d6 G( f8 i, {9 {/ D& F4 H/ y
02. 硬件资源+ `4 @' v+ ~& N8 [6 f' Z& Z
用到的硬件资源有:
! d# i4 _8 i& C6 D1) 指示灯 DS0
1 ]! b9 b8 m% D- c' W+ u% o2) TFTLCD 模块
6 ?( a( d) S9 U. }' g: e3 ~3) ADC* ~1 {* F; o% S! C8 t
4) 杜邦线% x$ F) b {( l: G: j
7 i. J) ] v/ F( ?5 W/ h5 J. y z03. 编程思路
" m$ c6 F/ b" r①开启PA口时钟和ADC1时钟,设置PA1为模拟输入。
: F4 e! r" r; g$ q+ C6 n% e0 b0 a; s' z1 v' S8 V
RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_GPIOA, ENABLE);
6 o) s$ M0 L% |( ]
4 E' E. r5 [: Q$ a2 M9 d6 XRCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
* y' T" X6 y9 X+ \7 B
0 }0 L0 ?" N p! MGPIO_Init();! ]5 b; l, f" u* {3 p) }8 |
& l, ]( ?8 F* O9 C
② 复位ADC1,同时设置ADC1分频因子。1 h, A# C: ^' W
2 f* r7 u2 g( u: Z$ c
ADC_DeInit(ADC1);
+ @1 N0 @5 y6 l# X/ a+ S. ^' t8 h) v8 A: \6 h @6 ^% ?% c# ~" T" S
③ 初始化ADC_CCR寄存器。! V+ B9 @+ F+ Z
5 K' z. | ?6 j' { \ADC_CommonInit();3 h9 ?* q# {8 g) V
1 M+ y3 w) Q7 K% {4 V4 Q9 F8 c④初始化ADC1参数,设置ADC1的工作模式以及规则序列的相关信息。- g0 I1 P3 s/ Z7 O! _3 a: m( `6 O
4 S* R# H- g& C4 g& O# [6 o
void ADC_Init(ADC_TypeDefADCx,ADC_InitTypeDef* ADC_InitStruct);*
5 U# v& d- _) ^- F) p2 C; V- Z5 O+ z8 x7 v) c2 K# c# L! z
⑤ 使能ADC。) P+ L1 ]9 u; ?0 r9 a+ T* M) e
+ d& }. X/ {( n2 V. ~ ADC_Cmd(ADC1, ENABLE);
; R& n7 k u1 e0 p8 i* A6 [
8 x# \/ a0 O. H: `& k6 M6 W |' ?⑥配置规则通道参数:5 y5 M2 }' B! U. `8 M
# Z7 A# j0 f$ B, O( y. p
ADC_RegularChannelConfig();
/ x' l+ z/ y8 A; e# z T6 m1 u2 u0 F0 u% ^; i+ c
⑦开启软件转换:ADC_SoftwareStartConvCmd(ADC1);% X+ j" i: T. w7 ?( \" D' Y6 q
# v; `. n$ F( N$ Y⑧ 等待转换完成,读取ADC值。+ |& D0 Z% D% K h
5 Z* ~5 Y! i: r% V9 q' fADC_GetConversionValue(ADC1);
4 L! U- _1 X; k, C
- f7 k$ O D7 s/ T1 d# k: V04. 程序示例- d7 ]& }/ R' y5 |! C7 p: s
adc.h4 |0 M$ X6 A0 ?2 D& ~1 M; J
+ C) ~2 `/ p0 H
- #ifndef __ADC_H__
$ u7 S" J& B. l2 B3 ? - #define __ADC_H__
( u" \! T1 ?5 d; ~) f
6 n+ G3 @$ O. x% [" N" J- #include "sys.h"* S3 J6 {& o! d: }' J X8 g, ?" U
) b) ` U `/ f- //ADC通道初始化
/ |' _ r) ]3 L0 c8 {: ^ v7 \ - void ADC1_Init(void);2 @, e! I# P" W8 a6 w- |
: x( A6 B9 Y' E/ \8 j- //获取某个通道的值3 T6 O! C7 B) J! @
- u16 Get_Adc(u8 ch);
5 J! S& Z. w- a
7 q: l$ Q: u7 p5 Y' U' J- //获取某个通道给定次数采样平均值* X5 c. z3 C3 U# A( g% ~) H
- u16 Get_Adc_Average(u8 ch, u8 times);$ O8 t8 Y T$ r$ h5 M0 n! \' ^2 ~
2 h2 |9 B o) ?( o) k- #endif/*__ADC_H__*/
3 ]! r; i& k, k* x
9 g- d; i3 p* [
复制代码
+ b4 l6 X- i4 e7 C) B# Gadc.c. P9 G4 {1 n0 j( E# [' O3 h
+ v1 ]1 E2 B9 I: R9 M) \8 Q
) T! h+ i3 R+ s! h7 P' C$ p6 Q8 i- #include "adc.h"
# I2 @" }4 H: g9 v* _2 P) t. |* ^ - #include "delay.h"2 a# D! |5 n8 v1 S4 a
- / l% X9 E+ P0 m( n% r* {
- ; g7 d: Q/ M# c1 U
- //ADC通道初始化9 `# S C( ?/ E- O
- void ADC1_Init(void)
) j) V7 Q" g3 _3 z - {
$ f" M* B: i6 ~0 c; m - GPIO_InitTypeDef gpio_InitTypeDef;3 f+ m& T' e( v/ N) T4 p- |
-
- }# l( Z/ z4 `' s - ADC_InitTypeDef ADC_InitStruct;( K- K1 @% r/ U' ]2 \
-
' c, N- ?1 V( }6 B - ADC_CommonInitTypeDef ADC_CommonInitStruct;- [. |. s! C+ U. d4 k
- 2 j- @( |( _5 a) q: Q" y6 P
- //开启ADC1时钟
; p$ ?! F2 g, Y$ Y - RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
) h# e7 s3 G8 b2 B - 6 q2 {7 R E* i* E% S
- //开启GPIO时钟 PA5
/ y4 J$ n* F" v5 l! H - RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); & i' q( z6 G% V
- , O- A; `1 R F. U
-
4 V2 F. G/ H; G4 g/ T - //GPIO初始化 初始化为模拟功能
1 `/ Z! e6 @) c; J& o" {: G g - gpio_InitTypeDef.GPIO_Pin = GPIO_Pin_5;
; t i8 Q" x; u# A - gpio_InitTypeDef.GPIO_Mode = GPIO_Mode_AN;3 x! x2 R/ z! [' z; y1 V7 Y
- gpio_InitTypeDef.GPIO_PuPd = GPIO_PuPd_NOPULL;- Z8 K z4 ^; l. L' |
- GPIO_Init(GPIOA, &gpio_InitTypeDef);) ~! _9 G! _8 T% V- L# y# [
-
; V! N1 e, t3 V+ ^3 I" u - RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE); //ADC1复位/ a8 Z, ?! I8 @
- RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE); //复位结束 + q& y! p2 _) Z. M$ N* O, l
-
. q* r+ _% e, }$ E3 ^2 Z# A- _ - * C1 H) s+ }( W! i" k1 Y
- //初始化ADC_CCR寄存器. m* A/ p3 \5 Y) p1 W+ F! n! c
- ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;* j" _$ ~4 E5 L/ j3 E
- ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;( L+ S: @ D, y- `) {
- ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div4;4 x; |* H/ P4 q; p
- ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
/ z% ]0 Q% f. O6 e4 W5 C' ] - ADC_CommonInit(&ADC_CommonInitStruct);
2 w/ G# ]+ j; C1 X& ]' g6 h+ l -
+ j# Z6 ]# R& m/ l B4 t; k; Q* \" u - //初始化ADC1
% k# E# z3 x Y0 Z' |( x, E) s - ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
$ l5 u" l' A1 X. R1 U2 g5 Z. ` - ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;! d' l2 d" N! b; C3 ~. Z
- ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
# S: D# \, [5 I8 S9 C9 b/ ]- M - ADC_InitStruct.ADC_NbrOfConversion = 1;1 x4 ^+ `0 N% H2 H2 m. ~6 q7 |& f
- ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;
+ ^' C6 @- V% |; d: Q) u# h1 N# N - ADC_InitStruct.ADC_ScanConvMode = DISABLE;' l2 E! A2 P7 V
- ADC_Init(ADC1, &ADC_InitStruct);
4 ~1 ?( l3 i; D - # g! |9 P& ?9 p6 [
- //使能ADC+ d7 A9 j. P+ U A- b2 _: `! m* t6 W/ R
- ADC_Cmd(ADC1, ENABLE);
7 d- g3 t# A4 i& e - % a% K& L; ]/ L0 f, w: {
- }; i0 s O8 A9 Y, {
- 1 m4 k; o3 p9 P; [' I2 Q2 a
- //获取某个通道的值: q, n5 q# n0 w4 `( {
- u16 Get_Adc(u8 ch)
* t( F% D# z5 v$ _- F& m9 Z8 z - {
. t& t% s% j) G7 U$ u+ B3 O7 d - 1 T0 J5 a5 C# U3 p* ] c
- //设置ADC规则组通道 一个序列 采样时间
$ ?/ w% w A$ e* f/ J* }8 N( B" y - ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_480Cycles);
& k' H9 d+ k6 A0 w7 t# Q# [ -
1 Z: |; V3 T7 l+ u+ a - //开启软件转换7 `! J1 Y9 ~* g+ |& D
- ADC_SoftwareStartConv(ADC1);/ J+ b/ M: h5 ^- N1 }3 A
-
) @ Y8 y) e8 [8 E - //等待转换结束
" j0 h4 \2 v K" Q/ s. m - while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET)1 H: }8 I" V- h
- ;
) N) }& x! X. W- {+ u - " C3 P3 T, Y2 i8 c" {" S
- //读取ADC的值
0 `! @ w# s# ]% C" D `5 Y6 z - return ADC_GetConversionValue(ADC1);9 t; G7 l- M) m3 C x8 a
- }4 r% I& v3 L! \& H
- + |/ v; g) `4 v$ ` T
- //获取某个通道给定次数采样平均值) Q* \7 f) y: q E& g+ D
- u16 Get_Adc_Average(u8 ch, u8 times)2 y6 v% p1 w7 J: O, i g
- {
9 B7 ^3 |* v, F' l/ p9 [ - u32 tmp_val = 0;
( X" y2 v3 x$ M1 J -
1 F* L$ `4 z# ^' p! O' }# n. O - u8 i = 0;
G+ q: N3 [; I1 W" D& x -
3 q7 T( X4 h# |! }. r) E - for (i = 0; i < times; i++)* Y: b5 B& ]) ^( X" d7 e. _
- {& M' Y5 [' v3 d4 i7 n/ l
- tmp_val += Get_Adc(ch);/ L+ S y2 \1 U2 H
- delay_ms(5);
. O7 h" k6 }, a% E - }2 h& s7 f7 W+ m4 ~8 j" H
- * Z- W B9 f2 R! G+ G; F
- return tmp_val / times;
& [' e! l+ o& T - }
复制代码 $ q6 P# Z. e& t4 c
main.c" G1 O2 u9 p; P# @6 U. H) Q2 Z3 j0 c7 |: Z
1 z; h5 \0 B, G
- #include "sys.h"
3 ?# V& n$ U: k1 c# i - #include "delay.h"7 E$ W! G& ]3 D2 b% i
- #include "usart.h") V9 m4 {* b6 V- Q3 u; j
- #include "led.h"
" H% \: u; z( @: v. _ - #include "beep.h"/ c3 k9 n* q, x+ w
- #include "key.h") J' V( z; W7 n# d
- #include "usmart.h"
5 E& ]+ L: L) T* A% w- T - #include "lcd.h"( Y7 n% X# [% P( K
- #include "rtc.h"9 ~* @$ O1 R h& e5 s- w$ s
- #include "rng.h"
" |0 ^: X& l! g; O6 \ - #include "key.h"
4 I d5 I/ E% j. o2 m( t9 { - #include "wkup.h"% s% K" K5 [7 g! y
- #include "adc.h"2 q. S% } e/ [
4 ~& A% b& E- H: X+ s7 Y" M8 h- int main(void), e D" D# y- c$ N
- { & S3 o4 @4 F: u7 E# s, X
- u16 value = 0;' X. c& ]' T( c5 n2 ?* f; I w
-
) ?2 {+ M, I0 d2 \/ [; N9 N - float temp = 0; e# \/ w, l, h; f. T/ Q% P7 i
- , S5 o/ {2 n7 v2 \; F2 J
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
. w8 P" [2 ` |# f5 r4 ?4 B - ! S) }: W8 ], r7 i& I
- delay_init(168);
8 C r0 V" F! R) g6 n8 ` -
( q* P7 h+ L2 H+ n, [ - uart_init(115200);2 I1 _" `( @' U' i6 {7 |
- 3 M ]/ Z1 e! _, i2 G
- usmart_dev.init(84);1 ]+ R3 R: b7 r0 n6 }/ ?
% G$ l) S2 M6 e2 K ^-
9 G2 P9 D1 r/ x' L8 g% S2 N8 M - LED_Init();# r5 K, I. o" J: U: Y, t
- / i/ B: [- v: Z# u, Z
-
, T8 F6 t2 ~) h1 Q3 Q9 S - LCD_Init();, X/ a! o9 \; A" H
4 k" @/ z/ y7 J! E5 i/ U- ADC1_Init();
& P- L, b: \6 N2 R -
! a9 {0 a6 H$ ^7 j& j, S -
: j, E" @5 B$ C8 S0 Q" I - POINT_COLOR = RED;! {/ t& U" n8 ^6 \8 I7 Y' |2 Y* P
- ; R) A$ L' Q) s! Q
- LCD_ShowString(30,50,200,16,16,"Explorer STM32F4"); ( v6 |4 c8 o( Q1 f
- LCD_ShowString(30,70,200,16,16,"ADC TEST");
7 [6 \/ w. H6 \# N - LCD_ShowString(30,90,200,16,16,"ATOM@tom");& \! p. {/ T% G7 k
- LCD_ShowString(30,110,200,16,16,"2020/09/10"); v8 C; x" b2 ^9 `7 y& b# h
-
: j, Z$ R% T2 S* K/ u) |, @. s - //设置字体为蓝色
5 J1 S2 |1 M, u$ ^' y( U1 T - POINT_COLOR = BLUE;
- i& x6 a7 M# r; x7 X$ \1 d" H - LCD_ShowString(30,130,200,16,16,"ADC1_CH5_VAL:"); % S- g2 V% z. J4 I8 T" R C' |
- LCD_ShowString(30,150,200,16,16,"ADC1_CH5_VOL:0.000V");
- _' z! R+ V9 u/ I' w -
9 I8 i. j# L+ E$ { - while(1)
1 v0 `6 [5 G b: q3 g3 x - {
8 L, H; e" n# X* U1 g5 S - value = Get_Adc_Average(ADC_Channel_5, 20);; F& p2 g2 b3 u1 r2 T
- 2 l* `! o5 k" E
- //显示采样之后的原始值
3 U' B7 g# w G" T# i - LCD_ShowxNum(134, 130, value, 4, 16, 0);
9 k- q* L0 E0 Y8 W! @+ x! |9 G% S - |/ Y8 {. e. j0 g
- temp = (float)value * (3.3 / 4096);
S2 {* ^3 T6 \" s. e$ X6 j - value = temp;3 Q. t1 q* N- P1 }8 o) n
- LCD_ShowxNum(134, 150, value, 1, 16, 0);) t! j+ b1 N& J" ~- {
-
! c! v3 i7 b: l# u" L) f - //小数部分/ y9 n+ R& d( l
- temp = temp - value;
2 l" `$ R; o9 x: Y' z! N' S% I3 k5 @ - temp *= 1000;* D; T5 c2 N$ M- g3 G9 B! B
- LCD_ShowxNum(150, 150, temp, 3, 16, 0x80);
; P- _8 m0 t- H' G -
! A0 P! \* h6 v$ [, L! m1 R8 B - LED1 = !LED1;* O2 B1 @4 m; {; p; W J
- 9 ]7 @, }/ \2 I8 L! }
- delay_ms(250);4 |* F+ T+ g% w) Z3 G
- }9 h$ d9 ]( b: N6 ]4 m* `, R% ^/ |
- }
0 q5 z) T0 i7 e" u _
复制代码 3 `8 v2 }2 V6 P! _
( C+ ]4 k; v( o9 {6 m
: c) p7 q( G9 P4 K4 F+ [& q* T$ u, l( B
|