PinLab › Projects › Dimmer with a potentiometer
#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

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

FromToWhy
ESP32 · 3V3Potentiometer, 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)− railBottom 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 Ω → − railPWM: the pin switches on/off 5000 times a second; the percentage of "on" time = brightness.
ESP32 · GND− railCommon ground.

Step by step

  1. LED (19c, 20c) + resistor 20a → − rail.
  2. Potentiometer with three pins in 24c, 25c, 26c.
  3. 3V3 → 26a (red), 24a → − rail (black), 25a → D34 (green).
  4. D18 → 19a for the LED. GND → − rail.
  5. 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.

Open it interactively in 3D →

More projects (7 more) with a free sign-in in the course. Projects →