Build a Programmable 7‑Segment Clock with ESP32
A glowing clock on your desk is more than a time‑keeper – it’s a little piece of art that reminds you that every second can be lit up with a bit of code. With the ESP32’s Wi‑Fi and the classic 7‑segment display, you can have a clock that you can change on the fly, add a splash of colour, or even make it show a secret message at midnight. Let’s dive in and build one together.
What You’ll Need
Parts List
- ESP32 development board (any model you like)
- Common‑anode 4‑digit 7‑segment module (or individual digits if you prefer)
- 220 Ω resistors (8 pieces for the segment lines)
- Breadboard and jumper wires
- 5 V power supply (USB works fine)
- Small push‑button (optional, for manual time set)
- Optional: a tiny real‑time clock (RTC) module like DS3231 for extra accuracy
Software
- Arduino IDE (latest version)
- ESP32 board package installed in the IDE
- A few libraries:
Wire.hfor I²C (if you use an RTC) andESP32Time.hfor simple time keeping
Having everything laid out before you start saves a lot of “where does this wire go?” moments. I still remember the first time I tried to wire a display without a diagram – the board looked like a spaghetti monster and the LEDs never lit. A quick sketch saved the day.
Understanding the 7‑Segment Display
A 7‑segment display is just eight LEDs arranged in a figure‑8 shape. The segments are labeled a through g, with an extra dp for the decimal point. By turning on the right combination of segments you can show any numeral 0‑9, and with a little creativity you can also make letters like “A” or “C”.
Because we are using a common‑anode module, all the anodes (positive side) of the LEDs are tied together and connected to +5 V. To light a segment you pull its cathode (negative side) low, i.e., you send a 0 from the ESP32 pin. This is the opposite of a common‑cathode display where you would send a 1 to turn a segment on. Keep that in mind when you write the code – the logic is inverted.
Wiring the ESP32 to the Segments
Pin Assignment
| ESP32 Pin | Segment |
|---|---|
| 16 | a |
| 17 | b |
| 18 | c |
| 19 | d |
| 21 | e |
| 22 | f |
| 23 | g |
| 5 | dp (optional) |
| 4, 15, 2, 0 | Digit control (common pins) |
You can pick any free GPIOs, but the above mapping keeps the wiring tidy on a breadboard. Each segment line needs a 220 Ω resistor to limit current; the digit control lines can share a single resistor each because only one digit is active at a time.
Multiplexing Basics
We only have eight segment pins but four digits, so we use multiplexing: light one digit at a time, fast enough that the eye sees all four as constantly on. The ESP32 will cycle through the digits, turning on the appropriate segments for each numeral, then move to the next digit. A delay of about 2 ms per digit gives a flicker‑free display.
Wiring Steps
- Connect the common anode pins of the display to the 5 V rail.
- Attach each segment pin to a resistor, then to the ESP32 pin listed above.
- Wire the four digit control pins (often labeled DIG1‑DIG4) to the ESP32 pins 4, 15, 2, and 0. These pins will be set LOW to enable a digit (again, because of the common‑anode design).
- If you are using a push‑button, connect one side to 3.3 V and the other side to a GPIO with an internal pull‑down resistor.
Double‑check every connection before plugging the board into USB. A shorted segment line can fry the ESP32’s pin in seconds.
Programming the Clock
Setting Up the Arduino Sketch
Create a new sketch in the Arduino IDE and start with the basics:
#include <Arduino.h>
#include <ESP32Time.h>
// Segment pins (a‑g, dp)
const int segPins[8] = {16,17,18,19,21,22,23,5};
// Digit control pins
const int digPins[4] = {4,15,2,0};
ESP32Time rtc; // Simple software RTC
Segment Map
We need a lookup table that tells us which segments to light for each numeral. Because the logic is inverted (0 = on), we store the off bits as 0 and the on bits as 1, then invert when writing.
// Bits: dp g f e d c b a (LSB = a)
const byte digitMap[10] = {
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111 // 9
};
Display Routine
The core of the multiplexing lives in a function that shows a four‑digit number:
void showNumber(int num) {
int thousands = num / 1000;
int hundreds = (num / 100) % 10;
int tens = (num / 10) % 10;
int ones = num % 10;
int digits[4] = {thousands, hundreds, tens, ones};
for (int i = 0; i < 4; i++) {
// Turn off all digits first
for (int d = 0; d < 4; d++) digitalWrite(digPins[d], HIGH);
// Set segments for current digit
byte seg = digitMap[digits[i]];
for (int s = 0; s < 8; s++) {
bool on = !(seg & (1 << s)); // invert because common‑anode
digitalWrite(segPins[s], on ? LOW : HIGH);
}
// Enable this digit
digitalWrite(digPins[i], LOW);
delay(2); // short pause for persistence
}
}
Keeping Time
The ESP32 has a built‑in RTC that can be set via Wi‑Fi NTP, but for a simple offline clock we’ll just start from a known time and let it run.
void setup() {
Serial.begin(115200);
// Set pins as outputs
for (int i = 0; i < 8; i++) pinMode(segPins[i], OUTPUT);
for (int i = 0; i < 4; i++) pinMode(digPins[i], OUTPUT);
// Start at 12:00
rtc.setTime(12, 0, 0);
}
void loop() {
// Update every second
static unsigned long last = 0;
if (millis() - last >= 1000) {
last = millis();
rtc.setTime(rtc.getHour(), rtc.getMinute() + 1, 0);
}
// Show HHMM
int displayVal = rtc.getHour() * 100 + rtc.getMinute();
showNumber(displayVal);
}
If you want to sync with internet time, add the Wi‑Fi library, connect to your router, and pull NTP. I usually keep a small button that, when held for three seconds, forces a resync – handy when the power blips.
Testing and Tweaking
Upload the sketch and watch the digits flicker into life. If you see only one digit lit, double‑check the digit control pins – they must be set LOW to enable. If some segments stay dark, verify the resistor values and that the segment pins match the map.
A common hiccup is the ESP32’s bootloader using some GPIOs (like 0 and 2) for flashing. In my first build the clock never showed the tens digit because I used pin 0 for a digit line. The fix? Move that line to a free pin such as 33, and re‑wire the display. The ESP32’s datasheet lists which pins are safe for general I/O.
Tips for a Reliable Build
- Use a proper power source. USB ports on laptops can be noisy; a wall adapter gives a steadier 5 V.
- Add a decoupling capacitor (100 µF) across the 5 V rail and ground to smooth out spikes when many segments switch at once.
- Consider a PCB once you’re happy with the breadboard layout. A small perfboard keeps the wires tidy and reduces the chance of a loose connection.
- Add a small buzzer for a “tick‑tock” sound if you like audible feedback. Connect it to a PWM‑capable pin and play a short tone each second.
- Play with colours. If you use a multi‑colour LED module, you can change the hue based on the hour (e.g., warm amber in the morning, cool blue at night). It’s a simple way to make the clock feel alive.
Building this clock reminded me why I fell in love with segment displays – they are simple, yet they let you create something that feels almost magical. Every time the numbers change, you see the result of a few lines of code and a handful of wires. That’s the joy of DIY electronics: the world literally lights up at your fingertips.
- → Transform Your Bedroom with a DIY LED Strip Accent Wall @glowspace
- → Build a Voice‑Controlled Light Switch with ESP32 for Under $15 @smarthomecrafts
- → Build a Wi‑Fi Plant‑Watering System with ESP32: Complete DIY Guide @techdiyhub
- → How to Build a Solar-Powered LED Desk Lamp for Under $30 @brightglowdiy
- → Step‑by‑Step Guide: Designing a Functional Prototype with a 3D Printing Pen @printcraftstudio