Skip to main content

4-Digit 7-Segment Clock Display Using Arduino Uno in Wokwi (Complete Guide with Code)

4-Digit 7-Segment Digital Clock using Arduino Uno – Wokwi | MakeMindz
▶ Open Wokwi
⏰ Summer Class Project

4-Digit 7-Segment
Digital Clock with Arduino

Build a real digital clock displaying HH:MM with a blinking colon, adjustable time buttons, and millis() timing — all in the free Wokwi browser simulator!

TM1637
1 2 : 0 0
HH : MM
Arduino UnoCLK→2 · DIO→3

What You'll Build

A fully functional digital clock showing hours and minutes on a bright red 7-segment display — with real time-keeping and manual set buttons.

⏱️
~25
Minutes to build
Inter.
Beginner–Intermediate
🖥️
Free
Wokwi simulator
📺
HH:MM
Display format
💡
No hardware needed! This project runs completely inside Wokwi. Three buttons let you SET, increment HOUR, and increment MINUTES — all interactive in the simulator!

What You Need

Virtual components in Wokwi — nothing to buy!

Arduino Uno R3
TM1637 4-Digit 7-Segment (red)
Push Button — SET (green)
Push Button — HOUR (blue)
Push Button — MIN (yellow)
10kΩ Resistors × 3 (pull-down)
📦
Library needed: TM1637Display — available in Wokwi's library manager with one click.

Pin Connections

The TM1637 module uses only 2 data wires (CLK + DIO). Buttons connect through 10kΩ pull-down resistors.

2
TM1637 CLK
Clock signal
3
TM1637 DIO
Data signal
4
HOUR Button
Increment hours
5
MIN Button
Increment minutes
6
SET Button
Enter/exit set mode
5V
TM1637 VCC
Power
🔌

Full Connection Table

FromTo (Arduino)Wire Color
TM1637 CLKPin 2🔵 Blue
TM1637 DIOPin 3🟢 Green
TM1637 VCC5V🔴 Red
TM1637 GNDGND⬛ Black
SET btn pin 1Pin 6🟢 Green
SET btn pin 2 → R1 → GNDGND⬛ Black
HOUR btn pin 1Pin 4🔵 Blue
HOUR btn pin 2 → R2 → GNDGND⬛ Black
MIN btn pin 1Pin 5🟡 Yellow
MIN btn pin 2 → R3 → GNDGND⬛ Black
⚠️
Each button uses a 10kΩ pull-down resistor to GND to prevent floating pin readings. This is already included in the diagram.json wiring below.
🔢

Segment Pins (a–g)

SegmentArduino Pin
a2
b3
c4
d5
e6
f7
g8
🔡

Digit Control Pins

DigitArduino Pin
D1 (leftmost)9
D210
D311
D4 (rightmost)12

Use 220Ω resistors on segment pins for raw 7-seg. The TM1637 module handles this internally.


Step-by-Step Guide

8 simple steps to get your digital clock ticking in Wokwi.

  1. Open the Wokwi Simulation

    Go to wokwi.com/projects/459618020796829697 or click ▶ Run Simulation above. The TM1637 display and Arduino Uno are pre-loaded.

  2. Add the TM1637 Library

    In Wokwi, click the Libraries 📚 icon in the sidebar. Search for TM1637Display and add it. This handles all the 7-segment display communication.

  3. Paste the diagram.json

    Click the diagram.json tab and paste the JSON from the Diagram JSON section below. This auto-wires the TM1637, all 3 buttons, and their 10kΩ resistors.

  4. Paste the Arduino code

    Open the sketch.ino tab and paste the full code from the Code section. The code starts the clock at 12:00 and uses millis() for accurate timekeeping.

  5. Click ▶ Start Simulation

    Hit the green play button. The display shows 12:00 with a blinking colon. Check the Serial Monitor for startup messages and live time output every second.

    Expected output: Serial Monitor prints Time: 12:00:01, 12:00:02... every second.
  6. Press the SET button (green)

    Click the green SET button to enter Set Mode. The colon stays on steady (not blinking) to indicate you're setting the time. Serial Monitor prints *** SET MODE ENABLED ***.

  7. Adjust time with HOUR and MIN buttons

    Click the blue HOUR button to increment hours (wraps at 24). Click the yellow MIN button to increment minutes (wraps at 60). Each press is debounced to prevent double-counting.

  8. Press SET again to save and run

    Press the green SET button again to exit Set Mode. Seconds reset to 0 and the clock resumes from the new time. Colon starts blinking again!


⏰ Try It Live in Wokwi

Watch the clock count up in real time — set your own time with the buttons!

Open Live Simulation

Button Functions

Three buttons let you interact with the clock — all debounced with a 200ms delay.

🟢 SET Button — Pin 6

Toggles between normal clock mode and time-setting mode. When active, the colon stays on steady and the clock pauses counting. Press again to save and resume.

Enters Set Mode Saves & Resumes Resets seconds to 0
🔵 HOUR Button — Pin 4

Increments hours by 1 each press while in Set Mode. Wraps from 23 back to 0 (24-hour format). Only active during Set Mode.

↑ Hours +1 Only in Set Mode Wraps 23 → 0
🟡 MIN Button — Pin 5

Increments minutes by 1 each press while in Set Mode. Wraps from 59 back to 0. Only active during Set Mode.

↑ Minutes +1 Only in Set Mode Wraps 59 → 0

Arduino Sketch

Paste this into sketch.ino in Wokwi. Uses the TM1637Display library.

sketch.ino — Arduino C++
/*
 * 4-Digit 7-Segment Clock Display
 * Displays time in HH:MM format using TM1637 display module
 * Features: Clock display, adjustable time, blinking colon
 * MakeMindz.com — Summer Class Project
 */

#include <TM1637Display.h>

// ── Pin definitions for TM1637 ──
#define CLK_PIN  2   // Clock pin
#define DIO_PIN  3   // Data pin

// ── Button pins ──
#define HOUR_BTN 4   // Increment hours
#define MIN_BTN  5   // Increment minutes
#define SET_BTN  6   // Enter / exit set mode

// ── Display object ──
TM1637Display display(CLK_PIN, DIO_PIN);

// ── Time variables ──
int hours   = 12;
int minutes = 0;
int seconds = 0;

// ── State variables ──
bool          setMode    = false;
bool          colonBlink = true;
unsigned long lastUpdate = 0;
unsigned long lastBlink  = 0;

// ── Button debouncing (200 ms) ──
unsigned long lastHourPress = 0;
unsigned long lastMinPress  = 0;
unsigned long lastSetPress  = 0;
const int     debounceDelay = 200;

// ─────────────────── SETUP ───────────────────
void setup() {
  Serial.begin(9600);

  pinMode(HOUR_BTN, INPUT_PULLUP);
  pinMode(MIN_BTN,  INPUT_PULLUP);
  pinMode(SET_BTN,  INPUT_PULLUP);

  display.setBrightness(0x0f);   // Max brightness

  // Clear display on start
  uint8_t blank[] = {0x00, 0x00, 0x00, 0x00};
  display.setSegments(blank);
  delay(500);

  Serial.println("4-Digit 7-Segment Clock Initialized");
  Serial.println("SET=enter/exit set mode  HOUR=+1hr  MIN=+1min");
}

// ─────────────────── LOOP ────────────────────
void loop() {
  unsigned long now = millis();

  checkButtons();

  // Advance time every 1 second (paused in set mode)
  if (!setMode && now - lastUpdate >= 1000) {
    lastUpdate = now;
    updateTime();
  }

  // Blink colon every 500 ms
  if (now - lastBlink >= 500) {
    lastBlink  = now;
    colonBlink = !colonBlink;
  }

  displayTime();
  delay(10);
}

// ─────────────────── TIME UPDATE ─────────────
void updateTime() {
  seconds++;
  if (seconds >= 60) {
    seconds = 0; minutes++;
    if (minutes >= 60) {
      minutes = 0; hours++;
      if (hours >= 24) hours = 0;
    }
  }

  // Print to Serial Monitor
  Serial.print("Time: ");
  if (hours   < 10) Serial.print("0");
  Serial.print(hours);   Serial.print(":");
  if (minutes < 10) Serial.print("0");
  Serial.print(minutes); Serial.print(":");
  if (seconds < 10) Serial.print("0");
  Serial.println(seconds);
}

// ─────────────────── DISPLAY TIME ────────────
void displayTime() {
  int val = hours * 100 + minutes;

  if (setMode) {
    // Steady colon in set mode
    display.showNumberDecEx(val, 0b01000000, true);
  } else {
    // Blinking colon in normal mode
    display.showNumberDecEx(val, colonBlink ? 0b01000000 : 0b00000000, true);
  }
}

// ─────────────────── BUTTON CHECK ────────────
void checkButtons() {
  unsigned long now = millis();

  // SET — toggle set mode
  if (digitalRead(SET_BTN) == LOW && now - lastSetPress > debounceDelay) {
    lastSetPress = now;
    setMode = !setMode;
    if (setMode) {
      Serial.println("*** SET MODE ENABLED — Use HOUR/MIN buttons ***");
    } else {
      seconds    = 0;      // Reset seconds on save
      lastUpdate = now;    // Reset 1-second timer
      Serial.println("*** TIME SAVED — Clock running ***");
    }
    delay(200);
  }

  // HOUR — only active in set mode
  if (setMode && digitalRead(HOUR_BTN) == LOW && now - lastHourPress > debounceDelay) {
    lastHourPress = now;
    hours = (hours + 1) % 24;
    Serial.print("Hours → "); Serial.println(hours);
  }

  // MIN — only active in set mode
  if (setMode && digitalRead(MIN_BTN) == LOW && now - lastMinPress > debounceDelay) {
    lastMinPress = now;
    minutes = (minutes + 1) % 60;
    Serial.print("Minutes → "); Serial.println(minutes);
  }
}

Wokwi diagram.json

Paste this into the diagram.json tab in Wokwi. It auto-places all parts and wires — including the 10kΩ pull-down resistors for the buttons.

diagram.json
{
  "version": 1,
  "author": "4-Digit Clock Display",
  "editor": "wokwi",
  "parts": [
    {
      "type": "wokwi-arduino-uno",
      "id": "uno",
      "top": 0, "left": 0,
      "attrs": {}
    },
    {
      "type": "wokwi-tm1637-7segment",
      "id": "tm1637",
      "top": -96, "left": 144,
      "attrs": { "color": "red" }
    },
    {
      "type": "wokwi-pushbutton",
      "id": "btn_set",
      "top": 124.8, "left": -124.8,
      "attrs": { "color": "green", "label": "SET" }
    },
    {
      "type": "wokwi-pushbutton",
      "id": "btn_hour",
      "top": 124.8, "left": -28.8,
      "attrs": { "color": "blue", "label": "HOUR" }
    },
    {
      "type": "wokwi-pushbutton",
      "id": "btn_min",
      "top": 124.8, "left": 67.2,
      "attrs": { "color": "yellow", "label": "MIN" }
    },
    {
      "type": "wokwi-resistor",
      "id": "r1",
      "top": 220.15, "left": -124.8,
      "rotate": 90,
      "attrs": { "value": "10000" }
    },
    {
      "type": "wokwi-resistor",
      "id": "r2",
      "top": 220.15, "left": -28.8,
      "rotate": 90,
      "attrs": { "value": "10000" }
    },
    {
      "type": "wokwi-resistor",
      "id": "r3",
      "top": 220.15, "left": 67.2,
      "rotate": 90,
      "attrs": { "value": "10000" }
    }
  ],
  "connections": [
    [ "tm1637:CLK", "uno:2",     "blue",  ["v0"] ],
    [ "tm1637:DIO", "uno:3",     "green", ["v0"] ],
    [ "tm1637:VCC", "uno:5V",    "red",   ["v0"] ],
    [ "tm1637:GND", "uno:GND.1", "black", ["v0"] ],

    [ "btn_set:1.l",  "uno:6",     "green",  ["v0"] ],
    [ "btn_set:2.l",  "r1:1",      "black",  ["v0"] ],
    [ "r1:2",         "uno:GND.2", "black",  ["v0"] ],

    [ "btn_hour:1.l", "uno:4",     "blue",   ["v0"] ],
    [ "btn_hour:2.l", "r2:1",      "black",  ["v0"] ],
    [ "r2:2",         "uno:GND.2", "black",  ["v0"] ],

    [ "btn_min:1.l",  "uno:5",     "yellow", ["v0"] ],
    [ "btn_min:2.l",  "r3:1",      "black",  ["v0"] ],
    [ "r3:2",         "uno:GND.2", "black",  ["v0"] ]
  ],
  "dependencies": {}
}

How It Works

Three core systems work together — timekeeping, display refresh, and button handling.

⏱️

millis() Timekeeping

Instead of using delay(1000), this project uses millis() to check if 1000 ms have passed since the last update. This keeps the loop() running fast so buttons always respond instantly — delay() would freeze the processor and miss button presses. Every 1000 ms, updateTime() increments seconds → minutes → hours in a nested rollover chain.

📺

TM1637 Display Module

The TM1637 uses its own 2-wire protocol (not I2C or SPI) over CLK and DIO pins. The library's showNumberDecEx() function takes an integer like 1230 and displays it as 12:30. The second argument is a bitmask — 0b01000000 turns the colon on, 0b00000000 turns it off. Toggling this every 500 ms creates the blinking effect.

🔘

Debouncing

Mechanical buttons bounce — they rapidly open and close for a few milliseconds after being pressed. Without debouncing, one press can register as 5–10 presses. This code compares millis() with the last press timestamp and only acts if 200 ms have passed. This is software debouncing — clean, no extra capacitors needed.


What You'll Learn

Key embedded systems and electronics concepts all in one project.

7-segment display interfacing with TM1637
Non-blocking timing with millis()
Software button debouncing technique
Multiplexing principle for multi-digit displays
State machine programming (normal vs set mode)
Real-time clock logic (seconds → minutes → hours)
Pull-down resistor circuit design
Serial Monitor debugging in Arduino

Frequently Asked Questions

Q1: Can I add seconds to this Arduino clock?
Yes! The code already tracks seconds internally. You can modify displayTime() to show seconds — though you'd need a 6-digit display or a second 4-digit module for the full HH:MM:SS format.
Q2: Can I use a DS3231 RTC module for more accuracy?
Absolutely. A DS3231 RTC keeps extremely accurate time even when the Arduino is powered off. Replace the millis() logic with RTC library calls — the display code stays the same. Check the MakeMindz DS3231 + TM1637 project for a ready-made example!
Q3: Why does millis() drift over time?
The Arduino's internal crystal oscillator is accurate to about ±0.5%, so a clock based purely on millis() can drift by 1–2 minutes per day. For a wall clock you'd use a DS3231 RTC. For learning timing concepts, millis() is perfect.
Q4: Is this project suitable for beginners?
Yes — it's rated beginner-to-intermediate. You don't need to understand every line of code to get it running. Focus on the millis() pattern and button logic — these two skills appear in almost every Arduino project.
Q5: Can I change the display from red to green or blue?
In Wokwi, change "color": "red" to "color": "green" or "color": "blue" in the diagram.json parts section. On real hardware, just use a different colour TM1637 module — the code is identical.

Comments

try for free