玩转硬件-手搓电流表

admin 2026-02-17 20:11:48 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文介绍基于ESP8266和INA219模块的锂电池监测系统硬件搭建与软件开发。通过I2C连接INA219电流传感器测量电池电压、电流和功率,使用滑动窗口滤波和库仑计法估算电池电量SOC,并在OLED屏幕实时显示。系统可识别充电、放电和待机状态,未来计划通过MQTT协议实现远程监控。提供完整Arduino源码,适合电子爱好者DIY电池管理项目。 综合评分: 68 文章分类: IoT安全,安全开发,安全工具,其他


cover_image

玩转硬件-手搓电流表

原创

大表哥吆 大表哥吆

kali笔记

2026年2月11日 08:02 甘肃

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

设备清单

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

设备清单

线路连接

| 连接类别 | 设备/引脚端 | 连接至 | | — | — | — | | esp8266-INA219 | GPIO4 OLED (D2) | INA219 SDA | | esp8266-INA219 | GPIO5 OLED(D1) | INA219 SCL | | esp8266-INA219 | 3.3V | INA219 VCC | | esp8266-INA219 | GND | INA219 GND | | 锂电池连接 | 18650 正极 | INA219 (vim -) | | 锂电池连接 | 18650 负极 | esp8266 (GND) | | 充电模块 | 正极 | INA219 (vim +) | | 充电模块 | 负极 | 锂电池负极 | | 用电器(负载) | 设备正极 | INA219 (vim +) | | 用电器(负载) | 设备负极 | esp8266 (GND) |

注意:oled和INA219共用D1和D2脚针

实物连接

效果

充电状态

负载状态

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

后期改进

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

源码

#include&nbsp;<Wire.h>
#include&nbsp;<Adafruit_INA219.h>
#include&nbsp;<U8g2lib.h>

Adafruit_INA219 ina219;
U8G2_SSD1306_128X64_NONAME_F_HW_I2C&nbsp;u8g2(U8G2_R0, U8X8_PIN_NONE);

constfloat&nbsp;BATTERY_CAPACITY =&nbsp;3.5;
constfloat&nbsp;FULL_VOLTAGE =&nbsp;4.15;
constfloat&nbsp;EMPTY_VOLTAGE =&nbsp;3.0;
constfloat&nbsp;CURRENT_THRESHOLD =&nbsp;5.0;
constint&nbsp;FILTER_WINDOW_SIZE =&nbsp;10;

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

float&nbsp;currentBuffer[FILTER_WINDOW_SIZE];
int&nbsp;filterIndex =&nbsp;0;
unsignedlong&nbsp;lastTime =&nbsp;0;

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

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

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

&nbsp; ina219.setCalibration_32V_2A();

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

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

&nbsp; lastTime = millis();

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

void&nbsp;loop()&nbsp;{
unsignedlong&nbsp;currentTime = millis();
float&nbsp;deltaTime = (currentTime - lastTime) /&nbsp;3600000.0;

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

&nbsp; lastTime = currentTime;
&nbsp; delay(1000);
}

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

float&nbsp;filterCurrentValue(float&nbsp;newValue)&nbsp;{
&nbsp; currentBuffer[filterIndex] = newValue;
&nbsp; filterIndex = (filterIndex +&nbsp;1) % FILTER_WINDOW_SIZE;

float&nbsp;sum =&nbsp;0.0;
for&nbsp;(int&nbsp;i =&nbsp;0; i < FILTER_WINDOW_SIZE; i++) {
&nbsp; &nbsp; sum += currentBuffer[i];
&nbsp; }
return&nbsp;sum / FILTER_WINDOW_SIZE;
}

void&nbsp;calculateSOC(float&nbsp;deltaTime)&nbsp;{
if&nbsp;(deltaTime >&nbsp;0) {
&nbsp; &nbsp;&nbsp;float&nbsp;chargeChange = (filteredCurrent /&nbsp;1000.0) * deltaTime;
&nbsp; &nbsp; totalCharge += chargeChange;

&nbsp; &nbsp;&nbsp;float&nbsp;voltageSOC;
&nbsp; &nbsp;&nbsp;if&nbsp;(batteryVoltage >=&nbsp;4.15) {
&nbsp; &nbsp; &nbsp; voltageSOC =&nbsp;100.0;
&nbsp; &nbsp; }&nbsp;elseif&nbsp;(batteryVoltage <=&nbsp;2.7) {
&nbsp; &nbsp; &nbsp; voltageSOC =&nbsp;0.0;
&nbsp; &nbsp; }&nbsp;else&nbsp;{
&nbsp; &nbsp; &nbsp; voltageSOC = ((batteryVoltage -&nbsp;2.7) / (4.15&nbsp;-&nbsp;2.7)) *&nbsp;100.0;
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;float&nbsp;estimatedSOC = (totalCharge / BATTERY_CAPACITY) *&nbsp;100.0;

&nbsp; &nbsp;&nbsp;if&nbsp;(batteryVoltage >=&nbsp;4.1) {
&nbsp; &nbsp; &nbsp; batterySOC = voltageSOC;
&nbsp; &nbsp; }&nbsp;elseif&nbsp;(batteryVoltage <=&nbsp;3.2) {
&nbsp; &nbsp; &nbsp; batterySOC = (estimatedSOC *&nbsp;0.1) + (voltageSOC *&nbsp;0.9);
&nbsp; &nbsp; }&nbsp;else&nbsp;{
&nbsp; &nbsp; &nbsp; batterySOC = (estimatedSOC *&nbsp;0.2) + (voltageSOC *&nbsp;0.8);
&nbsp; &nbsp; }

&nbsp; &nbsp; batterySOC = constrain(batterySOC,&nbsp;0.0,&nbsp;100.0);

&nbsp; &nbsp;&nbsp;if&nbsp;(batterySOC >=&nbsp;99.5) {
&nbsp; &nbsp; &nbsp; batterySOC =&nbsp;100.0;
&nbsp; &nbsp; }
&nbsp; }
}

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

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

void&nbsp;displayOnOLED()&nbsp;{
&nbsp; u8g2.clearBuffer();
&nbsp; u8g2.setFont(u8g2_font_ncenB08_tr);

&nbsp; u8g2.setCursor(0,&nbsp;10);
&nbsp; u8g2.print(F("Voltage: "));
&nbsp; u8g2.print(batteryVoltage,&nbsp;2);
&nbsp; u8g2.print(F(" V"));

&nbsp; u8g2.setCursor(0,&nbsp;24);
&nbsp; u8g2.print(F("Current: "));
&nbsp; u8g2.print(filteredCurrent,&nbsp;0);
&nbsp; u8g2.print(F(" mA"));

&nbsp; u8g2.setCursor(0,&nbsp;38);
&nbsp; u8g2.print(F("Power: "));
&nbsp; u8g2.print(power_mW,&nbsp;0);
&nbsp; u8g2.print(F(" mW"));

&nbsp; u8g2.setCursor(0,&nbsp;52);
&nbsp; u8g2.print(F("SOC: "));
&nbsp; u8g2.print(batterySOC,&nbsp;1);
&nbsp; u8g2.print(F(" %"));

&nbsp; u8g2.setCursor(0,&nbsp;64);
&nbsp; u8g2.print(F("Status: "));
if&nbsp;(batteryState ==&nbsp;"充电中") {
&nbsp; &nbsp; u8g2.print(F("Charging"));
&nbsp; }&nbsp;elseif&nbsp;(batteryState ==&nbsp;"放电中") {
&nbsp; &nbsp; u8g2.print(F("Discharging"));
&nbsp; }&nbsp;else&nbsp;{
&nbsp; &nbsp; u8g2.print(F("Idle"));
&nbsp; }

&nbsp; u8g2.sendBuffer();
}

更多精彩文章 欢迎关注我们


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:kali笔记 大表哥吆 大表哥吆《玩转硬件-手搓电流表》

评论:0   参与:  0