← До всіх проєктів
Сенсори Середній

Вимірювач струму й енергії на INA219: скільки насправді споживає ваш пристрій

Вмикаємо INA219 у розрив живлення й бачимо в браузері напругу, струм, потужність і накопичені мВт·год. Незамінно для оцінки автономності пристроїв на батарейках.

Складність
Середній
Час
1–2 h
Категорія
Сенсори

Навіщо

Мультиметр показує миттєвий струм, але пристрій на 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;
  }
}

Як користуватися

  1. Підключіть навантаження й відкрийте IP вимірювача в браузері.
  2. Натисніть Reset і залиште пристрій працювати хоча б кілька циклів сну/пробудження (наприклад, 30 хв).
  3. Поле 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, частота опитування.
  • Моніторинг сонячної панелі та заряду акумулятора.