一、简介
博主在使用ADC测量电池电压时,发现测出来的AD值转换为实际电压不匹配,偏差大,因此通过网上收集资料,最终得知ADC采集精度提升的方法。前半部分主要是涉及多通道电压值采集,CubeMx的配置以及代码实现,以采集ADC1通道0、通道8和内部基准电压为例。后半部分讲解使用内部基准电压计算精确度较高的电压值。
二、运行环境
MCU: STM32L071CBT6
配置工具:STM32CubeMx
IDE:MDK5
三、CubeMx配置
时钟配置:
使用RCC外部低速时钟。
ADC配置:
开启ADC的通道0、通道8和内部电压通道。
当使用多通道采集时,Discontinuous Conversion Mode(间断转换模式)要使能。
串口配置:
博主所用的板子将LPUART1引出来当调试串口,用来打印ADC转换的AD值,以验证ADC转换成功,串口配置如下,波特率设为9600Bit/s,Word Length为8 Bit,其余设置不变。
四、代码实现
上述配置完生成代码如下:
printf函数映射
#include
//printf函数映射
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&hlpuart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
为了使ADC采集值更准确,在ADC初始化完后使用HAL库函数HAL_ADCEx_Calibration_Start做自校准。
MX_ADC_Init();
if (HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED) != HAL_OK)
{
printf("校准失败\r\n");
}
采集数据并打印
uint8_t i;
uint16_t adValue[3];
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
for (i = 0; i < 3; i ++)
{
if (HAL_ADC_Start(&hadc) != HAL_OK)
{
printf("ADC开启失败\r\n");
}
if (HAL_ADC_PollForConversion(&hadc, 10) != HAL_OK)//等待转换完成,第二个参数表示超时时间,单位ms
{
printf("ADC转换失败\r\n");
}
if (HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc), HAL_ADC_STATE_REG_EOC))
{
adValue[i] = HAL_ADC_GetValue(&hadc);
printf("通道[%d]:%d\r\n", i, adValue[i]);
}
}
HAL_ADC_Stop(&hadc);
HAL_Delay(1000);
}
串口助手输出如下
通道[0]对应的为配置里的IN0,通道[1]对应的为配置里的IN8,通道[2]对应的为配置里的内部电压通道。由于通道[0]没有接任何输入电压,所以其采出来的AD值近乎为0,通道[1]通过外部做了1/2分压所以其采集出来的AD值为2326,通道[2]采集的是内部参考电压实际值,从数据手册可以得知内部参考电压的校准值存于地址0X1FF80078。
可将其值读出来:
uint16_t VREFINT_CAL;
VREFINT_CAL = *(__IO uint16_t *)(0X1FF80078);
printf("VREFINT_CAL:%d\r\n",VREFINT_CAL);
VREFINT_CAL = 1674,该值是在25°C,输入电压为3V情况下得到得,实际板子供电电压并不是如此,因此得出来会有误差,但基本接近。通道1的电压是博主自己给的,通过万用表测量得实际电压为1.71V。而理论代入公式应为:
(通道[1]AD值 / 4096) * 3.3V = (2297 / 4096) * 3.3 = 1.85V
跟实际差太多。通过查阅资料得知,为了更准确的获得采集的电压,需要使用内部参考电压计算实际的供电电压,将电源相关的 ADC 测量值转换为绝对电压值。具体计算公式在参考手册中:
VREFINT_CAL即为内部参考电压的校准值为1674,ADC_DATAx即为通道[1]测出来的AD值,VREFINT_DATA为内部参考电压实际值,即为通道[2]的值。所使用的单片机ADC分辨率为12位所以FULL_SCALE的值为4095。将上述值代入公式,用代码实现如下:
float realVol;
realVol = (float)(3 * VREFINT_CAL * adValue[1]) / (adValue[2] * 4095)
printf("V = %.4f\r\n", realVol);
最终得出的电压值在1.71V左右浮动,因此通过此方法可以测量出更精确的电压值。