INA219 Current & Voltage Sensor

How to measure current and voltage with the INA219 sensor and ESP32

The INA219 is a high-side current and voltage sensor that communicates over I2C. It can measure the voltage across a load, the current flowing through it, and calculate power -- all from a single chip. This makes it ideal for monitoring battery charge levels, solar panel output, motor current draw, or the power consumption of any DC circuit.

"High-side" means the INA219 sits between the power supply and the load (on the positive rail), so your load's ground connection stays undisturbed. This is the preferred approach for most monitoring applications.

🔗Key Specs

ParameterValue
Operating voltage3.0V -- 5.5V
Bus voltage range0 -- 26V
Current range+/- 3.2A (default config)
Current resolution0.8 mA (default config)
ADC resolution12-bit
InterfaceI2C
I2C address0x40 (default, configurable)
Shunt resistor0.1 ohm (on most breakout boards)

The I2C address can be changed by bridging solder pads on the breakout board, allowing up to four INA219 sensors on the same I2C bus (addresses 0x40, 0x41, 0x44, 0x45).

🔗What You'll Need

ComponentQtyNotesBuy
ESP32 dev board1AliExpress | Amazon.de .co.uk .com
INA219 current sensor module1AliExpress | Amazon.de .co.uk .com
Breadboard1AliExpress | Amazon.de .co.uk .com
Jumper wires4AliExpress | Amazon.de .co.uk .com

Links marked Amazon/AliExpress are affiliate links. We may earn a small commission at no extra cost to you.

🔗Wiring

The INA219 has two sets of connections: the I2C interface to the ESP32, and the measurement terminals that go in series with your load.

🔗I2C Connections

INA219 PinESP32 Pin
VCC3.3V
GNDGND
SDAGPIO 21
SCLGPIO 22

Board variation note: The default I2C pins on the ESP32-WROOM-32 DevKit are GPIO 21 (SDA) and GPIO 22 (SCL), but pin labels, GPIO numbers, and I2C defaults vary between ESP32 boards. Always check your specific board's pinout diagram.

🔗Measurement Connections

The INA219 breakout has two screw terminals (or header pins) labeled VIN+ and VIN-. You wire these in series with the load you want to measure:

Power Supply (+) ----> VIN+ [INA219] VIN- ----> Load (+)
Power Supply (-) -----------------------------------> Load (-)

The sensor measures the tiny voltage drop across its internal 0.1 ohm shunt resistor to calculate current. Using Ohm's law:

$$I = \frac{V_{shunt}}{R_{shunt}}$$

For example, if the shunt voltage reads $32\,\text{mV}$ across the $0.1\,\Omega$ resistor:

$$I = \frac{0.032\,\text{V}}{0.1\,\Omega} = 0.32\,\text{A} = 320\,\text{mA}$$

Important: The circuit being measured can have a voltage up to 26V and is completely separate from the ESP32's 3.3V power. The INA219 handles the level shifting internally. Just make sure VIN+ and VIN- are wired in series with your load -- not in parallel.

🔗High-Side vs. Low-Side Measurement

  • High-side (recommended): The INA219 sits between the power supply's positive terminal and the load's positive input. The load's ground remains connected directly to the supply ground. This is what the INA219 is designed for.
  • Low-side: The sensor sits between the load's ground and the supply ground. This can cause ground potential issues and is generally not recommended with the INA219.

🔗Required Libraries

Install through the Arduino IDE Library Manager:

  • Adafruit INA219 -- handles register configuration, calibration, and reading measurements.

This library also installs Adafruit BusIO as a dependency.

🔗Code Example

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

Adafruit_INA219 ina219;

void setup() {
    Serial.begin(115200);
    Wire.begin();

    if (!ina219.begin()) {
        Serial.println("Failed to initialize INA219. Check wiring.");
        while (1);
    }

    Serial.println("INA219 ready.");
    Serial.println("Voltage (V) | Current (mA) | Power (mW)");
    Serial.println("------------|--------------|----------");
}

void loop() {
    float busVoltage   = ina219.getBusVoltage_V();       // Voltage across the load
    float current_mA   = ina219.getCurrent_mA();         // Current through the load
    float power_mW     = ina219.getPower_mW();            // Power consumed by the load
    float shuntVoltage = ina219.getShuntVoltage_mV();    // Voltage across the shunt

    // The actual load voltage is busVoltage + (shuntVoltage / 1000)
    float loadVoltage = busVoltage + (shuntVoltage / 1000.0);

    Serial.print(loadVoltage, 3);
    Serial.print(" V    |  ");
    Serial.print(current_mA, 2);
    Serial.print(" mA   |  ");
    Serial.print(power_mW, 2);
    Serial.println(" mW");

    delay(1000);
}

🔗How It Works

  1. Shunt resistor -- The INA219 breakout board includes a precision $0.1\,\Omega$ shunt resistor. All the current flowing to your load passes through this resistor, creating a small voltage drop. The INA219's internal 12-bit ADC measures this drop with high precision.

  2. Bus voltage -- The INA219 also measures the voltage on the load side of the shunt (the "bus voltage"). Combined with the shunt voltage, you can calculate the actual supply voltage reaching your load.

  3. Power calculation -- The INA219 can compute power internally using:

$$P = V \cdot I$$

The getPower_mW() function returns this calculated value directly, saving you from doing the multiplication yourself.

  1. Calibration and gain -- By default, the Adafruit library configures the INA219 for a maximum current of 3.2A with 0.8 mA resolution. If you need to measure smaller currents more precisely, you can switch to higher-resolution mode:
// For higher resolution (max 400 mA, 0.1 mA resolution)
ina219.setCalibration_16V_400mA();

This trades maximum measurable current for better resolution. Choose the mode that fits your application:

ModeMax VoltageMax CurrentCurrent Resolution
setCalibration_32V_2A()32V2A~1 mA
setCalibration_32V_1A()32V1A~0.4 mA
setCalibration_16V_400mA()16V400 mA~0.1 mA
  1. I2C address configuration -- The INA219 breakout has solder pads (often labeled A0 and A1) that let you change the I2C address. This allows multiple INA219 modules on the same bus -- for example, one monitoring a battery and another monitoring a motor.

Tip: When measuring battery voltage, remember that getBusVoltage_V() measures the voltage after the shunt resistor. For the true supply voltage, add the shunt voltage: $V_{supply} = V_{bus} + V_{shunt}$. At low currents the difference is negligible, but at higher currents it can matter.

🔗Troubleshooting

ProblemPossible CauseSolution
Failed to initialize errorWiring issue or wrong I2C addressVerify SDA/SCL connections; run an I2C scanner sketch
Current reads 0 mALoad is not connected through VIN+/VIN-Ensure VIN+ and VIN- are wired in series with the load, not in parallel
Voltage reads 0VNo power applied to the measured circuitThe INA219 only reads voltage from the circuit connected to VIN+/VIN-
Negative current readingsVIN+ and VIN- are swappedSwap the connections so current flows from VIN+ to VIN-
Current maxes out at ~3.2ADefault calibration limit reachedThis is the default maximum; use a different shunt resistor for higher currents
Readings are noisyLong wires or interferenceUse short, twisted wires for VIN+ and VIN-; add decoupling capacitors
Multiple sensors not detectedSame I2C addressConfigure different addresses using the A0/A1 solder pads

🔗Next Steps

  • Build a battery monitor that tracks voltage, current, and remaining capacity over time.
  • Monitor a solar panel's output to see how power production changes throughout the day.
  • Measure the current draw of different ESP32 sleep modes to optimize battery life.
  • Use multiple INA219 modules to monitor individual subsystems in a larger project.
  • Send power data over WiFi to a dashboard for real-time monitoring.