持久化 🔗
为实现断电记忆功能,我们可以将累计的电池容量和总能量值保存到 ESP32 的 EEPROM 或类似的非易失性存储器中。这样即使设备断电,再次通电后也能从上次保存的状态继续。
以下是修改后的代码,增加了 EEPROM 的使用:
修改后的代码 🔗
#include <EEPROM.h>
// EEPROM 地址设置
#define EEPROM_SIZE 64 // EEPROM大小
#define CAPACITY_ADDR 0 // 电池容量存储的起始地址
#define ENERGY_ADDR 4 // 总能量存储的起始地址
void setup()
{
Serial.begin(115200);
Wire.begin();
// 初始化 EEPROM
EEPROM.begin(EEPROM_SIZE);
// 从 EEPROM 读取断电前保存的累计电池容量和总能量
EEPROM.get(CAPACITY_ADDR, totalCapacity_mAh);
EEPROM.get(ENERGY_ADDR, totalEnergy_Wh);
// 校验是否读取有效数据
if (isnan(totalCapacity_mAh)) totalCapacity_mAh = 0.0;
if (isnan(totalEnergy_Wh)) totalEnergy_Wh = 0.0;
Serial.print("Restored Capacity [mAh]: ");
Serial.println(totalCapacity_mAh);
Serial.print("Restored Energy [Wh]: ");
Serial.println(totalEnergy_Wh);
// 其余初始化代码保持不变...
}
void loop()
{
float shuntVoltage_mV = 0.0;
float loadVoltage_V = 0.0;
float busVoltage_V = 0.0;
float current_mA = 0.0;
float power_mW = 0.0;
shuntVoltage_mV = ina226.getShuntVoltage_mV();
busVoltage_V = ina226.getBusVoltage_V();
current_mA = ina226.getCurrent_mA();
power_mW = ina226.getBusPower();
loadVoltage_V = busVoltage_V + (shuntVoltage_mV / 1000);
checkForI2cErrors();
float current_A = current_mA / 1000.0; // 将电流从 mA 转换为 A
float power_W = power_mW / 1000.0; // 将功率从 mW 转换为 W
// 计算电池容量 (mAh)
unsigned long currentMillis = millis();
float deltaTimeHours = (currentMillis - lastMillis) / 3600000.0; // 时间间隔(小时)
lastMillis = currentMillis;
totalCapacity_mAh += current_mA * deltaTimeHours; // 累加容量 (mAh)
// 计算总能量 (Wh)
totalEnergy_Wh += power_W * deltaTimeHours; // 功率 (W) x 时间 (h)
// 定期将累计值保存到 EEPROM
static unsigned long lastSaveMillis = 0;
if (currentMillis - lastSaveMillis >= 10000) // 每 10 秒保存一次
{
EEPROM.put(CAPACITY_ADDR, totalCapacity_mAh);
EEPROM.put(ENERGY_ADDR, totalEnergy_Wh);
EEPROM.commit(); // 提交保存数据到 EEPROM
lastSaveMillis = currentMillis;
Serial.println("Data saved to EEPROM.");
}
// OLED 显示布局保持不变
display.clearDisplay();
display.setTextSize(1); // 设置文字大小
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("U: ");
display.print(loadVoltage_V, 3);
display.print(" V");
display.setCursor(64, 0);
display.print("I: ");
display.print(current_A, 3);
display.print(" A");
display.setCursor(0, 16);
display.print("P: ");
display.print(power_W, 3);
display.print(" W");
display.setCursor(0, 32);
display.print("C: ");
display.print(totalCapacity_mAh, 3);
display.print(" mAh");
display.setCursor(0, 48);
display.print("E: ");
display.print(totalEnergy_Wh, 3);
display.print(" Wh");
display.display();
delay(1000);
}
修改说明 🔗
-
EEPROM 初始化
- 在
setup()
中初始化EEPROM
,并从中读取之前保存的电池容量和总能量值。
- 在
-
定期保存数据
- 在
loop()
中,每隔 10 秒将累计的电池容量和总能量值写入 EEPROM。 - 使用
EEPROM.put
写入数据,EEPROM.commit
提交更改。
- 在
-
校验读取数据
- 如果读取的值为
NaN
(无效数据),将其重置为 0,确保数据正确。
- 如果读取的值为
注意事项 🔗
-
EEPROM 写入寿命
- ESP32 的 EEPROM 模拟 Flash 存储,写入寿命有限(大约 10,000 次)。定期保存间隔不宜过短。
-
内存大小
- 确保 EEPROM 的定义大小(64 字节)足够存储数据。
-
断电后的恢复
- 断电后设备重启时,会从 EEPROM 恢复保存的数据,避免从 0 开始累计。
运行结果 🔗
- 设备通电后,会读取上次保存的电池容量和总能量,并在 OLED 和串口中显示。
- 每 10 秒保存一次新计算的数据,确保断电后依旧能够恢复数据。