STM32L0开发系列——01 ADC采集
% b" Q' `' s/ Q' ~前言3 k& b- m/ f: ]# A
使用芯片:STM32L051C8T6
4 q5 Z1 Z f# c/ u( ]. x' u' h软件平台:KEIL V5、STM32CubeL0; W6 c9 R' G; z6 W7 D
库函数:HAL
( H. N9 D' J' c7 h7 w. ?7 ~+ G2 a8 |8 U
一、原理图
& K& e E6 q, e1 c' W N本文介绍在STM32上使用ADC1的第1通道,对电池电量进行采集。
; W1 q' K- X5 S+ P6 `
+ ?7 s& b, u# W9 |8 W: U$ c" m" I, L
' W( \* J, v G) h
二、ADC通道与引脚对应关系" y- ?9 K$ U; g: i8 j
$ T2 F, i2 z2 g3 ^
5 T5 G4 [+ q9 ~: C' L
5 I, I5 S6 p% j3 v E( l
' {5 {6 m4 n) y, O: P$ l* ?三、ADC相关5 @% p: N* `! P7 r7 c
1、 ADC 可由 APB 时钟或 HSI16 时钟提供。; |+ s& [/ e3 S* P/ h
2、 ADC 转换时间: 12 位分辨率对应的转换时间为 0.87 µs (1.14 MHz), 10 位分辨率/ U& K: i& V# m+ K
对应的转换时间为 0.81 µs,若降低分辨率,可进一步缩短转换时间。& H0 k7 F) z" N# q8 K/ R& B' r
! p4 f7 C8 y$ {5 Z! s+ g" L四、实验步骤 L3 a- k5 X* W' S6 J8 ^& W* {& S
1、系统时钟配置+ O h3 i3 m2 e, v ?1 C) ~
8 `& d+ b. d* ?6 w% L: G0 `8 i, A- //****************************************************************************** : ~& ?% H+ J6 o3 [1 K, y H- c: C
- //name: SystemClock_Config & R7 p. t6 s1 y% \
- //introduce: 系统时钟配置 . W4 R. ?$ B; `. n+ X
- //parameter: none . n4 K3 A# Q6 r/ y" R$ Z" Z% F
- //return: none 5 @0 r+ t! L+ T7 c* b" u0 h! {3 B
- ; e( x1 _2 ?+ b( s- T' i
- //changetime: 2019.05.21
) r4 V: k) A2 E - //******************************************************************************1 y A: w+ B5 P6 K3 v, s* m' {
- void SystemClock_Config(void)& o& Z/ p1 |0 s4 p' [
- {
' J+ @, U: x, b- A8 Q8 t
, L+ v; k% a" ^1 q- s/ g: X" k- RCC_ClkInitTypeDef RCC_ClkInitStruct;6 P, x2 k( C3 f! U/ j
- RCC_PeriphCLKInitTypeDef PeriphClkInit;1 i9 P% a) b( p; d4 [
- RCC_OscInitTypeDef RCC_OscInitStruct;
4 ], w) [+ x' u& q* D: S$ `5 G* w
! H/ N2 c7 Y1 ]. g9 q' f7 A; A- __PWR_CLK_ENABLE();3 q; w, Z2 @: S E
- 1 N$ u9 X9 K7 W! O( L4 s
- __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
7 q% K7 ] O; M+ D# L! ]6 p; @
+ a1 G2 E" Y8 |" I- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE;1 t. |: Z2 F& D( l+ c4 a" }! ?
- * `% d) [1 l& I
- RCC_OscInitStruct.HSEState = RCC_HSE_ON;
0 Q8 x( j, h4 z4 f0 H - RCC_OscInitStruct.HSIState = RCC_HSI_ON; //ADC的时钟源5 @1 l+ ^/ Z: g) U6 d6 d
- RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;2 |0 P' H n3 J& e
- RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
& s5 \, r' i3 s# j' P - RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_8;
; q" ^# p, e! C - RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_2;
$ c" C, e1 M1 G( a- Y+ w. Z% g - HAL_RCC_OscConfig(&RCC_OscInitStruct);/ s( l0 e' b+ m. x- {+ g0 p( `; W
- 9 i) S1 H. ~. e$ e; y
- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK3 C5 s z9 }3 a: m5 C z
- |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
( F/ j1 ]! f2 O+ a$ G - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
- ~' z2 V, d5 c9 m - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
0 Y* ]6 h! T" L8 B6 W P - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;5 b2 B* v3 ] q! W( o1 ?
- RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;7 s/ r$ J( k! G
- HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);
( i: K8 G+ }: c - 7 S' m' c! ^6 ~) I: z5 Q
- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
+ c6 e) N: _7 s* a - PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;( j$ x' n# f! } H( H8 M6 G
- HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);% u( c" s( A, D( P7 ~; O5 ?
- . q% |# {; I2 |; Z) \* S5 o4 L# @
- __SYSCFG_CLK_ENABLE();
2 B8 D6 v# ^# n4 q' M& O2 U - ) O7 e4 v v0 y' M
- }
复制代码 % P4 Z7 w2 H( I
注意:一开始程序中没有配置HSI时钟,采集不到电压2 P6 P7 Y& O3 f9 p+ g3 b" F
" m* o9 q: e7 ?! S2 _
2、ADC文件
6 F' k6 d6 D2 G5 y D9 u( \! v& ~' I! u
( ~, I: k: w0 o7 l# b1 u7 z7 D# Y, A8 r- #include "main.h", B; h# v: D: Q; f0 H! x
- 0 `& [! r" v) ~0 m5 M
- ADC_HandleTypeDef hadc;
; T- o0 }! _5 W& k# x2 U3 l - GPIO_InitTypeDef GPIO_InitStruct;
/ [- N' y1 v5 k" ^% D6 Y - ADC_ChannelConfTypeDef sConfig;' Q3 U* a" V2 [) L1 D# _9 R- s
- ( _# u9 C; S* J; v& w
- # G! l5 `' h/ a. O& @
- //****************************************************************************** & l5 m3 A+ E7 W9 l7 }
- //name: ADC_Init . Y7 m" B; s/ I9 V5 d
- //introduce: ADC初始化 6 t2 v6 _( D1 R8 |
- //parameter: none
* d8 g2 g2 u" K/ {. s# w/ l - //return: none ) k6 ]: G/ B" @ z* K; p( ]
- 6 I- J) C4 R- m1 X8 m( t
- //changetime: 2019.05.21 ( {8 A, c! B# a p7 F9 C- j
- //******************************************************************************( P& r2 A7 u& b3 D+ c- s+ E% ~8 }
- void ADC_Init(void)
9 j2 ?! e9 H: _0 V' u - {8 l9 g3 y) i, v/ B* @& s
- uint32_t Calibration=0; q( X5 |4 y7 v6 h L
- ! ]4 ?0 H! e- F: r6 z u9 z' b) t* V. G
- __HAL_RCC_ADC1_CLK_ENABLE();: t, p/ J8 P; z2 G9 U; v
- __HAL_RCC_GPIOB_CLK_ENABLE();
8 R/ N Y3 Z" U. ?/ G -
2 z. d L' S# y* u, L% |$ T - GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
( G6 | m; N% R( } D - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;+ Z$ C! Z1 _* t7 Y' F, s
- GPIO_InitStruct.Pull = GPIO_NOPULL;
' j9 k' x2 s" g4 Z( j - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);! W+ Q% M t+ O& V; c: X1 f8 v
-
1 @% E! X7 @% H: L( Q3 F - hadc.Instance = ADC1;
0 w6 I8 l9 f0 D% {+ n0 F - hadc.Init.OversamplingMode = DISABLE;
* I5 i* }7 _/ g# t - hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;: z; R! C' B7 p c' _) _
- hadc.Init.Resolution = ADC_RESOLUTION_12B;. b/ M+ }0 v9 H. N# E- m
- hadc.Init.SamplingTime = ADC_SAMPLETIME_79CYCLES_5;7 M; Q8 x' p# B' Z* T8 G9 [
- hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
* s- _7 z- H& q* m- T - hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
, p* Z& ^/ \% @1 s - hadc.Init.ContinuousConvMode = DISABLE;7 n% C+ ]; \4 a( Z
- hadc.Init.DiscontinuousConvMode = DISABLE;
# X% G. R; v# ?4 Z/ R4 k" [ - hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;% {& _0 o' d3 G
- hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;. u& F) t3 K' W$ C) ]
- hadc.Init.DMAContinuousRequests = DISABLE;
# o9 ]. S: o0 F' H2 s - hadc.Init.EOCSelection = ADC_EOC_SEQ_CONV;
( H+ T& ?3 H |, y0 r0 y - hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;8 T* a) u$ A; i& E
- hadc.Init.LowPowerAutoWait = DISABLE;
1 Q2 r* j" H& N% ~' U- { - hadc.Init.LowPowerFrequencyMode = DISABLE;
. k4 Q& B4 E" b1 i8 t* [/ h: z - hadc.Init.LowPowerAutoPowerOff = DISABLE;
: j5 Q% m! A( q9 v7 N% z( q - HAL_ADC_Init(&hadc) ;
( Z( H" K4 \- x. t - M( D, F7 a; P( B$ b: q6 _
- //启动ADC校验功能# I; l& m& p) ?7 P& v0 i
- HAL_ADCEx_Calibration_Start(&hadc,ADC_SINGLE_ENDED);
4 ]: ~) o# T5 E' ?+ O% P - //获取校验值" z4 }( C* `1 P$ P0 c1 J) [
- Calibration = HAL_ADC_GetValue(&hadc);
$ f% P4 p; y+ r1 Q! P - 7 b d" M( v. U! C5 G7 K
- // 清除之前通道9 e4 ^: z; [6 Y5 l* W- r
- sConfig.Channel = ADC_CHANNEL_1|ADC_CHANNEL_2|ADC_CHANNEL_3;
0 D. g( U; Q& f8 J3 f/ K" z3 x - sConfig.Rank = ADC_RANK_NONE; // 清除通道属性4 r. O9 X' I$ J" g6 v/ {1 R
- HAL_ADC_ConfigChannel(&hadc, &sConfig);
5 u. n- K h7 L' H+ n
! n. }2 b& C$ l' |! t, I- }
2 K2 H5 Q: x- _9 p3 M, I
9 F7 C4 W- I" H* C( c- //****************************************************************************** - A; R3 B" M+ b. v. c$ H% v s3 Z
- //name: GET_ADC
/ z; L6 u3 w5 {# h - //introduce: 单通道采集ADC的值 & n0 k* ?4 d* i
- //parameter: CH:ADC采集通道
- q& x( m) R' i3 y' W! Z* V - //return: ADC采集值 % \( G2 F% L" @8 j' G# @
3 d5 G) v9 T" |- //changetime: 2019.05.21 1 B! M u9 j g/ J/ e
- //******************************************************************************
' c1 r6 M) v3 f8 ~* J" i! I - uint32_t GET_ADC(uint32_t CH)# A5 r1 C# V% [. M6 ?5 z% M
- {) n* U, a2 d. [8 o& {
- uint32_t adc_conv_var;2 T9 R8 N6 \& H7 m( y7 p
- sConfig.Channel = CH;3 e& o/ m6 |8 u& U
- sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; // 设置通道* q) w, T' H! V& f3 ~9 Q9 B- G
- HAL_ADC_ConfigChannel(&hadc, &sConfig);- ]& u& Q+ S. F$ O- O
- 5 f6 _4 W g$ p1 \ H- ~/ Q1 p, |
- // 启动转换
# z4 n$ J# L6 E2 q - HAL_ADC_Start(&hadc);
6 k* V: K1 s, k- x+ m5 A5 U% H - ! m0 F2 w* W0 @5 a# V& T% T$ T
- // 等待转换结束; n# v; Z& P' x1 C+ K5 j
- HAL_ADC_PollForConversion(&hadc,20);// 超时20ms9 e; J5 ~& M% U% N
- 2 A- o) R3 \9 K4 f+ [/ l
- // 读取结果
7 |, P& ?5 p# _ - adc_conv_var = HAL_ADC_GetValue(&hadc);
7 v0 C5 b5 L* Q& ?1 C: K -
% n1 C0 V0 S4 @( S# K- x8 I - // 清除通道3 I$ D' l' p/ w/ ~1 S
- sConfig.Rank = ADC_RANK_NONE; // 清除通道
' Y: O. Z/ W0 b { |; C - HAL_ADC_ConfigChannel(&hadc, &sConfig);
/ o. ~3 P# @0 O A# O - 1 X+ f Q1 E7 u8 d u+ R7 P
- return adc_conv_var;) x( H: |0 W6 x3 ]/ d/ B
- }9 k- ~' j) }# H, i
- 2 r3 f" X- _4 e* o: U- Z) t
- //******************************************************************************
# O2 R2 A3 e4 ?% z( h } - //name: Get_Adc_Average
" C: n# }* P ?: K- j0 E - //introduce: 多次采集求平均值
6 f$ S" _4 }. G9 j9 l: o - //parameter: CH:ADC采集通道
0 Q! }5 k8 r2 W1 N: B - //return: ADC采集值 ! w/ n( Z |: T' q2 P
9 g$ @: T; U {* i- //changetime: 2019.05.21 ! S8 U9 R4 ]7 [4 F0 \* X* e
- //******************************************************************************
; f8 E' m2 W- ^; u4 d% f - ' R9 C$ g3 z- ^' X
- void Get_Adc_Average(uint32_t *ch,uint32_t *adcx,uint8_t times)
8 O$ l8 Z5 y1 f - {. P9 M. O; T3 ~# Z1 C6 {
- uint32_t temp_val[9]={0};
- l7 V2 [# z! a- p' {/ ~% @( b9 H - uint8_t t,i;
4 j9 a* Y" H% J0 e, \) ~3 O1 T4 i7 H - for(t=0;t<times;t++)
3 \+ R1 A+ Y: ^2 E - {
5 I/ j4 A% l3 d0 f- h - for(i=0;i<9;i++)
" J6 `1 w! V( B8 O0 x - {2 j) a" ^8 C2 g) ~& h+ l4 C
- temp_val<i style="font-style: italic;">+=GET_ADC(ch);, w3 \+ ~" I. G7 j3 r" N
- </i> HAL_Delay(5);
( f- k3 ?" n( y9 o. p - }
) R. `+ P" A, d* h -
$ y8 I- y$ c+ ^, E" x- h: w3 C - }' }' R% ?4 x0 f; ~
-
6 q% S' u# m8 l/ b8 ^ - for(i=0;i<9;i++)4 R* K; D; K" W$ ~! X! k* _. D
- {% q# \2 g6 D, D- R+ y2 i8 j+ K+ u
- adcx = temp_val/times;9 Z& E: m- n) f; L/ b( \
- }# } _* y8 `' \9 U
- N. n% B/ z2 o7 _7 O4 F5 C+ s/ _
- } ( m: b6 H' C* _2 j) k' i+ H
复制代码 : {; T/ u; P* z9 ] c
3、main中测试4 A, o1 l! p" {2 K- R4 }4 x
- while(1); U1 t: Y1 o. L8 P
- {
# E# e, g' U6 y - BATTER_VALUE = GET_ADC(ADC_CHANNEL_1);4 Z. N9 i$ ^6 M
- temp=(float)BATTER_VALUE*(3.3/4096)*2;
3 S& r$ u+ K" M4 g: t - printf("temp=%0.2f\r\n",temp);, ^5 a4 _& q, Q, m1 N5 }$ F# d
-
6 x) h2 ? q2 b5 ], r% S - HAL_Delay(100);
; @, `8 y _) z, x4 _ - }
复制代码 $ f R0 y( |: n" x3 g6 \+ [
6 N$ A' y- [4 h( j, O四、实验结果; q) ?9 \1 U& k
) \+ p5 N# @6 _7 g0 \! w6 m
由于ADC的精度是12bit(4096)、参考电压为3.3V,因此实际读出的电量值为BATTER_VALUE3.3/40962.! w" `% G$ _ u7 `* w* m- {( q- p
试验成功
. ^* }9 K" f3 t2 h% P- c1 b+ _5 x, }2 H+ W# T: v
8 H# Q8 f7 A$ w1 \ \7 Y8 J& D' H8 V) X4 r9 V9 H0 v
|