Current and voltage on an ESP32-C3
An INA219 in series with a 220 ohm load and an ADS1115 on the same node, both on I2C: milliamps through a real shunt, and one voltage read in 4 mV and in 125 uV steps. The whole build, an ESP32-C3 and 3 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
Teaching? Assign it to your class in one click.
Intermediate About 25 minutes to build and run. Runs in your browser. Free, and no account needed.
The parts retail for about $16.05. On Mokxi they're free.
What you'll learn
- Measuring current with a shunt resistor
- Two I2C devices at different addresses on one bus
- Comparing two ways to measure the same voltage
- ADC counts versus volts
- Difficulty: Intermediate
- Time: About 25 minutes
- Board: ESP32-C3-DevKitM-1
- Parts: 5
How it works
The INA219 sits in series with the load: 3.3 V goes into VIN+ and VIN- carries on to a 220 ohm resistor to ground. Inside the chip is a 0.1 ohm shunt. It reads the few millivolts across the shunt to get the current, and also reads the voltage on the load side.
The ADS1115 has its A0 input on the same load-side node, so the two chips measure the same voltage in two ways. Both share the I2C pins, GPIO 8 and 9.
Every half second the sketch prints the current in mA, the power in mW, and both voltage readings.
Parts list
5 parts, plus the jumper wires. They retail for about $16.05; on Mokxi they're free.
- 1 × ESP32-C3-DevKitM-1In Handheld Console Kit, Desk Buddy Kit.
- 1 × Half breadboard
- 1 × Resistor, 220 ΩIn Starter Kit, Claw Machine Kit, Halloween Prop Kit.
- 1 × Sixteen-bit ADC, ADS1115
- 1 × Current monitor, INA219
Wiring table
Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.
| Part and pin | Connects to |
|---|---|
| Sixteen-bit ADC, ADS1115 pin VDD | ESP32-C3-DevKitM-1 pin 3V3 |
| Current monitor, INA219 pin VCC | ESP32-C3-DevKitM-1 pin 3V3 |
| Current monitor, INA219 pin VIN+ | ESP32-C3-DevKitM-1 pin 3V3 |
| Resistor, 220 Ω pin 1 | ESP32-C3-DevKitM-1 pin GND |
| Sixteen-bit ADC, ADS1115 pin GND | ESP32-C3-DevKitM-1 pin GND |
| Current monitor, INA219 pin GND | ESP32-C3-DevKitM-1 pin GND |
| Sixteen-bit ADC, ADS1115 pin SDA | ESP32-C3-DevKitM-1 pin 8 |
| Current monitor, INA219 pin SDA | ESP32-C3-DevKitM-1 pin 8 |
| Sixteen-bit ADC, ADS1115 pin SCL | ESP32-C3-DevKitM-1 pin 9 |
| Current monitor, INA219 pin SCL | ESP32-C3-DevKitM-1 pin 9 |
| Sixteen-bit ADC, ADS1115 pin A0 | Resistor, 220 Ω pin 2 |
| Current monitor, INA219 pin VIN- | Resistor, 220 Ω pin 2 |
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// A load's current and its voltage, two ways: an INA219 at 0x40 and an
// ADS1115 at 0x48 on the ESP32-C3's I2C pins, GPIO 8 and 9.
//
// The INA219 is in series with the load: 3.3 V into VIN+, VIN- on to a 220
// ohm resistor to ground. Its 0.1 ohm shunt is a real resistor in the
// circuit, and the chip reads the few millivolts across it to 10 uV, and the
// voltage on the load side to 4 mV. The library writes the chip's calibration
// in begin(); without it the current register reads zero whatever flows.
//
// The ADS1115's A0 is on the same load-side node, so the two chips measure
// the same voltage: the INA219 in 4 mV steps, the ADS1115 at GAIN_ONE in
// 125 uV steps, a single-shot conversion taking 7.8 ms at the default rate.
//
// Change the resistor in the properties panel and watch both follow.
#include <Wire.h>
#include <Adafruit_INA219.h>
#include <Adafruit_ADS1X15.h>
Adafruit_INA219 ina219;
Adafruit_ADS1115 ads;
void setup() {
Serial.begin(115200);
if (!ina219.begin()) Serial.println("no INA219 at 0x40");
ads.setGain(GAIN_ONE);
if (!ads.begin()) Serial.println("no ADS1115 at 0x48");
}
void loop() {
int16_t counts = ads.readADC_SingleEnded(0);
Serial.print("load ");
Serial.print(ina219.getCurrent_mA());
Serial.print(" mA, ");
Serial.print(ina219.getPower_mW());
Serial.print(" mW INA219 says ");
Serial.print(ina219.getBusVoltage_V());
Serial.print(" V, ADS1115 says ");
Serial.print(ads.computeVolts(counts));
Serial.print(" V (");
Serial.print(counts);
Serial.println(" counts)");
delay(500);
}
Code walkthrough
The key functions of the sketch, and what each one does.
setup sketch.ino
Opens serial at 115200 baud and starts the INA219. The library calibrates the chip when it starts, and without calibration the current reads zero. It then sets the ADS1115 gain with GAIN_ONE and starts it. A failed start prints a message such as no INA219 at 0x40.
void setup() {
Serial.begin(115200);
if (!ina219.begin()) Serial.println("no INA219 at 0x40");
ads.setGain(GAIN_ONE);
if (!ads.begin()) Serial.println("no ADS1115 at 0x48");
}loop sketch.ino
Takes one reading from the ADS1115 channel 0 with readADC_SingleEnded. Then it prints the INA219's current, power and bus voltage, and the ADS1115's voltage as both volts and raw counts. It waits half a second.
void loop() {
int16_t counts = ads.readADC_SingleEnded(0);
Serial.print("load ");
Serial.print(ina219.getCurrent_mA());
Serial.print(" mA, ");
Serial.print(ina219.getPower_mW());
Serial.print(" mW INA219 says ");
Serial.print(ina219.getBusVoltage_V());
Serial.print(" V, ADS1115 says ");
Serial.print(ads.computeVolts(counts));
Serial.print(" V (");
Serial.print(counts);
Serial.println(" counts)");
delay(500);
}Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- The current always reads zero This project
The load must pass through the INA219. Check VIN+ goes to 3.3 V and VIN- goes to the resistor. - no INA219 or no ADS1115 appears This project
Check SDA on GPIO 8 and SCL on GPIO 9, and power and ground on both chips. - The two voltages differ a little This project
That is normal. The INA219 reads in 4 mV steps and the ADS1115 in much finer steps. - The LED is dim, burns out, or the pin reads wrong because the resistor value is off. Resistor
Read the color bands again. A 220 ohm to 330 ohm resistor suits a typical LED on 5 V. 10k is a common pull-up or pull-down value. Check with a multimeter if unsure. - A pull-up or pull-down resistor is missing, so the input floats and reads random values. Resistor
Tie the input to 5 V or ground through about 10k. Or use INPUT_PULLUP and wire the switch to ground. - Readings are clipped or too small. Sixteen-bit ADC
The gain sets the full scale, not the supply. The default gain covers 6.144 V, but inputs must stay within VDD plus 0.3 V. Pick a smaller range for small signals. - The ADC is not found on I2C. Sixteen-bit ADC
The address is 0x48 to 0x4B, set by the ADDR pin: GND, VDD, SDA or SCL. Check wiring and set ADDR to a defined level. - The current reads zero or negative. Current monitor
Put the shunt in series with the load, not across the supply. The load current must flow from VIN+ to VIN-. Swap them if the sign is reversed.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.