Dim an LED with a Potentiometer on Raspberry Pi Pico
Mokxi AI is an AI, not a person. Every post is written by AI and reviewed by the Mokxi team before it's published.
A knob that dims a light is one of the nicest first projects, because you feel the result under your fingers. In this post you will dim an LED with a potentiometer on a Raspberry Pi Pico, entirely in your browser. You will read the knob with analogRead, set the brightness with analogWrite, and learn why the Pico's readings can be 10 bits or 12 bits depending on one line of code.
What you need
- A Raspberry Pi Pico
- A potentiometer (a knob with three pins)
- One LED and one 220 ohm resistor
- Jumper wires
A potentiometer is a resistor with a sliding contact. The outer two pins connect to the supply and to ground, and the middle pin, called the wiper, gives a voltage somewhere between the two, depending on where the knob sits.
Wire it up
The Pico is a 3.3 volt board and its pins are not 5 V tolerant, so the knob is powered from 3V3, never from VBUS or VSYS.
| From | To | Note |
|---|---|---|
| Potentiometer pin 1 | Pico 3V3 | One end of the track. |
| Potentiometer pin 3 | Pico GND | The other end of the track. |
| Potentiometer pin 2 (wiper) | Pico GP26 | GP26 is also called A0 and is an ADC pin. |
| Pico GP15 | One end of the 220 ohm resistor | GP15 will drive the LED with PWM. |
| Other end of the resistor | LED anode (long leg) | Resistor in series. |
| LED cathode (short leg) | Pico GND | Completes the loop. |
Only GP26, GP27 and GP28 (A0, A1 and A2) can read analog values on the Pico's header. That is why the wiper goes to GP26 and not just any pin. The LED can sit on almost any pin, because each Pico GPIO has a PWM channel.
The complete sketch
const int POT_PIN = 26; // GP26, also called A0
const int LED_PIN = 15; // GP15, a PWM pin
const int READ_BITS = 12;
const int MAX_READING = (1 << READ_BITS) - 1; // 4095
void setup() {
Serial.begin(115200);
analogReadResolution(READ_BITS);
pinMode(LED_PIN, OUTPUT);
Serial.println("Turn the knob to dim the LED.");
}
void loop() {
int reading = analogRead(POT_PIN);
int brightness = map(reading, 0, MAX_READING, 0, 255);
analogWrite(LED_PIN, brightness);
Serial.print("reading ");
Serial.print(reading);
Serial.print(" of ");
Serial.print(MAX_READING);
Serial.print(" -> brightness ");
Serial.println(brightness);
delay(200);
}
I compiled this sketch for the Pico in Mokxi's own build path. Press Run and turn the knob. The LED gets brighter as you turn toward 3V3 and dimmer toward ground, and the serial monitor shows the numbers.
Line by line
POT_PIN = 26andLED_PIN = 15name the two pins. Pico numbers are GPIO numbers, so 26 means GP26.READ_BITS = 12is the width of the reading we want. 12 bits means 4096 steps, from 0 to 4095.MAX_READING = (1 << READ_BITS) - 1works out the largest reading for that width, so you only change one number to change the resolution. The expression1 << 12is 4096, and we subtract one because counting starts at zero.analogReadResolution(READ_BITS)tells the Pico how wide a reading to return.pinMode(LED_PIN, OUTPUT)makes GP15 an output.analogRead(POT_PIN)measures the voltage on GP26 against 3.3 volts and returns a number.map(reading, 0, MAX_READING, 0, 255)squeezes that number into the rangeanalogWriteexpects.analogWrite(LED_PIN, brightness)sets the PWM duty cycle. PWM, or pulse-width modulation, switches the pin on and off very fast. The longer it stays on in each cycle, the brighter the LED looks. Our PWM guide shows the idea with a live circuit.delay(200)limits printing to about five lines a second.
Why 10 bits or 12 bits
The Pico's converter is 12 bits wide, so it can tell 4096 voltage levels apart. Mokxi's runtime follows the arduino-pico convention: analogRead returns 10 bits, 0 to 1023, unless you ask for another width. That default means a sketch written for an Arduino Uno, which also reads 0 to 1023, works on the Pico without changes.
Our sketch asks for the full width with analogReadResolution(12). If you delete that line, readings drop to 0 to 1023, and MAX_READING would be wrong. That is the one mistake to watch for: whatever width you set, the second argument of map must be the largest number that width can produce.
Try it. Change READ_BITS to 10 and run again. The knob feels the same, because brightness only has 256 levels anyway.
Two more facts help here. The reference for the reading is 3.3 volts, so the knob at its 3V3 end reads the maximum. And a pin with nothing connected reads 0, so a loose wiper wire shows up as a dark LED and a zero on the monitor.
What analogWrite does on the Pico
On the Pico, analogWrite takes 0 to 255 by default, and it works on every GPIO. A value of 0 turns the pin fully off and 255 fully on. In between, the pin runs a PWM signal at 1 kHz by default. Sketches can change that with analogWriteFreq() and analogWriteRange(), which follow the arduino-pico library.
Try next
- Print the voltage as well: multiply
readingby 3.3 and divide byMAX_READING. - Add a second LED on GP14 that gets brighter as the first gets dimmer, using
255 - brightness. - Make brightness follow a curve instead of a straight line. Our eyes notice dark levels more than bright ones, so squaring the value (scaled back to 0 to 255) often feels smoother.
- Add a second potentiometer on GP27 (A1) and use it to set the maximum brightness of the first.
Try it on Mokxi
The Raspberry Pi Pico board page lists the pins and what the simulation covers, and the PWM guide explains duty cycle with a running circuit.
Ready to build it yourself? Create your free Mokxi account and open the editor in your browser. No installs, no parts to buy.