STM32L0开发系列——01 ADC采集
, a/ R V' u+ e8 Q前言
) b3 M. E! j/ y' p" N$ [9 R使用芯片:STM32L051C8T6
: l5 D- `7 A3 ^/ z% A( c: C; a软件平台:KEIL V5、STM32CubeL0
6 V; C) @7 e8 b( J# H5 y% o库函数:HAL
: r# ]) t# N; M1 O. C; n( ^) i+ d0 b
一、原理图
' m( W/ C4 R2 F S4 S* q本文介绍在STM32上使用ADC1的第1通道,对电池电量进行采集。& |, k: o/ x! L, R( \0 \) Q
0 R" r' D1 {+ S0 y8 {/ D9 U5 ?) q6 p1 N$ i* J% a: s6 n; R% ]" P
% s" I' g8 U5 F5 M8 D. P: O( X
二、ADC通道与引脚对应关系( Q: R5 F/ v7 O. e, P! j; f+ [
( n8 X \' W$ R* Z! C! n: E
9 ?* Z+ q5 X5 c! @+ \
; c1 r* U& E: `2 S5 c% ?- o
. _: D- Z- |' c+ [. k9 N三、ADC相关
( r i7 f( ]( {+ a( h: C1、 ADC 可由 APB 时钟或 HSI16 时钟提供。
, h8 Z4 N- w) H9 t0 p5 ?! y3 @0 `2、 ADC 转换时间: 12 位分辨率对应的转换时间为 0.87 µs (1.14 MHz), 10 位分辨率( ^% ^) r9 l# ~2 G
对应的转换时间为 0.81 µs,若降低分辨率,可进一步缩短转换时间。
% g" H9 N6 P: I3 l) w d
4 I4 [8 r2 ^2 a4 h; D3 c四、实验步骤5 y# K1 Z" V# S8 t6 V) S
1、系统时钟配置/ ]" R8 U+ ?" a2 W+ l
9 Z. l _+ o/ \9 t% L3 Q
- //******************************************************************************
8 e% c; `' j6 W4 L. h) l; A; _ - //name: SystemClock_Config
2 B+ m# t9 P; [8 R - //introduce: 系统时钟配置 ! Z. ]0 N! h, B5 V: J" @: s) D
- //parameter: none 6 m2 v* ?8 \+ g& g
- //return: none 0 [5 u0 L- }6 u6 z7 F% ?2 L$ @
8 h9 ?8 X5 [; L$ C$ f- //changetime: 2019.05.21 2 c, K+ b5 s/ p4 d
- //******************************************************************************5 u7 i7 Q# X6 o" t. s
- void SystemClock_Config(void)3 D7 _* d% {3 h+ m6 s" ]
- {
2 s9 }8 T9 |% U- z' H - . q9 M) }$ N# K) F
- RCC_ClkInitTypeDef RCC_ClkInitStruct;
% U% J- ?8 B6 H* p- A - RCC_PeriphCLKInitTypeDef PeriphClkInit;
- d8 c+ h( l8 }) \ - RCC_OscInitTypeDef RCC_OscInitStruct;
1 i8 B: \; l* b8 Y6 [4 \
% l4 O$ ?& ~( ]& K3 O2 T- __PWR_CLK_ENABLE();+ w3 B9 X; Z; e" Z
- # m- ^+ Y1 e O! i1 l7 L
- __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
0 f, E7 q5 _( B0 C% w
5 H9 k! }/ j; F# I# y- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE;
6 K8 j/ _: }: } - 5 U" C2 Y" a9 F" l5 C
- RCC_OscInitStruct.HSEState = RCC_HSE_ON;
3 s$ f- W0 x5 a1 [0 Q3 S/ I; b, V - RCC_OscInitStruct.HSIState = RCC_HSI_ON; //ADC的时钟源
. \" t# D# N+ T6 v9 o - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
8 c. B- ^% l0 ]: g: M. F8 D. K - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
/ p9 ]( s$ X9 q; p3 y; x - RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_8;
/ G& X7 ?( x. e9 ]* e - RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_2;6 M& M+ v6 q& s7 a& A
- HAL_RCC_OscConfig(&RCC_OscInitStruct);2 ~8 F* k" x; v3 u
- 7 M3 c% e! _8 D$ \: E
- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK3 L" m1 a- o# F0 y2 v) b
- |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;2 m' S3 p1 \2 I
- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
6 f+ R0 i6 ^6 e, q - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;5 y) t Z) E- Z: [9 j' o' c
- RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;. d4 s- A$ B% r
- RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;% o5 h- G. h9 v: v7 X5 L
- HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);
1 Y& E* ~3 X3 {2 @: a/ b9 ~/ ~
' e) D0 c5 Y! j- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;$ t6 L0 |) d% v% T* t, O$ g& ~+ v
- PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
7 R* o, X2 ~9 y9 T, C - HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
9 @2 {) s% B( R |" Z - 5 j' k0 q+ O8 I/ @; O# O* U
- __SYSCFG_CLK_ENABLE();
$ t* [0 b2 \2 y& ~% V$ c - 4 W& _$ `. r4 k# p% z* x( i
- }
复制代码 6 b- p- V6 p4 \* ^7 O
注意:一开始程序中没有配置HSI时钟,采集不到电压
9 K* T- Y! M6 ~9 m: T
9 ~3 r3 I9 |( x2、ADC文件6 D {3 w5 ^+ U% H; r1 C
% C* L* l2 d& {- #include "main.h"$ s2 N- c% d2 O: v
q7 d2 Y' V5 }# o' [) Q- ADC_HandleTypeDef hadc;4 n6 `! S6 c0 [/ x
- GPIO_InitTypeDef GPIO_InitStruct;
: F: F8 S5 Q. b" u& h - ADC_ChannelConfTypeDef sConfig;3 x! ]( P/ a( T$ n
- ) P0 K" e1 o; k ^) N/ ?, L
1 L5 q4 h2 K6 j- //****************************************************************************** 7 f3 Q1 y8 I$ i$ [4 B c$ R1 e/ T' X& d
- //name: ADC_Init - u/ Y: R$ d* w* A
- //introduce: ADC初始化
" V8 f6 C; Z' @( P& o. j+ |2 {, \4 P3 E - //parameter: none 7 t% D# u" v% G
- //return: none 2 l4 \! z$ I3 `2 S1 R/ Q+ k
- ' G4 T- K9 o8 O! g5 L; `8 \
- //changetime: 2019.05.21
; I' j P4 t' Y$ W4 L' p* I - //******************************************************************************
6 r3 N/ p2 B! k' u; Z1 f; W" j' c - void ADC_Init(void)
' p2 T% `% @: ^ - { I- Q1 O: B' q1 Y( Q
- uint32_t Calibration=0;
& j* X4 F3 X! K/ a" I5 ^' Q9 F -
" a8 y6 ?2 q% w3 x5 l; \- M& y - __HAL_RCC_ADC1_CLK_ENABLE();
! E9 _, B3 p/ }5 B4 S - __HAL_RCC_GPIOB_CLK_ENABLE();
7 }8 s, ~6 Q- l# r) {' z" s) H - + k; b& U% u* | Z. v1 V
- GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
5 `8 ~7 H( v3 A( [) k1 L - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
3 l. f( V. F- {! o) f - GPIO_InitStruct.Pull = GPIO_NOPULL;
2 _+ o/ s2 m* x J9 |0 ]+ j7 |5 v - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
7 y7 I4 k7 v3 f' p$ D- [3 E - ; j x' D+ m& h
- hadc.Instance = ADC1;
9 q2 \ m6 t) ~/ Z6 j - hadc.Init.OversamplingMode = DISABLE;5 T% s! L% Y/ E! m
- hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2; J7 P+ Q8 l& Q6 w
- hadc.Init.Resolution = ADC_RESOLUTION_12B;# Q; e2 W1 T, o3 w' d
- hadc.Init.SamplingTime = ADC_SAMPLETIME_79CYCLES_5;
l8 R# \4 V% f/ u5 s6 h& \% J - hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
" V+ J3 b. N3 w* w3 W - hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
: ] v* @' i2 E7 h0 q- \# G: ~ - hadc.Init.ContinuousConvMode = DISABLE;
7 S: A7 L R; P: F0 Y8 { - hadc.Init.DiscontinuousConvMode = DISABLE;
4 H$ W1 B- h4 E - hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
3 T" \% R/ o' x* i$ v. L$ ~ - hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;, Q" d0 ^2 K9 B8 S1 E5 ~
- hadc.Init.DMAContinuousRequests = DISABLE;, _, M1 y+ A1 ?% F0 d
- hadc.Init.EOCSelection = ADC_EOC_SEQ_CONV;
& ~9 \; U, W/ B+ m: _ - hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;4 H v9 z: r$ u0 H1 N8 ]
- hadc.Init.LowPowerAutoWait = DISABLE;9 R" I, g, k- R- @# O7 V
- hadc.Init.LowPowerFrequencyMode = DISABLE;8 a R& U' s% l2 m& l7 G" Q p
- hadc.Init.LowPowerAutoPowerOff = DISABLE;
5 ~* R- M- I4 P @! u - HAL_ADC_Init(&hadc) ;
6 T2 ~" S& ~* @. r - & R! p3 @: U1 g7 _5 c
- //启动ADC校验功能
6 F- s! v- O' G7 M# M" F$ A# n - HAL_ADCEx_Calibration_Start(&hadc,ADC_SINGLE_ENDED);
3 s# p. p, F5 A4 e1 U) ` - //获取校验值- }; i5 c a1 f- n& X, c- V: I
- Calibration = HAL_ADC_GetValue(&hadc);) I& q# i% S# ]# w4 j2 W- I
-
0 @* ^! i5 J' B5 G& d - // 清除之前通道6 o- m2 W ]+ H, Y+ Y$ _
- sConfig.Channel = ADC_CHANNEL_1|ADC_CHANNEL_2|ADC_CHANNEL_3;- O% d# Q v0 ]! J& z
- sConfig.Rank = ADC_RANK_NONE; // 清除通道属性
$ t% x0 j4 |2 P* t5 v' Z - HAL_ADC_ConfigChannel(&hadc, &sConfig);' o! b: Z+ ]4 p. M6 [% B0 j% K$ Q
B% g) M Q4 I) b n8 F! T& P- }
, P d& K1 Z+ [9 d& c
L1 D: V7 M5 [- //****************************************************************************** , A: t. b2 ^. w
- //name: GET_ADC " }5 B, b0 s1 R; J2 ]' V
- //introduce: 单通道采集ADC的值
8 s$ K K+ I, F# X- \ - //parameter: CH:ADC采集通道 ; L/ B5 c" E. ^/ U2 H
- //return: ADC采集值
k3 e0 n7 V) L+ y0 a
; [& }3 n5 `- H4 j3 U2 }% q- //changetime: 2019.05.21 + x0 U Z+ m* a* t9 C
- //******************************************************************************6 q4 Y7 q- Q) F; [$ h( G7 h
- uint32_t GET_ADC(uint32_t CH) j( z% b r9 n' h7 U, s7 T) {
- {
: K1 `2 h! M& N% h- ] - uint32_t adc_conv_var;0 M: N1 ?6 O5 o+ K
- sConfig.Channel = CH;' }9 S# R( Q; M9 j$ C2 C
- sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; // 设置通道+ E/ L1 ^- _% h# T! N6 J" u
- HAL_ADC_ConfigChannel(&hadc, &sConfig);4 f& f% k6 J2 N5 j
- ) V6 V# L' D& ~! E1 c8 `! \
- // 启动转换
9 O X" x/ O+ I! b2 F- G - HAL_ADC_Start(&hadc); F4 q7 ]7 |! p$ K1 Q
-
5 V! {' s0 _3 _% Y. O- ~$ `. s - // 等待转换结束' P. N0 i7 A2 N
- HAL_ADC_PollForConversion(&hadc,20);// 超时20ms& J+ e8 C8 ]; p
-
$ E4 b' {# p9 T7 ? - // 读取结果) k0 m# T" }* {( ?- ~ ]0 t- s
- adc_conv_var = HAL_ADC_GetValue(&hadc);
. A! i: m7 u& ^+ w1 p2 g9 ?; B. \ - 7 V U0 X( q6 m
- // 清除通道
/ ]/ u( d* W! D$ x& G+ ^% X7 j - sConfig.Rank = ADC_RANK_NONE; // 清除通道7 \4 ]3 R: n4 U
- HAL_ADC_ConfigChannel(&hadc, &sConfig);
7 L" P$ u# H( X$ d -
. F7 r) b! w5 C - return adc_conv_var;, z, H4 t; f0 u6 ?$ N$ M
- }
& ]' B) _ V0 U9 K* u
# d% y6 b7 G$ @1 a! [9 v5 W/ I3 n- //******************************************************************************
( J, ~3 H. D! f( M. C - //name: Get_Adc_Average - A# N( S8 @+ X' d
- //introduce: 多次采集求平均值 5 Y* L$ |2 D6 O. Y- W" ^, K5 b
- //parameter: CH:ADC采集通道 , d2 K4 L$ e/ }# Q! f
- //return: ADC采集值
0 \5 B! {2 c4 [0 I1 Z
: g! |: A) u: A8 B- //changetime: 2019.05.21
' A/ u. a' q7 l. P/ t9 L) ^8 ~$ O+ { - //******************************************************************************/ x) j3 W, q; ^ _; E0 i5 K) Q
2 S5 j/ E: D% p) V' t- void Get_Adc_Average(uint32_t *ch,uint32_t *adcx,uint8_t times)
$ W5 |7 M4 {0 l, A' W }, B - {
1 V2 A+ C- e5 \: P, P* c - uint32_t temp_val[9]={0};8 y: N, c4 D9 Z8 P2 p5 C# {
- uint8_t t,i;9 F8 w8 M) G+ Z) c# a9 @6 ]" l
- for(t=0;t<times;t++)4 {3 U6 u/ S4 u9 e3 {8 y- D5 e
- {" y* ?9 o7 p0 V6 Y5 }/ W3 W+ N. \
- for(i=0;i<9;i++)/ G- v! W" h9 Y8 @. s
- {
3 R" o0 ?0 i& }9 E) w* ^7 b - temp_val<i style="font-style: italic;">+=GET_ADC(ch);- k! r q. [ t7 V! }7 G
- </i> HAL_Delay(5);
* U4 S6 _! C4 S0 @ - }' x: e0 k3 a4 E! ]9 H& U' v
- 7 Z2 E- G( N+ S7 c+ L
- }3 q$ V/ i" n$ m. k* w6 C
- / d+ j- S3 J. j: n2 E6 s+ S
- for(i=0;i<9;i++)
9 W+ k8 w8 q- B: t8 V- J - {
* w7 N7 d3 ]; O# X0 v ] - adcx = temp_val/times;
/ B4 t0 a; n( ]3 c- B8 i! b - }
G: D2 d5 h- ~7 j' E* k
: w1 ? Z6 F! C# b- }
1 k0 t, I y: L* Z& B- |; i! a" j
复制代码
4 C' C3 k5 z! [- _# O0 `1 J3、main中测试
: I# U, m0 p9 A! ~: Y- while(1)8 [! T6 i( c! |. l" [$ A
- {' J% v) y. p! @& a4 f/ X9 j" f. I
- BATTER_VALUE = GET_ADC(ADC_CHANNEL_1);
# [. s" r9 ?) m) i - temp=(float)BATTER_VALUE*(3.3/4096)*2;
0 u, m5 C+ ?2 x% C ~& G - printf("temp=%0.2f\r\n",temp);5 O0 q. W. D$ ]
-
' g1 y8 ?: N6 G" O - HAL_Delay(100);* h$ u h! ~- {
- }
复制代码
: v. N& P4 J0 S% B) S7 O1 ^( K9 B7 g9 g) W
四、实验结果
, s& `0 G+ C7 e3 V* u1 j K6 [9 [
由于ADC的精度是12bit(4096)、参考电压为3.3V,因此实际读出的电量值为BATTER_VALUE3.3/40962.
3 c+ m/ `; E. F' }" G试验成功
3 G4 T6 A; X+ Z- c, c# F2 I4 q& X$ @
( T* {; @" @2 C* Z# {+ k
/ T4 n; O3 d3 Y+ P* T2 K4 B
$ C$ } W2 l) j |