Built-in project · ESP32-C3-DevKitM-1

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.

The circuit runs here once the page has loaded.

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.

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 pinConnects to
Sixteen-bit ADC, ADS1115 pin VDDESP32-C3-DevKitM-1 pin 3V3
Current monitor, INA219 pin VCCESP32-C3-DevKitM-1 pin 3V3
Current monitor, INA219 pin VIN+ESP32-C3-DevKitM-1 pin 3V3
Resistor, 220 Ω pin 1ESP32-C3-DevKitM-1 pin GND
Sixteen-bit ADC, ADS1115 pin GNDESP32-C3-DevKitM-1 pin GND
Current monitor, INA219 pin GNDESP32-C3-DevKitM-1 pin GND
Sixteen-bit ADC, ADS1115 pin SDAESP32-C3-DevKitM-1 pin 8
Current monitor, INA219 pin SDAESP32-C3-DevKitM-1 pin 8
Sixteen-bit ADC, ADS1115 pin SCLESP32-C3-DevKitM-1 pin 9
Current monitor, INA219 pin SCLESP32-C3-DevKitM-1 pin 9
Sixteen-bit ADC, ADS1115 pin A0Resistor, 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.

sketch.ino · ESP32-C3-DevKitM-1
// 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.