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.
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.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 1 × Power and energy monitor, INA228
- 1 × Power, 5 V
- 2 × Power, 12 V
- 1 × Filament lamp
- 1 × Ambient light, OPT3001
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 |
|---|---|
| Power and energy monitor, INA228 pin SCL | Arduino Uno R3 pin SCL |
| Power and energy monitor, INA228 pin SDA | Arduino Uno R3 pin SDA |
| Power and energy monitor, INA228 pin GND | Arduino Uno R3 pin GND |
| Ambient light, OPT3001 pin VCC | Arduino Uno R3 pin 5V |
| Ambient light, OPT3001 pin GND | Arduino Uno R3 pin GND |
| Ambient light, OPT3001 pin SDA | Arduino Uno R3 pin A4 |
| Ambient light, OPT3001 pin SCL | Arduino Uno R3 pin A5 |
| Power and energy monitor, INA228 pin VCC | 5 V |
| Power and energy monitor, INA228 pin VBUS | 12 V |
| Power and energy monitor, INA228 pin IN+ | 12 V |
| Filament lamp pin 1 | Power and energy monitor, INA228 pin IN- |
| Filament lamp pin 2 | Ground |
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// 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.