Analog measurement

Measuring a battery divider with the ESP32 ADC

· ESP32 ADC · battery measurement

I use a simple resistor divider to estimate battery voltage on one ESP32 sensor node. The first version used the ideal divider ratio directly in firmware and was wrong by as much as 140 mV. That is enough to make a battery graph look more precise than it really is, so I measured the complete input path and applied one practical correction.

Divider

The upper resistor is 220 kΩ and the lower resistor is 100 kΩ. The midpoint goes to ADC1 channel 6 through a 1 kΩ series resistor. A 100 nF capacitor from the ADC input to ground reduces noise. At 4.2 V the ideal ADC input is about 1.31 V, safely inside the range I use.

The divider itself continuously draws about 13 µA at 4.2 V. That is not free on a low-power node, but it is small enough for this device. A future revision may switch the divider from a GPIO-controlled transistor so it is disconnected during sleep.

Bench supply voltage compared with raw calculated voltage.
Bench valueRaw ESP32 resultError
3.20 V3.11 V−90 mV
3.60 V3.49 V−110 mV
4.00 V3.87 V−130 mV
4.20 V4.06 V−140 mV

The error was close to linear over the range that matters, so I fitted a scale and offset from the measured points instead of building a large lookup table. I also average 32 samples after discarding the first few conversions.

float readBatteryVoltage() {
  uint32_t sum = 0;

  for (int i = 0; i < 4; ++i) {
    analogRead(34);
  }

  for (int i = 0; i < 32; ++i) {
    sum += analogReadMilliVolts(34);
    delay(2);
  }

  const float adcV = (sum / 32.0f) / 1000.0f;
  const float dividerRatio = (220.0f + 100.0f) / 100.0f;
  const float rawBatteryV = adcV * dividerRatio;

  return rawBatteryV * 1.031f - 0.006f;
}

After correction, the four test points were within about 20 mV of the bench meter. That is more than adequate for trend logging. It is still not a fuel gauge: battery voltage depends on load, temperature, chemistry, and recovery time. I therefore store voltage as a measurement and avoid presenting a precise percentage.

The 100 nF capacitor made the largest improvement to short-term noise. Without it, repeated values at a fixed 3.8 V source wandered by roughly 35–45 mV. With the capacitor and averaging, the spread was usually under 10 mV.

Practical result: calibrating the assembled divider and ADC path produced a stable voltage trend. The result is useful as voltage, not as an exact state-of-charge estimate.