This project is perfect if you’ve ever wondered how to build a user-friendly countdown timer with an interactive menu, memory storage, and buzzer alerts. This step-by-step guide will walk you through creating an Arduino countdown timer using an I2C 20×4 LCD, push buttons, and a buzzer. The functions of this timer include setting and saving the countdown time, pausing and resetting, and even with buzzer notifications loudly when the time is up.
This project is great for beginners, but it’s also feature-packed for advanced makers. In addition, it uses EEPROM to store your settings, so your countdown configuration will survive even when power is lost. Let’s get started!
Why Build an Arduino Countdown Timer?
Timers are an integral part of a wide variety of activities, from cooking and workout routines to the operations in industry. While there are many timers commercially available, building your own enables feature customization, serves as an introduction to learning about microcontrollers, and, quite frankly, is a fun project.
With this timer, you’ll gain hands-on experience with:
- Using menus to navigate and configure settings.
- Saving time data to EEPROM, ensuring your settings persist even after a power cycle.
- Generating buzzer alerts for both button presses and when the countdown ends.
- Displaying dynamic information on a 20×4 I2C LCD screen.
Components You’ll Need
Here’s what you need to get started:
- Arduino Nano (or any compatible microcontroller)
- I2C 20×4 LCD Display
- 3 Push Buttons (for Increase, Decrease, and Shift/Set)
- Buzzer (for audio alerts)
- Resistors: 10kΩ (for pull-up configuration)
- Breadboard and connecting wires
Understanding the Circuit
Take a look at the circuit diagram. It’s simple yet functional:
- The buttons (Increase, Decrease, and Shift/Set) are connected to digital pins D3, D4, and D5, respectively. Each button is pull-up configured using 10kΩ resistors.
- The LCD display communicates via I2C, with SDA and SCL connected to pins A4 and A5.
- The buzzer is connected to D6, producing beeps on button presses and a continuous alert when the countdown finishes.
- Power is provided through the Arduino’s 5V and GND pins, ensuring stable operation.
How the Buttons Work
The buttons are in a pull-up resistor configuration—normally HIGH, pulled LOW when pressed. This helps to reduce noise and provide a reliable input detection.
Features of the Arduino Countdown Timer
Figure 2: Menu System of Arduino Countdown Timer
Interactive Menu System
The timer has a basic menu system to navigate between “Countdown“ and “Config“ modes. You can:
- Navigate the menu using the Increase and Decrease buttons.
- Select options using the Shift/Set button.
Configurable Time
In Config mode, you can set:
- Hours
- Minutes
- Seconds
The Shift/Set button cycles through these options, while the Increase and Decrease buttons adjust the values. Once configured, you can save the settings to EEPROM.
EEPROM Memory
The configured time is stored in the EEPROM, meaning it won’t be lost even if the Arduino is powered off. This feature makes the timer reliable for long-term use.
Countdown with Pause and Reset
During the countdown:
- Press Shift/Set to pause or resume the timer.
- Press Increase or Decrease while paused to reset the timer to the saved values.
Buzzer Alerts
The buzzer at pin D6 provides:
- A short beep on every button press for feedback.
- A 5-second continuous alert when the countdown reaches zero.
Figure 3: Prototype of Arduino Countdown Timer
Step-by-Step Instructions
Step 1: Assemble the Circuit
Follow the circuit diagram to connect all components:
- Connect the buttons to pins D3, D4, and D5 with 10kΩ pull-up resistors.
- Attach the LCD display to the I2C pins (SDA to A4, SCL to A5).
- Connect the buzzer to pin D6.
Step 2: Upload the Code
Use the Arduino IDE to upload the code provided in this project. Ensure you have the required libraries:
- Wire.h for I2C communication.
- LiquidCrystal_I2C.h for LCD functionality.
The code handles:
- Menu navigation
- Time configuration
- Countdown logic
- EEPROM storage
- Buzzer control
Step 3: Test the Timer
- Power on the Arduino. The LCD will display the main menu with two options: “Countdown“ and “Config.”
- Navigate to “Config“ mode using the buttons. Set the hours, minutes, and seconds, then save the settings.
- Select “Countdown“ mode to start the timer. Watch as the time counts down, and listen for the buzzer when it hits zero.
Code for the Arduino Countdown Timer
Here’s the full code for your Arduino timer. Copy and paste it into the Arduino IDE.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 |
#include <Wire.h> #include <EEPROM.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x25, 20, 4); // States enum SystemMode { MODE_MENU, MODE_CONFIG, MODE_RUNNING, MODE_PAUSED, MODE_FINISHED }; SystemMode currentMode = MODE_MENU; // Time variables int hours = 0; int minutes = 0; int seconds = 0; // Stored original time for reset int savedHours = 0; int savedMinutes = 0; int savedSeconds = 0; int currentTimeUnit = 0; // 0=hours, 1=minutes, 2=seconds, 3=save in config mode bool blinkState = true; unsigned long lastBlinkMillis = 0; const unsigned long blinkInterval = 500; // Countdown timing unsigned long previousMillis = 0; const unsigned long interval = 1000; // Button pins (no button on pin 2 now) const int buttonIncrease = 3; const int buttonDecrease = 4; const int buttonShiftStart = 5; // Buzzer pin const int buzzerPin = 6; bool incBtnPressed = false; bool decBtnPressed = false; bool shiftBtnPressed = false; // Menu navigation int menuIndex = 0; // 0=Count Down, 1=Config const int menuItems = 2; void loadTimeFromEEPROM() { hours = EEPROM.read(0); minutes = EEPROM.read(1); seconds = EEPROM.read(2); if (hours > 23) hours = 0; if (minutes > 59) minutes = 0; if (seconds > 59) seconds = 0; savedHours = hours; savedMinutes = minutes; savedSeconds = seconds; } void saveTimeToEEPROM() { EEPROM.write(0, hours); EEPROM.write(1, minutes); EEPROM.write(2, seconds); savedHours = hours; savedMinutes = minutes; savedSeconds = seconds; } void setup() { pinMode(buttonIncrease, INPUT); pinMode(buttonDecrease, INPUT); pinMode(buttonShiftStart, INPUT); pinMode(buzzerPin, OUTPUT); noTone(buzzerPin); lcd.init(); lcd.backlight(); loadTimeFromEEPROM(); displayMenu(); } void loop() { readButtons(); switch (currentMode) { case MODE_MENU: handleMenu(); break; case MODE_CONFIG: handleConfig(); break; case MODE_RUNNING: handleRunning(); break; case MODE_PAUSED: handlePaused(); break; case MODE_FINISHED: handleFinished(); break; } } void readButtons() { bool inc = (digitalRead(buttonIncrease) == LOW); bool dec = (digitalRead(buttonDecrease) == LOW); bool shift = (digitalRead(buttonShiftStart) == LOW); incBtnPressed = inc; decBtnPressed = dec; shiftBtnPressed = shift; } void shortBeep() { tone(buzzerPin, 1000); // 1kHz tone delay(100); // 100 ms beep noTone(buzzerPin); } void handleMenu() { if (incBtnPressed) { shortBeep(); delay(200); menuIndex = (menuIndex + 1) % menuItems; displayMenu(); } if (decBtnPressed) { shortBeep(); delay(200); menuIndex = (menuIndex - 1 + menuItems) % menuItems; displayMenu(); } if (shiftBtnPressed) { shortBeep(); delay(200); // Select current menu item if (menuIndex == 0) { // Count Down selected if (hours == 0 && minutes == 0 && seconds == 0) { lcd.clear(); lcd.print("Set time first!"); delay(1000); displayMenu(); } else { currentMode = MODE_RUNNING; previousMillis = millis(); displayRunningScreen(); } } else { // Config selected currentMode = MODE_CONFIG; currentTimeUnit = 0; blinkState = true; lastBlinkMillis = millis(); displayConfigScreen(); } } } void handleConfig() { if (millis() - lastBlinkMillis >= blinkInterval) { lastBlinkMillis = millis(); blinkState = !blinkState; displayConfigScreen(); } if (incBtnPressed) { shortBeep(); delay(200); if (currentTimeUnit < 3) changeTime(1); displayConfigScreen(); } if (decBtnPressed) { shortBeep(); delay(200); if (currentTimeUnit < 3) changeTime(-1); displayConfigScreen(); } if (shiftBtnPressed) { shortBeep(); delay(200); shiftTimeUnit(); } } void handleRunning() { if (millis() - previousMillis >= interval) { previousMillis = millis(); decrementTime(); if (hours == 0 && minutes == 0 && seconds == 0) { currentMode = MODE_FINISHED; displayTimeUp(); // Beep for 5 seconds tone(buzzerPin, 1000); delay(5000); noTone(buzzerPin); } else { displayRunningScreen(); } } // Pause/Resume with Shift if (shiftBtnPressed) { shortBeep(); delay(200); currentMode = MODE_PAUSED; displayPausedScreen(); } } void handlePaused() { // Shift resumes // Inc/Dec resets if (shiftBtnPressed) { shortBeep(); delay(200); currentMode = MODE_RUNNING; previousMillis = millis(); displayRunningScreen(); } if (incBtnPressed || decBtnPressed) { shortBeep(); delay(200); // Reset to saved time hours = savedHours; minutes = savedMinutes; seconds = savedSeconds; currentMode = MODE_MENU; displayMenu(); } } void handleFinished() { // Press shift to go back to menu if (shiftBtnPressed) { shortBeep(); delay(200); currentMode = MODE_MENU; displayMenu(); } } void changeTime(int delta) { switch (currentTimeUnit) { case 0: hours = (hours + delta + 24) % 24; break; case 1: minutes = (minutes + delta + 60) % 60; break; case 2: seconds = (seconds + delta + 60) % 60; break; } } void shiftTimeUnit() { currentTimeUnit++; if (currentTimeUnit > 3) { // On save saveTimeToEEPROM(); currentMode = MODE_MENU; displayMenu(); } else { displayConfigScreen(); } } void decrementTime() { if (seconds > 0) { seconds--; } else { if (minutes > 0) { minutes--; seconds = 59; } else { if (hours > 0) { hours--; minutes = 59; seconds = 59; } } } } String formatNumber(int val) { String out = ""; if (val < 10) out += "0"; out += val; return out; } String formatTime(int h, int m, int s) { return formatNumber(h) + ":" + formatNumber(m) + ":" + formatNumber(s); } void displayMenu() { lcd.clear(); lcd.setCursor(0,0); lcd.print("Main Menu:"); lcd.setCursor(0,1); if (menuIndex == 0) lcd.print(">"); else lcd.print(" "); lcd.print("Count Down"); lcd.setCursor(0,2); if (menuIndex == 1) lcd.print(">"); else lcd.print(" "); lcd.print("Config"); lcd.setCursor(0,3); lcd.print("Saved: " + formatTime(savedHours, savedMinutes, savedSeconds)); } void displayConfigScreen() { lcd.clear(); lcd.setCursor(0,0); lcd.print("Config:"); String hStr = formatNumber(hours); String mStr = formatNumber(minutes); String sStr = formatNumber(seconds); if (currentTimeUnit == 0 && !blinkState) hStr = " "; if (currentTimeUnit == 1 && !blinkState) mStr = " "; if (currentTimeUnit == 2 && !blinkState) sStr = " "; lcd.setCursor(0,1); if (currentTimeUnit == 0) lcd.print(">H:"); else lcd.print(" H:"); lcd.print(hStr); lcd.setCursor(0,2); if (currentTimeUnit == 1) lcd.print(">M:"); else lcd.print(" M:"); lcd.print(mStr); lcd.setCursor(0,3); if (currentTimeUnit == 2) lcd.print(">S:"); else lcd.print(" S:"); lcd.print(sStr); lcd.setCursor(10,3); if (currentTimeUnit == 3 && !blinkState) { lcd.print(" "); } else { if (currentTimeUnit == 3) lcd.print(">Save"); else lcd.print(" Save"); } } void displayRunningScreen() { lcd.clear(); lcd.setCursor(0,0); lcd.print("RUNNING"); lcd.setCursor(0,1); lcd.print("Time: " + formatTime(hours, minutes, seconds)); lcd.setCursor(0,2); lcd.print("Shift=Pause"); } void displayPausedScreen() { lcd.clear(); lcd.setCursor(0,0); lcd.print("PAUSED"); lcd.setCursor(0,1); lcd.print("Time: " + formatTime(hours, minutes, seconds)); lcd.setCursor(0,2); lcd.print("Shift=Resume"); lcd.setCursor(0,3); lcd.print("Inc/Dec=Reset"); } void displayTimeUp() { lcd.clear(); lcd.setCursor(0,0); lcd.print("Time's Up!"); lcd.setCursor(0,1); lcd.print("Shift=Menu"); } |
How It Works
During Setup
The EEPROM stores the configured time, ensuring the timer remembers your settings even after a restart. When you power on the Arduino, the saved time is loaded automatically.
During Countdown
The LCD updates every second to show the remaining time in HH:MM:SS format. The buzzer provides an audible alert at the end of the countdown, ensuring you don’t miss it.
Menu and Navigation
The menu is intuitive and easy to handle because of the timer’s setting and starting via this menu. The buttons guarantee smooth interaction with audible feedback while setting the time and starting the countdown.
Applications of the Arduino Countdown Timer
This versatile countdown timer finds application in:
- Kitchens: to keep track of cooking times.
- Workouts: for the timing of your exercises and rest periods.
- Labs: for timing experiments.
- Games: during board games or challenges
Conclusion
This project of building an Arduino Countdown Timer with Menu, EEPROM, and Buzzer Alerts is quite an interesting study process. You’ll learn essential topics such as I2C communication, using EEPROM memory, and easy interface development. Moreover, it can be used everywhere in life for whatever purpose you will find necessary or convenient.
So, grab your Arduino, some buttons, a buzzer, and build your personal countdown timer starting today! For real-this time, literally.