STM32L0开发系列——01 ADC采集2 z9 ?3 B& I" B3 _! j8 d# E
前言# h* [& u) I; M) B
使用芯片:STM32L051C8T6
+ P7 c! q+ m; T; c软件平台:KEIL V5、STM32CubeL0
5 @/ I1 d# T7 L; w4 p库函数:HAL [. |! Y- n3 d3 k- D6 d0 _) M
; d9 h1 H3 M( h
一、原理图1 Y- _7 O+ `$ U4 D/ `2 ~$ m! J" z
本文介绍在STM32上使用ADC1的第1通道,对电池电量进行采集。& ?9 _9 j1 |3 Z9 Q8 F
* A q. u |4 `8 }- W; [7 U9 m1 z
- Z4 @" X+ m) ]2 `
1 k. Q' ^1 H, g' l' ?3 O0 F二、ADC通道与引脚对应关系
3 B, d" W- j9 z) E+ b |; R7 j- ]8 V/ g
( T V2 D' {5 F( d$ I4 r( v1 u; ?! E/ h. D. |! S1 _" w( B
! T, Y, ~& z( F7 F* R' u, q三、ADC相关+ {1 s, E- N/ a+ q3 Y/ r6 T1 O
1、 ADC 可由 APB 时钟或 HSI16 时钟提供。; B4 _0 w! B* p! I& i
2、 ADC 转换时间: 12 位分辨率对应的转换时间为 0.87 µs (1.14 MHz), 10 位分辨率# s5 W% d: \. q( [. H
对应的转换时间为 0.81 µs,若降低分辨率,可进一步缩短转换时间。7 P: t9 |1 y+ Q/ G% q2 |4 L& G
! t- C1 [2 a( Y$ C0 H1 p/ Q K, m, ^
四、实验步骤
4 L# T9 U J$ {, i9 ` D; b. G; @1、系统时钟配置
/ R0 I! D' r9 l9 R0 x/ _8 q6 h' @. y0 M% x# X F" y" u! J
- //******************************************************************************
; `2 b7 {2 B, j W* |! p" [ - //name: SystemClock_Config & m, e% u9 E4 s5 u8 L) ~8 Q' ^; ]
- //introduce: 系统时钟配置 4 q: I2 n, b4 S2 e
- //parameter: none
. e4 P& _' d/ G W. x6 v/ q3 [' G - //return: none
% D" ^7 _/ f ^( O' e9 `2 a" | - , O7 u/ i, G) n! E: M
- //changetime: 2019.05.21 6 _' y$ }1 Z* X! [
- //******************************************************************************, ~, @" b' w e1 L
- void SystemClock_Config(void)
. {+ h6 i' |6 u0 k7 ?3 D# \6 { - {) D9 }$ C* Y# I! ^4 U
- 2 g( G3 o, }6 {% D6 g
- RCC_ClkInitTypeDef RCC_ClkInitStruct;* r& n, m2 W% D
- RCC_PeriphCLKInitTypeDef PeriphClkInit;7 l8 p3 W. v% a; u
- RCC_OscInitTypeDef RCC_OscInitStruct;
) O1 x& I0 i8 E/ @+ F- A8 L6 P. b - 8 G$ g; u' j# J8 h9 K7 Z
- __PWR_CLK_ENABLE();
0 l, J( } _' F! u* t7 Y) N - ) [/ Y$ S5 m+ I( M
- __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);/ K2 I9 s/ `, Y
- ' o9 ~# d5 Z2 B* d! U) n
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE;! U$ L! l P: O: j6 q
- ' `2 @& Q& i2 Q" _% g6 W
- RCC_OscInitStruct.HSEState = RCC_HSE_ON;
: d' o! Y! M! f* \+ c) r& P - RCC_OscInitStruct.HSIState = RCC_HSI_ON; //ADC的时钟源/ h" [, P) E5 D
- RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;0 D, X8 ?8 B- R: y3 z4 v) G
- RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;; Y' n2 b7 c2 C6 l k, @' X
- RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_8;
! e1 |- @% e% j8 S5 N/ @" n - RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_2;
y3 O0 C! A$ s" y+ x) G% y - HAL_RCC_OscConfig(&RCC_OscInitStruct);
$ I; k7 m: ?* `# c, i5 X- O3 _: t
5 k( f0 {# C. ~- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK# r T9 j: @: g: j2 ]
- |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
) x- e' b$ k* Z - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;0 h, A* ~1 Q; l4 b) b
- RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;' P9 b6 ~- P# A, R
- RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
- K% u' E m' o( N, ?( v - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;; ?7 V" l1 k! Z0 E
- HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);
7 S- Q) n9 I' [1 G6 R: m
$ r3 [( f! {" |6 o* `) j' K/ l- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
8 y& T! Q! {8 [ - PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;$ W( T+ c) }* L* N$ M0 k( R
- HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);' l5 P# F, O& }5 o/ c1 c3 d
- * {1 O+ k3 O3 [0 X. _' F/ m* ?, G
- __SYSCFG_CLK_ENABLE();
9 c6 L7 b6 j5 p8 u* n
. O8 X3 g4 U, j; b- }
复制代码 2 {* x& R# T( X F i4 {# H
注意:一开始程序中没有配置HSI时钟,采集不到电压
/ V! s7 Z5 I& W8 P/ d9 C3 R r% Y: o$ D, P) o8 l q
2、ADC文件
* h. g* A5 R' y Q: Q0 j; J: t$ V7 f! Z( w% D% P( c
- #include "main.h"
8 t( G# A. w6 D! I" i' O% ]% B
& m& ?+ \, U8 j- ADC_HandleTypeDef hadc;
! J" a7 R( `" S - GPIO_InitTypeDef GPIO_InitStruct;# \# X8 i: A ^6 Y" c D
- ADC_ChannelConfTypeDef sConfig;' a0 d0 |9 b5 r" L
- : Z8 \2 E4 E& J @2 b3 R$ W# [
- / I8 B- W- g% i" K( r
- //****************************************************************************** % Y2 x" a5 E* k7 k- q6 D1 {
- //name: ADC_Init
% [$ [& ~! _# }" C4 X - //introduce: ADC初始化 $ v) ^6 k$ L% b2 g5 X! p- {" l
- //parameter: none 9 k- t/ g( ~0 T% [
- //return: none
5 q' P- I/ @' D& [- R2 F
$ z( K; @! ^$ J! h: B' |- //changetime: 2019.05.21 $ P% s+ c; f$ v% Y
- //******************************************************************************
! |( z8 h' x/ i4 ~ - void ADC_Init(void)
+ n# e q' `- o' R) k$ y$ N x - {
8 z3 D3 ?4 O7 K3 k: O9 e9 o - uint32_t Calibration=0;
- s" J2 i, U# H% o" g2 \ -
+ i; R+ M- n7 f3 n ]6 o - __HAL_RCC_ADC1_CLK_ENABLE();- C; }& C& h8 l2 P; R
- __HAL_RCC_GPIOB_CLK_ENABLE();
7 m" f* Q o, D, P( K" C) Q - & R, a6 E9 ^7 }/ n! [' P3 }
- GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3; S- p! z' M4 N8 ^3 p
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
$ L. E8 c& s! d! v) _4 _ - GPIO_InitStruct.Pull = GPIO_NOPULL;
6 T0 J* [/ @9 m' }& n! d - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);" `2 r6 b3 T# F) I- p8 i
-
+ V# @9 [- K- Q! J - hadc.Instance = ADC1;6 ?& g8 M! @/ T5 l9 g: j
- hadc.Init.OversamplingMode = DISABLE;
5 v9 o# v5 H$ t1 s - hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;+ t7 u) R2 M; e+ X) u( w
- hadc.Init.Resolution = ADC_RESOLUTION_12B; }0 U; H1 Q5 J% [: }) v+ M
- hadc.Init.SamplingTime = ADC_SAMPLETIME_79CYCLES_5;
, }" t' t5 R1 w5 ] - hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
* O0 L% a) R4 U- Z t( G9 a D - hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;% W; G. i: e# N2 m8 u4 u
- hadc.Init.ContinuousConvMode = DISABLE;! Y0 G. m* z* O* G1 D/ ]
- hadc.Init.DiscontinuousConvMode = DISABLE;
& E# a- X" H$ ] - hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
2 \& ~' T0 V4 a. n: e7 _2 h) q - hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
; r5 K/ q& l- ], ^ R - hadc.Init.DMAContinuousRequests = DISABLE;
6 Y; P+ Z" p# Z3 t( q - hadc.Init.EOCSelection = ADC_EOC_SEQ_CONV;& D+ U Y2 q" L$ F3 ]
- hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
; N% Q- m: ^- G - hadc.Init.LowPowerAutoWait = DISABLE;2 ]8 C/ {9 C8 P0 j
- hadc.Init.LowPowerFrequencyMode = DISABLE;
" H# B6 }" Y; y! T - hadc.Init.LowPowerAutoPowerOff = DISABLE;
' W0 X, {% q# }0 n - HAL_ADC_Init(&hadc) ;" [4 P3 Q& }& P% h/ |- N7 y- z
- 1 c+ d# `- D$ }) i( z# N9 Z+ Y
- //启动ADC校验功能1 e! z9 k" M( B6 ^
- HAL_ADCEx_Calibration_Start(&hadc,ADC_SINGLE_ENDED);8 g, @% E a# T$ T
- //获取校验值
( d! u+ Q4 L/ C; [: t - Calibration = HAL_ADC_GetValue(&hadc);
1 q" o# T4 A+ e; _+ u -
* }2 o, F! K6 S - // 清除之前通道
2 r6 e5 H0 _7 M0 a/ c, i# b - sConfig.Channel = ADC_CHANNEL_1|ADC_CHANNEL_2|ADC_CHANNEL_3;! P8 a% w, Y) ]
- sConfig.Rank = ADC_RANK_NONE; // 清除通道属性- m0 C1 p% b( Y' e. M7 ~" I3 H
- HAL_ADC_ConfigChannel(&hadc, &sConfig);% x7 p1 q+ ~5 v4 P
8 a% T1 ]# H9 `( t( ~# T4 L8 k- }
% }7 l, ]) j4 Y8 ^ E
3 j* ~; ^4 F5 U7 q) r, e* `+ h- //****************************************************************************** 0 w, r: a' z6 I
- //name: GET_ADC 5 L% r# u- l7 Z4 k4 K& r0 y1 D
- //introduce: 单通道采集ADC的值
% m. V( V. L* j" l- G, [6 { - //parameter: CH:ADC采集通道
, Y+ t/ o: {; i1 D) D - //return: ADC采集值
9 j+ R0 o8 Z2 s - $ ^. L; s8 X5 `" g* M
- //changetime: 2019.05.21 # [7 l- R+ z. t4 k2 B/ j' ` B
- //******************************************************************************& \# B( }% U# t: a/ n: L4 l! N
- uint32_t GET_ADC(uint32_t CH), V% D- f) t/ j
- {
) l0 N/ b4 R* ~% \; J E3 Z$ H' _ - uint32_t adc_conv_var;# X9 V, ~0 A f. x4 r- f' k- p
- sConfig.Channel = CH;
' O2 D0 j1 P2 @ - sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; // 设置通道
1 y. ?% A; C0 P) s - HAL_ADC_ConfigChannel(&hadc, &sConfig);
% o8 O1 V# J( C2 Z' {4 c o
& [# p8 Q, R* O% c- J* {3 \' _- // 启动转换
( I/ B; f; L9 Y+ T& W' q' K - HAL_ADC_Start(&hadc);9 f5 y) q- B/ k4 X
-
- \* [6 p( Z. w1 b/ A. Z- v% J& w8 @ - // 等待转换结束
& @% P: P) x+ o* A - HAL_ADC_PollForConversion(&hadc,20);// 超时20ms' K" o! s: t# ~8 C% g
- 5 W/ J3 i+ c/ Q0 o
- // 读取结果0 a" Q9 T+ f0 ?: z, a
- adc_conv_var = HAL_ADC_GetValue(&hadc);
" t. x! o/ v2 i2 Y, u/ C( c, Z* a - & u8 z1 q! i; b& Z7 m7 O& k9 @
- // 清除通道$ i0 j. f% G$ A; l6 d& ]7 C
- sConfig.Rank = ADC_RANK_NONE; // 清除通道- i7 C5 I1 `) ?- @1 s
- HAL_ADC_ConfigChannel(&hadc, &sConfig);0 q! Y2 a( F7 s! L4 S) _
-
5 r' w8 q* T' _1 b( w z" l; |, k - return adc_conv_var;
& ^2 C& R5 s0 c- |# U& p - }: e4 M: s! I2 {7 T6 `0 k
- 7 @! j: C7 I6 D( _7 Z' H. ~$ \2 `
- //****************************************************************************** ) y; X5 X. e! v& y5 [; _
- //name: Get_Adc_Average
: Z' F9 H$ F, O9 ? - //introduce: 多次采集求平均值
1 d/ G+ J' K- x i" N- x; g - //parameter: CH:ADC采集通道
. W2 J- {6 k1 c. u - //return: ADC采集值 7 u# k; A, @, ^6 p; v8 ?
& J) W% m, h8 E( @! E- //changetime: 2019.05.21
; a. g4 L9 y+ O- g - //******************************************************************************
& ^5 D& r4 A2 ^2 R7 p; U. z8 x
+ K" F4 \. u- M* Y8 @' q) y- void Get_Adc_Average(uint32_t *ch,uint32_t *adcx,uint8_t times)4 R. y) j, D: l: K& X$ H6 I
- {
3 H4 P: Z, _9 f. V* I: u, W' Z - uint32_t temp_val[9]={0};
3 d! L) O8 Y3 P9 w - uint8_t t,i;
2 a% S6 K( Y8 o+ Y% Q) Y5 T - for(t=0;t<times;t++)8 z' r1 v2 ?; ^; N: s8 w
- {$ s7 _/ H' ]6 L; K
- for(i=0;i<9;i++)6 l* J: _. s9 G/ v# p; C3 K7 C
- {
' t( J% ^6 T' r' K) n - temp_val<i style="font-style: italic;">+=GET_ADC(ch);
$ w" C& g( F( R - </i> HAL_Delay(5);: v6 J0 ~9 w+ s2 i0 n S" S( E; V) f [: h
- }7 n0 m( ^0 s- e/ ^
- 4 [1 R9 G4 [) K* X" m. }6 b
- }
" t6 Z z7 X2 Z9 ]6 E -
6 ~& U8 I5 N4 l: d6 @ - for(i=0;i<9;i++)
% H7 \5 s `% |4 k. I; y; L - {
+ p# D' g2 W' @6 Q/ a! M - adcx = temp_val/times;
+ D& w B8 j; ? - }, J6 d( z9 d! @5 S3 U+ s& M# F
- 6 {$ _+ }5 ^$ n e. y% R# [
- } : a4 e" Z, X; {" d, F
复制代码
; ]4 K& N2 W# d! P0 S& ]3、main中测试+ e/ q/ A9 X4 B2 g" z: @
- while(1)
) ^3 A5 `" X5 L k, z- W - {1 h: F: ?; f' m: t" A1 w& T
- BATTER_VALUE = GET_ADC(ADC_CHANNEL_1);4 f: d" t2 H! c' E: `! y) ]
- temp=(float)BATTER_VALUE*(3.3/4096)*2; ' \& C+ V7 ~2 r
- printf("temp=%0.2f\r\n",temp);
$ u! ?" k7 c% u( E- i -
/ u& s, {0 ], s! a1 \" q# e( C4 G& M; f - HAL_Delay(100);
' [" |& _* x; e - }
复制代码
, k& }9 a/ E2 q1 {2 U5 a
4 p. P8 {+ V# l6 G2 r四、实验结果& c# D, \6 b2 `8 \; Q
& }/ d# i$ }: u% v; b) g+ {由于ADC的精度是12bit(4096)、参考电压为3.3V,因此实际读出的电量值为BATTER_VALUE3.3/40962.
7 J7 f7 D3 ?! H5 F试验成功8 p4 C8 @0 l6 p
; F: {: l8 u; ]- R3 }
' Q! u9 N" o6 ?) ^
2 [4 b2 N3 F$ P8 X9 l0 d |