STM32L476低电压环境下电池电量精准测量技巧,HAL编程DMA多通道ADC采集与内部基准修正实战指南。
1、项目背景概述
1.1、供电低于外部校准电压,导致ADC采集不准描述
最近接触的项目是由3.6V(新电池)电池供电,需要在3.4V、3.2V、2.9V分别提示一级、二级、三级低电,低于2.9V认为掉电。同时还有一个7.2V(新电池)通信电池,也需要精准采集电压。项目需要LCD点阵液晶屏显示,要求可设开启或关闭背光灯。
但是在开启背光灯的时候,电压采集很明显不准(偏高),原因是开启背光需要很大的电流,导线上也有点阻值,导致接入板子的电压只有3.4V,再经过二极管和稳压芯片后达不到理想的3.0V电压(实际只有2.7V)给单片机供电,其此电压也是连接STM32单片机的外部基准电压。如果电池电压实际低于3.6V可能检测结果更离谱。
根据查阅芯片手册,可以采用STM32L476单片机内部基准电压修正,达到精准检测的目的。
1.2、理想状态
想要的理想情况是,只要不低于单片机重启电压,对外部电池电压能精准的采集。如上图电路所示,若外接电池是3.2V,经过D95二极管再经过U90稳压芯片到系统供电(只有2.7V),不足理想的3.0V系统供电,但需要ADC采集电池电压是3.2V左右,而不是因为系统供电低而偏高这种错误情况出现。
通过DMA多通道采集电压,HAL库编程。实验目的:
①DMA方式多通道采集电压。
②采用内部基准电压修正读取的电压值。
2、解决方案
2.1、解决方案描述
这里直接拿出精简公式
Vbat : 待求电池电压值
Vdda: 单片机VDDA引脚接入的外部基准电压,我这边是3.0V。
vrefint:单片机内部存储的参考电压值,STM32L476单片机存储地址在0x1FFF75AA~0x1FFF75AB
BATadc:当前实际的电池的ADC值(我这选择的12bit)。
VREadc:当前实际的内部通道的ADC值(我这选择的12bit),STM32L476单片机采集通道是ADC1_IN0 。
其中4096表示选择12bit精度,如果选择10bit精度则是1024,具体原理参考博文STM32 ADC采样使用内部参考电压_stm32adc参考电压-CSDN博客
2.2、HAL库编程配置实现
1、打开debug调试,并配置系统时钟,我这边使用的内部高速时钟。
2、首先打开自己项目对应的通道(15通道3.6V电池,16通道7.2V通道),然后开启内部基准电压采集通道。
3、ADC1的通道参数配置,根据自己项目需求开打对应的通道配置。
4、采用的是DMA数据传输,如下配置。
2.3、HAL库编程程序实现
1、获取内部的基准电压值,用于修正读取的电压。
#define VREFINT_CAL (uint16_t)(*(__I uint16_t *)(0x1FFF75AA))//读取内部存储的基准值
2、通过DMA读取三个通道的ADC值,并做计算得出电压值(扩大100倍的)。
void dong_start_adc()
{
if (HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED) != HAL_OK)
{
Error_Handler();
}
//启动DMA
if(HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_Values,ADC_MAX_NUM) != HAL_OK)
{
Error_Handler();
}
// while(!(__HAL_DMA_GET_FLAG(&hdma_adc1,DMA_FLAG_TC1))){;}//等待DMA转换完成
// __HAL_DMA_CLEAR_FLAG(&hdma_adc1,DMA_FLAG_TC1);//清楚DMA标志位
HAL_DMA_PollForTransfer(&hdma_adc1,HAL_DMA_FULL_TRANSFER,1000);
// HAL_Delay (10);
HAL_ADC_Stop_DMA(&hadc1);//停止ADC常规组转换,禁用ADC DMA传输
uint32_t VBAT1_mV,VBAT2_mV;
uint16_t vrefint = *((uint16_t*)0x1FFF75AA);//获取单片机内部校验电压值(固定不变的)
double vrefint_f,bat1_t,bat2_t;
vrefint_f = ADC_Values[2]; //读取当前的内部基准电压ad值
bat1_t = ADC_Values[0]; //读取当前的3.6V电池电压ad值
bat2_t = ADC_Values[1]; //读取当前的7.2V电池电压ad值
VBAT1_mV = 3000*(3.0*(vrefint/4096.0))*(bat1_t/vrefint_f);//计算计量电池电压(默认扩大1000倍)
VBAT2_mV = 6000*(3.0*(vrefint/4096.0))*(bat2_t/vrefint_f);//计算通讯电池电压(默认扩大1000倍)
HAL_Delay(2000);
}
3、其中3000*公式 与 6000*公式,分别是根据硬件电路的分压公式。
4、看实际效果如下:
作者:L一宇航员的嵌入式笔记