A battery coulomb counter measures the exact amount of charge (in milliampere-hours) flowing into and out of a battery, providing the most accurate state-of-charge (SoC) estimation possible. Unlike simple voltage-based fuel gauges that guess capacity from voltage curves, coulomb counting tracks every electron, giving you precise readings even under varying load conditions. This guide covers coulomb counting theory, IC selection, and an Arduino implementation using the INA219.
What Is a Coulomb Counter?
A coulomb counter (also called a current integrator or charge counter) continuously measures current flowing through a battery’s terminals and integrates it over time to calculate total charge transferred:
Charge (mAh) = Integral of Current (mA) x Time (hours)
In digital systems:
mAh += current_mA * (delta_time_ms / 3600000)
Sample every 100ms for good accuracy
Positive current = charging (SoC increases)
Negative current = discharging (SoC decreases)
The unit is coulombs (1 coulomb = 1 ampere-second), but battery capacity is conventionally expressed in milliampere-hours (mAh), so most implementations integrate in mAh.
How Coulomb Counting Works
The coulomb counter consists of three key elements:
- Current sensor: A precision sense resistor (1-10 milliohm) in series with the battery, or a Hall-effect sensor for non-invasive measurement
- ADC: High-resolution analog-to-digital converter (16-24 bit) that measures voltage across the sense resistor at regular intervals
- Integrator: Software or hardware accumulator that sums current samples over time
The drift problem: Coulomb counting accumulates errors over time. A 1% measurement error means 1% SoC error per full cycle. After 10 cycles without calibration, the error can reach 10%. Solutions:
- Calibrate SoC to 100% when charge termination is detected (CV phase ends)
- Calibrate SoC to 0% when low-voltage cutoff triggers
- Combine coulomb counting with voltage-based estimation for hybrid accuracy
Popular Coulomb Counter ICs
| IC | Resolution | Interface | Key Feature | Cost |
|---|---|---|---|---|
| INA219 | 12-bit ADC | I2C | Current + voltage + power | ₹80-150 |
| INA226 | 16-bit ADC | I2C | Higher precision, alert pin | ₹120-200 |
| MAX17048 | Fuel gauge | I2C | ModelGauge (no sense resistor) | ₹150-300 |
| BQ27441 | Fuel gauge | I2C | TI Impedance Track | ₹200-400 |
| LTC2941 | Dedicated CC | I2C | Hardware coulomb counter | ₹300-500 |
Coulomb Counting with Arduino and INA219
#include <Wire.h>
#include <Adafruit_INA219.h>
Adafruit_INA219 ina219;
float totalCharge_mAh = 0; // Accumulated charge
float batteryCapacity_mAh = 2200; // Known full capacity
float socPercent = 100.0; // Start at 100% (just charged)
unsigned long lastTime = 0;
void setup() {
Serial.begin(9600);
ina219.begin();
lastTime = millis();
}
void loop() {
float current_mA = ina219.getCurrent_mA();
float voltage_V = ina219.getBusVoltage_V();
float power_mW = ina219.getPower_mW();
unsigned long now = millis();
float dt_hours = (now - lastTime) / 3600000.0;
lastTime = now;
// Integrate current (positive=charge, negative=discharge)
totalCharge_mAh += current_mA * dt_hours;
// Calculate SoC
socPercent = (totalCharge_mAh / batteryCapacity_mAh) * 100.0;
socPercent = constrain(socPercent, 0, 100);
// Calibration points
if (voltage_V >= 4.18 && abs(current_mA) < 50) {
totalCharge_mAh = batteryCapacity_mAh; // Full calibration
socPercent = 100.0;
}
if (voltage_V <= 3.0) {
totalCharge_mAh = 0; // Empty calibration
socPercent = 0.0;
}
Serial.print("V:"); Serial.print(voltage_V, 2);
Serial.print(" I:"); Serial.print(current_mA, 1);
Serial.print("mA SoC:"); Serial.print(socPercent, 1);
Serial.println("%");
delay(100); // 10 Hz sampling
}
State of Charge Estimation
Best practices for accurate SoC in battery-powered Indian projects:
- Hybrid approach: Use coulomb counting for short-term tracking and voltage-based calibration at rest (after 30+ minutes with no load)
- Temperature compensation: Battery capacity varies with temperature. In Indian winters (10-15degC in North India), effective capacity drops 10-15%. Factor this into SoC calculation.
- Aging compensation: Reduce the full-capacity reference by 0.5-1% per 100 cycles to account for capacity fade
- Self-discharge: For long idle periods, subtract 2-5% per month for lithium cells at Indian room temperature (25-35degC)
Shop All Batteries & Power Modules →
Frequently Asked Questions
How accurate is coulomb counting compared to voltage-based SoC?
Coulomb counting is accurate to 1-3% per cycle (with calibration). Voltage-based estimation has 10-20% error because lithium cells have very flat discharge curves (3.4-3.7V covers 80% of capacity). For critical applications, always use coulomb counting with voltage calibration.
Do I need a special sense resistor for coulomb counting?
The INA219 module includes a 0.1-ohm sense resistor suitable for currents up to 3.2A. For higher currents, replace with a lower-value precision resistor (10 milliohm for 10A, 1 milliohm for 50A+) and reconfigure the INA219 calibration register.
Can I use coulomb counting for LiFePO4 batteries?
Yes, and it is especially important for LiFePO4. The LiFePO4 discharge curve is extremely flat (3.2-3.3V for most of its range), making voltage-based SoC nearly useless. Coulomb counting is the primary SoC method for LiFePO4 systems.
Add comment