STM32L0开发系列——01 ADC采集
% D) H) f8 z k8 ?4 n/ I+ f前言
4 r* w& F/ f0 M使用芯片:STM32L051C8T6, B X9 N5 |' g0 y+ w: `. ]
软件平台:KEIL V5、STM32CubeL0
8 u. V; `" @7 `1 V% U库函数:HAL5 D( V9 P" }! n6 _. s# q
: L) n9 t4 z+ y# ]: y% e' h- x一、原理图
% [8 B: A$ R9 ^/ F$ L$ P本文介绍在STM32上使用ADC1的第1通道,对电池电量进行采集。
# D8 W! A8 q) f* l' F* z# ?2 s; A( x6 U5 b* C2 i
& k6 F; `# ^/ E3 x5 e
; @) |; h% ~$ X4 x" P' d+ E& h/ n8 C二、ADC通道与引脚对应关系
: X& {9 A1 Q! s& x. ~0 }, C% n3 A( q( \9 k& I2 E1 ?2 c
: |8 _, S; S/ g3 y3 B. ^
. r+ W, C' O, w% z+ j [: s
0 [2 i5 y; [9 W- X9 v: d% W: @# m- ~三、ADC相关8 M/ f( `! V$ E, u
1、 ADC 可由 APB 时钟或 HSI16 时钟提供。
, Y* f# T( Z" F2、 ADC 转换时间: 12 位分辨率对应的转换时间为 0.87 µs (1.14 MHz), 10 位分辨率
9 C5 C; u2 n# Q( w0 \对应的转换时间为 0.81 µs,若降低分辨率,可进一步缩短转换时间。' ?# y" A( X# @* m/ E. t& V& Q
5 k3 Y, c* r1 R( ?* ~; F四、实验步骤
4 i$ g+ a# o& q% e; l7 j# G1、系统时钟配置
+ X- e5 B" c; R G! r' Z/ G% G4 _% d: s7 W/ _
- //******************************************************************************
/ C, |# }: G+ E2 @* X - //name: SystemClock_Config ! q2 M" ~- y1 w( c- G2 z: d
- //introduce: 系统时钟配置 0 P9 N+ ^/ ]. P& S) E1 e
- //parameter: none
\/ e/ i$ e: _7 m; r7 Q$ j+ k$ @ - //return: none
: e6 T5 ~9 t5 F - ( K7 [# Z" {3 A
- //changetime: 2019.05.21
1 C8 X' }& u' [4 Y. a - //******************************************************************************+ T$ n3 {: Z# K, Z; _5 O) ~
- void SystemClock_Config(void)
9 c' K0 d$ q, _. ?, e5 q) _ - {
' n+ s& _) Q" `: e* D% e' F% ^, z
3 k& P. ?# c" v5 y5 W4 L! s0 I+ m- RCC_ClkInitTypeDef RCC_ClkInitStruct;
R" }) f, l. x, h6 | - RCC_PeriphCLKInitTypeDef PeriphClkInit;6 F! H9 x7 M% j+ h8 }% }4 M9 I
- RCC_OscInitTypeDef RCC_OscInitStruct;0 F1 G9 d6 W& L( B$ y6 {0 n' ~
- * D+ k% y5 [$ ?. C
- __PWR_CLK_ENABLE();
. V+ h: A0 M% W Q+ m
% W: M3 l8 ^. v+ Q! ~7 o- __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
# o0 k- @% R. K - ) q/ ]' Y; C; ^5 C! U9 w
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE;- c7 J4 p9 y6 F% U/ D% X( R: H
& e* Q3 U% b8 }" Z- RCC_OscInitStruct.HSEState = RCC_HSE_ON;
$ u( Z# u& ]3 Y8 w: o" q y8 g - RCC_OscInitStruct.HSIState = RCC_HSI_ON; //ADC的时钟源
! P; h" B* a n: ?, L" I) r1 C - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;6 H* \) O4 ?+ } H" R. e" _9 z% C
- RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
8 M* i% w0 \( ^ - RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_8;
0 B: Q4 V; E7 }2 s1 F. w/ b2 d - RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_2;
) n6 u* ^- J0 ^* b0 o4 s - HAL_RCC_OscConfig(&RCC_OscInitStruct);. `5 s( @8 p# @2 ^2 C0 l
6 [% |, T$ v& t- ^) t- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK" G d: r0 ?- d0 o) m4 V& B/ q+ e
- |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;) t) Q' Y( H# C( o+ R* E: J
- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;# u+ Z7 W$ ~) C0 D0 s! {( @
- RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
- G$ S. Q A1 q, e" K, R. T - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
' m! i* n" \' ?8 A* g& v3 E, x - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
# ^3 c; i4 B: Z1 W$ P& O+ w, U - HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);
! e4 q! A* {; C- y6 ?6 x1 l9 B/ |
1 g# Z, j7 O+ Z: O# s+ W# |3 s8 N- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
# j2 F1 p! L3 i U - PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;5 J& o9 t4 O8 Y8 [
- HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
1 o6 w, s: y4 n% B/ A/ ]
4 \9 o9 [* a9 K+ Z- __SYSCFG_CLK_ENABLE();: P! v! e# n: u% k! C. D" \+ Y! ?
3 g7 W1 v+ @5 z+ m4 e- }
复制代码 $ O2 A$ p, k' s) A( s
注意:一开始程序中没有配置HSI时钟,采集不到电压
1 M' ]& x; `, [; L' b% Q* r5 J' |: D4 k
7 G! j8 |& v4 `- ?; g2、ADC文件/ Z9 ?# \7 q- I P* q2 [/ y/ T1 l
9 ^: `5 `2 l4 C5 S7 U3 y0 C/ X ?6 e0 ^
- #include "main.h"% P& c s) [+ Q" s
* u S" R; x. @6 @- ADC_HandleTypeDef hadc;0 V& D7 M6 i' N, _, B
- GPIO_InitTypeDef GPIO_InitStruct;: @2 O4 d4 b; q) b/ D
- ADC_ChannelConfTypeDef sConfig;+ o8 V* l2 t) b, U$ e/ o
- 3 h8 i% A2 i4 ]: s2 z+ O: A
- * P1 u5 O" ?1 ]2 z1 w
- //****************************************************************************** 9 [4 y, u/ E0 h
- //name: ADC_Init
% I) c# u6 g' z1 L, S) [) D$ s - //introduce: ADC初始化
3 t; k* k/ ]' c - //parameter: none
4 P8 O" ] p4 P, x" x | W - //return: none 2 k) O1 [0 `5 H4 _- Z1 ^& G
# f( {! J" D# C$ q# [- //changetime: 2019.05.21 $ s+ d& A0 \ q1 i2 T6 ]
- //******************************************************************************. J( t% F; [4 _6 f2 E
- void ADC_Init(void)* I. ^8 r. n) ^
- {
5 ~9 D% k& x- W0 W6 R! X4 ? - uint32_t Calibration=0;
& {' h( e8 M. T - $ T6 P! z2 ?$ i# a8 O
- __HAL_RCC_ADC1_CLK_ENABLE();: f7 O- ]$ h& H5 K0 _
- __HAL_RCC_GPIOB_CLK_ENABLE();" `9 l" d" ^, l8 V+ r
- 1 l$ s; [! [+ x! n6 R
- GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
# K& d. |2 b5 D0 t - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;$ n- a" o5 f: a. }
- GPIO_InitStruct.Pull = GPIO_NOPULL;. l, T( {6 n* S; d( f3 A: t
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);5 E5 C$ c; b5 D3 o$ B" Y
- ( s q& b4 T% c. k/ ^
- hadc.Instance = ADC1;( S; t' Y/ ~( d
- hadc.Init.OversamplingMode = DISABLE; P" }- ~9 S+ P) j0 C9 p3 h
- hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
: ]2 K- ]9 z% @$ q4 u# ]: W4 F - hadc.Init.Resolution = ADC_RESOLUTION_12B;' g0 M; K) ~: H1 m: y/ O: I
- hadc.Init.SamplingTime = ADC_SAMPLETIME_79CYCLES_5;. l( S# X. u4 X9 |# `. Y! d
- hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;- l* X U( M) Q! k
- hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;1 B, ]) ^: ]( v ^
- hadc.Init.ContinuousConvMode = DISABLE;
) n+ k, O" d. w7 O3 l( k - hadc.Init.DiscontinuousConvMode = DISABLE;
! ^7 z8 Z0 Q2 P7 d( { - hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
, ]% }* O8 L! M N* f - hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;7 U6 O9 T) Z0 v* B6 I+ X- x. i
- hadc.Init.DMAContinuousRequests = DISABLE;$ ]! b/ a/ R# l5 z/ X' h
- hadc.Init.EOCSelection = ADC_EOC_SEQ_CONV;
" ?1 N8 D, v( a4 w [ - hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
S4 m8 h1 C9 u0 g - hadc.Init.LowPowerAutoWait = DISABLE;
* u S. T4 }# s - hadc.Init.LowPowerFrequencyMode = DISABLE;( B# c! C* l, b1 S/ y& a
- hadc.Init.LowPowerAutoPowerOff = DISABLE;
& X3 i3 E3 Z3 A" I8 @ - HAL_ADC_Init(&hadc) ;2 X7 d& K( {# y) c" Z7 i
- 1 Z) z+ e( I2 l/ y: h/ r2 l! [; R% g" S
- //启动ADC校验功能1 _" {2 l. v0 @% T, s
- HAL_ADCEx_Calibration_Start(&hadc,ADC_SINGLE_ENDED);4 w! v1 ?. [0 R' c9 x/ @3 R* |
- //获取校验值
2 h& [( o' W' B" Y: { - Calibration = HAL_ADC_GetValue(&hadc);
( l4 A5 V- ]+ m* b/ I, T6 G2 l9 N/ C - 7 n- @' y6 Z6 U3 \. U R
- // 清除之前通道
; ^4 W7 j; @/ |6 l" Y, d5 ^' i - sConfig.Channel = ADC_CHANNEL_1|ADC_CHANNEL_2|ADC_CHANNEL_3;
+ Y# {: F2 @+ w - sConfig.Rank = ADC_RANK_NONE; // 清除通道属性" u) a4 f: o5 I& t. S7 H+ e
- HAL_ADC_ConfigChannel(&hadc, &sConfig);) b0 j- Y2 n3 r- t. Z3 W+ Y
- # u" ~; Y/ q5 I! x I* I
- }4 r; t( U# W9 Z$ C1 {$ z4 {1 K
- 3 s8 l( c& `" W
- //******************************************************************************
+ V/ b. k5 T# S% X) H y - //name: GET_ADC ' O/ M7 _& C+ l) {1 K G
- //introduce: 单通道采集ADC的值
% o- N/ p! G2 x' O - //parameter: CH:ADC采集通道 4 {/ e3 N+ \3 X, @2 b! S5 \; _
- //return: ADC采集值 5 c9 R3 n: k, F f4 c8 K' q
- # M4 c+ A U3 y. g; ?3 P
- //changetime: 2019.05.21 3 B, N0 Y9 \! s9 O* T5 |
- //******************************************************************************) l% G! O" m* Z1 G
- uint32_t GET_ADC(uint32_t CH)* a; `; r# X0 N: X
- {( E$ R0 j* [6 H* I# w7 _
- uint32_t adc_conv_var;: d+ A. E% n8 e% G9 Q4 A
- sConfig.Channel = CH;$ I5 k. I0 r9 m+ o% D8 t0 D0 f( y
- sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; // 设置通道 Q+ z5 O O3 M. m
- HAL_ADC_ConfigChannel(&hadc, &sConfig);* c2 O) X3 o2 S# N5 R* r
7 z2 O' }& i. Z4 x# C0 Y4 r% R- // 启动转换& U+ r7 y" X% ?! ^& d
- HAL_ADC_Start(&hadc);* w F8 c9 ], a% w* n5 d: ?
- - X, I. k2 ?! ~: _* F. S4 C
- // 等待转换结束( g/ m, `1 q8 j& W/ `
- HAL_ADC_PollForConversion(&hadc,20);// 超时20ms, g+ f1 J* m5 D, S
-
) K9 g0 l5 A; J - // 读取结果+ h9 r" t i" `% [
- adc_conv_var = HAL_ADC_GetValue(&hadc);# t5 t0 X1 z6 J# e2 w/ l& b# \
- 4 E* `* v2 z" H3 Y2 w# g- v
- // 清除通道' P0 C2 a7 `# D! x
- sConfig.Rank = ADC_RANK_NONE; // 清除通道
; ^" i* H) x1 q" ?8 N - HAL_ADC_ConfigChannel(&hadc, &sConfig);) {3 W* P8 v* n" Z. x
- ! U3 k4 F) S/ a3 d3 E
- return adc_conv_var;2 l( k, E8 {2 z8 f
- }
1 b8 U& X& q( s$ d2 f5 F+ t - 6 w- K0 Z4 O0 l5 } K% P
- //****************************************************************************** 5 [6 _5 ^! A8 `4 B
- //name: Get_Adc_Average
6 Z/ {3 t$ B b& O2 g - //introduce: 多次采集求平均值 ( V+ T6 N- I+ `2 E4 a
- //parameter: CH:ADC采集通道 ! R& V0 ?; s% ?, @
- //return: ADC采集值
" v* c* K n, |5 T
2 b9 Y7 z" h1 `- //changetime: 2019.05.21 4 @6 s; G) ?7 W% w- Z
- //******************************************************************************' J6 c) R$ ?2 T7 h- C$ M) @
- 5 [8 I0 X8 c7 b1 q, t: \
- void Get_Adc_Average(uint32_t *ch,uint32_t *adcx,uint8_t times)
- X2 o6 H4 B- w, } - {- `& v& S# Q2 ?) R
- uint32_t temp_val[9]={0};5 l7 S& B; U) I: p5 N/ y( W
- uint8_t t,i;
4 k* J) Z: Y; z( w Y. d% Z - for(t=0;t<times;t++)
H4 O2 L; K1 ^& r; T4 F - {+ {5 G% N% n% I" l
- for(i=0;i<9;i++)
, s5 Q3 e: ~9 ~ i* E! }3 H- B - {4 V! ~( J! o; \2 M5 H
- temp_val<i style="font-style: italic;">+=GET_ADC(ch);
" O2 B' M9 b, E - </i> HAL_Delay(5);
7 b% {9 o3 P7 o" I - }# M5 ~% q) B d4 i- x
- 8 C7 [9 R$ Q; |/ }' I- t! t% Q4 ]9 z
- }0 w7 Y, e* K9 o7 C/ c
- - l" v7 Y# K% x) n; l
- for(i=0;i<9;i++)
8 ]. ~. g1 j/ F. T - {
8 z( V. q7 x4 D, T0 v - adcx = temp_val/times;
+ y! |4 M4 r3 m- |6 S& e - }4 ?; K, L7 ^9 G+ H, f% `9 j
8 s- h- h( K+ o0 T/ f& D6 ?! U( t" g- }
& X- t. i, I2 l1 g4 [0 o) |. ~5 j
复制代码 ; f( r/ U3 {' D3 c* t* \3 H0 T6 s" v
3、main中测试% A* v3 {1 E8 X* S, l7 h6 L) q
- while(1)# T) ]' |! O/ n8 B% x
- {
' M) a. J. t9 L/ ] - BATTER_VALUE = GET_ADC(ADC_CHANNEL_1);
2 l* P8 r$ o) U/ N# V1 `# d" | - temp=(float)BATTER_VALUE*(3.3/4096)*2; - ^1 G# q$ u, g, a- m3 I2 ]- q
- printf("temp=%0.2f\r\n",temp);9 E( b8 T4 b# L& S) g! F% U
- ( k% a7 O* t+ A: C, P
- HAL_Delay(100);% w3 y$ W5 h& v* ^ a
- }
复制代码
1 C: W# i: \% I9 y
7 H# c) K' ~( H四、实验结果5 |: E* a0 J4 |8 F4 D# D5 {) n
/ b- K h( s! j( @
由于ADC的精度是12bit(4096)、参考电压为3.3V,因此实际读出的电量值为BATTER_VALUE3.3/40962.
! U, C0 u; I3 o试验成功! D2 W/ k t+ G% a# p) B+ h; X
/ W8 |3 S8 K+ |1 W6 `' N3 J, I) q4 c- C7 {$ K
# I8 q( g/ G& i4 c& t6 ? |