Pomodoro timer on an active buzzer (pin 9), on an Arduino Uno
An active buzzer on pin 9 times 25 minutes of work and 5 minutes of rest with millis(): one long beep to start work, two short ones to start the break, and the minutes left in the serial monitor. The whole build, an Arduino Uno and 1 more part, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
Teaching? Assign it to your class in one click.
Beginner About 10 minutes to build and run. Runs in your browser. Free, and no account needed.
The parts retail for about $30. On Mokxi they're free.
What you'll learn
- Timing with millis instead of delay
- Switching between two states with a flag
- Driving a buzzer from a pin
- Printing progress to the serial monitor
- Difficulty: Beginner
- Time: About 10 minutes
- Board: Arduino Uno R3
- Parts: 3
How it works
A buzzer on pin 9 marks a work and rest cycle: 25 minutes of work, then 5 minutes of rest, over and over. One long beep at the start tells you work has begun.
The sketch keeps time with millis and not delay. It remembers when the current period began and switches when enough time has passed. That leaves the loop free while it waits.
At the end of work the buzzer beeps twice, short. At the end of rest it beeps once, long. Each minute the serial monitor shows how many minutes are left.
Parts list
3 parts, plus the jumper wires. They retail for about $30; on Mokxi they're free.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 1 × Half breadboard
- 1 × BuzzerIn Starter Kit, Rocket Flight Computer Kit.
Kits that can build it
These 9 starter kits have every part in the circuit. Each kit's page lists what else it can build.
Wiring table
Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.
| Part and pin | Connects to |
|---|---|
| Buzzer pin 2 | Arduino Uno R3 pin GND |
| Buzzer pin 1 | Arduino Uno R3 pin 9 |
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// A Pomodoro timer: 25 minutes of work, 5 of rest, on a buzzer on pin 9.
//
// pin 9 -> the active buzzer's + leg; the other leg -> GND
//
// delay() would freeze the board for 25 minutes, so the timer keeps time with
// millis() instead: the milliseconds since the board started. It remembers
// when the current period began and switches when enough time has passed,
// with the loop free to do other things (here, print the minutes left).
const int BUZZER = 9;
const unsigned long WORK_MS = 25UL * 60UL * 1000UL;
const unsigned long BREAK_MS = 5UL * 60UL * 1000UL;
bool working = true;
unsigned long started = 0;
long lastMinute = -1;
void beep(int times, int ms) {
for (int i = 0; i < times; i++) {
digitalWrite(BUZZER, HIGH);
delay(ms);
digitalWrite(BUZZER, LOW);
delay(200);
}
}
void setup() {
pinMode(BUZZER, OUTPUT);
Serial.begin(9600);
Serial.println("Mokxi Uno: Pomodoro timer, 25 minutes of work, then 5 of rest");
beep(1, 600);
started = millis();
}
void loop() {
unsigned long period = working ? WORK_MS : BREAK_MS;
unsigned long elapsed = millis() - started;
if (elapsed >= period) {
working = !working;
started = millis();
lastMinute = -1;
if (working) beep(1, 600);
else beep(2, 200);
Serial.println(working ? "back to work" : "break time");
return;
}
long minutesLeft = (period - elapsed + 59999UL) / 60000UL;
if (minutesLeft != lastMinute) {
lastMinute = minutesLeft;
Serial.print(working ? "work: " : "break: ");
Serial.print(minutesLeft);
Serial.println(" min left");
}
}
Code walkthrough
The key functions of the sketch, and what each one does.
beep sketch.ino
It sounds the buzzer a number of times. Each time, it sets the pin high for the given number of milliseconds, sets it low, and waits 200 ms before the next beep.
void beep(int times, int ms) {
for (int i = 0; i < times; i++) {
digitalWrite(BUZZER, HIGH);
delay(ms);
digitalWrite(BUZZER, LOW);
delay(200);
}
}setup sketch.ino
It sets the buzzer pin as an output and starts the serial port. It gives one 600 ms beep so you know the timer started. Then it saves the current millis as the start of the work period.
void setup() {
pinMode(BUZZER, OUTPUT);
Serial.begin(9600);
Serial.println("Mokxi Uno: Pomodoro timer, 25 minutes of work, then 5 of rest");
beep(1, 600);
started = millis();
}loop sketch.ino
It works out the time elapsed in this period. When that reaches the period length, it flips between work and break, restarts the clock and beeps. Otherwise it prints the minutes left, once per minute.
void loop() {
unsigned long period = working ? WORK_MS : BREAK_MS;
unsigned long elapsed = millis() - started;
if (elapsed >= period) {
working = !working;
started = millis();
lastMinute = -1;
if (working) beep(1, 600);
else beep(2, 200);
Serial.println(working ? "back to work" : "break time");
return;
}
long minutesLeft = (period - elapsed + 59999UL) / 60000UL;
if (minutesLeft != lastMinute) {
lastMinute = minutesLeft;
Serial.print(working ? "work: " : "break: ");
Serial.print(minutesLeft);
Serial.println(" min left");
}
}Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- The buzzer makes no sound. This project
Check pin 9 goes to the buzzer's + leg (pin 1) and the other leg goes to GND. - Testing takes far too long. This project
MakeWORK_MSandBREAK_MSshorter while you test. They are in milliseconds. - The buzzer makes a constant tone, or you cannot change its pitch. Buzzer
An active buzzer has its own oscillator, so it only beeps on and off. A passive buzzer needs tone() to set pitch. Check which type you have. - The buzzer is silent or very quiet. Buzzer
Check polarity: the plus mark goes to the pin or supply. For loud buzzers, drive them through a transistor instead of straight from a pin. - Upload fails or nothing runs after wiring pins 0 and 1 to a module. Arduino Uno R3
Pins 0 and 1 are the USB serial port. Move the module to other pins, or unplug it while uploading. Also check the right board is selected. - Pins misbehave or the board resets when you power motors or servos from it. Arduino Uno R3
Each I/O pin gives about 20 mA, 40 mA max. Power motors and servos from their own supply and join its ground to the Uno's GND.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.