AD转换即模拟信号转换为数字信号,一般在单片机中模拟信号对应电压,通过ADC口将相应的电压转换为二进制的数字信号,从而推算出测得电压。下面我介绍下STM32中L0系列调用库函数来实现AD转换。
' D+ V% U: j0 G. k9 `/ e ^/ E: m; B) i6 T
首先最基本的AD转换模式,即单次单通道检测,且不用到DMA。L0系列一共有19个AD口对应19个AD通道,其中16到18为检测内部模拟信号的通道。下面代码中用到是PA0即对应通道0,具体代码如下图:
: L" p, U8 T+ v' a/ z6 @2 @7 ^; N# i" j
- Adc_init()
" A, h& D. L& B! i
% p- t; x5 R# _# K* a" a" |) k% a- {
2 k+ y8 ]& u Y/ _6 y; |) _ - __HAL_RCC_ADC1_CLK_ENABLE();
; B& t! d4 o5 d a$ _; b+ \* B - AdcHandle.Instance = ADC1;' r3 D4 A1 \$ Z0 r1 _
- * e/ h O- k) v3 ~# z/ w: g
- AdcHandle.Init.OversamplingMode = DISABLE;
0 d) [; {+ w- l8 ]0 D; d- T - . o( @) M, b; A
- AdcHandle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV1;3 |* C3 R& b3 Z
- AdcHandle.Init.LowPowerAutoPowerOff = DISABLE;
8 X9 V0 }% z" I# k( ^7 \ - AdcHandle.Init.LowPowerFrequencyMode = ENABLE;, Y- `- H. b4 l' c7 }/ }( W7 j: N
- AdcHandle.Init.LowPowerAutoWait = DISABLE;
2 q+ b- g: q/ ^9 A4 [5 j8 |( Z
/ |4 A8 S) k |! u5 ^2 O- AdcHandle.Init.Resolution = ADC_RESOLUTION_12B;; p) A9 Z% u2 `4 U! F
- AdcHandle.Init.SamplingTime = ADC_SAMPLETIME_7CYCLES_5;; \5 \0 I- w6 N; g, v3 s
- AdcHandle.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
! \ _2 O8 w6 c - AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT;& j2 z9 Q: b/ s! ?/ L
- AdcHandle.Init.ContinuousConvMode = ENABLE;
) i0 K; u2 e0 F" K, @ D# r2 f - AdcHandle.Init.DiscontinuousConvMode = DISABLE;
- v2 z9 [; N T3 l) t - AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
- I2 s5 \' [9 l6 F1 x - AdcHandle.Init.EOCSelection = ADC_EOC_SINGLE_CONV;1 P+ p1 ^+ g2 l v
- AdcHandle.Init.DMAContinuousRequests = DISABLE;
% x5 o8 U* N7 n9 k, W& e
% H, {! D4 M4 n# u z- HAL_ADC_Init(&AdcHandle);
/ l4 t- H+ q' m7 X3 ` - HAL_ADCEx_Calibration_Start(&AdcHandle, ADC_SINGLE_ENDED);6 k! ?/ {+ Z# f2 l: ?
- o3 r, D% |. p; P
- }6 I9 K: I; P, t6 E- o0 G; i
- 3 s3 m& ^: d$ O( \ Q8 [7 b
- //配置ADC初始化
; \3 w6 t% C' R( p - # R [' [( X4 m# ^
- void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)1 f K' g! C. u @8 Q: l
- {+ T$ y, F4 t& A+ z
- GPIO_InitTypeDef GPIO_InitStruct;
' ?0 v0 i/ x6 r1 r# p y" D. p2 T - / A6 X R, x' J
- /*##-1- Enable peripherals and GPIO Clocks #################################*/
+ X2 P) m& T' Y1 }% z1 ` - /* Enable GPIO clock ****************************************/
' o( E7 u) m! Y0 f$ a5 r - __HAL_RCC_GPIOA_CLK_ENABLE();
5 f1 p7 t5 i" p0 v6 Y - /* ADC1 Periph clock enable */
" O: j; k- {* G' _ z" { - __HAL_RCC_ADC1_CLK_ENABLE();+ M1 v# R$ [( e: h8 M: u
! b. {* w8 J) U" V7 b! x- /*##- 2- Configure peripheral GPIO #########################################*/
1 u4 Z8 |9 o* e# u8 s, A - /* ADC3 Channel8 GPIO pin configuration */ O2 {/ K* z6 s b8 M
- GPIO_InitStruct.Pin = GPIO_PIN_0;4 z R: C1 E( `6 @4 j Q) |8 } v
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
# J% O. x0 T; E1 l - GPIO_InitStruct.Pull = GPIO_NOPULL;& y3 i# @7 s4 s3 F% i4 n
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
0 Q) }9 p* |2 r; X" L - }& Z, n7 g- X M( @/ t4 v7 ?
- ) u9 \3 R: U% u4 x8 B$ S
- //初始化ADC引脚PA0,开启时钟
) v* K4 {; h. I7 T - & u: P s4 C! f( i
- void get_voltage(void)
0 v7 K# ?* g: U( p6 S: b3 g - {: X" m5 q) }, b, \' X
- bsp_adc_init();
: a, O3 y( }# _2 V6 J, V - HAL_ADCEx_EnableVREFINT();
( k6 E# M' i+ s* @1 [6 H - HAL_ADC_Stop(&AdcHandle);! Y5 r" t/ n) H: L: g$ a. }" a
- AdcHandle.Instance->CHSELR=0;
. G. C% ]. b+ H1 R8 d: ^! {" y4 e* V - sConfig.Channel = ADC_CHANNEL_17; //通道17专门测内部电压值$ Q7 V! e: F4 Q3 q
- HAL_ADC_ConfigChannel(&AdcHandle, &sConfig);( w( B4 \* y: x, H( M
- HAL_ADC_Start(&AdcHandle);
, X+ ?" @) a+ o - HAL_ADC_PollForConversion(&AdcHandle, 10); $ ~+ G5 {5 k6 u n
- /* Check if the continous conversion of regular channel is finished */
: r2 _5 b5 U1 A - if ((HAL_ADC_GetState(&AdcHandle) & HAL_ADC_STATE_REG_EOC) == HAL_ADC_STATE_REG_EOC)
* e7 ~/ e0 l6 t; a/ v; e8 R - {
0 s. g# Z/ u' ]' z ?9 O - /*##-6- Get the converted value of regular channel ########################*/
0 S0 Z# f& R) F( V9 l2 N2 U - uwADCxConvertedValue = HAL_ADC_GetValue(&AdcHandle);& k0 v- g9 Z2 @( ]' V
- }) Q& D7 B6 D, n( q5 |8 e5 n
& a r, E+ p% o- vdd_value=VREF_IN_VALUE*FULL_ADC_DIGTIL_VALUE/uwADCxConvertedValue; //内部电源电压
% d' b0 |8 H8 W5 s - HAL_ADCEx_DisableVREFINT();
: M& V: S: [7 R; a; Q3 q! N, ]1 e - HAL_ADC_Stop(&AdcHandle);
; a9 t/ `* v4 M5 ^8 M3 C - AdcHandle.Instance->CHSELR=0;$ ], ?/ w- K, I
- sConfig.Channel = ADC_CHANNEL_0; //ADC0,去测外部PA0口接的电压* b% \/ I' W' k" e6 J. p* T
- HAL_ADC_ConfigChannel(&AdcHandle, &sConfig);3 j( e7 A& D- ?, e7 {4 v3 s8 u
- HAL_ADC_Start(&AdcHandle);( Z- Z8 N ]6 P; s! T
- HAL_ADC_PollForConversion(&AdcHandle, 10);
7 {5 D- |8 v; f' n - /* Check if the continous conversion of regular channel is finished */
p, a- C& X; x; H3 g. } - if ((HAL_ADC_GetState(&AdcHandle) & HAL_ADC_STATE_REG_EOC) == HAL_ADC_STATE_REG_EOC)2 y O' d4 ` I, i/ @
- {0 ?+ v! S* B4 C# ?
- /*##-6- Get the converted value of regular channel ########################*/9 Q+ F3 W8 d( Y7 V% c4 }
- uwADCxConvertedValue = HAL_ADC_GetValue(&AdcHandle);
- n6 [' i9 ^4 M2 T% X - }
4 R, y: I& v8 ]/ Y3 l, G5 c - //直接获取的是二进制码,14位对应最大值4095,内部电压为vdd_value通过比例计算得到电压数值/ c7 V; D1 g8 J5 |# V9 k$ H
- temp_voltage=(float)uwADCxConvertedValue*vdd_value/4095;( T" k! P, u: q. m; g: ~
- //得到浮点型电压值 是乘了1000倍的 . }" z( Q8 T/ {0 {* S
- HAL_ADC_Stop(&AdcHandle);) r* c! A- |1 [0 O, p" J2 l. T
- //HAL_ADCEx_DisableVREFINT();2 i' C* a( H6 B7 O, x$ n
- __HAL_RCC_ADC1_CLK_DISABLE();7 d) b8 i; ^0 x3 M) l3 y
- }. L9 r9 o% L7 K
- }
复制代码 , h- U" Y- P2 F: u6 i: l; ~
* t3 Q! ~, u: [
以上ADC检测,相当于一次连续检测了两次,第一次为内部电压用的特地通道17,第二次检测的是外部电压对应硬件连接的PA0对应通道0+ @1 [3 ^; M6 B( K' K* B8 m; V* b
; `6 w8 F; M: U
7 _4 F$ C/ Q1 C& \( N# \0 y0 a
|