0%

HAL库 - ADC

在STM32中,集成了12位逐次逼近型ADC。
12位:指ADC的采样深度,使用12位2进制数来表示一个采样点。例如4位ADC,就是把0-3.3V分成了2^4 -1份,每份为0.22V。参考下表

二进制数对应电压
00000V
00010.22V
00110.44V
11113.30V

逐次逼近型(SAR):每次比较输入电压与内部基准电压,逐步逼近输入电压。
默认的ADC时钟为4Mhz(最大为14Mhz)。
假设输入到ADC的时钟周期为14Mhz,时钟周期为$\frac{1}{14}MHz$ us
采样时间$0.1 us = 1.5 \times \frac{1}{14} us = 1.5 cycle$
转换时间$0.9 us = 12.5 \times \frac{1}{14} us = 12.5 cycle$

最优采样时间计算:

$$
T_S = (R_{AIN} + R_{ADC}) \times C_{ADC} * ln(2^{N+2})
$$

$R_{AIN}$ 表示模拟输入的内阻
$R_{ADC}$表示采样保持电路的电阻,为1k欧姆
$C_{ADC}$表示采样保持电路的电容,为8pF
$ln(2^{N+2})$里面的N表示采样深度,为12

带入计算,得到:
$$
T_S = (R_{AIN} + 1000) \times 77.6 * 10^{-12}
$$
只和模拟输入的内阻有关。

例如,当$R_{AIN}$ = 400欧姆时
$$
T_S = (400 + 1000) \times 77.6 * 10^{-12} = 0.11us
$$
当$R_{AIN}$ = 10k欧姆时
$$
T_S = (10e3 + 1000) \times 77.6 * 10^{-12} = 0.85us
$$
当$R_{AIN}$ = 50k欧姆时
$$
T_S = (50e3 + 1000) \times 77.6 * 10^{-12} = 3.96us
$$

计算cycle还要在后面乘上$f_{ADC}$,例如设置的$f_{ADC} = 14MHz$
当$R_{AIN}$ = 400欧姆时
$$
T_S = 0.11us \times f_{ADC} = 0.11us \times 14MHz = 1.54 cycle
$$
当$R_{AIN}$ = 10k欧姆时
$$
T_S = 0.85us \times f_{ADC} = 0.85us \times 14MHz = 11.9 cycle
$$
当$R_{AIN}$ = 50k欧姆时
$$
T_S = 3.96us \times f_{ADC} = 3.96us \times 14MHz = 55.4 cycle
$$

常用函数

1
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef *hADC);

作用:启动常规序列

1
HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef *hADC, uint32_t Timeout);

作用:以轮询(标志位)的方式等待(常规序列)转换完成

1
uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef *hADC);

作用:获取常规序列的转换结果

示例:单通道转换ADC,光敏电阻点灯

光敏电阻的阻值为10k欧姆,计算采样时间
$$
T_S = (1e4 + 1000) \times 77.6 * 10^{-12} = 0.85us
$$
设定的ADC时钟为4MHz,计算cycle
$$
T_S = 0.85us \times 4MHz = 3.4cycle
$$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  while (1)
{
//1.启动常规序列
HAL_ADC_Start(&hadc1);
//2.等待转换完成
HAL_ADC_PollForConversion(&hadc1,HAL_MAX_DELAY);
//3.把转换结果保存在DR中
uint32_t dr = HAL_ADC_GetValue(&hadc1);
//4.把结果转换为电压
float voltage = dr * (3.3f - 0.0f) / 4095.0f;
if(voltage > 1.5f)//光线暗
{
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_2,GPIO_PIN_SET);
}
else//光线亮
{
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_2,GPIO_PIN_RESET);
}
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}

示例:定时器触发ADC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
	HAL_TIM_Base_Start(&htim3);//启动TIM3
HAL_ADC_Start(&hadc1);//启动ADC
while (1)
{
//1.等待转换结束
HAL_ADC_PollForConversion(&hadc1,HAL_MAX_DELAY);
//2.读取转换结果
uint32_t dr = HAL_ADC_GetValue(&hadc1);
//3.将结果转换成电压
float voltage = dr * (3.3f - 0.0f) / 4095.0f;
//4.串口发送出去
char buffer[32];
sprintf(buffer,"%.3f\n",voltage);
HAL_UART_Transmit(&huart1,(uint8_t*)buffer,strlen(buffer), HAL_MAX_DELAY);
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}