A potentiometer is the simplest analog input there is, which makes it the best way to learn how the ESP32’s ADC really behaves.
Wire the outer legs to GND and 3V3, the middle (wiper) to D34. The sketch prints the raw 12-bit count, the calibrated millivolts and a percentage, and dims the DevKit V1’s blue LED (GPIO2) with the core 3.x LEDC API as you turn the knob.
Wiring
| ESP32 DevKit V1 | Rotary potentiometer (10 kΩ, B10K) | Wire | Notes |
|---|---|---|---|
| GND | Pin 1 | black | Swap Pin 1 and Pin 3 to reverse the direction. |
| 3V3 | Pin 3 | red | Never VIN — the wiper would then reach 5 V. |
| D34 | Wiper | yellow | ADC1, input-only. Works with Wi-Fi on. |
Passive — across the board’s 3.3 V or 5 V part, 3.3 V board. Connect the outer legs to the same voltage your ADC uses: 3.3 V and GND on ESP32 and Pico, 5 V and GND on Uno. The wiper can then never exceed the pin limit.
Board quirks
- The ESP32 ADC is 12-bit (0–4095) but not linear at the ends: with the default 11 dB attenuation it reads 0 below about 0.15 V and reaches 4095 a little above 3.1 V. That’s why the first and last few degrees of the knob don’t change the value. The sketch maps the usable 150–3100 mV window to 0–100 %.
analogReadMilliVolts()(core 3.x) applies the chip’s factory calibration. Use it whenever you need volts; raw counts differ by a few percent between ESP32 chips.- Arduino-ESP32 3.x replaced
ledcSetup()+ledcAttachPin()withledcAttach(pin, freq, bits)andledcWrite(pin, duty). Old tutorials fail to compile on core 3.x — see the LEDC fix. - D34 is one of the input-only pins (34, 35, VP, VN): fine for analog, and it frees the output-capable pins for other parts.
- A 10 kΩ pot draws 0.33 mA. Higher values (100 kΩ) work too but read noisier; add a 100 nF capacitor from the wiper to GND if the number jitters.
Code
// 10 kΩ potentiometer on an ESP32 DevKit V1 — reads the wiper and dims the on-board LED.
// Pin 1 → GND, Pin 3 → 3V3, Wiper → D34 (GPIO34, ADC1). LED on GPIO2 via LEDC PWM (core 3.x API).
constexpr uint8_t POT_PIN = 34;
constexpr uint8_t LED_PIN = 2;
void setup() {
Serial.begin(115200);
analogReadResolution(12); // 0–4095 (the default, set here to be explicit)
ledcAttach(LED_PIN, 5000, 12); // core 3.x: pin, frequency (Hz), resolution (bits)
Serial.println("Potentiometer on GPIO34 — turn the knob");
}
void loop() {
int raw = analogRead(POT_PIN); // 0–4095, not perfectly linear
int mv = analogReadMilliVolts(POT_PIN); // calibrated millivolts
int pct = constrain(map(mv, 150, 3100, 0, 100), 0, 100); // usable ADC window ≈ 0.15–3.1 V
ledcWrite(LED_PIN, raw); // 12-bit duty follows the knob
Serial.printf("raw %4d %4d mV %3d %%\n", raw, mv, pct);
delay(200);
}// 10 kΩ potentiometer on an ESP32 DevKit V1 — reads the wiper and dims the on-board LED.
// Pin 1 → GND, Pin 3 → 3V3, Wiper → D34 (GPIO34, ADC1). LED on GPIO2 via LEDC PWM (core 3.x API).
constexpr uint8_t POT_PIN = 34;
constexpr uint8_t LED_PIN = 2;
void setup() {
Serial.begin(115200);
analogReadResolution(12); // 0–4095 (the default, set here to be explicit)
ledcAttach(LED_PIN, 5000, 12); // core 3.x: pin, frequency (Hz), resolution (bits)
Serial.println("Potentiometer on GPIO34 — turn the knob");
}
void loop() {
int raw = analogRead(POT_PIN); // 0–4095, not perfectly linear
int mv = analogReadMilliVolts(POT_PIN); // calibrated millivolts
int pct = constrain(map(mv, 150, 3100, 0, 100), 0, 100); // usable ADC window ≈ 0.15–3.1 V
ledcWrite(LED_PIN, raw); // 12-bit duty follows the knob
Serial.printf("raw %4d %4d mV %3d %%\n", raw, mv, pct);
delay(200);
}Expected serial output
Potentiometer on GPIO34 — turn the knob
raw 0 98 mV 0 %
raw 2048 1720 mV 53 %
raw 4095 3142 mV 100 %Potentiometer on GPIO34 — turn the knob raw 0 98 mV 0 % raw 2048 1720 mV 53 % raw 4095 3142 mV 100 %
Common errors
Value jumps by ±20 counts while the knob is still
Normal ESP32 ADC noise. Average several readings, add a 100 nF capacitor from the wiper to GND, and keep the wires short.
‘ledcSetup’ was not declared in this scope
Code written for core 2.x. Use ledcAttach(pin, freq, resolution) and ledcWrite(pin, duty), as in this sketch.
Reads 4095 at half-turn
The outer legs are on VIN (5 V) instead of 3V3, or the wiper is on an outer leg. Fix the wiring before the pin is damaged.