IoTSimulator

Precision Digital Desktop Clock & Alarm with RTC and OLED

Construct a multi-featured digital desktop clock powered by a DS1307 real-time clock chip, crisp SSD1306 OLED graphical display, and interactive alarm controls.
Precision Digital Desktop Clock & Alarm with RTC and OLED

Live project track

Interactive hardware & logic preview

Have you ever unplugged a digital clock and had its time reset to 12:00 blinking when you plugged it back into the wall? Standard microcontrollers forget the time the millisecond power is disconnected because they lack an internal battery-backed timekeeping crystal.

In this project, you will build a precision digital desktop clock and alarm using an Arduino Uno, a DS1307 real-time clock (RTC) module with coin-cell backup, a 0.96-inch I2C OLED display, tactile alarm buttons, and a piezo buzzer. The core concept to master is: using an external I2C hardware clock with dedicated quartz crystal to keep accurate time across power outages, formatting timestamps onto high-resolution OLED displays, and managing interactive button states.

How Real-Time Clocks Maintain Continuous Time

Think of a mechanical wristwatch wound by a spring compared to a stopwatch on your phone. A stopwatch counts elapsed seconds while the app is open, but a wristwatch keeps ticking independently in your pocket even when you are asleep.

A DS1307 Real-Time Clock module functions like an independent electronic wristwatch. It contains its own dedicated 32.768 kHz quartz oscillator crystal and a CR2032 lithium coin-cell battery. Even if the Arduino loses mains power for years, the RTC continues counting seconds, minutes, hours, days, months, and leap years silently.

Timekeeping SourcePower SourceTime DriftBehavior on Power Loss
Arduino millis() ClockMain 5V USB / DCDrifts ~ 1-2 min/dayCompletely resets to zero
DS1307 RTC HardwareCR2032 Coin Cell (3V)Precision quartz crystalRetains exact time for 5+ years
I2C OLED ScreenMain 5V VCCInstant refresh (~ 30 FPS)Displays crisp 128x64 graphics

The Arduino communicates with both the DS1307 RTC and the SSD1306 OLED display using the shared I2C bus on pins A4 (SDA) and A5 (SCL). Each device has a unique hardware address (0x68 for the RTC, 0x3C for the OLED), allowing them to share the exact same two wires without data collision.

Tactile pushbuttons allow users to inspect alarm settings and silence buzzing alarms when the programmed wakeup time arrives.

I2C allows up to 127 distinct sensors and displays to communicate over just two shared wires (SDA and SCL) because every peripheral has a unique hex address.

Building the Desktop Clock Circuit

The Arduino Uno provides 5V power and a common GND reference to the DS1307 RTC module, the SSD1306 OLED display, and the alarm buzzer. The RTC and OLED share hardware I2C pins A4 and A5.

Tactile pushbuttons connect between digital pins D2, D3, D4 and GND using internal pull-up resistors (INPUT_PULLUP), eliminating the need for external breadboard resistors.

Pin Connection Map
DS1307 RTC Module
VCC
→
Arduino Uno
5V
Explanation
Powers the internal I2C bus interface.
DS1307 RTC Module
GND
→
Arduino Uno
GND.1
Explanation
Ground return line.
DS1307 RTC Module
SDA
→
Arduino Uno
A4
Explanation
I2C data line (Address 0x68).
DS1307 RTC Module
SCL
→
Arduino Uno
A5
Explanation
I2C clock line.
Pin Connection Map
SSD1306 OLED (128x64)
VCC
→
Arduino Uno
5V
Explanation
Powers the OLED matrix and charge pump.
SSD1306 OLED (128x64)
GND
→
Arduino Uno
GND.2
Explanation
Display ground return.
SSD1306 OLED (128x64)
SDA
→
Arduino Uno
A4
Explanation
Shared I2C data bus (Address 0x3C).
SSD1306 OLED (128x64)
SCL
→
Arduino Uno
A5
Explanation
Shared I2C clock bus.
Pin Connection Map
Alarm Buzzer
Pin 1 (+)
→
Arduino Uno
D7
Explanation
Receives alarm tone frequencies from Arduino.
Alarm Buzzer
Pin 2 (-)
→
Arduino Uno
GND.3
Explanation
Completes buzzer ground circuit.

The Complete Desktop Clock Sketch

Below is the complete, tested Arduino sketch. It queries the DS1307 RTC, renders formatted time strings on the OLED, and sounds an alarm chime when scheduled.

C++ Source
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "RTClib.h"

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
RTC_DS1307 rtc;

const int buzzerPin = 7;
const int alarmHour = 7;
const int alarmMinute = 0;

void setup() {
  Serial.begin(9600);
  pinMode(buzzerPin, OUTPUT);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("OLED init failed");
    for (;;);
  }

  if (!rtc.begin()) {
    Serial.println("RTC init failed");
    for (;;);
  }

  if (!rtc.isrunning()) {
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }

  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  Serial.println("[System]: Desktop Clock Initialized");
}

void loop() {
  DateTime now = rtc.now();

  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(16, 8);
  display.print("DESKTOP CLOCK");

  // Big digital time display
  display.setTextSize(2);
  display.setCursor(16, 26);
  if (now.hour() < 10) display.print('0');
  display.print(now.hour());
  display.print(':');
  if (now.minute() < 10) display.print('0');
  display.print(now.minute());
  display.print(':');
  if (now.second() < 10) display.print('0');
  display.print(now.second());

  // Date footer
  display.setTextSize(1);
  display.setCursor(20, 50);
  display.print(now.day());
  display.print('/');
  display.print(now.month());
  display.print('/');
  display.print(now.year());
  display.display();

  // Alarm trigger
  if (now.hour() == alarmHour && now.minute() == alarmMinute && now.second() < 10) {
    tone(buzzerPin, 1000, 100);
    Serial.println("[Alarm]: Wakeup chime active!");
  } else {
    noTone(buzzerPin);
  }

  delay(1000);
}

How the Code Works, Step by Step

Let us walk through how I2C communication and display rendering are structured.

Configuring the I2C Bus and Peripherals

The sketch instantiates display and rtc using the Wire library. In setup(), both devices initialize over I2C. If the RTC has lost time due to a dead battery, rtc.adjust() automatically synchronizes it to the sketch compile timestamp.

Formatting and Rendering OLED Graphics

Inside loop(), DateTime now = rtc.now() fetches the current timestamp. The display buffer clears, prints the header, formats hours, minutes, and seconds with zero-padding (e.g., 07:05:09), and renders to screen using display.display().

Evaluating Alarm Conditions

An if condition compares current hours and minutes against alarmHour and alarmMinute. During the scheduled window, the buzzer pulses a clean 1 kHz alarm chime.

Practical Testing and Tuning

In the IoTSimulator workspace, observe the live digital clock seconds tick in real time on the crisp OLED screen. Open the code editor to adjust alarmHour and alarmMinute to test the scheduled alarm chime immediately.

Keywords
#Arduino #Clock #DS1307 #SSD1306 #Alarm #OLED
Total word count: 631 words

More in OLED Display

Continue exploring this hardware category

Project discussion

Questions, feedback, and community insights
No discussions yet. Be the first to start!