The INA219 measures current through a small shunt resistor and the voltage on the load side, all over I2C. With the R100 shunt fitted to the common purple board, two register reads give you volts, milliamps, milliwatts and a running mAh total.
Wire the module to 3V3 and I2C0 (GP4/GP5), then put it in the positive wire of the circuit you want to measure: supply + to VIN+, VIN− to the load. Keep that circuit to DC under 26 V.
Wiring
| Raspberry Pi Pico W | INA219 DC current/voltage sensor | Wire | Notes |
|---|---|---|---|
| — | VIN- | — | To Load + (load − back to supply −) (not drawn) |
| 3V3 | VCC | red | 3V3 is pin 36. Pull-ups follow VCC. |
| GND | GND | black | Shared ground: the INA219, the Pico and the measured circuit. |
| GP5 | SCL | yellow | GP5 is physical pin 7 (I2C0 SCL). |
| GP4 | SDA | blue | GP4 is physical pin 6 (I2C0 SDA). |
| Circuit supply to measure (up to 26 V DC) · + | VIN+ | red | The current flows in through VIN+ and out of VIN− to the load (high-side measurement). |
| Circuit supply to measure (up to 26 V DC) · - | GND | black | Without a shared ground the bus voltage reads nonsense. |
3.0–5.5 V part, 3.3 V board. Power VCC from your board's logic voltage (3.3 V or 5 V); the I2C pull-ups go to VCC, so they match your board.
Board quirks
- No calibration register is needed: the script reads the shunt voltage (10 µV per bit) and divides by the 0.1 Ω R100 shunt. A different shunt? Change
SHUNT_OHMS. - The default ±320 mV shunt range means up to 3.2 A with R100. The INA219 measures up to 26 V on the bus — never mains.
- Bus voltage is measured at VIN−, i.e. what your load actually gets.
- The mAh counter integrates current over time — run a battery-powered gadget for an hour and you have its real consumption.
Code
# INA219 current / voltage / power monitor on a Raspberry Pi Pico W (MicroPython, no library).
# Wiring: VCC -> 3V3 (pin 36), GND -> GND (also the measured circuit's GND), SCL -> GP5 (pin 7),
# SDA -> GP4 (pin 6). Measured circuit: supply + -> VIN+, VIN- -> load +. Max 26 V, 3.2 A.
# Assumes the usual R100 (0.1 Ohm) shunt on the purple breakout.
from machine import Pin, I2C
import time
SHUNT_OHMS = 0.1
i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400_000)
found = i2c.scan()
addr = None
for a in (0x40, 0x41, 0x44, 0x45):
if a in found:
addr = a
break
if addr is None:
raise SystemExit("No INA219 at 0x40/0x41/0x44/0x45 - found {}".format([hex(a) for a in found]))
# Config 0x3FFF: 32 V bus range, +-320 mV shunt range, 12-bit x128 averaging, continuous.
i2c.writeto_mem(addr, 0x00, bytes([0x3F, 0xFF]))
def reg(r, signed=False):
hi, lo = i2c.readfrom_mem(addr, r, 2)
v = (hi << 8) | lo
return v - 65536 if signed and v > 32767 else v
print("INA219 at", hex(addr))
mah = 0.0
last = time.ticks_ms()
while True:
shunt_mv = reg(0x01, True) * 0.01 # 10 uV per bit, signed
bus_v = (reg(0x02) >> 3) * 0.004 # 4 mV per bit: the voltage at VIN- (what the load sees)
ma = shunt_mv / SHUNT_OHMS
now = time.ticks_ms()
mah += ma * time.ticks_diff(now, last) / 3_600_000
last = now
print("Load {:.3f} V {:7.1f} mA {:7.1f} mW used {:.2f} mAh".format(bus_v, ma, bus_v * ma, mah))
time.sleep(1)# INA219 current / voltage / power monitor on a Raspberry Pi Pico W (MicroPython, no library).
# Wiring: VCC -> 3V3 (pin 36), GND -> GND (also the measured circuit's GND), SCL -> GP5 (pin 7),
# SDA -> GP4 (pin 6). Measured circuit: supply + -> VIN+, VIN- -> load +. Max 26 V, 3.2 A.
# Assumes the usual R100 (0.1 Ohm) shunt on the purple breakout.
from machine import Pin, I2C
import time
SHUNT_OHMS = 0.1
i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400_000)
found = i2c.scan()
addr = None
for a in (0x40, 0x41, 0x44, 0x45):
if a in found:
addr = a
break
if addr is None:
raise SystemExit("No INA219 at 0x40/0x41/0x44/0x45 - found {}".format([hex(a) for a in found]))
# Config 0x3FFF: 32 V bus range, +-320 mV shunt range, 12-bit x128 averaging, continuous.
i2c.writeto_mem(addr, 0x00, bytes([0x3F, 0xFF]))
def reg(r, signed=False):
hi, lo = i2c.readfrom_mem(addr, r, 2)
v = (hi << 8) | lo
return v - 65536 if signed and v > 32767 else v
print("INA219 at", hex(addr))
mah = 0.0
last = time.ticks_ms()
while True:
shunt_mv = reg(0x01, True) * 0.01 # 10 uV per bit, signed
bus_v = (reg(0x02) >> 3) * 0.004 # 4 mV per bit: the voltage at VIN- (what the load sees)
ma = shunt_mv / SHUNT_OHMS
now = time.ticks_ms()
mah += ma * time.ticks_diff(now, last) / 3_600_000
last = now
print("Load {:.3f} V {:7.1f} mA {:7.1f} mW used {:.2f} mAh".format(bus_v, ma, bus_v * ma, mah))
time.sleep(1)Expected serial output
INA219 at 0x40
Load 11.912 V 142.3 mA 1695.1 mW used 0.04 mAh
Load 11.908 V 145.0 mA 1726.7 mW used 0.08 mAhINA219 at 0x40 Load 11.912 V 142.3 mA 1695.1 mW used 0.04 mAh Load 11.908 V 145.0 mA 1726.7 mW used 0.08 mAh
Common errors
Current reads negative
VIN+ and VIN− are swapped. The supply goes to VIN+, the load to VIN−.
Voltage reads 0 V but current looks right
The measured circuit’s ground is not joined to the INA219 GND.