How to read battery voltage with ESP32 ADC (calibration + attenuation tips)

You can't shove a battery straight into an ESP32 analog pin unless it's already within the ADC input range. The safe pattern is: voltage divider + ADC1 pin + attenuation + averaging.

Step 1: Use a voltage divider (protect the ADC)

For a 1S LiPo (up to ~4.2V), use a divider so the ADC sees something safely below 3.3V.

  • Example divider: 100k (top) + 100k (bottom) → halves the battery voltage.
  • So 4.2V becomes ~2.1V at the ADC pin.

Step 2: Prefer ADC1 pins (especially if you use WiFi)

On classic ESP32, ADC2 is shared with WiFi. If you read ADC2 while WiFi is on, results can be garbage. Use ADC1 pins when possible.

Step 3: Set attenuation and average samples

Attenuation changes the input range. Then you average readings to reduce noise.

esp32_battery_adc.ino
cpp
#include <Arduino.h>

// Example: battery divider connected to GPIO34 (ADC1)
static const int adcPin = 34;

// Divider: R1 (top) from battery+ to ADC pin, R2 (bottom) from ADC pin to GND
static const float R1 = 100000.0f;
static const float R2 = 100000.0f;

// Optional calibration factor (start with 1.0, then tune with a multimeter)
static const float CAL = 1.00f;

void setup() {
  Serial.begin(115200);
  delay(200);

  analogReadResolution(12);           // 0-4095
  analogSetPinAttenuation(adcPin, ADC_11db); // wider range, good for battery via divider
}

float readBatteryVolts() {
  const int samples = 32;
  uint32_t sum = 0;
  for (int i = 0; i < samples; i++) {
    sum += analogRead(adcPin);
    delay(2);
  }
  float raw = (float)sum / (float)samples; // 0..4095

  // Convert ADC reading to volts at the pin (approx). ESP32 ADC isn't perfect; calibrate.
  float vPin = (raw / 4095.0f) * 3.3f;

  // Undo divider to get battery voltage
  float vBat = vPin * (R1 + R2) / R2;

  return vBat * CAL;
}

void loop() {
  float v = readBatteryVolts();
  Serial.print("Battery: ");
  Serial.print(v, 2);
  Serial.println(" V");
  delay(2000);
}

Calibration (the part nobody tells you)

The ESP32 ADC is not a lab instrument. If you need accurate voltage, calibrate it:

  1. Measure battery voltage with a multimeter.
  2. Compare with the serial output.
  3. Adjust CAL until it matches.

If readings jump around

  • Add a small capacitor (like 0.1µF) from ADC pin to GND.
  • Keep divider wiring short.
  • Don't use ADC2 if WiFi is active.
Bottom line

Use a divider, read on ADC1, set attenuation, and average samples. Then calibrate with a multimeter if you care about accuracy.

Related: ESP32 deep sleep · Power ESP32 from batteries · Random readings and noise