Learn

Reading a potentiometer with an ESP32

Start building free

Or see every lesson.

  • 505parts on the bench
  • 45boards running now
  • 1.00xreal time, on every board
ESP32 DevKit: knoblive0.000 s 0.00x
Click to open it in the editor
A 10 k pot on GPIO 32 (ADC1 channel 4) sets the brightness of an LED on GPIO 4.

analogRead on an ESP32 looks like the Arduino call you already know, but three things about it catch almost everyone: the numbers go to 4095 instead of 1023, the reading is not a straight line from 0 V to your supply voltage, and half the analog pins stop working the moment WiFi starts. This page walks through all three with a potentiometer and an LED.

The circuit above is a classic ESP32 DevKit with a 10 k potentiometer between 3.3 V and ground, its wiper on GPIO 32, and an LED on GPIO 4. The sketch reads the pot five times a second, maps the reading to a brightness from 0 to 255, writes it to the LED and prints both. With the knob in the middle the serial monitor reads "knob 1892 -> duty 117". Drag the knob and watch both numbers move.

Twelve bits, and why the middle is not 2048

The ESP32’s converter is 12-bit, so readings run from 0 to 4095 against an Uno’s 0 to 1023. But the reading is not a straight line from 0 V to 3.3 V. The input goes through an attenuator first, and at the default setting, 11 dB, a real ESP32’s raw reading sits at 0 for the first 80 mV or so, climbs close to linearly through the middle, bends upward near the top and saturates at 4095 at about 3.1 V. Turn the pot all the way up and the serial monitor reads 4095 for the last few percent of its travel.

Check it against the reading above. The wiper in the middle sits at 1.65 V, and a straight line to 3.3 V would make that 2048. The simulator printed 1892, which is what a typical ESP32 reads there: Mokxi models the converter with the curve measured on real parts, not the straight line the nominal 3.9 V full scale suggests.

The example sketch maps 0 to 4095 onto 0 to 255, so with the pot all the way up the duty reaches 255 and the LED is at full brightness, while the middle of the knob gives about 117 rather than 127. When you need volts rather than counts, use analogReadMilliVolts, which undoes the curve the way the chip’s own calibration does: it reads about 1650 at the middle.

firmware/esp32/examples/knob (the program running above, comments trimmed)
const int kKnob = 32;   // ADC1 channel 4
const int kLed = 4;

void setup() {
  Serial.begin(115200);
  pinMode(kLed, OUTPUT);
}

void loop() {
  int raw = analogRead(kKnob);
  int duty = map(raw, 0, 4095, 0, 255);
  analogWrite(kLed, duty);
  Serial.print("knob ");
  Serial.print(raw);
  Serial.print(" -> duty ");
  Serial.println(duty);
  delay(200);
}

Open this sketch in the editorThe code alone: the editor places the board and the parts it can read from the sketch.

Attenuation settings

analogSetAttenuation (or analogSetPinAttenuation for one pin) trades range for resolution. At 0 dB the full scale is about 1.1 V, at 2.5 dB about 1.5 V and at 6 dB about 2.2 V. At 11 dB the datasheet’s nominal figure is 3.9 V, but the raw reading of a real part saturates at about 3.1 V. If your sensor never goes above one volt, 0 dB gives you about three times as many steps across its range.

Espressif only promises accuracy from about 150 mV to 2450 mV at 11 dB, and every chip differs slightly. Mokxi models a typical part at 11 dB, the dead zone at the bottom and the saturation at the top included, and the other settings as their nominal straight lines; it does not model one chip’s own calibration. On hardware, keep the signal inside the middle of the range, and average several readings, because a real ESP32 reading jumps by a few counts even with the pot standing still.

ADC1, ADC2 and WiFi

The classic ESP32 has two converters. ADC1 is on GPIO 32 to 39. ADC2 is on a set of other pins, and on a real board the WiFi driver uses ADC2 itself, so analogRead on an ADC2 pin fails while WiFi is running. That is why this example uses GPIO 32: it keeps working in a project that later adds a web page. Mokxi does not model ADC2 at all, so use ADC1 pins here and your sketch will carry over.

GPIO 34 to 39 are input only, which makes them good analog inputs and useless as outputs. And never put more than 3.3 V on any ESP32 pin. The attenuator’s nominal 3.9 V full scale is a measuring range, not a safe input voltage; a 5 V sensor output needs a divider before it reaches the pin.

The LED side: analogWrite on an ESP32

The ESP32 has no timers wired to fixed PWM pins the way an Uno does. analogWrite here hands the pin to LEDC, the chip’s LED PWM controller, which can drive almost any GPIO. The runtime uses 8 bits at 1 kHz, so the 0 to 255 values behave the same as on an Uno. When the frequency or resolution matters, for a servo or a motor driver, ledcAttach(pin, frequency, bits) and ledcWrite set them explicitly.

The LED on GPIO 4 runs at 3.3 V, so the resistor math changes from an Uno: with about 2 V across a red LED, (3.3 - 2) / 150 ohms is roughly 9 mA. The same 220 ohm resistor you would use on 5 V gives about 6 mA, a little dimmer and perfectly safe.

Open this circuit in the editor. ESP32 DevKit: knob, wired as it runs at the top of this page. Change a part or a value and run it again.

Questions

Why does my ESP32 analogRead reach 4095 before the knob is all the way around?

Because at the default 11 dB attenuation the raw reading saturates at about 3.1 V, short of the 3.3 V rail, and it is not a straight line on the way there: the middle of a pot reads about 1890, not 2048. Use analogReadMilliVolts when you want volts.

Which ESP32 pins can I use for analogRead with WiFi on?

The ADC1 pins, GPIO 32 to 39. ADC2 pins stop working for analogRead on a real ESP32 while WiFi is active.

Is the ESP32 ADC accurate?

Adequate for knobs and light sensors, not for precise measurement. It is noisy and non-linear near the ends of each range. For accurate voltages, use an external ADC such as an ADS1115 over I2C.

Does the ESP32-C3 behave the same way?

Mostly. The C3 has a 12-bit ADC on GPIO 0 to 4 and the same attenuation idea, but its top range differs from the classic ESP32. Check the board page for the pins and range Mokxi models.

Build this for real

Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.