STM32L0开发系列——01 ADC采集
% q& R0 Y) x, J$ y u前言, M) g6 O" B* P, w" r5 e
使用芯片:STM32L051C8T63 _' ~" T7 V( `$ C% B
软件平台:KEIL V5、STM32CubeL03 ~" z- J; F M9 V; Q* p
库函数:HAL
2 X5 D$ u6 O' \/ c
b; I( q- |: V, h! G- K5 E# o一、原理图& p% A% O5 p a# z
本文介绍在STM32上使用ADC1的第1通道,对电池电量进行采集。 Q/ r3 C) g) N4 @* Z* H8 l$ ]
% P" X! D9 R- f" @( S' D! F
! @- l( H8 |, ]9 p" q4 Q1 P7 ?
% d; \: }- O/ b4 ]. W8 f" r二、ADC通道与引脚对应关系( k& J% X3 v7 i4 _
0 Q; V' s# A ^/ |, \3 y
3 b9 i5 Q* i6 W) w3 v/ z
! R, q2 G$ q3 K8 M& x, K* ]* f
( n" T0 n+ r/ {三、ADC相关
1 }5 `1 b1 M y+ M* }1 i1、 ADC 可由 APB 时钟或 HSI16 时钟提供。
. f% y# K8 k, m$ D- }7 V; }2、 ADC 转换时间: 12 位分辨率对应的转换时间为 0.87 µs (1.14 MHz), 10 位分辨率% z! h$ {) @3 p- O! a/ f
对应的转换时间为 0.81 µs,若降低分辨率,可进一步缩短转换时间。
: J( V2 b- Q8 \- C7 G
% v$ p2 B( L6 s! O* t+ D四、实验步骤
3 }0 X' l# M' P1、系统时钟配置6 }; \+ L8 k( t, h2 Y
c8 _7 V6 S2 U. C; m) g% S: R) ~- j- //****************************************************************************** * W/ c) S$ U+ B: R6 s
- //name: SystemClock_Config
1 _" f9 ~( F. S) o% j - //introduce: 系统时钟配置 " o2 O4 k: \4 b" n2 _
- //parameter: none / q7 t* M! o0 S; V5 o
- //return: none - o* L9 T0 c+ z3 S# x; M8 R
- # X8 m6 r* O4 S" \6 v0 C2 }1 H
- //changetime: 2019.05.21 + ]* I; P/ F+ e" h( W8 a
- //******************************************************************************
+ T, F1 P+ E3 D4 W! o2 v - void SystemClock_Config(void)
' s1 F$ Z+ U5 }# O. X+ y - {
% J3 n/ D1 f6 n( Z/ i
" I2 ]5 `7 K/ \$ s" @- RCC_ClkInitTypeDef RCC_ClkInitStruct;% S. I+ i& G: Q# q. m1 z
- RCC_PeriphCLKInitTypeDef PeriphClkInit;
, g/ M' T; x* P/ @ - RCC_OscInitTypeDef RCC_OscInitStruct;
7 s1 D: }+ N- s7 y - : ?8 P9 ?/ B. b( S% W, f* u' V( t
- __PWR_CLK_ENABLE();2 w/ A3 s2 u7 i. V9 t
6 ?$ q* g7 Q' j0 D- __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);, w% l: O8 a* l k+ u: m3 W
5 J/ g# Y& a+ Y+ @- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE;' m, O; c2 M7 ~: W5 v
- : C3 S9 }" _/ ~5 U
- RCC_OscInitStruct.HSEState = RCC_HSE_ON;7 y+ g! {% {4 P0 c$ Z
- RCC_OscInitStruct.HSIState = RCC_HSI_ON; //ADC的时钟源1 F( D! ]) H, x! W4 z4 ]
- RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
8 t$ f# N& t9 z. W - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
+ Y3 T9 Y; }; U - RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_8;* {, J0 }8 v& c) N6 {
- RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_2;
! N \+ L" I# |2 a- V& Q - HAL_RCC_OscConfig(&RCC_OscInitStruct);: X) l! D9 W& @4 _# @4 j2 I
1 \/ i& T- z8 f$ K: w( t: b- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
5 J: W m* r+ W+ \/ n( { - |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;( M% x: c: x; H
- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;1 e, _: q" D# e# W5 `0 D8 X/ m' w
- RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
! Q' l) V* P. r1 d0 \5 v - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
1 A1 r& {: ]6 |0 b# x- n+ I8 g1 T - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;( S d) @; @. j' I Z l6 G
- HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);
& q' m* ?- D# O9 ^ - `( L8 b2 a9 z; Z: g# O) H: `4 h! b; \
- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
! Q1 H, x1 O: ?( q+ F - PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;0 t! W! }- _4 s5 v- \
- HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
* r+ h* W) B$ H3 ?$ f# J. m
r0 X" G9 o; s/ j( ^) N- __SYSCFG_CLK_ENABLE();8 v. q2 W! }: V, c
7 m' d V" x' m# k- }
复制代码 . a- v* m- S8 c' A
注意:一开始程序中没有配置HSI时钟,采集不到电压7 K( F; ?" \. V9 o% C q" J
5 r" w! H' T9 ^, `) E
2、ADC文件1 L' e/ ^) {3 E2 l3 I4 o1 [ y
1 \. q# s, \8 g
- #include "main.h"$ \8 h+ b% O' {7 `; _+ G
$ o% k- j4 `3 W* M7 R2 |% d- ADC_HandleTypeDef hadc;- l- @% Q0 Y& V
- GPIO_InitTypeDef GPIO_InitStruct;/ y& [) E2 Y9 f" O
- ADC_ChannelConfTypeDef sConfig;
0 v6 n2 d% Y" w+ k% O - $ L9 y4 W2 l& v+ M7 F* D2 n! T; @" |
$ B7 C; F; }0 Z- //****************************************************************************** $ O! f: o* g" I, R
- //name: ADC_Init
$ }. {+ l# N: _ - //introduce: ADC初始化 9 h/ e- {0 I1 V1 g0 ~
- //parameter: none
; G, v5 C m" w* Q& w7 \ - //return: none - B* I2 [" U; W
- ! d- n. ?" p' U% Y" j' x
- //changetime: 2019.05.21
" w1 Y8 K' r8 s0 S - //******************************************************************************
/ r4 |1 n! E6 t- ^4 v; e, ? - void ADC_Init(void)8 @# e! V% j/ p% ^1 v! ~$ V. E* M
- {
" W8 q- R K k% e7 L" w$ m - uint32_t Calibration=0;
4 q5 F& C# o: x3 h* G4 v -
" w u9 U1 B; p% J0 H - __HAL_RCC_ADC1_CLK_ENABLE();
' f9 `4 v J0 t2 j* C6 E - __HAL_RCC_GPIOB_CLK_ENABLE();" Q& V2 F0 a4 X
- 8 ~' ?1 y" R) l+ {6 c) @
- GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
; v" N: t3 A' Q6 r: e8 r - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
/ B% N! O* R: ]5 W& q# x0 o6 \( F/ @ - GPIO_InitStruct.Pull = GPIO_NOPULL;2 N. p3 q4 }+ W# ]9 K! G" u
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
H9 e: M( L# }5 k7 D1 ?# n -
% W$ U; j$ L. O& Y# v - hadc.Instance = ADC1;" \" \% p% A3 {* ^
- hadc.Init.OversamplingMode = DISABLE;
( T9 [0 b' M, a$ w - hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
2 R# o& O& f7 `9 X. V. j- K - hadc.Init.Resolution = ADC_RESOLUTION_12B;- j4 ]* ~; I& r% a& [
- hadc.Init.SamplingTime = ADC_SAMPLETIME_79CYCLES_5;
+ h s3 t8 A8 O+ P, D: @5 b y - hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
5 U$ h" |2 e5 s- b7 K6 y4 b - hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
. z0 A( W. o# |) C6 S% j( J2 T4 H - hadc.Init.ContinuousConvMode = DISABLE;
1 F; [$ X+ [% y! N3 c* I7 Q; l) t - hadc.Init.DiscontinuousConvMode = DISABLE;4 F8 [$ V; V" C! ]4 R4 o2 H
- hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;& j5 X# V4 E! H1 p+ Y: l6 q
- hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;" n" P: c7 D" I" x6 R7 C
- hadc.Init.DMAContinuousRequests = DISABLE;
7 L* y8 T% B5 U+ R6 u+ \ - hadc.Init.EOCSelection = ADC_EOC_SEQ_CONV;3 A F0 O" A) }% y( _
- hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;; o3 |2 A8 A4 ^. j7 B
- hadc.Init.LowPowerAutoWait = DISABLE;
/ T/ R/ N& g5 h* b3 T$ Y1 Q - hadc.Init.LowPowerFrequencyMode = DISABLE; [- T: p: K# X) b5 U! j5 L
- hadc.Init.LowPowerAutoPowerOff = DISABLE;
! \- _4 [; l$ V! [: v1 Z; V' ]$ ] L - HAL_ADC_Init(&hadc) ;
3 d7 z" [/ S( A6 Z: M9 k - : l, @& h7 t5 C! I
- //启动ADC校验功能
6 j; u8 \+ y4 x6 _ - HAL_ADCEx_Calibration_Start(&hadc,ADC_SINGLE_ENDED);
# n9 R) V5 c+ n' r - //获取校验值4 J, S' @! R) ]0 e" S. G# q- Y* P
- Calibration = HAL_ADC_GetValue(&hadc);. z% b6 F: N! t! d/ u9 j. p4 C2 O
-
# k9 X& t6 F0 p" O: x - // 清除之前通道4 n/ u2 o$ q' j% x& B
- sConfig.Channel = ADC_CHANNEL_1|ADC_CHANNEL_2|ADC_CHANNEL_3;2 P: [( A+ r9 }+ d9 t
- sConfig.Rank = ADC_RANK_NONE; // 清除通道属性) L: B# M' l# X& \
- HAL_ADC_ConfigChannel(&hadc, &sConfig);
, o* s( d7 b- Q2 x
6 I9 h% v2 e1 j) q; a: b, I& e5 t* K- }- Z n% k/ H- {& B ]# e% M/ I. W
- $ ?0 N. Z# ]+ d4 L3 t) B: k X
- //****************************************************************************** $ m! V/ Q3 t" r$ F8 A c
- //name: GET_ADC
2 V9 a/ n( z% }2 B, S; o6 _" e - //introduce: 单通道采集ADC的值
' A3 S( V% ~$ X9 z0 ~ - //parameter: CH:ADC采集通道 & O" \ N' e/ g7 @' \1 E
- //return: ADC采集值
% e( C0 S. t& V g' o - : _- i& i5 h E
- //changetime: 2019.05.21
* {2 x" K, J6 c5 g, D, M - //******************************************************************************
# A2 A. t( r2 q- P' {) Y - uint32_t GET_ADC(uint32_t CH)
) f0 e- a8 F }) B" k0 k1 I1 U, ~ - {
, r! M) e! E9 |4 d1 v2 b" z( L - uint32_t adc_conv_var;) a n0 L: g0 {1 U6 h, {
- sConfig.Channel = CH;
8 w( ~7 [( y# ~* s - sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; // 设置通道( K& Y- F) \1 d& k, D4 ^
- HAL_ADC_ConfigChannel(&hadc, &sConfig);
b' E# G; ~* d5 u& o! _
+ w% x: i# G9 I. s: {7 R& J- // 启动转换
/ J% C' I% m. g2 g+ `' \ - HAL_ADC_Start(&hadc);, q3 q. o$ t& E e) A
- / p. H4 I3 _, K# ?# X4 W
- // 等待转换结束
5 E6 q4 d) x9 I H. g - HAL_ADC_PollForConversion(&hadc,20);// 超时20ms
* Z9 g" `; m9 R1 e* a g, a - + Z. v! [7 f4 G( P; H
- // 读取结果0 D' o6 z. U, s+ x
- adc_conv_var = HAL_ADC_GetValue(&hadc);
9 c! P, |" o4 N+ O5 N5 N -
/ X1 n" X" }& O6 B5 n+ x - // 清除通道
2 G- @- Y" Y6 J# k c - sConfig.Rank = ADC_RANK_NONE; // 清除通道
+ y- U9 [$ M& `$ r0 B* }0 e" ^ - HAL_ADC_ConfigChannel(&hadc, &sConfig);8 g: S A. `* x$ T* q( L9 p8 [
- 6 s e+ o. o* U2 Q9 z
- return adc_conv_var;
: [6 n+ }; ~5 v# `0 E" [ - }( z! b5 s; m, D$ I2 B
' c. {8 }. j: k: \- //******************************************************************************
% }0 Q1 B# A0 I# e8 u; ? - //name: Get_Adc_Average
* y5 e- [9 h6 p Q2 r) h9 w& n - //introduce: 多次采集求平均值
- ^# }4 H) ]5 C - //parameter: CH:ADC采集通道
. w+ g& d8 [2 l- a) u! p - //return: ADC采集值 % V, a6 j3 D3 m5 r0 M% r
0 E9 A3 S# f8 t* ~, L* W$ x- //changetime: 2019.05.21
8 B& \3 I* ~7 Z/ x% N( s+ J - //******************************************************************************
- [; J; ~2 p( K8 r
4 e! `0 @8 A9 ?$ N$ m9 ]- void Get_Adc_Average(uint32_t *ch,uint32_t *adcx,uint8_t times)
; ]( @: L$ w! _- x - {7 F+ v3 a/ O5 U% s% O4 ]
- uint32_t temp_val[9]={0};2 x" x0 ?- r& b i0 v+ ^6 K& C1 K1 ?2 j
- uint8_t t,i;' f$ z8 j+ R" _- o. P
- for(t=0;t<times;t++)
8 z& ]. D5 l* R6 c( \ - {' B8 I7 ]2 r6 r9 m
- for(i=0;i<9;i++)% u Y! x0 f* @8 M& D9 W
- {. \) w5 B2 t. N8 \' _$ ^
- temp_val<i style="font-style: italic;">+=GET_ADC(ch);
( }; V4 ]7 y4 {5 U. i1 i - </i> HAL_Delay(5);
( q$ Y+ n- K: N* T - }
- { V2 h& v3 r7 e4 e* I -
" l, Q7 n7 N( q9 q5 A - }
7 E. u& h7 o6 R - 4 I8 n. V: e; ~
- for(i=0;i<9;i++)0 f8 F3 K2 Z' U4 k$ k1 V( w; i3 j7 k! `
- {
& O6 I5 v/ ?- o2 i! k - adcx = temp_val/times;" T% j! G8 I/ [% U2 b
- }
# Y. S k1 a! z/ [" R) k
! x, {' y% n" f% S1 T- } ' a- a- N( S( N: e
复制代码
* {. |, ^$ `" B5 C! |: X- q1 Q3、main中测试
( |. n" i- n9 e( J! o- while(1)& z' m9 O N3 G
- {
9 C9 T% ~( H. J1 d& U - BATTER_VALUE = GET_ADC(ADC_CHANNEL_1);
: t* \- _3 E4 N: r! B9 | - temp=(float)BATTER_VALUE*(3.3/4096)*2;
3 m8 |& M2 z4 e0 V3 V2 P. p2 l - printf("temp=%0.2f\r\n",temp); X) l% x; W4 v+ p8 p" F( m7 `" G
-
) t$ u. d+ {/ V- `$ v- q. a - HAL_Delay(100);
* r9 A$ d, j# x) ^( T+ l# b8 U p - }
复制代码 3 n8 }: O% H- ]% I5 Y; J; k" e
M; w1 W9 |% M) P: |+ Q6 @
四、实验结果3 b: l- y* f7 C, C+ K7 _9 ^$ I
' S: ~, ?( r# S# E由于ADC的精度是12bit(4096)、参考电压为3.3V,因此实际读出的电量值为BATTER_VALUE3.3/40962.
7 H) I' o. `! [4 @试验成功4 p/ K$ N$ i3 O0 | Z w9 {1 }/ d
2 U8 w3 g8 E9 s3 W" {6 U5 `
5 n, K- h7 Z" W8 q8 I9 X/ _
$ y* k4 b7 E7 l, r" ]8 Q$ v/ ~
|