如何获取锂电池的电压、电流、电量等信息呢?本文基于ESP8266 + INA219 实现电池监测。喜欢就收藏吧!

设备清单

  • esp8266
  • INA219模块
  • 18650锂电池
  • 5v充电模块
  • 0.96Oled屏幕
    设备清单

线路连接

连接类别设备/引脚端连接至
esp8266-INA219GPIO4 OLED (D2)INA219 SDA
esp8266-INA219GPIO5 OLED(D1)INA219 SCL
esp8266-INA2193.3VINA219 VCC
esp8266-INA219GNDINA219 GND
锂电池连接18650 正极INA219 (vim -)
锂电池连接18650 负极esp8266 (GND)
充电模块正极INA219 (vim +)
充电模块负极锂电池负极
用电器(负载)设备正极INA219 (vim +)
用电器(负载)设备负极esp8266 (GND)

效果

类似电流表,可实时测量电池的电压,电流、容量、充放电状态等。

后期改进

后期,我们可以通过MQTT协议,将电池信息通过json发送。这样我们便可以远程查看电池的信息了。

源码

#include <Wire.h>
#include <Adafruit_INA219.h>
#include <U8g2lib.h>

Adafruit_INA219 ina219;
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

const float BATTERY_CAPACITY = 3.5;
const float FULL_VOLTAGE = 4.15;
const float EMPTY_VOLTAGE = 3.0;
const float CURRENT_THRESHOLD = 5.0;
const int FILTER_WINDOW_SIZE = 10;

float batteryVoltage = 0.0;
float shuntVoltage_mV = 0.0;
float current_mA = 0.0;
float filteredCurrent = 0.0;
float power_mW = 0.0;
float batterySOC = 50.0;
float totalCharge = 0.0;
String batteryState = "";

float currentBuffer[FILTER_WINDOW_SIZE];
int filterIndex = 0;
unsigned long lastTime = 0;

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    delay(1);
  }

  Serial.println("ESP8266 + INA219 电池监测系统启动中...");

  if (!ina219.begin()) {
    Serial.println("INA219初始化失败!请检查接线");
    while (1);
  }

  ina219.setCalibration_32V_2A();

  u8g2.begin();
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_ncenB10_tr);
  u8g2.setCursor(20, 35);
  u8g2.print(F("Starting..."));
  u8g2.sendBuffer();
  delay(2000);

  for (int i = 0; i < FILTER_WINDOW_SIZE; i++) {
    currentBuffer[i] = 0.0;
  }

  lastTime = millis();

  Serial.println("INA219初始化成功!");
  Serial.println("使用滑动窗口滤波 + 库仑计法");
  Serial.println("----------------------------------------");
  Serial.println("电压(V) | 分流电压 | 电流(mA) | 功率(mW) | 电量(%) | 状态");
  Serial.println("----------------------------------------");
}

void loop() {
  unsigned long currentTime = millis();
  float deltaTime = (currentTime - lastTime) / 3600000.0;

  readBatteryData();
  filteredCurrent = filterCurrentValue(current_mA);
  calculateSOC(deltaTime);
  determineState();
  displayData();
  displayOnOLED();

  lastTime = currentTime;
  delay(1000);
}

void readBatteryData() {
  batteryVoltage = ina219.getBusVoltage_V();
  shuntVoltage_mV = ina219.getShuntVoltage_mV();
  current_mA = ina219.getCurrent_mA();
  power_mW = ina219.getPower_mW();
}

float filterCurrentValue(float newValue) {
  currentBuffer[filterIndex] = newValue;
  filterIndex = (filterIndex + 1) % FILTER_WINDOW_SIZE;
  
  float sum = 0.0;
  for (int i = 0; i < FILTER_WINDOW_SIZE; i++) {
    sum += currentBuffer[i];
  }
  return sum / FILTER_WINDOW_SIZE;
}

void calculateSOC(float deltaTime) {
  if (deltaTime > 0) {
    float chargeChange = (filteredCurrent / 1000.0) * deltaTime;
    totalCharge += chargeChange;
    
    float voltageSOC;
    if (batteryVoltage >= 4.15) {
      voltageSOC = 100.0;
    } else if (batteryVoltage <= 2.7) {
      voltageSOC = 0.0;
    } else {
      voltageSOC = ((batteryVoltage - 2.7) / (4.15 - 2.7)) * 100.0;
    }
    
    float estimatedSOC = (totalCharge / BATTERY_CAPACITY) * 100.0;
    
    if (batteryVoltage >= 4.1) {
      batterySOC = voltageSOC;
    } else if (batteryVoltage <= 3.2) {
      batterySOC = (estimatedSOC * 0.1) + (voltageSOC * 0.9);
    } else {
      batterySOC = (estimatedSOC * 0.2) + (voltageSOC * 0.8);
    }
    
    batterySOC = constrain(batterySOC, 0.0, 100.0);
    
    if (batterySOC >= 99.5) {
      batterySOC = 100.0;
    }
  }
}

void determineState() {
  if (filteredCurrent > CURRENT_THRESHOLD) {
    batteryState = "充电中";
  } else if (filteredCurrent < -CURRENT_THRESHOLD) {
    batteryState = "放电中";
  } else if (filteredCurrent > 1.0 && batteryVoltage >= 4.0) {
    batteryState = "充电中";
  } else {
    batteryState = "待机";
  }
}

void displayData() {
  Serial.print(batteryVoltage, 2);
  Serial.print("V   | ");
  Serial.print(shuntVoltage_mV, 1);
  Serial.print("mV | ");
  Serial.print(filteredCurrent, 0);
  Serial.print("mA | ");
  Serial.print(power_mW, 0);
  Serial.print("mW | ");
  Serial.print(batterySOC, 1);
  Serial.print("%  | ");
  Serial.println(batteryState);
}

void displayOnOLED() {
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_ncenB08_tr);
  
  u8g2.setCursor(0, 10);
  u8g2.print(F("Voltage: "));
  u8g2.print(batteryVoltage, 2);
  u8g2.print(F(" V"));
  
  u8g2.setCursor(0, 24);
  u8g2.print(F("Current: "));
  u8g2.print(filteredCurrent, 0);
  u8g2.print(F(" mA"));
  
  u8g2.setCursor(0, 38);
  u8g2.print(F("Power: "));
  u8g2.print(power_mW, 0);
  u8g2.print(F(" mW"));
  
  u8g2.setCursor(0, 52);
  u8g2.print(F("SOC: "));
  u8g2.print(batterySOC, 1);
  u8g2.print(F(" %"));
  
  u8g2.setCursor(0, 64);
  u8g2.print(F("Status: "));
  if (batteryState == "充电中") {
    u8g2.print(F("Charging"));
  } else if (batteryState == "放电中") {
    u8g2.print(F("Discharging"));
  } else {
    u8g2.print(F("Idle"));
  }
  
  u8g2.sendBuffer();
}

相关计算公式

$容量(mAh) = \sum |I(t)| \times \Delta t(h)$

最后修改:2026 年 02 月 11 日
可怜可怜吧!正在沿街乞讨~