battery_monitor 电池电量监测模块
概述
battery_monitor
是一个用于监测电池电量和电压的组件,基于 ESP-IDF 的 ADC(模数转换器)功能。该模块通过测量电池电压,计算出电池的剩余电量百分比,并提供了相应的 API 接口。
支持功能:
- 电压测量: 通过 ADC 测量电池电压。
- 电量计算: 根据电压值计算电池的剩余电量百分比。
- 校准功能: 提供校准功能,用于补偿 ADC 和电池电压的测量误差。
要将组件添加到项目中请在IDF终端执行下方命令:
idf.py add-dependency "ningzixi/battery_monitor^1.0.0"
battery_monitor 仓库地址:
https://github.com/NingZiXi/battery_monitor.git
硬件要求
电池电压分压电路,将电池电压分压到 ADC 输入引脚。
1. ADC 工作原理及电路设计
ESP32S3 的 ADC 通道可以读取输入引脚上的模拟电压,并将其转换为数值。ESP32 内置两个 ADC 模块,每个模块有多个通道,支持 0~3.3V 的输入电压。
然而,大部分电池(如 18650 锂电池)的电压通常高于 3.3V,因此需要通过分压电路将电压降至 ADC 可测范围。
电池电压检测电路:
如下图所示,我们使用了一个简单的分压电路,将电池电压(VB+)通过电阻分压降低到适合 ADC 输入的范围。
VB+ ---- R1 (20k) ----+---- R2 (10k) ---------- GND
|-----C1 (100nF)---|
IO2
- R1 和 R2:构成一个分压器,将电池电压缩小到三分之一。
- C1 (100nF):去耦电容,滤除高频干扰。
- IO2:ADC 读取点。
校准
修改battery_monitor.h中的 ADC_OFFSET
和 VOL_OFFSET
参数,以补偿 ADC 和电池电压的测量误差。
具体计算步骤如下:
1. ADC_OFFSET
(ADC 偏移电压校正)
ADC_OFFSET
用于补偿 ADC 原始值的偏差。
计算步骤:
-
测量实际输入电压:
使用精确的万用表测量分压电路输出到 ADC 输入引脚的实际电压,记为V_actual
。 -
读取 ADC 输出电压:
运行git_adc_voltage()
代码读取 ADC 转换的电压值,记为V_adc_raw
。 -
计算偏移:
ADC_OFFSET = V actual − V adc_raw \text{ADC\_OFFSET} = V_{\text{actual}} - V_{\text{adc\_raw}} ADC_OFFSET=Vactual−Vadc_raw
采样多组数据,取平均值,以降低噪声影响。
2. VOL_OFFSET
(电池电压校正)
VOL_OFFSET
用于校正计算出的电池电压偏差。
计算步骤:
-
测量电池电压:
使用万用表直接测量电池端子的实际电压,记为V_battery_actual
。 -
计算推导电压:
使用battery_monitor_get_voltage()
测量电池电压,记为V_battery_calculated
。 -
计算校正偏移:
VOL_OFFSET = V battery_actual − V battery_calculated \text{VOL\_OFFSET} = V_{\text{battery\_actual}} - V_{\text{battery\_calculated}} VOL_OFFSET=Vbattery_actual−Vbattery_calculated
在多个不同电压水平(例如电池电量高、中、低)下测量并校正,以确保偏移在整个范围内有效。
使用示例
#include "battery_monitor.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#define TAG "Main"
void app_main()
{
// 初始化电池监测模块
battery_monitor_init();
while (1) {
float voltage = battery_monitor_get_voltage();
float percentage = battery_monitor_get_percentage();
ESP_LOGI(TAG, "Battery Voltage: %.2f V", voltage);
ESP_LOGI(TAG, "Battery Percentage: %.2f%%", percentage);
vTaskDelay(pdMS_TO_TICKS(1000)); // 每秒打印一次
}
}