STM32L0开发系列——01 ADC采集
( P. \8 R/ e% ?' z& S1 C; F前言+ L: _) z0 {5 c* H j
使用芯片:STM32L051C8T6
+ z, t% d/ V! U" Y9 i, s软件平台:KEIL V5、STM32CubeL0
. M& n! |; |* e! u; p" [( @库函数:HAL
8 i' e- p! s6 D; v/ h2 v$ ]1 [; R' b9 b0 }, v+ i7 E5 t" t
一、原理图8 t* L$ z w& \; ~4 Q+ a7 n8 Y
本文介绍在STM32上使用ADC1的第1通道,对电池电量进行采集。
; n- s1 n. r- B! h: m
7 r) I( b8 e, ~$ e4 X
* C8 V) c) x8 @+ u, X) p$ x9 k; `2 A
+ W# V* D8 z/ l- [- V7 C二、ADC通道与引脚对应关系* g( y" E. s4 _+ U
8 `* Q9 w( w9 t; [# {1 l
' l- B( G, I! C8 i% N! a
) a; A' ^6 Z) k. ^) V, M
5 G1 @/ {7 C* _- z三、ADC相关
: q O+ R$ T9 I; m9 u! N" j1、 ADC 可由 APB 时钟或 HSI16 时钟提供。# N7 Z2 {+ u8 s r2 G1 m( B
2、 ADC 转换时间: 12 位分辨率对应的转换时间为 0.87 µs (1.14 MHz), 10 位分辨率
' a6 X S' _$ m0 H% o8 [对应的转换时间为 0.81 µs,若降低分辨率,可进一步缩短转换时间。
8 U' `& \* J/ _# ~ |9 j
1 u. P) t/ r- f9 `- x四、实验步骤& r6 u" A' _# B7 s2 {
1、系统时钟配置
: e4 X# y" p) j3 Y& \) s0 ]
8 a$ Q* q! L5 e3 I7 L! `7 A- //****************************************************************************** + d2 M( V8 ^: T |# m5 z& r
- //name: SystemClock_Config . }7 y4 [! ?: A* r& t# n
- //introduce: 系统时钟配置
8 Y2 O$ f2 f% A5 F. A8 g p! V - //parameter: none " d4 R3 M- Y/ m9 A8 P5 a8 I
- //return: none
0 a! o5 k6 H6 n8 J - ( Z$ A' S: l1 f$ _! U' ]
- //changetime: 2019.05.21
7 h$ O( N9 M0 F. d0 Q4 T - //******************************************************************************
) [# O$ _& c8 ?* f: j - void SystemClock_Config(void)
. G& ? G+ w$ c+ F - {
- G+ n( U3 [& N1 K: e
' f/ ^2 j m$ m$ x% K+ i7 Y- RCC_ClkInitTypeDef RCC_ClkInitStruct;2 }# p+ f2 ?1 N- c7 j5 g- w
- RCC_PeriphCLKInitTypeDef PeriphClkInit;
; h( Z' ?" j7 g" L6 z8 g - RCC_OscInitTypeDef RCC_OscInitStruct;
$ Z3 B y" X, M0 _ - ! F; X+ K G% |
- __PWR_CLK_ENABLE();
% s7 g ?4 U; u A
- d' J0 j- c: [! l" I9 N5 d- __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
7 ^; Z/ {# _$ n. i9 n" U) p - 0 V* Y" {7 V; J( z( [
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE;
: L6 N0 T7 e+ a" v - 5 U3 U6 s. |7 j1 A% u+ A( E4 D: [
- RCC_OscInitStruct.HSEState = RCC_HSE_ON;
4 x+ \. H7 ^; M# m9 g, o* f& e8 X - RCC_OscInitStruct.HSIState = RCC_HSI_ON; //ADC的时钟源
+ S" d3 T6 _6 G! z) [/ ~ - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;% Q. }- S3 L0 N0 t8 A+ R8 U
- RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;+ `# J. v/ E x: _4 J: K0 X
- RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_8;) k6 v6 U+ b& h9 D/ r
- RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_2;; Y' b! \; A) u1 M0 z* A
- HAL_RCC_OscConfig(&RCC_OscInitStruct);
" F' E, Q( _# X - 2 z' l8 `+ H+ B; A5 s9 X7 D% m1 e. ?3 i
- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
8 f+ l3 }: H; n8 V" f `. u - |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;( H% l3 a& ~3 _9 E* A+ Q% `
- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;. ^* s8 X" j9 E, e9 s8 x B
- RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
: t1 F1 N7 l* Q# y z! T' w# ~- b - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
/ w; j0 U6 S! y8 s0 u4 j - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;' o W# H6 V$ c5 ?" D! L |* q
- HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);3 Y0 u1 F2 q& q. o9 e2 r% `4 }
- 3 K0 y2 J2 W. z- J/ o
- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
' L6 J, Z1 F8 m& I - PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
/ v. h, B9 C* f6 ~% A: p- L - HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
, g, A- n E3 l1 I% J- ? - ; v8 J. k1 S8 d% g
- __SYSCFG_CLK_ENABLE();
$ ]+ b- u$ J; K% P - " i$ H$ Y8 l( w
- }
复制代码
# F# @3 j" k8 z! D# C Y2 l注意:一开始程序中没有配置HSI时钟,采集不到电压
5 L7 M) P# t2 N1 d6 h& b/ u
$ q7 |. Y: \9 @9 w2、ADC文件
# q( n* L- L# a7 A; Y4 T+ c0 c" K* }- |5 u! u6 W' c( f! ~
- #include "main.h"6 j" M% _+ q0 I
" L$ r# f, {+ n+ i- ADC_HandleTypeDef hadc;
! {4 I6 ?0 r- s' s7 [$ d- T5 D - GPIO_InitTypeDef GPIO_InitStruct;/ k1 @& M5 q+ J$ l% x5 k
- ADC_ChannelConfTypeDef sConfig;# f ^8 R0 m8 P3 _( F1 y6 w
1 ^. Q( I& }; S) P9 m- 7 t- w* J; \5 ~- H
- //****************************************************************************** $ c, R8 n0 y' K) K' s- ]4 P
- //name: ADC_Init
( W5 T3 E& w0 s$ q) A, l! A - //introduce: ADC初始化 8 T6 W4 E8 k3 m0 R: X" D* ?% G
- //parameter: none 4 a$ S- O D; [, m
- //return: none ( k- C/ ]8 }, ?3 c7 n
- " y1 y& i& P2 ~1 t
- //changetime: 2019.05.21
& h/ {3 N6 x Y - //******************************************************************************
: I5 F8 ~9 }$ ^% W- w - void ADC_Init(void)
$ R# ^% X( A% c/ P( [; p. e- M3 K - {
2 m) f0 K) P% E- C! ?$ z( T6 P - uint32_t Calibration=0;
9 H$ ^# B$ e/ n2 \ -
1 `, T2 N7 _8 r/ A - __HAL_RCC_ADC1_CLK_ENABLE();4 P7 v7 H# T' R0 V5 D- s
- __HAL_RCC_GPIOB_CLK_ENABLE();
" B. w" ^- @& ?5 u2 s8 V) ` - 5 N* V/ X/ L) S
- GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;/ z' _) W& G$ y+ C* ^
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
% }! G: t W5 W - GPIO_InitStruct.Pull = GPIO_NOPULL;0 Z. ?/ I/ W( K! @% z2 S
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);( \" k5 _/ B+ T9 i/ W# {
- 7 t' h4 w8 r7 {1 {$ s- x* O. A
- hadc.Instance = ADC1;
8 M# S" f; k" v1 c( ]0 H% w: h - hadc.Init.OversamplingMode = DISABLE;
7 P* T( g9 r X& J$ C4 L- p - hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;5 |. E& V% V, @' _
- hadc.Init.Resolution = ADC_RESOLUTION_12B;; |- w: m7 ^" e$ C% A5 X% ^% [
- hadc.Init.SamplingTime = ADC_SAMPLETIME_79CYCLES_5;6 r0 n- A) h, h* `5 |7 i
- hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;; Y; V1 q: ~9 i) L6 W6 ?% r
- hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
2 T& K3 e, w& F3 Z3 R - hadc.Init.ContinuousConvMode = DISABLE;9 h& R1 {0 n. P3 u0 s/ r0 a
- hadc.Init.DiscontinuousConvMode = DISABLE;; o) W& J! G1 }: b/ h
- hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;" a; `0 q+ K; O0 g9 [3 W9 Z
- hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;9 G- W% u G1 M% Q. V U3 \. A
- hadc.Init.DMAContinuousRequests = DISABLE;% T' u' S! w/ c; Y$ ^8 o' c
- hadc.Init.EOCSelection = ADC_EOC_SEQ_CONV;
- N2 ?* L1 y" }0 l& l' v - hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;8 }( X9 D: ~" V9 _
- hadc.Init.LowPowerAutoWait = DISABLE;
' ?9 K& s; c S4 I% s5 E/ K - hadc.Init.LowPowerFrequencyMode = DISABLE;7 y# \! Q: ~! Q' l
- hadc.Init.LowPowerAutoPowerOff = DISABLE;/ b% \8 E3 G3 O
- HAL_ADC_Init(&hadc) ;
5 W* r6 I7 ]3 d1 p! J9 r -
9 I) ], R4 c' _; f& v+ \ - //启动ADC校验功能7 ~4 m [) S2 l# e q! Z( \
- HAL_ADCEx_Calibration_Start(&hadc,ADC_SINGLE_ENDED);
+ G6 k' G0 j: c$ K) V& E% i$ R/ U - //获取校验值- K9 r6 l6 P @
- Calibration = HAL_ADC_GetValue(&hadc);
- T. j- X/ E" X. p -
; I1 b/ I8 p) h4 k; K - // 清除之前通道
* A+ {; D) Q* k9 y - sConfig.Channel = ADC_CHANNEL_1|ADC_CHANNEL_2|ADC_CHANNEL_3;& K! F! w2 q. q
- sConfig.Rank = ADC_RANK_NONE; // 清除通道属性5 n# D- _1 w0 ?" E" \" P& t
- HAL_ADC_ConfigChannel(&hadc, &sConfig);9 |- o, H2 o# V8 ^2 u E
$ }# V+ a: B# L; f. l6 f( t- }. N* A! Z; e$ M
; Z( L q" u3 b3 P( P5 q- //******************************************************************************
% l2 |% R2 ~ W7 O* s" C+ n5 B! @ - //name: GET_ADC 7 |! m5 H5 g$ o0 U" C4 ]6 t
- //introduce: 单通道采集ADC的值
; y) R) W W1 e4 L7 t, q - //parameter: CH:ADC采集通道 + _* Y2 ]* ~9 N. m% R' Q" Z
- //return: ADC采集值
R) I( p) l- U& v) T4 @ Z
' u! T; H5 [- ]0 Y- //changetime: 2019.05.21
, R" }3 p9 e* d$ ?) M9 t - //******************************************************************************$ F- G- E# J5 i8 ^$ Y& @+ P4 G
- uint32_t GET_ADC(uint32_t CH)' [. y0 p) t! G7 }' y
- {. f w1 b+ }) o7 [( H( I
- uint32_t adc_conv_var;# f# F/ N* o0 J4 c$ i( |
- sConfig.Channel = CH;: T6 F C' g0 i5 V
- sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; // 设置通道( w& }4 t$ |1 o+ E/ [: ]$ O1 x
- HAL_ADC_ConfigChannel(&hadc, &sConfig);
1 B1 b# O8 p" D: X! z" v
4 Z- Z' c5 D9 |7 q6 D1 V. P2 d* A- // 启动转换
/ t% v' D% j# R5 ^% O) g - HAL_ADC_Start(&hadc);
/ U' r1 }2 U m0 p- M& | - ' s9 L/ P( _: `3 x+ X
- // 等待转换结束
) X, r1 Q, h* [: u3 i \. O9 \$ H - HAL_ADC_PollForConversion(&hadc,20);// 超时20ms+ c8 a" Z0 U" G. |9 R' K
- 3 J8 v l. L& k7 d
- // 读取结果
$ Z# G8 U6 s1 d* J: s - adc_conv_var = HAL_ADC_GetValue(&hadc);' ~& }0 Q$ L( n
-
# z2 |& K" l# }0 I8 A$ R - // 清除通道
) B" A) k( L2 t! ] - sConfig.Rank = ADC_RANK_NONE; // 清除通道
& c+ ~4 `; @, e - HAL_ADC_ConfigChannel(&hadc, &sConfig);
' f" h. S( v2 {& t6 W1 Z( V -
; y3 y5 Q- r9 E) b: w9 K0 S8 K - return adc_conv_var;0 C6 {* [# _- X$ U) N6 T
- }
% w8 G5 L9 P' k0 N6 [
7 n9 A- ^( k @" v7 z- //******************************************************************************
/ T$ ^* k+ o( f7 e - //name: Get_Adc_Average % C- n3 L+ R6 T4 ?$ k
- //introduce: 多次采集求平均值
. {+ J% m' S6 o9 e! M& l: \5 y( z - //parameter: CH:ADC采集通道 " E( C" y0 `) h6 m K) J* I
- //return: ADC采集值
: H ?' x2 {; A4 | - 5 @! _; o$ x& g. O Q5 \7 V
- //changetime: 2019.05.21
1 M, k2 u y* D {! _+ S5 s( x - //******************************************************************************# b8 D" E0 I& m0 u! D% V
- 1 ]4 y0 W$ b& ~* H! Q( o. T4 R/ B* [
- void Get_Adc_Average(uint32_t *ch,uint32_t *adcx,uint8_t times)
1 M* l) H5 P0 I9 R$ _ - {
' L' m( T) N" X1 G0 E K - uint32_t temp_val[9]={0};) e0 r& g& {" V( c; I6 H
- uint8_t t,i;
6 [4 E2 i2 O' d9 X - for(t=0;t<times;t++)
# X: b% r( w, t- y. B' h- y - { e4 V) v, g# C
- for(i=0;i<9;i++)
# ^" f( k9 ?' h$ H; m2 u - {
% L8 x1 \9 D- j1 a/ ^ - temp_val<i style="font-style: italic;">+=GET_ADC(ch);
2 t7 [ r: D: S. `) j% I - </i> HAL_Delay(5);
1 q, J' v+ |! f/ }: D* T - }
: M0 u3 B7 i& G0 x -
- S" w3 I3 }. l/ ]$ ^ - }- b: A; c. @+ K5 Q; c. G, |
-
; e$ F' m$ j- k# C2 n( X& M - for(i=0;i<9;i++)
) d- Q8 |$ d" U5 o6 O# \* i - {0 p' T! `5 E% g; ~! X
- adcx = temp_val/times;
6 {' z' X2 @3 r1 Q# Z: N7 R+ |7 A - }
! T# m' s* ^: ~) K- v& t
- G& v8 C+ c( Z8 S- } $ Q; u( `) f$ n ~
复制代码 6 m; A# h4 z" n, e
3、main中测试
+ I& H3 z8 n2 `( l: W- while(1)
. H) f4 |4 Z+ E- @ - {3 K: J- f0 u* ]4 c2 m- i" p/ q
- BATTER_VALUE = GET_ADC(ADC_CHANNEL_1);4 l) |8 v4 p+ X- Q+ L: U
- temp=(float)BATTER_VALUE*(3.3/4096)*2; 6 ]) {7 Q$ O- y4 u: K
- printf("temp=%0.2f\r\n",temp);
0 J: @9 N" \1 c1 H# }, P - / \. J2 ^4 E1 B* a t% m2 P5 M
- HAL_Delay(100);% D- A6 s+ E2 z! k5 p
- }
复制代码
% e/ t) [5 o& w7 p
0 X9 H8 A3 m3 C8 Q" q+ D; c四、实验结果( m) T9 L: d1 v& M6 y
. l' O7 ~& `# H由于ADC的精度是12bit(4096)、参考电压为3.3V,因此实际读出的电量值为BATTER_VALUE3.3/40962.
4 R4 G$ e" k+ _+ m2 B! @试验成功% J+ d; g/ F j* T0 \. D }
4 I2 t a2 e* N: }: ^" k# y
9 f. f7 ]- p/ T/ `
/ P" |, }/ A6 j: _6 u4 n
|