AD转换即模拟信号转换为数字信号,一般在单片机中模拟信号对应电压,通过ADC口将相应的电压转换为二进制的数字信号,从而推算出测得电压。下面我介绍下STM32中L0系列调用库函数来实现AD转换。4 j5 d' A* L3 X; u M" L/ L% v4 I
8 p, q$ z* O' n" [5 l 首先最基本的AD转换模式,即单次单通道检测,且不用到DMA。L0系列一共有19个AD口对应19个AD通道,其中16到18为检测内部模拟信号的通道。下面代码中用到是PA0即对应通道0,具体代码如下图:
0 f5 T* ?0 e1 i: v, _9 G7 J/ S
1 | v) X# w) \. {+ v. P2 _( K - Adc_init()
0 h' ?$ k7 l; u0 q |: m
3 F( P) J( \% W7 E2 K7 U- {. \& ]$ a$ a! ^+ Z W0 |( i: r8 Y) M
- __HAL_RCC_ADC1_CLK_ENABLE();
& h/ J C! X8 m. F- l - AdcHandle.Instance = ADC1;
9 Q9 B( Q' e, [
' F4 l3 @/ u7 m" M |3 S1 L+ E- AdcHandle.Init.OversamplingMode = DISABLE;
& ~3 X0 r. r; p8 M/ Q9 A$ H
( \! p e/ `% M, e' M3 g- AdcHandle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV1;
& m* D5 ?: Q/ p2 f/ Q - AdcHandle.Init.LowPowerAutoPowerOff = DISABLE;4 l- Y' `& n6 ]3 z' K% v: D0 P |
- AdcHandle.Init.LowPowerFrequencyMode = ENABLE;2 o1 B# D9 ~' S& s
- AdcHandle.Init.LowPowerAutoWait = DISABLE;: S7 T+ N o1 D( [4 `. U9 H
9 i! w% C ^0 V; j" s* K- AdcHandle.Init.Resolution = ADC_RESOLUTION_12B;
" _$ ~( o/ ^+ W - AdcHandle.Init.SamplingTime = ADC_SAMPLETIME_7CYCLES_5;4 d( z# z2 G' o9 Q: g
- AdcHandle.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
r2 x0 K; g9 X& W6 e) a. D - AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
* L7 R r" _, ~0 C - AdcHandle.Init.ContinuousConvMode = ENABLE;9 Q+ {( E! I- O2 ^* T$ [
- AdcHandle.Init.DiscontinuousConvMode = DISABLE;; A* F) Z6 h& V5 c
- AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
8 Z3 ], V7 E% K2 h/ |$ [* K$ | - AdcHandle.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
- |" C* I9 U( S% ^1 _ - AdcHandle.Init.DMAContinuousRequests = DISABLE;
# }) L& c; a1 Q9 E$ o) P8 p* A
4 [( S. G; {* o5 }! q1 N- HAL_ADC_Init(&AdcHandle);" G" f: L5 B. c" F5 y
- HAL_ADCEx_Calibration_Start(&AdcHandle, ADC_SINGLE_ENDED);2 @4 c& |( O7 H9 H
7 @; Y8 K% y3 h! o Q- }
5 H$ ^5 a9 F* H' d+ J* f
/ ?/ ^6 E# I) l8 _- //配置ADC初始化
! c# J% E. v2 |( {6 s. ]# \& O
5 L; J* K1 H# l- void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
# i: S7 [5 {& E, g$ Z+ U - {
' w$ w0 `2 p' L4 D7 ~ - GPIO_InitTypeDef GPIO_InitStruct;# Z' `4 T% Q( a6 p. o P
4 I8 q7 `0 s: T& o* }# t! c- /*##-1- Enable peripherals and GPIO Clocks #################################*/
& C1 V/ D+ Y& N, ]5 y8 I - /* Enable GPIO clock ****************************************/
1 }( L4 |8 J% o p+ @ - __HAL_RCC_GPIOA_CLK_ENABLE();. u3 Q7 p& [& H1 Q# d6 A/ p
- /* ADC1 Periph clock enable */
( `: ~, i& r! Y& P# Q - __HAL_RCC_ADC1_CLK_ENABLE();
% z7 B% O9 s7 u6 ~3 Z3 V# f
; M p/ Y" `( H6 ]) ?, F$ T6 W- /*##- 2- Configure peripheral GPIO #########################################*/2 e* q9 \# w' b( F$ V3 G
- /* ADC3 Channel8 GPIO pin configuration */! e: K; D1 \: c5 L% g$ |) _' Y( z
- GPIO_InitStruct.Pin = GPIO_PIN_0;; I1 c5 e5 L3 A- B0 l* N
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;; T/ w; F6 U" D( v. b# a7 j% [
- GPIO_InitStruct.Pull = GPIO_NOPULL;0 e7 A; `/ ~% s+ \ U" Y2 }7 Q8 k
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
6 k2 Z- I8 w7 h* A - }9 @- L) n6 A0 r8 A" ^+ z
4 V% u# L8 a- Z! R- R- //初始化ADC引脚PA0,开启时钟6 ]4 p! F% m% ^3 ~# r9 ]2 I
, _1 B4 j! v- U1 I: e6 \- void get_voltage(void)
- |9 T- N# e8 N* x/ ?# ~ - {& J, P7 T# U) t2 ?; B
- bsp_adc_init();0 R9 K t7 C+ n
- HAL_ADCEx_EnableVREFINT();
$ p# B% ^5 v, k, \$ j5 X - HAL_ADC_Stop(&AdcHandle);/ i8 h# A0 O! j& W
- AdcHandle.Instance->CHSELR=0;
2 _# v. [7 J- \7 o - sConfig.Channel = ADC_CHANNEL_17; //通道17专门测内部电压值/ G; P" q+ E W0 v2 h- R
- HAL_ADC_ConfigChannel(&AdcHandle, &sConfig);/ L6 p9 @& s5 |# e. L- q1 r, q; V
- HAL_ADC_Start(&AdcHandle);0 R* Y6 v+ V5 [) {
- HAL_ADC_PollForConversion(&AdcHandle, 10);
( {- q9 N! u4 [- O" V* I7 n - /* Check if the continous conversion of regular channel is finished */' {) n) p% }, w) c8 ]$ X* `' P1 e
- if ((HAL_ADC_GetState(&AdcHandle) & HAL_ADC_STATE_REG_EOC) == HAL_ADC_STATE_REG_EOC)
8 C: R- r- M0 C' Y0 i - {, R, X( K7 O3 ?
- /*##-6- Get the converted value of regular channel ########################*/
3 Y3 @1 Z; W! e# N - uwADCxConvertedValue = HAL_ADC_GetValue(&AdcHandle);
p) }* D: h1 M- f - }
6 l. W7 H+ \0 o - $ @/ A' e+ q% }
- vdd_value=VREF_IN_VALUE*FULL_ADC_DIGTIL_VALUE/uwADCxConvertedValue; //内部电源电压7 \; u0 K2 I: p/ \2 D- z/ W: H
- HAL_ADCEx_DisableVREFINT();
5 C4 G/ L, \2 e# D9 H - HAL_ADC_Stop(&AdcHandle);! b7 C: @7 k' M7 P6 b
- AdcHandle.Instance->CHSELR=0;, `5 M+ P" i$ w C5 x; m
- sConfig.Channel = ADC_CHANNEL_0; //ADC0,去测外部PA0口接的电压" H: {, R# ^+ l
- HAL_ADC_ConfigChannel(&AdcHandle, &sConfig);
+ I4 q4 a" U! N9 F1 ], f - HAL_ADC_Start(&AdcHandle);
0 `8 ]8 U4 c0 ~# H- W - HAL_ADC_PollForConversion(&AdcHandle, 10);
) p% n3 T7 G) D5 h - /* Check if the continous conversion of regular channel is finished */
' y( c: T/ |/ n4 ?+ U6 ^8 L7 a - if ((HAL_ADC_GetState(&AdcHandle) & HAL_ADC_STATE_REG_EOC) == HAL_ADC_STATE_REG_EOC)3 m5 b" w! g0 B3 j
- {
' @5 s( i4 L/ h$ l+ H - /*##-6- Get the converted value of regular channel ########################*/
# K1 q( s# }% a* k! x% ^ - uwADCxConvertedValue = HAL_ADC_GetValue(&AdcHandle);
) e3 x1 z7 ~1 @2 P# Y% ]: c M - }
/ W7 ~* a" ?6 K: ?! O) Y$ d) R - //直接获取的是二进制码,14位对应最大值4095,内部电压为vdd_value通过比例计算得到电压数值
" z% `9 s% d' o, `/ L - temp_voltage=(float)uwADCxConvertedValue*vdd_value/4095;
/ D6 \+ G5 a0 O. ~& ^ - //得到浮点型电压值 是乘了1000倍的
$ E) y6 y* ], @: z8 p, g8 F* p - HAL_ADC_Stop(&AdcHandle);
S/ _$ `7 n( h' R$ p: h% @5 I( `& Y* \ - //HAL_ADCEx_DisableVREFINT();( V3 i$ a8 `: [+ B2 Z( a1 l/ \
- __HAL_RCC_ADC1_CLK_DISABLE();# O2 g+ V0 H4 T
- }
$ D5 S6 }: P# X% b2 M0 W& _ - }
复制代码 % B+ I! l& }; @* {" @( X- j" Q0 U
" s4 p/ v4 R* @, Q& C2 U3 B 以上ADC检测,相当于一次连续检测了两次,第一次为内部电压用的特地通道17,第二次检测的是外部电压对应硬件连接的PA0对应通道0
R5 ]' X2 T2 h8 W
8 k8 c/ n. Q2 n+ h; P
: R) w9 R) W Z5 y6 e5 Z% h( V, | C |