原理:为什么用VREFINT反推VDDA
STM32的ADC参考电压来自VDDA引脚。当电池电压下降时,VDDA随之变化,导致ADC转换结果失去绝对参考。VREFINT是芯片内部一个与电源无关的带隙基准电压,典型值1.20V(具体见数据手册),连接至ADC的固定内部通道(如STM32F1为通道17)。
- 测量VREFINT得到ADC原始值
adc_vrefint - 已知VREFINT典型电压
VREFINT_CAL(如1.20V) - 则当前VDDA = VREFINT_CAL × 满量程 / adc_vrefint
- 再用VDDA作为参考去换算电池分压后的ADC值,即可得到真实电池电压
该方法无需外部基准芯片,仅需一次出厂校准(或利用芯片内置校准值),成本极低。
关键校准数据来源
STM32在系统存储区(System Memory)中预置了VREFINT的校准值 VREFINT_CAL,该值是在VDDA=3.3V、温度25℃条件下测得的ADC原始值。不同系列地址不同,例如STM32F1为 0x1FFFF7BA(16位)。使用该值可消除芯片间VREFINT的个体差异。
- 若芯片无内置校准值,可自行在已知VDDA(如3.3V)下测量一次VREFINT ADC值作为校准
- 校准值仅代表典型条件,实际应用中建议结合软件滤波
配置步骤
- 使能ADC时钟与GPIO时钟,配置电池检测引脚为模拟输入
- 配置ADC为单次转换或扫描模式,使能内部通道VREFINT
- 设置采样时间足够长(VREFINT内阻较大,建议≥17.1μs)
- 依次转换VREFINT通道和电池通道,读取原始值
- 用公式计算VDDA与电池电压
完整代码示例(以STM32F1 HAL库为例)
#include "stm32f1xx_hal.h"
ADC_HandleTypeDef hadc1;
#define VREFINT_CAL_ADDR ((uint16_t*)0x1FFFF7BA) // 内置校准值地址
#define VREFINT_TYPICAL 1.20f // 典型VREFINT电压
#define ADC_FULL_SCALE 4095.0f // 12位ADC
#define BATT_DIV_RATIO 2.0f // 分压比(R1+R2)/R2
// 读取指定ADC通道的原始值
static uint16_t adc_read_channel(uint32_t channel)
{
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = channel;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; // 长采样
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 10);
uint16_t val = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
return val;
}
// 获取当前VDDA电压(单位V)
float get_vdda(void)
{
uint16_t vrefint_raw = adc_read_channel(ADC_CHANNEL_VREFINT);
uint16_t vrefint_cal = *VREFINT_CAL_ADDR;
// 公式:VDDA = 3.3V * VREFINT_CAL / vrefint_raw
// 等价于用典型值:VDDA = VREFINT_TYPICAL * FULL / raw
// 推荐使用内置校准值以消除个体差异:
return 3.3f * (float)vrefint_cal / (float)vrefint_raw;
}
// 获取电池电压(单位V)
float get_battery_voltage(void)
{
float vdda = get_vdda();
uint16_t batt_raw = adc_read_channel(ADC_CHANNEL_0); // 假设电池接PA0
return vdda * (float)batt_raw / ADC_FULL_SCALE * BATT_DIV_RATIO;
}
注意事项
- 采样时间:VREFINT内部阻抗较高,采样时间不足会导致读数偏低,建议≥17.1μs(如239.5周期@14MHz)
- 多次平均:单次测量噪声较大,建议对VREFINT和电池通道各采样8~16次取平均
- 温度影响:VREFINT随温度有微小漂移(典型±20ppm/℃),高精度场景需温度补偿
- VDDA范围:确保VDDA在数据手册规定范围内(通常2.0V~3.6V),过低时VREFINT可能失效
- 分压电阻:电池分压电阻不宜过大(建议≤100kΩ),否则ADC输入阻抗影响精度;同时考虑漏电流对电池的消耗
- 校准值地址:不同STM32系列地址不同,务必查阅对应参考手册
- 低功耗场景:测量时短暂开启ADC,完成后关闭以节省功耗
总结
利用VREFINT反推VDDA,无需外部基准即可实现电池电压的绝对测量,成本低、精度满足多数应用。核心是使用芯片内置校准值消除个体差异,并保证足够采样时间与软件滤波。掌握该方法后,可轻松扩展至低电量报警、充电管理等功能。
暂无评论,来抢沙发~