Measuring a 12 V battery
Two resistors get 12 V down to something a 3.3 V pin can survive, and everybody finds the ratio. The two numbers nobody finds are what the divider drains from the battery while you are not looking, and how much of the voltage never arrives because the resistors are too large.
Start from the highest voltage, not the nominal one
A "12 V" lead-acid battery is 12.7 V charged and about 14.4 V while a charger is on it. Design for 14.4 V, or the first time it charges you will be putting more than the supply on an input pin.
The rule is: at the battery's highest, the junction between the two resistors must be below your supply. With a 3.3 V board and 14.4 V to handle, you need to divide by at least 4.4.
Move the battery slider up to 14.4 V and check every pair. The one to notice is
10k / 2.2k — the same ratio as 100k / 22k, the same voltage at the pin, and
ten times the drain.
The three numbers
The ratio is the easy one: the pin sees V × Rbottom / (Rtop + Rbottom). For
100 kΩ and 22 kΩ that is 0.180, so 14.4 V arrives as 2.60 V — comfortably under a
3.3 V supply with room to spare. A more generous 100 kΩ and 33 kΩ gives 0.248 and
3.57 V, which is fine on a 5 V board and over the limit on a 3.3 V one. That
single decision is the whole design.
The drain is the one that ruins winter projects. The divider is permanently across the battery. 12.6 V across 122 kΩ is 103 µA, or about 74 mAh a month — a detail on a car battery, and fatal on a small sealed cell over a season. Larger resistors cost less current.
The loading is the one that pulls the other way. The converter's inputs are a switched capacitor, which behaves like a resistance to ground — about 6 MΩ at ±4.096 V, and lower at the narrow ranges. Your divider's own source impedance is the two resistors in parallel: 18 kΩ for 100k/22k. That splits against the 6 MΩ and about 0.3% of the voltage never arrives, so every reading comes back low by the same fraction.
Which is why the last line of the setup is a meter.
Calibrate once
Measure the battery with a multimeter, look at what the sketch printed, and
scale DIVIDER by the ratio between them. One measurement removes the resistor
tolerance and the input loading together, because both are a fixed percentage.
After that the reading is as good as your meter, which for most people is better than anything the arithmetic was going to produce.
Why 8 SPS and four averages
A battery does not move. At 8 SPS the last bit is real, four readings take half a second, and the averaging flattens the last of the wobble. At ±4.096 V one count is 125 µV at the pin, which through a 5.545 divider is about 0.7 mV of battery — far finer than anything you need, and finer than any meter you will check it against.
What the same pattern measures
Anything bigger than your supply: a solar panel's open-circuit voltage, a motor supply, a 24 V industrial rail. The arithmetic is identical and so are the three numbers. Only the resistors change.
The code
A 12 V lead-acid monitor. It reads A0 at 8 SPS, multiplies by the divider ratio, and prints the battery voltage. DIVIDER is the one number you may need to change, and the note says how to get it right.
// Wiring for this sketch.
//
// ESP32 3V3 -> VCC
// ESP32 GND -> GND, and the battery's negative terminal
// ESP32 SDA -> SDA
// ESP32 SCL -> SCL
//
// battery + --[ 100k ]--+--[ 22k ]-- GND
// |
// +-> A0
//
// Check with a meter BEFORE connecting A0: the junction must read under
// 3.3 V with the battery at its highest, which for a 12 V lead-acid on
// charge is about 14.4 V.
//
// Arduino IDE: any board. Library: "ADS1X15" by Rob Tillaart.
#include <Wire.h>
#include <ADS1X15.h>
const float DIVIDER = 5.545; // (100k + 22k) / 22k - then trim against a meter
ADS1115 ADS(0x48);
void setup() {
Serial.begin(115200);
delay(500);
Wire.begin();
if (!ADS.begin()) {
Serial.println("no ADS1115 at 0x48");
while (true) delay(1000);
}
ADS.setGain(1); // +/-4.096 V - the widest that is not wasted on 3.3 V
ADS.setDataRate(0); // 8 SPS - quietest, and a battery does not move
}
float batteryVolts() {
long sum = 0;
for (int i = 0; i < 4; i++) sum += ADS.readADC(0);
return ADS.toVoltage(sum / 4.0) * DIVIDER;
}
void loop() {
float v = batteryVolts();
Serial.printf("%.3f V %s\n", v,
v > 12.7 ? "charged" : v > 12.0 ? "ok" : "low");
delay(5000);
}Calculate DIVIDER as (Rtop + Rbottom) / Rbottom — 5.545 for 100k and 22k. Then measure the battery with a meter and adjust the constant until the sketch agrees: real resistors are 1% parts at best, and one calibration reading is worth more than any arithmetic. Everything in this sketch assumes the battery's negative terminal is joined to the board's GND.
When it does not work
Two likely causes and they add up. Real resistors are 1% parts at best, so the ratio is never exactly what you calculated. And large resistors are loaded by the converter's own input, which behaves like about 6 MΩ at ±4.096 V — with 100k and 22k the source is around 18 kΩ, costing roughly 0.3%. Measure the battery with a meter once and trim DIVIDER until the sketch agrees.
It is probably not drifting — the divider is draining it. 100k and 22k across 12.6 V is about 103 µA, which is 74 mAh a month, every month, whether anything is reading or not. On a small battery that is real. A MOSFET switching the divider's bottom end to ground, turned on only while reading, removes it.
The junction is above the selected range. Disconnect A0 and measure that junction with a meter: if it is under 3.3 V the fix is the range setting, and if it is over then the divider is wrong for this battery and the chip has been taking more than it should. Recalculate for the battery's highest voltage, not its nominal one.
Only each one against the shared negative, never one against the other. Every input on this chip is measured relative to its own ground, and an input below ground is not something it accepts. For the upper cell of a stack you need a divider from the top of the stack and one from the midpoint, and you subtract the two readings in software.
Edit this page — content/books/ads1115/measuring-a-12v-battery.mdx
Questions about this product
See what other owners have asked, and read their solutions.
This page covers several products. Choose yours to see the right discussions.
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.