Вимірювач струму й енергії на INA219: скільки насправді споживає ваш пристрій
Вмикаємо INA219 у розрив живлення й бачимо в браузері напругу, струм, потужність і накопичені мВт·год. Незамінно для оцінки автономності пристроїв на батарейках.
Навіщо
Мультиметр показує миттєвий струм, але пристрій на ESP32 споживає імпульсно: 150 мА на пів секунди під час Wi-Fi, потім 10 мкА уві сні. Щоб чесно порахувати, на скільки вистачить акумулятора, потрібно інтегрувати споживання в часі. Саме це робить наш вимірювач: він опитує INA219 сотні разів на секунду і накопичує енергію в мВт·год.
Компоненти
- ESP32 DevKit (вимірювач)
- Модуль INA219 (шунт 0.1 Ом: до 26 В і ±3.2 А)
- Пристрій, який вимірюємо, і його джерело живлення
Підключення
INA219 вмикається в розрив плюсового дроту навантаження:
Джерело + ──► VIN+ [INA219] VIN- ──► + Навантаження
Джерело − ──────┬──────────────────► − Навантаження
└── GND INA219 ── GND ESP32
Мінус джерела, GND модуля та GND ESP32 мають бути з'єднані — інакше INA219 не зможе виміряти напругу.
| INA219 | ESP32 |
|---|---|
| VCC / GND | 3V3 / GND |
| SDA / SCL | GPIO 21 / GPIO 22 |
Бібліотека
Adafruit INA219 (разом з Adafruit BusIO).
Код
#include <WiFi.h>
#include <WebServer.h>
#include <Wire.h>
#include <Adafruit_INA219.h>
const char* WIFI_SSID = "YOUR_SSID";
const char* WIFI_PASS = "YOUR_PASSWORD";
Adafruit_INA219 ina;
WebServer server(80);
float voltage = 0, current = 0, power = 0, peakCurrent = 0;
double energy_mWh = 0;
unsigned long lastSample = 0;
unsigned long startedAt = 0;
const char PAGE[] = R"rawliteral(
<!doctype html><html><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Power meter</title>
<style>
body{font-family:system-ui;max-width:520px;margin:30px auto;padding:0 16px}
.g{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.c{background:#f1f4f7;border-radius:10px;padding:14px}
.v{font-size:1.8rem;font-weight:700}.l{color:#667;font-size:.9rem}
button{margin-top:16px;padding:10px 16px;font-size:1rem}
</style></head><body>
<h2>Power meter</h2>
<div class="g">
<div class="c"><div class="v" id="V">-</div><div class="l">V</div></div>
<div class="c"><div class="v" id="I">-</div><div class="l">mA</div></div>
<div class="c"><div class="v" id="P">-</div><div class="l">mW</div></div>
<div class="c"><div class="v" id="E">-</div><div class="l">mWh</div></div>
<div class="c"><div class="v" id="K">-</div><div class="l">peak mA</div></div>
<div class="c"><div class="v" id="A">-</div><div class="l">avg mA</div></div>
</div>
<button onclick="fetch('/reset').then(update)">Reset</button>
<script>
async function update() {
const d = await (await fetch('/data')).json();
V.textContent = d.v.toFixed(3); I.textContent = d.i.toFixed(1);
P.textContent = d.p.toFixed(0); E.textContent = d.e.toFixed(2);
K.textContent = d.peak.toFixed(0); A.textContent = d.avg.toFixed(2);
}
update(); setInterval(update, 1000);
</script></body></html>
)rawliteral";
void resetStats() {
energy_mWh = 0;
peakCurrent = 0;
startedAt = millis();
}
void setup() {
Serial.begin(115200);
if (!ina.begin()) {
Serial.println("INA219 not found");
while (true) delay(1000);
}
// Для слабких струмів (до 400 мА) точніше: ina.setCalibration_16V_400mA();
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) delay(500);
Serial.println(WiFi.localIP());
server.on("/", [] { server.send(200, "text/html", PAGE); });
server.on("/reset", [] { resetStats(); server.send(200, "text/plain", "ok"); });
server.on("/data", [] {
double hours = (millis() - startedAt) / 3600000.0;
double avg_mA = (hours > 0 && voltage > 0.1) ? energy_mWh / hours / voltage : 0;
char json[160];
snprintf(json, sizeof(json),
"{\"v\":%.3f,\"i\":%.2f,\"p\":%.1f,\"e\":%.4f,\"peak\":%.1f,\"avg\":%.3f}",
voltage, current, power, energy_mWh, peakCurrent, avg_mA);
server.send(200, "application/json", json);
});
server.begin();
resetStats();
lastSample = millis();
}
void loop() {
server.handleClient();
// Опитуємо ~200 разів на секунду, щоб не пропустити короткі піки
unsigned long now = millis();
if (now - lastSample >= 5) {
unsigned long dt = now - lastSample;
lastSample = now;
voltage = ina.getBusVoltage_V() + ina.getShuntVoltage_mV() / 1000.0;
current = ina.getCurrent_mA();
power = voltage * current; // мВт
energy_mWh += power * dt / 3600000.0; // мВт × год
if (current > peakCurrent) peakCurrent = current;
}
}
Як користуватися
- Підключіть навантаження й відкрийте IP вимірювача в браузері.
- Натисніть Reset і залиште пристрій працювати хоча б кілька циклів сну/пробудження (наприклад, 30 хв).
- Поле avg mA — середній струм. Автономність ≈
ємність акумулятора (мА·год) / avg mAгодин.
Приклад: датчик із проєкту «Датчик на батарейці» показав 0.7 мА у середньому → акумулятор 2000 мА·год протримається ~2850 год ≈ 4 місяці.
Обмеження
- INA219 з шунтом 0.1 Ом має роздільну здатність ~0.1 мА. Струми сну в мікроамперах він не побачить — для них потрібен спеціалізований прилад (Nordic PPK2, µCurrent) або шунт 10 Ом.
- Опитування раз на 5 мс пропускає імпульси коротші за кілька мілісекунд — для оцінки середнього цього достатньо.
- Максимум 26 В — не підключайте до мережі 230 В!
Ідеї
- Лог у CSV на SD-карту для графіків.
- Порівняння різних оптимізацій сну: статичний IP, ESP-NOW, частота опитування.
- Моніторинг сонячної панелі та заряду акумулятора.