ADC详解
) |9 B$ w9 N: Z前面的博客中详细介绍了STM32中ADC的相关信息,这篇博客是对ADC内容的一个总结提升,ADC的详细介绍:ADC详解6 o, U! G4 }- \* B; R7 @: O+ D
" o9 ~( h( U' P5 l0 K程序说明
$ d( [ d# ~4 `1 X @7 H为了使这次代码阅读方便,博主没有在头文件中宏定义变量,都是直接采样库函数中的规定形参。此次采用多通道采集电压,使用ADC1的通道10、11、12、13、14、15一共六个通道,采用DMA将转换结果传输至内存。 f1 h! j; q9 f! k1 z; G- F% E& a
6 D( E; @8 d2 j* J6 C' F! ?+ y
7 W2 N+ h" a( H6 p, A; ^& X
函数主体
4 T4 q5 a, |* e/ r7 Q$ L引脚配置' |& }1 q6 n9 t' B! [1 b
引脚配置的时候,将所有引脚一次性配置好,过于简单,不作详细说明。
% r% d5 }- `# _: p9 r6 i- void ADC_GPIO_Config(void)
' s( S- b$ k& v0 z" \ v+ Z - {% i. Q$ x c! N
- GPIO_InitTypeDef GPIO_InitStruct;
( R9 Z0 w+ L$ @2 Z/ E - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);0 Y) K }: v- j y, H) o
-
$ F9 ?" U# C2 y* k+ W+ q -
: A% N9 I, `& k - GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN ;
$ v2 e( A2 b) K. r e# W - GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|
$ N: P& I+ q0 x' b4 } - GPIO_Pin_1|
8 d6 l1 ~# h, S) a; B8 j - GPIO_Pin_2|. q7 T. L1 Q3 J0 X
- GPIO_Pin_3|
0 t7 h; z- m2 ^8 R4 x& c - GPIO_Pin_4|
8 b* l) \6 ^ `1 w4 s3 S& H - GPIO_Pin_5;4 A g% F" c/ z2 L% D5 R1 B$ [
-
' t* G( G1 T' r1 j! R# ` - GPIO_Init(GPIOC , &GPIO_InitStruct);
3 H! a, F0 r) d% j - }
' N# h3 s N8 M: A - : p! d: Y; i6 W% i9 N
复制代码
% q0 W5 K2 l. L3 L9 V7 TADC和DMA配置
# S+ W8 E1 x! v此函数中主要配置了ADC的相关信息和DMA的信息。: O( w5 s; a6 z: f" U
- uint16_t result[6]={0,0,0,0,0,0};" b9 ]9 |$ |/ h
- / d+ Q# y9 J- K& q! |3 m& I
- void ADC_DMA_COnfig(void)+ K$ T0 r% x8 r7 Q. U
- {
; Q! |9 A# ~5 U3 k7 o C - ADC_InitTypeDef ADC_InitStructure; x+ z/ \& e- Z4 D9 m w
- DMA_InitTypeDef DMA_InitStructure;
1 s$ b& c) M9 U5 O P -
3 v2 ~0 |: Y+ _- f" S, O3 s - RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);( k8 ]" f2 H9 j% j, I
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);! R9 O3 j" ^5 F2 z* _. \. o4 d2 I
- % ?, R8 o' G! }( X1 l
- /* 复位DMA1的通道1 */
' s* X- ]& m! y - DMA_DeInit(DMA1_Channel1);7 J3 B- J& Y- s4 F! N& J8 W& u
- ( c7 L& U- n/ D U
- // 配置 DMA 初始化结构体
6 `) O) B/ D9 ^# [ - // 外设基址为:ADC 数据寄存器地址
5 [9 V- }, s6 T8 z - DMA_InitStructure.DMA_PeripheralBaseAddr = ( u32 ) ( ADC1_BASE+0x4c);
8 ~0 b/ ]9 w5 F' R& d. j$ j - % f* d( q' o9 |9 G8 `4 S
- // 存储器地址
: q/ `# ~, B% J - DMA_InitStructure.DMA_MemoryBaseAddr = (u32)result;; o) E8 p9 `; C e% {. y# U" E$ Z
- + a5 J; b, k6 ?. Z2 |& \
- // 数据源来自外设
; C3 w4 }% @1 s7 p* c6 W3 x' p - DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
* i; G6 z. C1 e - ! a3 L! S+ ]) r1 g( W, k* o+ B" M
- // 缓冲区大小,应该等于数据目的地的大小+ \0 _: A2 r& B G
- DMA_InitStructure.DMA_BufferSize = 6;- ^1 W5 K' ?3 {. V: x" C
-
. `6 C$ D4 n+ @; J4 n - // 外设寄存器只有一个,地址不用递增
+ v. _; I a& z7 S - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;4 @ H- |; p9 p$ z D! ~; J
0 t1 j3 t9 e6 U2 r/ e+ r! E" E; B- // 存储器地址递增
+ ]! y2 [% q. d% {( V/ k - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 0 d8 u2 D+ P; Y8 e; H- h( l
- 2 |* D( T. b+ {
- // 外设数据大小为半字,即两个字节
1 `& e9 v; d% J0 b% e; }* z! j - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;2 A; H& o, n0 L1 ?
- 9 \+ ~ x) h+ z. s+ E F
- // 内存数据大小也为半字,跟外设数据大小相同) \8 D$ ]* b0 B
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
: |8 K2 _7 y2 r d8 L -
( p5 m* o+ n! K9 v3 q- G0 Z - // 循环传输模式
K/ c6 |7 E' f/ S - DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
& ], p0 o3 F# ^3 _ - , @- }' e' e- }, O2 f/ k7 B1 K1 h# o
- // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响
( Q7 {# p% S ?/ X* l1 X - DMA_InitStructure.DMA_Priority = DMA_Priority_High;
1 M" `, r5 ^% s6 {* o! k" { - % S2 C Y" F Z+ {
- // 禁止存储器到存储器模式,因为是从外设到存储器1 D# z* @8 p" C) _
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
& j& D2 u* L) J: L1 l0 y9 K4 I) i -
' K& L7 i: a/ ?& c - // 初始化DMA0 o4 }' o3 r$ f3 @' Y
- DMA_Init(DMA1_Channel1, &DMA_InitStructure);/ [. q3 b' Q' n7 X+ W2 X( U% R: @' Y3 ?
-
8 ^5 W/ Y7 k! \* ` - // 使能 DMA 通道
( n, J+ t; N, ^3 g# N4 K9 a - DMA_Cmd(DMA1_Channel1 , ENABLE);
1 x* A0 J8 Y: v, E' m -
% P. @ |) u* D+ B - 4 u- v8 X, _4 T' P; N
- // ADC 模式配置
/ C" [, m6 U3 P5 l - // 只使用一个ADC,属于单模式$ i3 q) S+ M5 f6 P7 X* I% C8 R
- ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
" x7 K7 r$ S* n; n. |5 }% F& j - 9 u- v2 _' k0 p4 G: W
- // 扫描模式* B+ L# J" Y; A/ c
- ADC_InitStructure.ADC_ScanConvMode = ENABLE ;
/ r* n% {. T% t9 ~; x/ L
% F, J9 D' p1 b4 g- // 连续转换模式
9 j/ m- k! l+ V$ d @5 u - ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;1 F0 `, ~* \4 h! C' l& j
% d: E) b- v2 j _- // 不用外部触发转换,软件开启即可
* N3 W' f. ^, O! \+ _5 O - ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
$ i# {' Q0 o+ l2 d
0 a$ Z3 q( c7 ~3 d# K1 C' s- // 转换结果右对齐 w# I" y8 v- [7 M, T$ Y. g9 `* b
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
9 H, w$ {2 c/ T- ^+ [ -
; X/ T0 j7 o- G. u& x4 y - // 转换通道个数
8 Z; a$ d# k" ?9 G3 Q/ Y - ADC_InitStructure.ADC_NbrOfChannel = 6;
* D) D. V& @% |# r: l0 _- B: Y - ! ~, v F$ l2 h' t" _0 x5 L# M
- // 初始化ADC0 F& d& n K, o, B
- ADC_Init(ADC1, &ADC_InitStructure);4 K, `: H$ I$ F. d6 V
-
& ?# G8 [: m( `' } - // 配置ADC时钟为PCLK2的8分频,即9MHz
) X0 r% @# b/ G6 D3 \: L' j - RCC_ADCCLKConfig(RCC_PCLK2_Div8); + U( L$ B3 h/ ]7 r, n3 c
-
" U. V2 X* e) k- N! I2 S1 ~ - // 配置ADC 通道的转换顺序和采样时间- ^) T% k- y. r8 q" S1 N
- ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5);5 F6 Y6 T/ k$ m) r) v2 r# L* ~
- ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_55Cycles5);
- g: v1 x' |1 H8 l2 F* I! T- y - ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 3, ADC_SampleTime_55Cycles5);
8 C/ f3 ^" `1 c( f/ v) B, e" U" o - ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 4, ADC_SampleTime_55Cycles5);
* n b9 H" o, U - ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 5, ADC_SampleTime_55Cycles5);
$ M/ J7 d5 U; V1 c# b% M - ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 6, ADC_SampleTime_55Cycles5);0 D8 v4 D, T# l8 I K1 }
-
" r. ]1 l Z0 f/ p - // 使能ADC DMA 请求
, c" a! f( l- O4 H; A- J5 T6 M1 X - ADC_DMACmd(ADC1, ENABLE);) ~' c' [6 U6 D% K# J! w9 \$ N
- 7 X$ U$ } E) q% o
- // 开启ADC ,并开始转换4 M2 A: f u; @5 C$ ~# b
- ADC_Cmd(ADC1, ENABLE);9 s F- d. }: G6 R4 o
-
+ p1 C+ R$ H) B% g% f& b - // 初始化ADC 校准寄存器
J3 G1 R1 C+ F' Q8 y |9 M0 I5 y0 b - ADC_ResetCalibration(ADC1);
3 \& x7 x k0 u7 B1 Q - // 等待校准寄存器初始化完成 K6 s7 \9 F; G% u2 L8 Q
- while(ADC_GetResetCalibrationStatus(ADC1));
f/ T- Y, L7 M9 Z6 A/ E9 b8 T7 D -
) z% n) J# w' D. c2 @ - // ADC开始校准
4 B& J) R7 a3 J2 q - ADC_StartCalibration(ADC1);
+ @. Q# J9 D: H' @ - // 等待校准完成2 O% e8 Y- s! L8 m/ g
- while(ADC_GetCalibrationStatus(ADC1));
. @. Y {" G+ {) Z6 u - " Q% `$ z# V) {9 k/ f- W
- // 由于没有采用外部触发,所以使用软件触发ADC转换
. n1 g. x9 y9 G: s - ADC_SoftwareStartConvCmd(ADC1, ENABLE);7 ]7 Y( |8 r- B0 |
复制代码 0 i* _3 s2 ?4 {+ a9 [$ S
函数开头定义了ADC和DMA的结构体变量,并且打开了俩个外设的时钟(DMA挂载在AHB总线上)。DMA模块可以参考之前写的博客:DMA8 F4 w J) D, c" H' m" u) V/ g
这次DMA传输是从外设到内存,直接从ADC的数据寄存器中取数据,然后传输到全局数组变量result中。剩下的都在函数中作了详细注解。 X5 x+ o) F( z3 l# |. x
7 R3 v9 G* G# \+ p+ b# ^
1 v: P8 P2 d) _5 A5 M: u
主函数
2 _7 j& C! S% k- #include "stm32f10x.h"! H* u, @1 n# i F
- #include "usart.h". P0 O+ X+ g8 R4 t3 P+ J6 N
- #include "adc.h"
# }% N7 N- g4 ~7 R* G0 U; o
- Y$ I* e$ z- Q. U' M: ^, T
, y: e* X a6 f2 H- % ~7 a+ B) L5 x
- extern uint16_t result[6];
. J7 w6 c1 I' Y/ G& B0 D - float voltage[6];- w W) o# F9 ~9 Y6 G9 x
# J; {1 W: O* f/ u/ s+ p' u- I
V8 w( k$ }+ t9 H) u5 M- void delay(void)6 ]/ K. ~4 r/ z
- {8 w: l& J% y3 v
- uint32_t k=0xffffff;
: F3 r4 i# ]" A4 l* y; Y; j - while(k--);5 S0 ]' g& i& V# i8 ]* Z
- }( X4 A3 L+ G# L# S$ \9 X
! `% F, @/ }+ k& \7 v- int main(void)
. F7 u' c4 k+ G, I, V' m( j( l - {
6 E( U$ q5 Q8 n+ p1 ?3 i: c/ s( m - uint8_t n;+ G8 ?+ f( t6 d5 ^
- /* 配置串口 */5 N0 r* _5 e" h: h6 I* Q9 F
- DEBUG_USART_Config();+ H+ A7 W) ]0 \; d, E6 l
- /* 有关ADC的函数打包 */
: Z2 Q# }+ q8 F( { - ADCx_Init();
+ B1 R" o& R3 @' B - while(1)
0 [0 ]5 c9 R6 F' Y6 K6 i1 C, b - {" m6 w( W3 ?* r- u0 n
- for(n=0;n<6;n++)
! i7 j8 l2 _% N; i1 I: j5 m% l0 e" c& _ - {- O0 k7 D4 P$ ?/ r
- /* 转换为实际电压 */' }; c) |8 ~2 o0 M0 t, K
- voltage[n]=(float) result[n]/4096*3.3;6 V. q- \) J1 b- e
- printf("\n通道%d的值为:%fV\n",n,voltage[n]);
0 A5 ^; d, P7 {. |0 A6 N - }6 b2 `6 V- A0 M: j. C+ M
- delay();; _5 S V$ D1 g# ?: B: Q
- }0 X9 Y# }% r9 |$ {- @
- }
2 Y& U0 Z; q6 C' X6 D - & t p5 x: R4 a# e
复制代码 7 U" D( x3 d2 H+ \+ W, w$ n" |: [
主函数中也有相应注解。9 r# Z9 L% }% }
————————————————! g+ U2 E& }/ y/ _# G
版权声明:Aspirant-GQ
8 i1 o" b1 ~3 d- {
# B1 |9 k! {7 E5 `) J5 s. `# ^ |