· 807字 · 2分钟 · 阅读量

持久化 🔗

为实现断电记忆功能,我们可以将累计的电池容量和总能量值保存到 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);
}

修改说明 🔗

  1. EEPROM 初始化

    • setup() 中初始化 EEPROM,并从中读取之前保存的电池容量和总能量值。
  2. 定期保存数据

    • loop() 中,每隔 10 秒将累计的电池容量和总能量值写入 EEPROM。
    • 使用 EEPROM.put 写入数据,EEPROM.commit 提交更改。
  3. 校验读取数据

    • 如果读取的值为 NaN(无效数据),将其重置为 0,确保数据正确。

注意事项 🔗

  1. EEPROM 写入寿命

    • ESP32 的 EEPROM 模拟 Flash 存储,写入寿命有限(大约 10,000 次)。定期保存间隔不宜过短。
  2. 内存大小

    • 确保 EEPROM 的定义大小(64 字节)足够存储数据。
  3. 断电后的恢复

    • 断电后设备重启时,会从 EEPROM 恢复保存的数据,避免从 0 开始累计。

运行结果 🔗

  • 设备通电后,会读取上次保存的电池容量和总能量,并在 OLED 和串口中显示。
  • 每 10 秒保存一次新计算的数据,确保断电后依旧能够恢复数据。