Built-in project · Arduino Uno R3

Energy meter on an Arduino Uno

An INA228 on a 12 V load adds up the joules and coulombs through its shunt, and an OPT3001 reads the light falling on the panel that would charge it. The whole build, an Arduino Uno 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 20 minutes to build and run. Runs in your browser. Free, and no account needed.

The parts retail for about $45. On Mokxi they're free.

The circuit runs here once the page has loaded.

What you'll learn

  • Measuring current with a shunt resistor
  • Power, energy and charge as running totals
  • Reading several I2C sensors on one Uno
  • Joules and coulombs versus watt hours and amp hours
  • Difficulty: Intermediate
  • Time: About 20 minutes
  • Board: Arduino Uno R3
  • Parts: 7

How it works

An INA228 power monitor sits in series with a 12 V filament lamp. It measures the small voltage across its shunt to find current, reads the bus voltage, and works out power. It also adds up the energy in joules and the charge in coulombs on its own, the way a battery monitor does.

The Uno only has to read those totals. Every half second it prints voltage, current in mA, power in mW, energy in J and charge in C. A coulomb count of 3600 is one amp hour.

An OPT3001 light sensor on A4 and A5 reports lux, standing in for a solar panel that would charge the battery.

Parts list

7 parts, plus the jumper wires. They retail for about $45; 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
Power and energy monitor, INA228 pin SCLArduino Uno R3 pin SCL
Power and energy monitor, INA228 pin SDAArduino Uno R3 pin SDA
Power and energy monitor, INA228 pin GNDArduino Uno R3 pin GND
Ambient light, OPT3001 pin VCCArduino Uno R3 pin 5V
Ambient light, OPT3001 pin GNDArduino Uno R3 pin GND
Ambient light, OPT3001 pin SDAArduino Uno R3 pin A4
Ambient light, OPT3001 pin SCLArduino Uno R3 pin A5
Power and energy monitor, INA228 pin VCC5 V
Power and energy monitor, INA228 pin VBUS12 V
Power and energy monitor, INA228 pin IN+12 V
Filament lamp pin 1Power and energy monitor, INA228 pin IN-
Filament lamp pin 2Ground

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · Arduino Uno R3
// Energy meter: an INA228 on a 12 V load adds up the energy and the charge
// that flow through its shunt, the way a battery monitor counts what is
// left, and an OPT3001 reads the light falling on the solar panel that
// would charge the battery.
//
//   INA228    SDA -> SDA   SCL -> SCL   in series with the load
//   OPT3001   SDA -> A4    SCL -> A5
//
// The chip keeps the running totals itself, so the sketch only reads them:
// joules of energy and coulombs of charge (3600 coulombs is one amp hour).
//
// Things to try. Swap the lamp for another model and watch the totals climb
// faster or slower. Drag the light slider on the OPT3001.

#include <Adafruit_INA228.h>
#include <ClosedCube_OPT3001.h>

Adafruit_INA228 meter;
ClosedCube_OPT3001 light;

void setup() {
  Serial.begin(9600);
  if (!meter.begin()) {
    Serial.println("No INA228");
    while (1);
  }
  meter.setShunt(0.015, 10.0);
  light.begin(0x44);
  OPT3001_Config config;
  config.rawData = 0;
  config.RangeNumber = 0b1100;      // automatic range
  config.ModeOfConversionOperation = 0b11;  // continuous, 100 ms
  light.writeConfig(config);
  Serial.println("Energy meter");
}

void loop() {
  delay(500);
  Serial.print(meter.getBusVoltage_V(), 2);
  Serial.print(" V  ");
  Serial.print(meter.readCurrent(), 0);
  Serial.print(" mA  ");
  Serial.print(meter.readPower(), 0);
  Serial.print(" mW  ");
  Serial.print(meter.readEnergy(), 2);
  Serial.print(" J  ");
  Serial.print(meter.readCharge(), 3);
  Serial.print(" C  panel ");
  Serial.print(light.readResult().lux, 0);
  Serial.println(" lux");
}

Code walkthrough

The key functions of the sketch, and what each one does.

setup sketch.ino

Starts serial, then tries meter.begin. If the INA228 is not found it prints a message and stops. It tells the meter its shunt value with setShunt(0.015, 10.0), then starts the OPT3001 at address 0x44 and sets automatic range with continuous conversion.

void setup() {
  Serial.begin(9600);
  if (!meter.begin()) {
    Serial.println("No INA228");
    while (1);
  }
  meter.setShunt(0.015, 10.0);
  light.begin(0x44);
  OPT3001_Config config;
  config.rawData = 0;
  config.RangeNumber = 0b1100;      // automatic range
  config.ModeOfConversionOperation = 0b11;  // continuous, 100 ms
  light.writeConfig(config);
  Serial.println("Energy meter");
}

loop sketch.ino

Waits 500 ms, then prints one line: bus voltage, current, power, energy from readEnergy, charge from readCharge, and the panel's lux. The chip keeps the running totals itself, so the sketch does no adding.

void loop() {
  delay(500);
  Serial.print(meter.getBusVoltage_V(), 2);
  Serial.print(" V  ");
  Serial.print(meter.readCurrent(), 0);
  Serial.print(" mA  ");
  Serial.print(meter.readPower(), 0);
  Serial.print(" mW  ");
  Serial.print(meter.readEnergy(), 2);
  Serial.print(" J  ");
  Serial.print(meter.readCharge(), 3);
  Serial.print(" C  panel ");
  Serial.print(light.readResult().lux, 0);
  Serial.println(" lux");
}

Troubleshooting

The usual mistakes with this circuit, and the fix for each.

  • The monitor says No INA228 This project
    Check its SDA and SCL, its VCC, and that its GND joins the Uno's ground.
  • Current and power read zero This project
    The lamp must be in series: IN+ on the 12 V rail, IN- to the lamp, and the lamp's other pin to ground.
  • The device is not found. Power and energy monitor
    It is an I2C part, with the address set by the A0 and A1 pins (0x40 default). Check SDA, SCL, and power. Use 3.3 V logic or a level shifter.
  • Current or power values are wrong. Power and energy monitor
    Set the shunt value (15 milliohm here) and the calibration register to match. Without the right shunt setting, current and power are off by that factor.
  • The lamp is dim or does not light when driven from a board pin. Filament lamp
    A lamp needs far more current than a pin gives (a pin is limited to about 20 mA). Switch it with a transistor or MOSFET from its own supply that matches the lamp's voltage rating.
  • The lamp's brightness lags or it burns out the switch when it first turns on. Filament lamp
    A cold filament draws several times its running current at first. Size the switch for that surge, not just the steady current.
  • The sensor does not answer. Ambient light
    The address depends on ADDR: GND is 0x44, VDD is 0x45, SDA is 0x46 and SCL is 0x47. Do not leave ADDR floating. Supply is 1.6 V to 3.6 V.
  • A 5 V board kills or confuses the sensor. Ambient light
    The OPT3001 is not 5 V safe. Power it from 3.3 V and use 3.3 V I2C pull-ups, or a level shifter. Keep the sensor window clear, as it is the only light path.

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.