Arduino battery level indicator
Beginner
Or see every lesson.
- 465parts on the bench
- 43boards running now
- 1.00xreal time, on every board
A battery level indicator is an analogRead and a little arithmetic. The circuit above is an Arduino Uno reading one 18650 lithium-ion cell on A0, with the voltage and the charge in percent on a 16x2 I2C LCD and a traffic light module for the level: green over 50 %, yellow from 20 to 50 %, and a blinking red under 20 %.
Press Run, then drag the charge slider on the battery. Full, the serial monitor prints 4.20 V and 100 %. At half charge it prints 3.60 V and 50 % and the light turns yellow. At 10 % it prints 3.12 V and the red light blinks, and empty is 3.00 V and 0 %.
What you need
- An Arduino Uno
- One 18650 lithium-ion cell in a holder
- A 16x2 LCD with an I2C backpack
- A traffic light LED module, or three LEDs with 220 ohm resistors
- Jumper wires and a breadboard for the power rails
Wiring
| Part and pin | Goes to | Note |
|---|---|---|
| Battery + (red lead) | A0 | Straight in: 4.2 V is under the Uno’s 5 V reference |
| Battery - (black lead) | GND | The cell and the Uno must share ground |
| Traffic light G, Y, R | Pins 2, 3, 4 | GND to GND |
| LCD SDA, SCL | A4, A5 | VCC to 5V, GND to GND; address 0x27 |
Why one 18650 goes straight into A0
analogRead() compares a pin with the Uno’s 5 V and counts 0 to 1023. A lithium-ion cell is 4.2 V full and about 3.0 V empty, always under 5 V, so it can go straight onto an analog pin with no divider. Its minus lead must go to the Uno’s GND, or the pin has nothing to measure against.
The volts are the count times 5 / 1023. The sketch averages 16 readings first, which steadies the last digit on a real board where the reading wanders by a count or two.
From volts to percent
The sketch maps 3.0 V to 0 % and 4.2 V to 100 % on a straight line and clamps it to 0 to 100. Then it picks the light and prints both to the LCD and the serial monitor every half second.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
const int BATTERY_PIN = A0;
const int GREEN_PIN = 2;
const int YELLOW_PIN = 3;
const int RED_PIN = 4;
const float EMPTY_V = 3.0;
const float FULL_V = 4.2;
LiquidCrystal_I2C lcd(0x27, 16, 2);
bool blink = false;
void setup() {
pinMode(GREEN_PIN, OUTPUT);
pinMode(YELLOW_PIN, OUTPUT);
pinMode(RED_PIN, OUTPUT);
Serial.begin(9600);
Serial.println("Battery level indicator");
lcd.init();
lcd.backlight();
lcd.print("18650 battery");
}
void loop() {
// Average 16 readings to steady the last digit.
long sum = 0;
for (int i = 0; i < 16; i++) sum += analogRead(BATTERY_PIN);
float volts = sum / 16.0 * 5.0 / 1023.0;
int percent = (int)((volts - EMPTY_V) / (FULL_V - EMPTY_V) * 100.0 + 0.5);
percent = constrain(percent, 0, 100);
blink = !blink;
digitalWrite(GREEN_PIN, percent > 50 ? HIGH : LOW);
digitalWrite(YELLOW_PIN, percent >= 20 && percent <= 50 ? HIGH : LOW);
digitalWrite(RED_PIN, percent < 20 && blink ? HIGH : LOW);
lcd.setCursor(0, 1);
lcd.print(volts, 2);
lcd.print(" V ");
lcd.print(percent);
lcd.print(" % ");
Serial.print(volts, 2);
Serial.print(" V ");
Serial.print(percent);
Serial.println(" %");
delay(500);
}A battery above 5 V needs a divider
Two 18650s in series are 8.4 V full, a 9 V battery is 9.6 V fresh, and a 12 V lead-acid battery is 12.8 V. Any of them straight on A0 is over the pin’s limit. Put two resistors in series from the battery’s plus to GND and read the point between them. With two equal 10 k resistors, 8.4 V reads as 4.2 V; with 10 k on top and 4.7 k below, 12 V reads as 3.84 V. Multiply the reading back up in the sketch by the same ratio, and keep to resistors of about 10 k: the divider then drains under a milliamp, and its output stays inside the 10 k source the ATmega328P’s ADC is designed for.
Then change the empty and full points to the battery’s own: 6.0 V and 8.4 V for two lithium-ion cells, or 11.8 V and 12.8 V at rest for a lead-acid battery. The LM2596 guide reads a 12 V adapter through that 10 k and 4.7 k divider, in a running circuit.
Why the percent is only a guide
A real lithium-ion cell does not fall in a straight line. Its voltage is flat through the middle and drops fast at both ends, so a straight-line gauge reads a little low when the cell is fresh and falls quickly near empty. The voltage also sags under load: read it while a motor runs and the cell looks emptier than it is. Fuel gauge chips count the current in and out instead.
Mokxi’s battery moves in a straight line between its empty and full points as you drag the charge, so the readings here follow the slider exactly. It does not run down on its own while the circuit runs, so the charge slider is how you test the low-battery warning.
Running the Arduino from the same battery
On a real Uno the 5V pin wants a steady 5 V, and VIN or the barrel jack want 7 to 12 V for the onboard regulator. One 18650 is neither, so a single cell needs a boost converter up to 5 V. Two cells in series, 6 to 8.4 V, sit at the bottom of what VIN wants, so many builds use a buck converter down to 5 V instead. Once the Uno runs from the battery, its own 5 V reference can move with it, so measure the battery against the internal reference or through a divider fed from a regulated supply.
In Mokxi the Uno is always powered from its USB and ignores VIN, so the circuit here shows the measuring half. The battery part has every common kind, from AA packs and coin cells to LiPo pouches, 2S and 3S RC packs and a 12 V lead-acid block.
Questions
Can I connect a battery straight to an Arduino analog pin?
Only if its voltage stays under the board’s reference, 5 V on an Uno. One lithium-ion cell, 3.0 to 4.2 V, is fine. Anything higher needs a voltage divider in front of the pin, and the battery’s minus must go to GND.
What voltage is a full and an empty 18650?
About 4.2 V full and 3.0 V empty at rest. Under a heavy load a cell’s datasheet lets it fall to 2.5 V, and it recovers to about 3.0 V when the load stops.
How do I monitor a 12 V battery with an Arduino?
Through a divider, for example 10 k from the battery’s plus to A0 and 4.7 k from A0 to GND, which turns 12 V into 3.84 V. Multiply the reading by 14.7 / 4.7 in the sketch.
How accurate is a battery percentage from the voltage?
Rough. A lithium-ion cell’s voltage is flat through the middle of its charge and sags under load, so a voltage gauge is good for full, low and empty, not for an exact figure.
Can Mokxi simulate an Arduino running on a battery?
It simulates batteries feeding the rest of a circuit, with their internal resistance and charge. The simulated Uno itself always runs from USB and ignores VIN.
Keep going
Where the facts on this page come from
Build this for real
Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.