Skip to content
Tutorial
13 min read
October 17, 2026

ESP32 ADC Pins: analogRead, ADC1 vs ADC2, Attenuation & Calibration

Why ESP32 analogRead stops working with WiFi, which pins belong to ADC1 and ADC2, how attenuation sets your voltage range, why readings are non-linear, and how to get accurate millivolt values with calibration and averaging.

If you have ever wired a potentiometer to an ESP32, seen it work perfectly, then watched it return nothing but zeros the moment you added WiFi, you have met the most famous quirk of this chip: the analog-to-digital converter is split in two, and one half switches off when the radio is on.

That is only the first surprise. The ESP32 ADC also has a limited voltage range that depends on a setting called attenuation, a visible non-linearity at both ends of its scale, and a noisy output that needs filtering. None of this makes the ADC useless. It makes it something you have to configure properly. This guide covers the pin map, the right way to read voltages in millivolts, how to measure higher voltages such as a battery, and how to clean up noisy readings.

Image pending: ESP32 DevKit with a potentiometer connected to GPIO 34 and the Serial Monitor Plotter showing the analog value changing smoothly as the knob turns

ADC1 vs ADC2: The Rule You Must Know

The ESP32 has two 12-bit successive-approximation ADCs. Together they provide 18 analog channels, and they are not equal.

ADCChannelGPIO
ADC1CH036 (VP)
CH339 (VN)
CH432
CH533
CH634
CH735
ADC2CH04
CH10
CH22
CH315
CH413
CH512
CH614
CH727
CH825
CH926

ADC1 also has CH1 and CH2 on GPIO 37 and 38, but those pins are not broken out on common dev boards.

ADC2 is shared with the WiFi driver. While WiFi is running, the radio takes control of ADC2, and calling analogRead() on an ADC2 pin returns invalid data or fails. Bluetooth does not cause this, but WiFi does, including a sketch that merely connected once.

The practical rule: if your project uses WiFi, MQTT, a web server or any network feature, read analog sensors on ADC1 pins (GPIO 32, 33, 34, 35, 36, 39). ADC2 pins are only safe for analog input in sketches that never start WiFi.

GPIO 34, 35, 36 and 39 are also input-only, which suits sensors well, but remember they have no internal pull-up or pull-down.

Image pending: Diagram of ESP32 GPIOs split into ADC1 (green, always available) and ADC2 (red, unavailable while WiFi is active)

Reading an Analog Value

The simplest reading is one line:

const int SENSOR_PIN = 34; // ADC1 channel 6

void setup() {
  Serial.begin(115200);
}

void loop() {
  int raw = analogRead(SENSOR_PIN);   // 0 to 4095
  Serial.println(raw);
  delay(200);
}

The default resolution is 12 bits, so the output ranges from 0 to 4095, unlike the 10-bit 0 to 1023 range on an Arduino Uno. You can change it between 9 and 12 bits:

analogReadResolution(10); // now returns 0 to 1023

Wire a 10 kΩ potentiometer with the outer legs to 3.3V and GND and the middle leg to GPIO 34. The raw value should run from near 0 to near 4095 as you turn it.

Never connect more than 3.3V to an ADC pin. The inputs are not 5V tolerant, and exceeding about 3.6V can damage the chip.

Image pending: Wiring diagram of a 10k potentiometer between 3.3V and GND with the wiper connected to GPIO 34 on the ESP32

Attenuation: Choosing Your Voltage Range

The ESP32 ADC natively measures only a small voltage range, about 0 to 1.1V. To read larger voltages, an input attenuator scales the signal down first. You choose how much with analogSetAttenuation() (all pins) or analogSetPinAttenuation() (one pin).

SettingConstantApproximate usable range
0 dBADC_0db100 to 950 mV
2.5 dBADC_2_5db100 to 1250 mV
6 dBADC_6db150 to 1750 mV
11 dBADC_11db150 to 2450 mV

The Arduino core defaults to 11 dB, which is why a full-scale reading appears around 3.1V. These ranges are the accurate, linear region. Beyond them the converter keeps going, but it saturates and the numbers stop meaning anything. In practice, an input of 3.3V and an input of 3.1V both read near 4095.

analogSetPinAttenuation(34, ADC_11db); // best for sensors up to ~3.1V

Choose the smallest attenuation that covers your signal. A sensor that only swings between 0 and 1V reads more accurately at 0 dB or 2.5 dB than at 11 dB.

Getting Real Voltages: analogReadMilliVolts

Raw counts are not volts, and the relationship is not a straight line. The ESP32 ADC is noticeably non-linear near 0V and near the top of the range. A reading of 2048 does not mean exactly half scale.

Espressif calibrates each chip at the factory and stores correction data in eFuse. The Arduino function analogReadMilliVolts() uses that data and returns a calibrated value directly in millivolts:

const int SENSOR_PIN = 34;

void setup() {
  Serial.begin(115200);
  analogSetPinAttenuation(SENSOR_PIN, ADC_11db);
}

void loop() {
  int mv = analogReadMilliVolts(SENSOR_PIN);
  Serial.printf("%d mV  (%.2f V)\n", mv, mv / 1000.0);
  delay(500);
}

Compare it with a multimeter reading on a known voltage. A difference of tens of millivolts is normal on this chip. If you need better than about 1 to 2 percent accuracy, add an external ADC such as the ADS1115 over I2C, which offers 16 bits and a stable reference.

On the original ESP32 the non-linear region is the weak point, so avoid designing a circuit whose important values sit below about 150 mV or above about 2.45V at 11 dB.

Image pending: Graph comparing raw ESP32 ADC counts against true input voltage showing the non-linear curve at the low and high ends

Cleaning Up a Noisy Reading

ESP32 analog readings jitter, often by 10 to 50 counts even on a steady voltage. Three fixes work well together.

1. Average multiple samples.

int readAveraged(int pin, int samples = 32) {
  long sum = 0;
  for (int i = 0; i < samples; i++) {
    sum += analogReadMilliVolts(pin);
    delayMicroseconds(100);
  }
  return sum / samples;
}

2. Add a small capacitor. A 100 nF ceramic capacitor between the ADC pin and GND filters high-frequency noise, especially on a long wire or a high-impedance source.

3. Smooth over time with an exponential filter.

float smoothed = 0;
const float ALPHA = 0.1; // lower = smoother but slower

void loop() {
  int mv = analogReadMilliVolts(34);
  smoothed = ALPHA * mv + (1 - ALPHA) * smoothed;
  Serial.println(smoothed);
  delay(50);
}

Also keep analog wires short, route them away from the WiFi antenna and away from motor or relay wiring, and power the sensor from the stable 3.3V pin rather than from a noisy supply.

Image pending: Serial Plotter comparing raw noisy ADC readings with the same signal after 32-sample averaging and an exponential filter

Measuring Higher Voltages With a Voltage Divider

To read a battery or any source above 3.3V, scale it down with two resistors before it reaches the pin.

Vin --- R1 ---+--- ADC pin
              |
              R2
              |
             GND

The voltage at the pin is Vout = Vin × R2 / (R1 + R2).

Example: monitoring a single-cell lithium battery (4.2V full, 3.0V empty) with two equal 100 kΩ resistors halves the voltage to a safe 2.1V at full charge.

const int BATT_PIN = 35;
const float DIVIDER_RATIO = 2.0; // (R1 + R2) / R2 with 100k + 100k

float readBatteryVoltage() {
  int mv = analogReadMilliVolts(BATT_PIN);
  return (mv * DIVIDER_RATIO) / 1000.0;
}

void setup() {
  Serial.begin(115200);
}

void loop() {
  Serial.printf("Battery: %.2f V\n", readBatteryVoltage());
  delay(2000);
}

Use resistors of 100 kΩ or higher to keep the divider's constant current draw tiny on a battery project, and add a 100 nF capacitor from the ADC pin to GND so the high-impedance divider has a stable source for the sampling capacitor. Higher resistor values give more noise, so adjust to your needs.

For a 12V measurement, choose resistors so that the maximum output stays below 3.1V, for example 100 kΩ on top and 33 kΩ on the bottom gives 12V × 33 / 133 = 2.98V.

Image pending: Voltage divider schematic and breadboard photo measuring an 18650 lithium battery through two 100k resistors into GPIO 35

Common Sensors on the ESP32 ADC

SensorWiringNotes
Potentiometer3.3V, GND, wiper to ADC1 pinIdeal first test
LDR (light)Voltage divider with a 10 kΩ resistorReads brightness; calibrate by observation
Soil moisture (analog)3.3V supply, signal to ADC1 pinPower from 3.3V, not 5V, so the signal stays within range
MQ gas sensorsOften 5V poweredUse a divider on the analog output
ThermistorDivider with a fixed resistorNeeds the Steinhart-Hart equation for degrees
TMP363.3V supplyOutput is 10 mV per degree plus a 500 mV offset

Always power analog modules from 3.3V, or divide their output if they run on 5V. A 5V module outputting 4.5V into an ESP32 pin will damage it.

Common Problems and Fixes

analogRead returns 0 or garbage when WiFi is connected. The pin is on ADC2. Move the sensor to GPIO 32, 33, 34, 35, 36 or 39.

Reading is stuck at 4095. The input voltage exceeds the selected attenuation range. Lower the voltage with a divider or use 11 dB.

Reading jumps around. Average samples, add a 100 nF capacitor, and keep wires short.

Voltage reads differently from my multimeter. Use analogReadMilliVolts() for calibration, and expect tens of millivolts of error. For precision, use an ADS1115.

Floating pin shows random values. An unconnected ADC input picks up noise. That is normal. Connect a source or a pull resistor.

Hall sensor or deep-sleep conflicts. GPIO 36 and 39 are tied to internal circuits that can add noise. If these two pins misbehave, use another ADC1 pin first.

Frequently Asked Questions

How many analog pins does the ESP32 have? Up to 18 channels in total, but on common 30-pin boards you can access 15: six on ADC1 and nine on ADC2. Only the ADC1 pins are dependable with WiFi.

Is the ESP32 ADC accurate? Good enough for hobby sensors after calibration, typically within a few percent. It is not a precision instrument. Add an external ADC for anything that needs real accuracy.

Can I use ADC2 at all? Yes, in projects that never turn on WiFi, or if you stop WiFi before reading. For anything connected, pick ADC1.

What is the maximum input voltage? 3.3V on the pin, with accurate readings only up to about 3.1V at the default attenuation.

Does the ESP32-S3 or C3 behave the same? They have different ADC channel mappings and better linearity, but ADC2 still conflicts with WiFi. Check the pinout for your chip: ESP32-S3, ESP32-C3.

For the full map of every pin, return to the ESP32 pinout guide.

Image pending: Finished test setup with an ESP32 on a breadboard, a potentiometer on GPIO 34 and a battery divider on GPIO 35, with the Serial Monitor open

Signal In

Built from what makers search for

The lookups piling up in SolderHub's search bar every day shape what we publish next — new component pages, board guides, and firmware notes, sent out as they go live.

By subscribing you agree to our Privacy Policy. Unsubscribe anytime.