Embedded Systems
Build an Arduino night lamp with a button and a dimmer
An Arduino night lamp needs three parts and one idea. A button toggles the lamp, a knob sets its brightness, and an LED on a PWM pin is the lamp. The idea is a bool that remembers whether the lamp is on, flipped once per press, so the lamp stays on after you let go.
The wiring
- A push button from pin 2 to GND, with the pin set to
INPUT_PULLUP: released reads HIGH, pressed reads LOW - A 10 kΩ potentiometer with its ends on 5V and GND and its wiper on A0
- An LED on pin 9, a PWM pin, through a 220 Ω resistor to GND
The plan
- Remember: a
bool lampOn, false at power-up, so the lamp starts off whatever the knob says. - The press: when pin 2 reads LOW, flip
lampOn, then wait out the bounce and wait for the release. - The brightness: while the lamp is on, read A0, map 0 to 1023 into 0 to 255, and analogWrite it to pin 9.
- Off means off: while it's off, analogWrite 0.
Live experiment
Find the right glow
A dark bedroom with Pip as the bulb. One press of the button turns the lamp on, the next turns it off, and it stays as you left it in between. Turn the knob to set how bright it glows while it's on. While it's off, the knob does nothing.
“Project: Night lamp” is the project that ends Blink Bay, Embedded Systems World 1. Free with an account. Lessons unlock in order, so you’ll do the 6 before it first.
The sketch
bool lampOn = false;
void setup() {
pinMode(2, INPUT_PULLUP);
pinMode(9, OUTPUT);
}
void loop() {
if (digitalRead(2) == LOW) { // a press
lampOn = !lampOn; // flip on or off
delay(50); // let the contacts settle
while (digitalRead(2) == LOW) {} // wait for the release
delay(50); // let the release settle
}
if (lampOn) {
int level = map(analogRead(A0), 0, 1023, 0, 255);
analogWrite(9, level);
} else {
analogWrite(9, 0);
}
}
! means NOT, so lampOn = !lampOn turns false into true and back again. The while holds the program until the finger lifts, so one press flips the lamp exactly once, however long it's held.
Check the numbers
The knob is a voltage divider: three quarters of the way round, A0 sees about 3.75 V and reads about 768. map() turns that into 768 × 255 ÷ 1023 ≈ 191, rounded down, so pin 9 is on about 75% of each cycle. The brightness is read on every pass of loop(), so turning the knob changes the glow straight away.
Free lesson
Now build it yourself
Each lesson comes in three short parts: see the idea, try it on a live board, then build it yourself, with quick checks as you go.
“Project: Night lamp” is the project that ends Blink Bay, Embedded Systems World 1. Free with an account. Lessons unlock in order, so you’ll do the 6 before it first.
Or start from the very first lesson, no account neededPractice questions
Three quick questions from the lessons. Pick an answer to check it.
Show the answer
Answer: true. ! means NOT: it flips a bool. false becomes true, and the next flip makes it false again. That's how one line toggles a light.
- Why not “false”? The NOT operator flips a bool, so false becomes true. It would be false again only after a second flip.
- Why not “an error”? The NOT operator works on any bool, so the line compiles and flips the value.
- Why not “LOW”? lightOn is a bool, true or false. LOW is a pin level, not something the NOT operator produces.
Show the answer
Answer: LOW. The button joins the pin to 0 V, which beats the weak pull-up, so it reads LOW. Released, the pull-up lifts it back to HIGH.
- Why not “1023”? 1023 is a top analogRead value. digitalRead only ever gives HIGH or LOW.
- Why not “HIGH”? HIGH is what the pin reads with the button released, when the pull-up holds it at 5 V. A press joins it to GND.
Show the answer
Answer: About 127. map keeps the fraction. Halfway up 0 to 1023 becomes halfway up 0 to 255, about 127, so the LED glows about half bright.
- Why not “About 512”? 512 is the reading before mapping. map() squeezes 0 to 1023 into 0 to 255, so halfway becomes about 127.
- Why not “1023”? 1023 is the top of analogRead's range. map()'s output here tops out at 255.
- Why not “0”? 0 would be the knob turned all the way down. Halfway maps to about halfway up 0 to 255.
“Project: Night lamp” is the project that ends Blink Bay, Embedded Systems World 1. Free with an account. Lessons unlock in order, so you’ll do the 6 before it first.
Questions people ask
How do I make a button toggle an LED on Arduino?
Keep a bool for the lamp's state. When a press arrives, flip it to its opposite with the NOT operator, then ignore the button until it has been released and settled. Without that wait, one press flips the state on every pass of loop() and it lands at random.
Why does my lamp turn on and off randomly when I press the button?
Either the button bounces, so one press looks like several, or the code flips the state on every pass while the button is held. Wait about 50 ms after the press, then wait for the release, or act only on the change from HIGH to LOW.
Which pin should the LED use for dimming?
A PWM pin, marked with a ~. On an Uno that's 3, 5, 6, 9, 10 or 11. analogWrite on any other pin can only switch the LED fully on or fully off.
Related topics
- What is a pull-up resistor?Why an input pin needs a pull-up, and why a pressed button reads LOW.
- How the Arduino map() function worksRescale a reading from one range to another, and the traps that come with it.
- How to debounce a button on ArduinoWhy one press counts as four, and the 50 ms fixes that make it count once.
- Arduino analogWrite values: from percent to 0–255analogWrite counts to 255, not 100: turning a percentage into a value, and what the LED really gets.