Countdown timer on a four-digit display, on an Arduino Uno
A kitchen timer: a 74HC595 (pins 8, 13 and 12) and four digit lines on pins 2 to 5 show minutes and seconds. Buttons on A3, 6 and A1 set and start it, and a buzzer on A2 sounds when it runs out. The whole build, an Arduino Uno and 12 more parts, 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.
Advanced Runs in your browser. Free, and no account needed.
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// A countdown timer: set it with two buttons, start it with a third.
//
// 74HC595 DS -> pin 8 SHCP -> pin 13 STCP -> pin 12
// Q0 to Q7 -> segments a to g and the dot of a four-digit display
// digit commons DIG1 to DIG4 -> pins 2, 3, 4, 5 (LOW lights a digit)
// "minute" button -> A3, to GND "second" button -> pin 6, to GND
// "function" button -> A1, to GND (all three on INPUT_PULLUP)
// LED -> A0, through 220 ohm buzzer -> A2 (through a transistor on the bench)
//
// The four digits share their segment lines, so the sketch lights one digit
// at a time, a few milliseconds each, round and round: fast enough that you
// see all four at once. That is multiplexing, and it is why the display code
// runs on every pass of loop() and nothing in loop() may delay() for long.
//
// Press "minute" to add a minute and "second" to add a second. Press
// "function" to start; press it again to clear. When the time runs out the
// buzzer sounds and the LED flashes until you press "function".
//
// The analog pins work as ordinary digital pins: A0 to A5 are pins 14 to 19.
const int DATA_PIN = 8;
const int LATCH_PIN = 12;
const int CLOCK_PIN = 13;
const int DIGIT_PINS[4] = {2, 3, 4, 5};
const int BUTTON_MINUTE = A3;
const int BUTTON_SECOND = 6;
const int BUTTON_FUNCTION = A1;
const int LED = A0;
const int BUZZER = A2;
// gfedcba
const byte DIGITS[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
enum State { SETTING, RUNNING, RINGING };
State state = SETTING;
long remaining = 0; // seconds
unsigned long lastTick = 0;
int digit = 0;
struct Button {
int pin;
bool down;
unsigned long changedAt;
};
Button buttons[3] = {{BUTTON_MINUTE, false, 0}, {BUTTON_SECOND, false, 0}, {BUTTON_FUNCTION, false, 0}};
// True once per press, after the contact has settled for 30 ms.
bool pressed(Button &b) {
bool now = digitalRead(b.pin) == LOW;
if (now != b.down && millis() - b.changedAt > 30) {
b.down = now;
b.changedAt = millis();
return now;
}
return false;
}
void showDigit(int which, byte pattern) {
for (int i = 0; i < 4; i++) digitalWrite(DIGIT_PINS[i], HIGH);
digitalWrite(LATCH_PIN, LOW);
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, pattern);
digitalWrite(LATCH_PIN, HIGH);
digitalWrite(DIGIT_PINS[which], LOW);
}
void refresh() {
int minutes = remaining / 60;
int seconds = remaining % 60;
byte patterns[4] = {DIGITS[minutes / 10 % 10], (byte)(DIGITS[minutes % 10] | 0x80), DIGITS[seconds / 10],
DIGITS[seconds % 10]};
showDigit(digit, patterns[digit]);
digit = (digit + 1) % 4;
}
void printTime() {
Serial.print(remaining / 60);
Serial.print(remaining % 60 < 10 ? ":0" : ":");
Serial.println(remaining % 60);
}
void setup() {
pinMode(DATA_PIN, OUTPUT);
pinMode(LATCH_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
for (int i = 0; i < 4; i++) pinMode(DIGIT_PINS[i], OUTPUT);
pinMode(BUTTON_MINUTE, INPUT_PULLUP);
pinMode(BUTTON_SECOND, INPUT_PULLUP);
pinMode(BUTTON_FUNCTION, INPUT_PULLUP);
pinMode(LED, OUTPUT);
pinMode(BUZZER, OUTPUT);
Serial.begin(9600);
Serial.println("Mokxi Uno: countdown timer. minute (A3) and second (6) set it, function (A1) starts it.");
// Something to count down from straight away, so it is not a blank display.
remaining = 5;
state = RUNNING;
lastTick = millis();
Serial.println("start: 0:05");
}
void loop() {
bool minute = pressed(buttons[0]);
bool second = pressed(buttons[1]);
bool function = pressed(buttons[2]);
if (state == SETTING) {
if (minute && remaining < 99L * 60) remaining += 60;
if (second && remaining < 99L * 60 + 59) remaining += 1;
if (minute || second) printTime();
if (function && remaining > 0) {
state = RUNNING;
lastTick = millis();
Serial.println("start");
}
} else if (state == RUNNING) {
if (function) {
state = SETTING;
remaining = 0;
Serial.println("cleared");
} else if (millis() - lastTick >= 1000) {
lastTick += 1000;
remaining--;
printTime();
if (remaining <= 0) {
remaining = 0;
state = RINGING;
Serial.println("time is up");
}
}
} else {
bool on = (millis() / 250) % 2 == 0;
digitalWrite(LED, on ? HIGH : LOW);
digitalWrite(BUZZER, on ? HIGH : LOW);
if (function) {
state = SETTING;
digitalWrite(LED, LOW);
digitalWrite(BUZZER, LOW);
Serial.println("quiet");
}
}
refresh();
delay(3);
}
Parts list
14 parts, plus the jumper wires. Every one is in the editor's parts bin.
How it is wired
27 connections, pin by pin, read from the circuit itself. Each line is one set of pins joined together, by a jumper wire or a breadboard strip.
- Ground: Arduino Uno R3 pin GND; 74HC595 shift register pin GND; 74HC595 shift register pin OE; Pushbutton (1) pin 2b; Pushbutton (2) pin 2b; Pushbutton (3) pin 2a; LED, red pin C; Buzzer pin 2
- Arduino Uno R3 pin 13; 74HC595 shift register pin SHCP
- Arduino Uno R3 pin 12; 74HC595 shift register pin STCP
- Arduino Uno R3 pin 8; 74HC595 shift register pin DS
- Arduino Uno R3 pin 6; Pushbutton (3) pin 1a
- Arduino Uno R3 pin 5; Resistor, 220 Ω (4) pin 2
- Arduino Uno R3 pin 4; Resistor, 220 Ω (3) pin 2
- Arduino Uno R3 pin 3; Resistor, 220 Ω (2) pin 2
- Arduino Uno R3 pin 2; Resistor, 220 Ω (1) pin 2
- Arduino Uno R3 pin 5V; 74HC595 shift register pin MR; 74HC595 shift register pin VCC
- Arduino Uno R3 pin A0; Resistor, 220 Ω (5) pin 1
- Arduino Uno R3 pin A1; Pushbutton (2) pin 1b
- Arduino Uno R3 pin A2; Buzzer pin 1
- Arduino Uno R3 pin A3; Pushbutton (1) pin 1b
- 74HC595 shift register pin Q1; Four-digit seven segment, multiplexed pin B
- 74HC595 shift register pin Q2; Four-digit seven segment, multiplexed pin C
- 74HC595 shift register pin Q3; Four-digit seven segment, multiplexed pin D
- 74HC595 shift register pin Q4; Four-digit seven segment, multiplexed pin E
- 74HC595 shift register pin Q5; Four-digit seven segment, multiplexed pin F
- 74HC595 shift register pin Q6; Four-digit seven segment, multiplexed pin G
- 74HC595 shift register pin Q7; Four-digit seven segment, multiplexed pin DP
- 74HC595 shift register pin Q0; Four-digit seven segment, multiplexed pin A
- Four-digit seven segment, multiplexed pin DIG4; Resistor, 220 Ω (4) pin 1
- Four-digit seven segment, multiplexed pin DIG3; Resistor, 220 Ω (3) pin 1
- Four-digit seven segment, multiplexed pin DIG2; Resistor, 220 Ω (2) pin 1
- Four-digit seven segment, multiplexed pin DIG1; Resistor, 220 Ω (1) pin 1
- Resistor, 220 Ω (5) pin 2; LED, red pin A
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.