Christmas countdown on an Arduino Uno
A DS3231 keeps the date and an eight-digit MAX7219 display in the window counts the days, hours, minutes and seconds to Christmas, then flashes 25.12. The whole build, an Arduino Uno and 2 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.
Intermediate Runs in your browser. Free, and no account needed.
Build it as the Christmas Lights Kit: the parts in numbered bags and a booklet that checks every step. Free.
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// Christmas countdown: a display for the front window that counts down the
// days, hours, minutes and seconds to Christmas morning, then flashes the
// date all through Christmas Day.
//
// DS3231 SCL -> SCL SDA -> SDA VCC -> 5 V GND -> GND
// MAX7219 8-digit seven-segment module: DIN -> pin 12, CLK -> pin 11,
// CS -> pin 10, VCC -> 5 V, GND -> GND
//
// The display reads DD.HH.MM.SS: days on the left two digits, then hours,
// minutes and seconds, each pair split by a decimal point.
//
// Why a real-time clock: the Uno's own millis() forgets everything at every
// power cut and drifts over weeks. The DS3231 has a coin cell and a
// temperature-compensated crystal, so it keeps the date through a blown fuse
// on the porch and stays close to the right time all season. Set it once:
// uncomment the rtc.adjust() line, upload, then comment it out and upload
// again, or every reset will put the clock back to the moment you built it.
//
// The countdown is plain arithmetic on DateTime: Christmas minus now is a
// TimeSpan, and TimeSpan already knows how to split itself into days, hours,
// minutes and seconds.
//
// On the bench: turn INTENSITY down for a window at night; full brightness
// is a lot of light through glass.
//
// Things to try. Count to New Year's Eve instead by changing the month and
// day in christmasAfter(). Show only the days when there are more than
// thirty of them, so it changes once a day.
#include <Wire.h>
#include <RTClib.h>
#include <LedControl.h>
const int INTENSITY = 6; // 0 to 15
RTC_DS3231 rtc;
LedControl display(12, 11, 10, 1); // DIN, CLK, CS, one module
uint32_t lastShown = 0;
// The next Christmas morning that has not yet ended.
DateTime christmasAfter(const DateTime &now) {
DateTime target(now.year(), 12, 25, 0, 0, 0);
if (now.unixtime() >= target.unixtime() + 86400UL) {
target = DateTime(now.year() + 1, 12, 25, 0, 0, 0);
}
return target;
}
// Two digits at positions `left` and `left - 1`, with an optional point.
void pair(int left, int value, bool point) {
display.setDigit(0, left, value / 10, false);
display.setDigit(0, left - 1, value % 10, point);
}
void showCountdown(const TimeSpan &left) {
int days = left.days();
if (days > 99) days = 99;
pair(7, days, true);
pair(5, left.hours(), true);
pair(3, left.minutes(), true);
pair(1, left.seconds(), false);
}
void showChristmas(const DateTime &now) {
// 25.12.2026, on for a second and off for a second.
if (now.second() % 2 == 0) {
pair(7, 25, true);
pair(5, 12, true);
pair(3, now.year() / 100, false);
pair(1, now.year() % 100, false);
} else {
display.clearDisplay(0);
}
}
void setup() {
Serial.begin(9600);
display.shutdown(0, false);
display.setIntensity(0, INTENSITY);
display.clearDisplay(0);
if (!rtc.begin()) {
Serial.println("No DS3231 answered: check SDA and SCL");
while (true) {
}
}
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // set once, see above
if (rtc.lostPower()) Serial.println("The clock has lost power: set it once with rtc.adjust()");
Serial.println("Christmas countdown");
}
void loop() {
DateTime now = rtc.now();
if (now.unixtime() == lastShown) return; // once a second is enough
lastShown = now.unixtime();
DateTime christmas = christmasAfter(now);
if (now.unixtime() >= christmas.unixtime()) {
showChristmas(now);
if (now.second() == 0) Serial.println("Merry Christmas!");
return;
}
TimeSpan left = christmas - now;
showCountdown(left);
Serial.print(left.days());
Serial.print(" days ");
Serial.print(left.hours());
Serial.print(" h ");
Serial.print(left.minutes());
Serial.print(" min ");
Serial.print(left.seconds());
Serial.println(" s to go");
}
Parts list
4 parts, plus the jumper wires. Every one is in the editor's parts bin.
How it is wired
7 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.
- Arduino Uno R3 pin SCL; Real-time clock, DS3231 pin SCL
- Arduino Uno R3 pin SDA; Real-time clock, DS3231 pin SDA
- Arduino Uno R3 pin 12; Eight-digit display, MAX7219 pin DIN
- Arduino Uno R3 pin 11; Eight-digit display, MAX7219 pin CLK
- Arduino Uno R3 pin 10; Eight-digit display, MAX7219 pin CS
- Arduino Uno R3 pin 5V; Eight-digit display, MAX7219 pin VCC; Real-time clock, DS3231 pin VCC
- Ground: Arduino Uno R3 pin GND; Eight-digit display, MAX7219 pin GND; Real-time clock, DS3231 pin 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.