Build a dimmable desk lamp

Control an LED with a microcontroller, read a button without false presses, and set brightness with pulse-width modulation.

Needs nothing first About 90 minutes 6 milestones 3 walls

What you are building

A microcontroller pin can be configured as a digital input or output. In this project, one output drives an LED through a current-limiting resistor and one input reads a push button. Check the board voltage, pin-current limits, and LED polarity before wiring the circuit.

Teal entries are build checks. The three magenta entries explain an electrical or timing problem and link to the lesson needed to solve it.

Build the virtual circuit first

Start with the LED, resistor, push button and potentiometer in Wokwi. Choose a supported board from the same family as your real board when possible, and keep the pin numbers in one small configuration block. Run the same firmware here that you plan to put on the physical board.

  1. Wire the LED and resistor, then check the off and on states before adding the button.
  2. Add the button and potentiometer. Exercise a held press, rapid presses and a press while the lamp is blinking.
  3. Connect Wokwi's logic analyser to the button and PWM pins. Measure the blink interval and duty cycle instead of judging them by eye.

The simulator is useful for program logic, pin states and timing. It does not prove that a real resistor has the right power rating, that the LED is the right way round, or that the board can safely supply the current. Check those from the part data sheets before moving the circuit to a breadboard. The Simulating Physical Systems course explains the virtual-circuit and transfer checks.

Project milestones

  1. Set a digital output and measure its voltage.

    Set one pin high, put a voltmeter on it, and read the number. Nothing is connected to the pin yet. This is the smallest thing the machine can do, and every other milestone is a rearrangement of it.

  2. Light an LED from that pin.

    One LED, one resistor, and the light comes on. Then take the resistor out in the simulator and find out what the resistor was for.

  3. Blink the LED at a measured interval.

    On, wait, off, wait, repeat. Your first program with a loop in it, and the first time the board does something without you.

  4. Give the button input a defined idle level.

    With nothing holding it, an input pin is not zero. It is whatever the air and the wires around it happen to be, and it changes when you move your hand.

    What you need

    A pin left unconnected is called floating, and the fix is a pull-up resistor: a weak connection to 3.3 volts that decides the answer when the button is not pressed.

    step 4Read a button, and stop the pin from guessing
  5. Read the button and control the light while held.

    Press, the light comes on. Release, it goes off. Now try to count presses, which is where it goes wrong again.

  6. Measure switch bounce.

    One finger, one press, and the count jumps by several. Nothing is broken. The metal inside the switch bounces and the pin sees every bounce.

    What you need

    Debouncing: ignore any further change for a few thousandths of a second after the first one. The trick is choosing that window, because too long and a fast real press gets thrown away.

    step 5Count one press as one press
  7. Debounce the button and count one event per press.

    Press four times, the counter says four. Check it against the trace rather than against your memory of how many times you pressed.

  8. Control apparent brightness with PWM.

    The pin has two settings: 3.3 volts, or nothing. There is no half. And yet every screen you own dims.

    What you need

    Switch it on and off faster than an eye can follow, and change the fraction of the time it spends on. The fraction has a name, duty cycle, and the technique is pulse width modulation.

    step 6Dim an LED without changing the voltage
  9. Read a dial while continuing to count button presses.

    Both at once, in one program. That is the build finished, and it is also the smallest thing that deserves to be called a device.

Review the lamp in four passes

Review the same lamp for normal operation, edge cases, responsiveness, and recovery from a hang.

Make it work

Done, above. It blinks, it reads the button, it dims.

Make it correct

Hold the button down for a full minute. Press it during a blink. Press it twice inside one debounce window. Does the count stay right in all three?

Make it fast

Your loop waits by doing nothing. Find out how much of the time the chip is asleep in a delay rather than watching the button, and get the wait out of the way.

Make it survive

Make the program hang on purpose, then make the board notice and restart itself without you touching it.

Course links for each pass

Each of those three later passes has a step behind it, in the same course. Take them when you want them and not before.

  1. Getting the wait out of the way.
    Make it fast

    A delay stops everything. Two jobs at two different rates need a clock you check rather than a wait you sit in.

    step 13Run two jobs at two rates with no delay
  2. Catching a press while the program is busy.
    Make it correct

    An interrupt lets a pin stop the program mid-line, run a few instructions, and put it back, so a press is never missed while something else was happening.

    step 12Catch a press while the program is busy
  3. Recovering from a hang on its own.
    Make it survive

    A watchdog is a timer that restarts the chip unless the program keeps telling it not to. If the program hangs, it stops telling it, and the board comes back.

    step 14Make the board recover from a hang on its own

Related projects and courses

A pin that can be switched fast, a sensor that can be read, and a loop that keeps time are the three pieces every machine in this stream is made of. The next build spins a motor, counts its turns, and drives to a place you point at.

All builds or read Embedded Systems straight through, which covers the same ground in order and goes considerably further.