电池电量实时预测手表
💡 划重点
- 主控采用 ESP32-S3,成本可控且具备原生 Wi-Fi/蓝牙能力。
- 电量感知使用 MAX17048 高精度库仑计芯片,通过 I2C 读取电压与剩余电量。
- 表盘显示使用 0.96 英寸 I2C OLED,全局共用 I2C 总线。
- 两个物理按键分别用于切换显示页面与触发手动校准。
- 关键创新:基于线性回归的剩余使用时长预测模型,而非简单显示百分比。
- 整机 BOM 成本控制在 95 元以内,适合极客批量制作。
- 代码基于 Arduino 框架编写,可直接编译烧录,支持日志串口输出与网络时间同步。
需求洞察
目标用户是电子极客、DIY 手表爱好者、嵌入式学习者和长续航穿戴设备尝鲜者。佩戴者常见的痛点是:普通智能手表电量显示不准确,往往 20% 瞬间掉到 5%,导致焦虑;同时现有手表只能显示百分比,无法估计剩余可用分钟数。充电频次高、电池健康度衰减无感知,使用体验粗糙。
本项目值得做的原因在于,通过 MAX17048 的动态电压检测与库仑积分算法,结合 ESP32-S3 的本地计算能力,可以实时预测电池在当前负载模式下的剩余使用时间,并将预测结果可视化显示在 OLED 上。这不仅提升了表盘的信息密度,更具备教育意义——让玩家理解电池模型、I2C 通信和低功耗调度。整个系统成本低、零件易得,适合极客群体作为周末项目,也可作为嵌入式课程的综合实践案例。
方案设计
感知层:MAX17048 负责电池电压、电流、充放电状态和剩余容量估算,输出数据格式为 16 位寄存器,硬件 I2C 地址为 0x36。它内部集成电压与电流累计器,可输出带符号的剩余容量百分比。电量感知采用库仑计模式,比单纯查表法准确度高。
控制层:ESP32-S3 负责所有逻辑处理,通过 Wire 库读取 MAX17048 数据,运行轻量级平滑滤波和线性回归算法,预测剩余使用时间。同时驱动 OLED 屏幕进行画面渲染。系统使用 FreeRTOS 任务:传感器读取任务、显示刷新任务、按键扫描与省电管理任务。
执行层:OLED 显示剩余百分比、预测剩余分钟数、当前电流估算、电压值。按键短按切换电压/电流/预测时间显示页面;长按执行电池零点校准,清除 MAX17048 的累计误差。
日志/联网层:系统通过串口输出结构化的电量日志,便于上位机分析。可选连接 Wi-Fi 获取网络时间戳,用于日志记录校准曲线。日志数据包含电压、电流、预测分钟数、电池温度等,便于玩家跟踪电池劣化趋势,建立长期预测模型。
物料清单
| 序号 | 物料名称 | 数量 | 用途 | 估算单价(元) |
|---|---|---|---|---|
| 1 | ESP32-S3-DevKitC-1 开发板 | 1 | 主控 | 30.0 |
| 2 | MAX17048 电量计模块 | 1 | 电压/电量感知 | 15.0 |
| 3 | 0.96 英寸 OLED(I2C) | 1 | 显示 | 12.0 |
| 4 | 侧按轻触按键 | 2 | 交互输入 | 1.5 |
| 5 | 3.7V 18650 锂电池(或聚合物电池) | 1 | 供电 | 18.0 |
| 6 | 充电保护板(TP4056 或 IP5306) | 1 | 充电管理 | 5.0 |
| 7 | 外壳/表带/PCB 转接板/导线/电阻 | 若干 | 装配结构 | 12.0 |
| 8 | 总计 | - | - | 93.5 |
总成本 93.5 元,未超 95 元预算。若使用裸片 ESP32-S3-WROOM 模块自己画最小系统,还能再省 8 元,但需要额外焊接工作。
接线与结构
- GPIO 8(I2C SDA)、GPIO 9(I2C SCL):并联连接 MAX17048 与 OLED,共用上拉电阻(4.7kΩ)。
- GPIO 3:接入左侧按键(参数切换),一端接 GND,另一端接 GPIO。
- GPIO 4:接入右侧按键(校准触发),一端接 GND,另一端接 GPIO。
- 电池正极连接 MAX17048 的 BAT 引脚和充电保护板输出。ESP32-S3 的 VIN(5V 输入)由充电保护板提供。
此接线方案保留了 GPIO 0、GPIO 1 等常用下载/调试引脚,方便后续烧录和调试。按键直接连接到地线,内部启用 ESP32-S3 的上拉输入,无需外部电阻。I2C 总线上的两个设备地址互不冲突(MAX17048 地址 0x36,OLED 通常为 0x3C)。如需扩展,可将 OLED 地址改为 0x3D。
核心代码
以下为核心 Arduino 骨架代码,包含电量读取与预测显示逻辑。
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <MAX17048.h>
#define OLED_SDA 8
#define OLED_SCL 9
#define BTN_PAGE 3
#define BTN_CAL 4
Adafruit_SSD1306 display(128, 64, &Wire;, -1);
MAX17048 battery(0x36);
float predictMinutes;
int page = 0;
float samples[10];
int idx = 0;
void readBatteryData() {
voltage = battery.voltage();
percent = battery.percent();
current = battery.current(); // mA
}
void updatePrediction() {
samples[idx] = current;
idx = (idx + 1) % 10;
float avgCurrent = 0;
for (int i = 0; i < 10; i++) avgCurrent += samples[i];
avgCurrent /= 10;
if (avgCurrent > 5.0) {
// 已知电池平均容量 mAh,预测剩余时间(分钟)
float capacity = 1800; // mAh
predictMinutes = (capacity * percent / 100.0) / (avgCurrent / 60.0);
} else {
predictMinutes = 9999;
}
}
void setup() {
Serial.begin(115200);
battery.begin();
}
void loop() {
readBatteryData();
updatePrediction();
if (digitalRead(BTN_PAGE) == LOW) {
page = (page + 1) % 3;
delay(200);
}
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
display.setCursor(0, 16);
if (page == 0) {
display.print("Pct: "); display.print(percent); display.println(" %");
} else if (page == 1) {
} else {
display.print("Remain: ");
if (predictMinutes > 999) {
display.println(">10h");
} else {
}
}
if (digitalRead(BTN_CAL) == LOW) {
battery.quickStart();
display.println("CAL");
delay(300);
}
display.display();
delay(500);
}
代码可直接在 PlatformIO 或 Arduino IDE 中编译,需要安装 Adafruit SSD1306 与 MAX17048 库。预测模型通过读取最近 10 次采样电流值的滑动平均来估算剩余时间,避免单次突变的干扰。
调试步骤
- 先只焊接最小系统:ESP32-S3 + I2C 总线,使用 I2C 扫描程序确认两个设备地址。
- 单独读取 MAX17048 的电压和百分比,对比万用表实测电压校准。
- 测试 OLED 显示,通过修改
display.println验证连接是否稳定。 - 连接电池后,测量空载与烧录时电流差异,确定库仑计工作正常。
- 使用示波器或逻辑分析仪检查 I2C 时序,关注 400kHz 速率下的波形质量。
- 按键扫描使用内部上拉,若出现误触则添加 100ms 去抖。
- 连续运行 2 小时,记录显示预测时间与实际时间对比,调整
capacity参数。