Practical case: relay timer on Arduino UNO

Practical case: relay timer on Arduino UNO — hero

Objective and use case

What you’ll build: A standalone workshop countdown relay timer using an Arduino UNO R3, pushbuttons, a 1-channel relay module, and a piezo buzzer. Users can set a duration, start a non-blocking countdown with millis(), keep a 5 V or 12 V load energized through the relay while time remains, and trigger an audible alert when the timer reaches 0.

Why it matters / Use cases

  • Automatically shut off small bench loads such as a 5 V fan, miniature pump, or 12 V test lamp after a fixed 30 s to 10 min work cycle.
  • Improve repeatability for workshop tasks like adhesive warming, PCB fume extraction, cleaner runs, or jig activation where consistent timing matters more than manual estimation.
  • Teach core embedded skills in one build: button reading, debounce timing in the 10–50 ms range, relay control, buzzer feedback, and finite-state logic without using delay().
  • Run fully standalone after upload, with near-instant button response under typical loop times of a few milliseconds and no PC connection required.

Expected outcome

  • A timer that lets the user increase or decrease duration with pushbuttons, then start or stop the countdown reliably.
  • A relay output that stays active for the programmed interval and switches off immediately when time expires or the cycle is canceled.
  • A buzzer pattern at completion, for example 2–3 short beeps over 1–2 s, to clearly signal the end of the timed run.
  • A responsive low-load Arduino implementation: no meaningful GPU usage, very low CPU demand on the ATmega328P, and sub-10 ms control latency for normal button and output events.

Audience: Arduino beginners, makers, students, and electronics workshop users; Level: beginner to lower-intermediate

Architecture/flow: Pushbuttons feed the UNO digital inputs; the sketch debounces presses, updates the selected time, and tracks countdown state with millis(); the UNO drives the relay input to energize the external load during the active window and toggles the piezo buzzer when the countdown completes.

Educational validation note

Before publication, this case passed the Prometeo automated validation gate with status PASS. The validator checked the code blocks, article structure, copy/paste-safe commands and consistency with the supported device catalog.

Published validation evidence

  • Automatic result: PASS.
  • Parsed structure: 3 sections, 3 tables and 2 code blocks detected before publication.
  • Checked code: 1 Arduino/arduino-cli compile, 1 Bash/copy-paste checks.
  • Supported catalog: the article text was checked against Prometeo’s validation-capable device profiles, and unsupported stacks block publication.
  • Report findings: no blocking findings.

This validation confirms syntax and tool compatibility for the published material, but it does not replace physical testing on your exact hardware, wiring and runtime environment.

Educational safety note

This prototype is intended for education and bench-level experimentation. Its limits are important:

  • Do not use this beginner build to switch household mains voltage unless you are trained and your lab explicitly permits it.
  • Relay modules can expose dangerous voltages on their contact terminals.
  • For classroom validation, use a low-voltage DC load only.
  • The Arduino side and relay contact side are different electrical domains. Treat the relay contact wiring carefully even if the control side is only 5 V.
  • Do not use this timer to control:
  • safety-critical tools
  • unattended heating systems
  • medical devices
  • vehicle systems
  • high-power machinery
  • If you later connect motors, solenoids, or other inductive loads, additional protection and proper power design may be required.
  • Keep wiring insulated, stable, and strain-relieved. Loose relay wiring can create unreliable switching or hazardous shorts.
  • The piezo buzzer is only an alert aid. It is not guaranteed to be heard in a noisy workshop.
  • This tutorial demonstrates a useful educational prototype, not a certified product.

Prerequisites

Before starting, make sure you have:

  • Basic familiarity with the Arduino IDE concept, even though this tutorial uses Arduino CLI
  • A USB cable for the Arduino UNO R3
  • A computer with:
  • Arduino CLI installed
  • A serial terminal available, or the Arduino IDE Serial Monitor if preferred
  • Basic understanding of:
  • Digital inputs with pull-up resistors
  • Digital outputs
  • Safe use of relay modules
  • A low-voltage load for testing the relay output
  • Recommended: a small DC lamp, LED load module, low-voltage fan, or small DC motor supply line through the relay contacts
  • Do not start with household mains loads in a beginner lab

Materials

Use the exact platform below.

  • Arduino UNO R3 (ATmega328P)
  • 3 pushbuttons
    Suggested labels:
  • ADD
  • START/PAUSE
  • CANCEL/RESET
  • 1-channel relay module
  • 5 V coil/module version compatible with Arduino logic
  • Prefer a module with transistor driver and input indicator LED
  • Piezo buzzer
  • Passive or active buzzer; this tutorial assumes a simple piezo buzzer that can be driven from a digital pin
  • Breadboard
  • Jumper wires
  • USB cable for Arduino UNO R3
  • Optional but recommended:
  • Small low-voltage DC lamp or fan as the relay-switched test load
  • External low-voltage supply for that test load if needed by the load

Setup/Connection

This project uses the Arduino’s internal pull-up resistors for all pushbuttons. That means each button is wired between the input pin and GND. When not pressed, the input reads HIGH. When pressed, it reads LOW.

Pin assignment

FunctionArduino pinWiring details
ADD buttonD2One side of pushbutton to D2, other side to GND
START/PAUSE buttonD3One side of pushbutton to D3, other side to GND
CANCEL/RESET buttonD4One side of pushbutton to D4, other side to GND
Relay inputD8Relay module IN to D8
BuzzerD9Buzzer signal to D9, buzzer ground to GND
Relay VCC5VRelay module VCC to Arduino 5V
Relay GNDGNDRelay module GND to Arduino GND
Buzzer GNDGNDBuzzer ground to Arduino GND
USB power/dataUSBArduino to computer

Connection notes

  1. Pushbuttons
  2. Connect one terminal of each button to the assigned digital pin.
  3. Connect the other terminal of each button to GND.
  4. No external resistors are needed because the sketch enables INPUT_PULLUP.

  5. Relay module

  6. Connect:
    • VCC -> 5V
    • GND -> GND
    • IN -> D8
  7. Many relay modules are active-low, meaning the relay turns on when the Arduino pin outputs LOW.
  8. The code below is written for a common active-low relay module and includes one constant you can change if your module is active-high.

  9. Piezo buzzer

  10. Connect the positive/signal pin to D9.
  11. Connect the negative pin to GND.
  12. For many small piezo buzzers, direct connection is acceptable for a basic educational prototype.

  13. Relay contact side

  14. The relay contact terminals are separate from the Arduino side.
  15. For a timer-controlled output, use the relay’s COM and NO terminals if you want the load to turn on only while timing is active.
  16. Keep your first test simple:
    • Use a low-voltage load
    • Use a known safe supply
    • Verify the relay switches correctly before connecting anything more complex

Suggested operating behavior

  • ADD button: increases preset time by 1 minute, from 1 to 60 minutes, then wraps back to 1
  • START/PAUSE button: starts the timer if idle; pauses/resumes if already running
  • CANCEL/RESET button: stops the timer and returns to the current preset value
  • Buzzer feedback:
  • Short beep on valid button actions
  • Distinct multi-beep pattern when time completes

Validated Code

workshop_countdown_relay_timer.ino

Public preview of the validated file. The complete source is shown to members and in PDF/Print.

/*
  workshop_countdown_relay_timer.ino

  Device model:
  Arduino UNO R3 (ATmega328P) + pushbuttons + 1-channel relay module + piezo buzzer

  Project goal:
  workshop-countdown-relay-timer

  Behavior:
  - ADD button: increase preset time by 1 minute (1..60, wrap around)
  - START/PAUSE button:
      * if idle -> start countdown
      * if running -> pause
      * if paused -> resume
  - CANCEL/RESET button:
      * stop countdown
      * relay off
      * restore remaining time to preset
  - Relay is active while countdown is running
  - Buzzer gives short feedback on actions and a completion pattern at the end

  Notes:
  - Buttons use INPUT_PULLUP, so pressed = LOW
  - Relay modules are often active-low; set RELAY_ACTIVE_LOW accordingly
*/

const byte PIN_BTN_ADD = 2;
const byte PIN_BTN_START = 3;
const byte PIN_BTN_CANCEL = 4;
const byte PIN_RELAY = 8;
const byte PIN_BUZZER = 9;

const bool RELAY_ACTIVE_LOW = true;

const unsigned long DEBOUNCE_MS = 35;
const unsigned long STATUS_PRINT_MS = 1000;
const unsigned long MINUTES_MAX = 60;
const unsigned long DEFAULT_PRESET_MIN = 5;

enum TimerState {
  IDLE,
  RUNNING,
  PAUSED,
  FINISHED
};

TimerState timerState = IDLE;

unsigned long presetMinutes = DEFAULT_PRESET_MIN;
unsigned long remainingMs = DEFAULT_PRESET_MIN * 60UL * 1000UL;
unsigned long lastTickMs = 0;
unsigned long lastStatusPrintMs = 0;

struct Button {
  byte pin;
  bool stableState;
  bool lastReading;
  unsigned long lastChangeMs;
};

Button btnAdd    = {PIN_BTN_ADD, HIGH, HIGH, 0};
Button btnStart  = {PIN_BTN_START, HIGH, HIGH, 0};
Button btnCancel = {PIN_BTN_CANCEL, HIGH, HIGH, 0};

void setRelay(bool on) {
  if (RELAY_ACTIVE_LOW) {
    digitalWrite(PIN_RELAY, on ? LOW : HIGH);
  } else {
    digitalWrite(PIN_RELAY, on ? HIGH : LOW);
  }
}

void beep(unsigned int frequency, unsigned long durationMs) {
  tone(PIN_BUZZER, frequency, durationMs);
}

void shortBeep() {
  beep(2200, 70);
}

void doubleBeep() {
  beep(2000, 60);
  delay(100);
  beep(2600, 80);
}

void finishBeepPattern() {
  for (int i = 0; i < 3; i++) {
    beep(1800, 120);
    delay(180);
  }
  beep(2600, 350);
  delay(400);
}

bool buttonPressedEvent(Button &button) {
  bool reading = digitalRead(button.pin);

  if (reading != button.lastReading) {
    button.lastChangeMs = millis();
    button.lastReading = reading;
  }

  if ((millis() - button.lastChangeMs) > DEBOUNCE_MS) {
    if (reading != button.stableState) {
      button.stableState = reading;

      // Because INPUT_PULLUP is used, LOW means pressed
      if (button.stableState == LOW) {
        return true;
      }
    }
  }

  return false;
}

void printHelp() {
  Serial.println(F("Workshop Countdown Relay Timer"));
  Serial.println(F("Buttons:"));
  Serial.println(F("  ADD         -> +1 minute preset (1..60)"));
  Serial.println(F("  START/PAUSE -> start, pause, resume"));
  Serial.println(F("  CANCEL      -> stop and reset to preset"));
  Serial.println();
}

void printStateLine() {
  unsigned long totalSeconds = remainingMs / 1000UL;
  unsigned int minutesPart = totalSeconds / 60UL;
  unsigned int secondsPart = totalSeconds % 60UL;

  Serial.print(F("Preset="));
  Serial.print(presetMinutes);
  Serial.print(F(" min, Remaining="));
  if (minutesPart < 10) Serial.print('0');
  Serial.print(minutesPart);
  Serial.print(':');
  if (secondsPart < 10) Serial.print('0');
  Serial.print(secondsPart);
  Serial.print(F(", State="));

  switch (timerState) {
    case IDLE: Serial.print(F("IDLE")); break;
    case RUNNING: Serial.print(F("RUNNING")); break;
    case PAUSED: Serial.print(F("PAUSED")); break;
    case FINISHED: Serial.print(F("FINISHED")); break;
  }
// ...

🔒 This content is premium. With the monthly subscription (7-day free trial) you can unlock the full didactic material and the print-ready PDF pack.🔓 Unlock it — 7-day free trial
/*
  workshop_countdown_relay_timer.ino

  Device model:
  Arduino UNO R3 (ATmega328P) + pushbuttons + 1-channel relay module + piezo buzzer

  Project goal:
  workshop-countdown-relay-timer

  Behavior:
  - ADD button: increase preset time by 1 minute (1..60, wrap around)
  - START/PAUSE button:
      * if idle -> start countdown
      * if running -> pause
      * if paused -> resume
  - CANCEL/RESET button:
      * stop countdown
      * relay off
      * restore remaining time to preset
  - Relay is active while countdown is running
  - Buzzer gives short feedback on actions and a completion pattern at the end

  Notes:
  - Buttons use INPUT_PULLUP, so pressed = LOW
  - Relay modules are often active-low; set RELAY_ACTIVE_LOW accordingly
*/

const byte PIN_BTN_ADD = 2;
const byte PIN_BTN_START = 3;
const byte PIN_BTN_CANCEL = 4;
const byte PIN_RELAY = 8;
const byte PIN_BUZZER = 9;

const bool RELAY_ACTIVE_LOW = true;

const unsigned long DEBOUNCE_MS = 35;
const unsigned long STATUS_PRINT_MS = 1000;
const unsigned long MINUTES_MAX = 60;
const unsigned long DEFAULT_PRESET_MIN = 5;

enum TimerState {
  IDLE,
  RUNNING,
  PAUSED,
  FINISHED
};

TimerState timerState = IDLE;

unsigned long presetMinutes = DEFAULT_PRESET_MIN;
unsigned long remainingMs = DEFAULT_PRESET_MIN * 60UL * 1000UL;
unsigned long lastTickMs = 0;
unsigned long lastStatusPrintMs = 0;

struct Button {
  byte pin;
  bool stableState;
  bool lastReading;
  unsigned long lastChangeMs;
};

Button btnAdd    = {PIN_BTN_ADD, HIGH, HIGH, 0};
Button btnStart  = {PIN_BTN_START, HIGH, HIGH, 0};
Button btnCancel = {PIN_BTN_CANCEL, HIGH, HIGH, 0};

void setRelay(bool on) {
  if (RELAY_ACTIVE_LOW) {
    digitalWrite(PIN_RELAY, on ? LOW : HIGH);
  } else {
    digitalWrite(PIN_RELAY, on ? HIGH : LOW);
  }
}

void beep(unsigned int frequency, unsigned long durationMs) {
  tone(PIN_BUZZER, frequency, durationMs);
}

void shortBeep() {
  beep(2200, 70);
}

void doubleBeep() {
  beep(2000, 60);
  delay(100);
  beep(2600, 80);
}

void finishBeepPattern() {
  for (int i = 0; i < 3; i++) {
    beep(1800, 120);
    delay(180);
  }
  beep(2600, 350);
  delay(400);
}

bool buttonPressedEvent(Button &button) {
  bool reading = digitalRead(button.pin);

  if (reading != button.lastReading) {
    button.lastChangeMs = millis();
    button.lastReading = reading;
  }

  if ((millis() - button.lastChangeMs) > DEBOUNCE_MS) {
    if (reading != button.stableState) {
      button.stableState = reading;

      // Because INPUT_PULLUP is used, LOW means pressed
      if (button.stableState == LOW) {
        return true;
      }
    }
  }

  return false;
}

void printHelp() {
  Serial.println(F("Workshop Countdown Relay Timer"));
  Serial.println(F("Buttons:"));
  Serial.println(F("  ADD         -> +1 minute preset (1..60)"));
  Serial.println(F("  START/PAUSE -> start, pause, resume"));
  Serial.println(F("  CANCEL      -> stop and reset to preset"));
  Serial.println();
}

void printStateLine() {
  unsigned long totalSeconds = remainingMs / 1000UL;
  unsigned int minutesPart = totalSeconds / 60UL;
  unsigned int secondsPart = totalSeconds % 60UL;

  Serial.print(F("Preset="));
  Serial.print(presetMinutes);
  Serial.print(F(" min, Remaining="));
  if (minutesPart < 10) Serial.print('0');
  Serial.print(minutesPart);
  Serial.print(':');
  if (secondsPart < 10) Serial.print('0');
  Serial.print(secondsPart);
  Serial.print(F(", State="));

  switch (timerState) {
    case IDLE: Serial.print(F("IDLE")); break;
    case RUNNING: Serial.print(F("RUNNING")); break;
    case PAUSED: Serial.print(F("PAUSED")); break;
    case FINISHED: Serial.print(F("FINISHED")); break;
  }

  Serial.print(F(", Relay="));
  Serial.println((timerState == RUNNING) ? F("ON") : F("OFF"));
}

void resetToPreset() {
  remainingMs = presetMinutes * 60UL * 1000UL;
  lastTickMs = millis();
}

void handleAddButton() {
  // For simplicity in a basic project, allow preset changes only when not running
  if (timerState == RUNNING) {
    doubleBeep();
    Serial.println(F("ADD ignored while running. Pause or cancel first."));
    return;
  }

  presetMinutes++;
  if (presetMinutes > MINUTES_MAX) {
    presetMinutes = 1;
  }

  resetToPreset();

  if (timerState == FINISHED) {
    timerState = IDLE;
  }

  shortBeep();
  Serial.print(F("Preset changed to "));
  Serial.print(presetMinutes);
  Serial.println(F(" minute(s)."));
  printStateLine();
}

void handleStartButton() {
  if (timerState == IDLE || timerState == FINISHED) {
    resetToPreset();
    timerState = RUNNING;
    setRelay(true);
    lastTickMs = millis();
    shortBeep();
    Serial.println(F("Countdown started."));
    printStateLine();
    return;
  }

  if (timerState == RUNNING) {
    timerState = PAUSED;
    setRelay(false);
    shortBeep();
    Serial.println(F("Countdown paused."));
    printStateLine();
    return;
  }

  if (timerState == PAUSED) {
    timerState = RUNNING;
    setRelay(true);
    lastTickMs = millis();
    shortBeep();
    Serial.println(F("Countdown resumed."));
    printStateLine();
    return;
  }
}

void handleCancelButton() {
  timerState = IDLE;
  setRelay(false);
  resetToPreset();
  doubleBeep();
  Serial.println(F("Countdown canceled and reset to preset."));
  printStateLine();
}

void updateTimer() {
  if (timerState != RUNNING) {
    return;
  }

  unsigned long now = millis();
  unsigned long elapsed = now - lastTickMs;
  lastTickMs = now;

  if (elapsed >= remainingMs) {
    remainingMs = 0;
    timerState = FINISHED;
    setRelay(false);
    Serial.println(F("Countdown complete. Relay turned OFF."));
    printStateLine();
    finishBeepPattern();
    return;
  }

  remainingMs -= elapsed;
}

void setup() {
  pinMode(PIN_BTN_ADD, INPUT_PULLUP);
  pinMode(PIN_BTN_START, INPUT_PULLUP);
  pinMode(PIN_BTN_CANCEL, INPUT_PULLUP);

  pinMode(PIN_RELAY, OUTPUT);
  pinMode(PIN_BUZZER, OUTPUT);

  setRelay(false);

  Serial.begin(9600);
  delay(300);

  printHelp();
  resetToPreset();
  printStateLine();
}

void loop() {
  if (buttonPressedEvent(btnAdd)) {
    handleAddButton();
  }

  if (buttonPressedEvent(btnStart)) {
    handleStartButton();
  }

  if (buttonPressedEvent(btnCancel)) {
    handleCancelButton();
  }

  updateTimer();

  unsigned long now = millis();
  if (now - lastStatusPrintMs >= STATUS_PRINT_MS) {
    lastStatusPrintMs = now;
    printStateLine();
  }
}

What the code is doing

This sketch uses a state machine with four states:

  • IDLE – waiting for user input
  • RUNNING – countdown active, relay on
  • PAUSED – countdown frozen, relay off
  • FINISHED – countdown reached zero, relay off, buzzer alert completed

Important beginner-friendly design choices:

  • No blocking countdown loop
    The timer uses millis() instead of a long delay(), so button presses stay responsive.
  • Debounced buttons
    Each button is filtered with a small debounce interval to reduce false triggers from contact bounce.
  • Preset and remaining time are separate
    presetMinutes stores the chosen duration, while remainingMs tracks what is left during a run.
  • Serial status output
    The Arduino prints regular updates, which makes troubleshooting much easier during validation.

Build/Flash/Run commands

Command table

PurposeCommand
Update board indexarduino-cli core update-index
Install AVR corearduino-cli core install arduino:avr
Compile sketcharduino-cli compile --fqbn arduino:avr:uno workshop_countdown_relay_timer
Upload sketcharduino-cli upload --fqbn arduino:avr:uno --port <PORT> workshop_countdown_relay_timer

Example terminal session

arduino-cli core update-index
arduino-cli core install arduino:avr
arduino-cli compile --fqbn arduino:avr:uno workshop_countdown_relay_timer
arduino-cli upload --fqbn arduino:avr:uno --port <PORT> workshop_countdown_relay_timer

Short workflow

  1. Create a folder named workshop_countdown_relay_timer.
  2. Save the sketch as:
  3. workshop_countdown_relay_timer/workshop_countdown_relay_timer.ino
  4. Open a terminal in the parent directory of that folder.
  5. Run the compile command.
  6. Connect the Arduino UNO R3 by USB.
  7. Replace <PORT> with your actual serial port and run the upload command.
  8. Linux example: /dev/ttyACM0
  9. Windows example: COM4
  10. macOS example: /dev/cu.usbmodem14101
  11. Open a serial monitor at 9600 baud to observe timer status.

Step-by-step Validation

Use these checkpoints in order. The goal is to validate the exact workshop-countdown-relay-timer behavior.

1. Power-up and idle status

Action
– Connect the Arduino by USB.
– Open the serial monitor at 9600 baud.

Expected observation
– You should see a startup banner like:
Workshop Countdown Relay Timer
– You should also see a status line with:
Preset=5 min
State=IDLE
Relay=OFF

Pass condition
– The relay is not energized at startup.
– The serial monitor shows the preset time and idle state without random characters.

2. Preset adjustment using the ADD button

Action
– Press the ADD button once.
– Then press it several more times.

Expected observation
– Each press increases the preset by 1 minute.
– The serial monitor reports:
Preset changed to 6 minute(s).
– and updated state lines
– After 60 minutes, the next press wraps to 1 minute.

Pass condition
– One button press produces one preset change.
– No frequent double-counting occurs from switch bounce.
– The timer remains in IDLE and the relay stays off during preset adjustment.

3. Start countdown and confirm relay activation

Action
– Set a short test preset such as 1 minute.
– Press START/PAUSE once.

Expected observation
– Serial output says:
Countdown started.
State=RUNNING
Relay=ON
– The relay module indicator LED, if present, should change state.
– Your connected low-voltage test load should turn on through the relay.

Pass condition
– Relay activates only when the timer enters RUNNING.
– The remaining time decreases once per second in the serial monitor.

4. Pause, resume, and cancel behavior

Action
– While running, press START/PAUSE again.
– Press it once more to resume.
– Then press CANCEL/RESET.

Expected observation
– On pause:
State=PAUSED
Relay=OFF
– On resume:
State=RUNNING
Relay=ON
– On cancel:
Countdown canceled and reset to preset.
State=IDLE
Relay=OFF

Pass condition
– Pause stops the countdown without losing the remaining time.
– Resume continues from the paused remaining time.
– Cancel immediately turns off the relay and restores the full preset value.

5. End-of-countdown completion test

Action
– Set the preset to 1 minute and let it run to zero without pressing buttons.

Expected observation
– At completion:
– Serial output reports Countdown complete. Relay turned OFF.
– State changes to FINISHED
– The buzzer sounds a recognizable completion pattern
– The low-voltage test load turns off at the same moment the relay deactivates.

Pass condition
– Relay turns off automatically at timeout.
– Completion buzzer sounds once per countdown completion event.
– The system does not restart by itself.

Troubleshooting

SymptomLikely causeFix
Button press does nothingButton wired to 5V instead of GND, wrong pin, poor breadboard contactVerify each button goes between pin and GND, and matches D2/D3/D4
Relay is always onRelay module active-low behavior not matched, or wiring errorCheck RELAY_ACTIVE_LOW; if needed change to false and re-upload
Relay clicks but load does not switchCOM/NO/NC contacts wired incorrectlyUse relay contact terminals correctly; for normal timed-on behavior use COM and NO
Buzzer silentBuzzer polarity reversed, wrong pin, or incompatible buzzer typeConfirm buzzer is on D9 and GND; try another piezo buzzer
Serial monitor shows unreadable textWrong baud rateSet serial monitor to 9600 baud
Timer resets unexpectedlyUSB power unstable or load noise affecting supplyUse a stable USB cable, keep relay/load wiring tidy, and avoid powering noisy loads from the Arduino 5V rail
One press causes two actionsSwitch bounce or loose connectionRe-seat wires, use better pushbuttons, keep button wiring short
Upload failsWrong port, missing board core, cable issueRe-run core install, verify port, use a known data-capable USB cable

Improvements

Usability upgrades

  • Add a 4-digit 7-segment display or LCD to show remaining time without using the serial monitor.
  • Add a long-press feature on the ADD button for faster time setting.
  • Store the last preset in EEPROM so the timer remembers it after power loss.

Control and timing features

  • Add a 10-second adjustment mode for short process timing.
  • Add a post-run buzzer mute option so the timer can be used in quieter classrooms.
  • Add a relay overrun mode, where a fan keeps running for an extra minute after a work cycle ends.

Electrical robustness

  • Use a proper project enclosure with labeled buttons.
  • Add screw terminals for the load side and strain relief for wires.
  • If switching inductive DC loads, add the right suppression methods on the load side according to the module and load type.

Final Checklist

  • [ ] I used Arduino UNO R3 (ATmega328P)
  • [ ] I used 3 pushbuttons, 1-channel relay module, and piezo buzzer
  • [ ] Buttons are wired from input pin to GND
  • [ ] Relay module is connected to 5V, GND, and D8
  • [ ] Buzzer is connected to D9 and GND
  • [ ] I saved the file as workshop_countdown_relay_timer/workshop_countdown_relay_timer.ino
  • [ ] I ran arduino-cli core update-index
  • [ ] I ran arduino-cli core install arduino:avr
  • [ ] I compiled with arduino-cli compile --fqbn arduino:avr:uno workshop_countdown_relay_timer
  • [ ] I uploaded with arduino-cli upload --fqbn arduino:avr:uno --port <PORT> workshop_countdown_relay_timer
  • [ ] Serial monitor at 9600 baud shows startup status
  • [ ] ADD changes the preset time
  • [ ] START begins countdown and turns relay on
  • [ ] PAUSE turns relay off and preserves remaining time
  • [ ] CANCEL stops the timer and restores the preset
  • [ ] Countdown completion turns relay off and triggers the buzzer pattern

Find this product and/or books on this topic on Amazon

Go to Amazon

As an Amazon Associate, I earn from qualifying purchases. If you buy through this link, you help keep this project running.

Quick Quiz

Question 1: What is the main controller used in the workshop countdown relay timer project?




Question 2: Which function is specifically mentioned for creating a non-blocking countdown?




Question 3: What happens to the relay while time still remains in the countdown?




Question 4: What kind of alert is triggered when the timer reaches 0?




Question 5: Which of the following is listed as a possible timed load?




Question 6: What duration range is mentioned for the fixed work cycle examples?




Question 7: Which embedded skill does this build help teach without using delay()?




Question 8: How does the system operate after the program is uploaded?




Question 9: What button-related technique is mentioned as part of the build?




Question 10: Besides the Arduino and relay, which input component is explicitly included in the project?




Carlos Núñez Zorrilla
Carlos Núñez Zorrilla
Electronics & Computer Engineer

Telecommunications Electronics Engineer and Computer Engineer (official degrees in Spain).

Follow me:
Scroll to Top