#03 Beginner ⏱ 25 min
ESP32: Dimmer with a potentiometer
Turn a knob → the LED gradually gets brighter. Two new concepts: analog input (ADC, 0–4095) and analog output via PWM (0–255).
Open it interactively in 3D →What you learn
analogRead and the 12-bit ADCPWM with ledcAttach / ledcWriteThe map() functionWhy ADC1 (GPIO 32–39)
You need
- ESP32 DevKit V1 — microcontroller with WiFi and Bluetooth
- Breadboard — wiring without soldering
- Jumper wires — M–M, M–F, F–F
- LED — light-emitting diode 5 mm
- Resistor — 220 Ω, 1 kΩ, 10 kΩ…
- Potentiometer — 10 kΩ variable resistor
How it works
Input: the ESP32 has no "analog eye", but it has an ADC — a circuit that measures voltage and converts it to a number. 12 bits → 4096 levels: 0 V = 0, 3.3 V = 4095. analogRead(34) returns that number.
Output: a digital pin only knows 0 or 3.3 V. But if you switch it on and off very fast (5 kHz), the eye sees an average. 25 % on → dim glow, 100 % → full. That is PWM (Pulse Width Modulation). With ledcAttach(pin, 5000, 8) we say: 5000 Hz, 8 bits (0–255). map() converts 0–4095 into 0–255.
Wiring
| From | To | Why |
|---|---|---|
| ESP32 · 3V3 | Potentiometer, outer pin (column 26) | Top end of the resistor at 3.3 V. NEVER 5 V — the ADC tolerates max 3.3 V. |
| Potentiometer, outer pin (column 24) | − rail | Bottom end at 0 V. Through the whole potentiometer flows 3.3 V / 10 kΩ = 0.33 mA. |
| Potentiometer, middle pin (column 25) | ESP32 · D34 (GPIO 34, ADC1) | The wiper "picks up" 0–3.3 V depending on position. GPIO 34 is an input-only ADC1 pin — ideal. |
| ESP32 · D18 (PWM) | LED → 220 Ω → − rail | PWM: the pin switches on/off 5000 times a second; the percentage of "on" time = brightness. |
| ESP32 · GND | − rail | Common ground. |
Step by step
- LED (19c, 20c) + resistor 20a → − rail.
- Potentiometer with three pins in 24c, 25c, 26c.
- 3V3 → 26a (red), 24a → − rail (black), 25a → D34 (green).
- D18 → 19a for the LED. GND → − rail.
- Upload the code, open the Serial Monitor. Turn → numbers change 0…4095 and the LED follows.
Code (Arduino IDE)
// Project 3: Dimmer — ADC input + PWM output
const int POT_PIN = 34; // ADC1_CH6, input only
const int LED_PIN = 18;
void setup() {
Serial.begin(115200);
// PWM: pin, frequency 5 kHz, resolution 8 bits (0–255)
ledcAttach(LED_PIN, 5000, 8);
// For Arduino-ESP32 core 2.x instead of the line above:
// ledcSetup(0, 5000, 8); ledcAttachPin(LED_PIN, 0); and ledcWrite(0, duty)
}
void loop() {
int raw = analogRead(POT_PIN); // 0 … 4095
int duty = map(raw, 0, 4095, 0, 255); // 0 … 255
ledcWrite(LED_PIN, duty);
Serial.printf("ADC: %4d -> PWM: %3d\n", raw, duty);
delay(50);
}Typical problems
Value flickers by ±20? Normal for the ESP32 ADC. Average 10 readings.
The outer 3 % "stick" at 0 and 4095 — the ADC is not linear there.
If you later add WiFi — the ADC2 pins (0,2,4,12–15,25–27) stop working. Hence GPIO 34.
More projects (7 more) with a free sign-in in the course. Projects →