Here, I demonstrate how to build a high-precision digital clock and thermometer using the DS3232 Real-Time Clock (RTC) and a 0.91-inch I2C OLED display. This project is a perfect upgrade for any embedded system that requires accurate timekeeping and a professional-looking visual output.
Schematic and Wiring
Below is the schematic diagram which shows how to interface the DS3231 RTC module with Arduino and OLED LCD.
To begin the build, I placed the 0.91-inch I2C OLED LCD and the DS3231 RTC module onto the schematic. Because both of these components utilize the I2C communication protocol, the wiring is incredibly efficient.
The connection to the Arduino Uno is as follows:
Power Connections: I connected the VCC pins of both the OLED and the DS3231 to the Arduino’s 5V rail, and the GND pins of both modules to the Ground rail.
I2C Data (SDA): The SDA pin on the OLED and the SDA pin on the DS3231 are tied together and connected to Arduino analog pin A4.
I2C Clock (SCL): The SCL pin on the OLED and the SCL pin on the DS3231 are tied together and connected to Arduino analog pin A5.
By sharing these two data lines, we save a significant number of GPIO pins for other sensors or peripherals.
How the Circuit Works
The heart of this system is the DS3231 Real-Time Clock. Unlike standard clock crystals that can drift due to temperature changes, the DS3231 contains an internal temperature-compensated crystal oscillator (TCXO). It constantly monitors the ambient temperature and adjusts the clock frequency to maintain pinpoint accuracy.
When the Arduino powers on, it initializes the I2C bus and communicates with the DS3231 to retrieve the current time and temperature data. The Arduino then processes this information and sends it to the SSD1306 OLED controller. The display shows an initial splash screen for ee-diary.net before switching to the live time and temperature display. Even if the main power is disconnected, the small CR2032 battery on the back of the RTC module ensures the clock continues to keep time.
Software & Libraries
The following is the code used in this demonstration;
#include <DS3232RTC.h>
#include <TimeLib.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 OLEDLCD(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, 600000, 200000, OLED_RESET);
DS3232RTC myRTC;
// Forward declaration
time_t processSyncMessage();
void setup() {
Serial.begin(9600);
myRTC.begin();
if(!OLEDLCD.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
for(;;);
}
// Sync time from PC on upload
setRTCfromPC();
// --- INITIAL DISPLAY (Shows only once) ---
OLEDLCD.clearDisplay();
OLEDLCD.setTextColor(WHITE);
OLEDLCD.setTextSize(1);
// Line 1
OLEDLCD.setCursor(25, 5);
OLEDLCD.println("ee-diary.net");
// Line 2
OLEDLCD.setCursor(18, 18);
OLEDLCD.println("Real Time Clock");
OLEDLCD.display();
delay(3000); // Show this for 3 seconds before switching to live time
}
void loop() {
tmElements_t tm;
if (myRTC.read(tm) == 0) {
OLEDLCD.clearDisplay();
// Show Time in the middle
OLEDLCD.setTextSize(2);
OLEDLCD.setCursor(15, 0);
printDigits(tm.Hour);
OLEDLCD.print(":");
printDigits(tm.Minute);
OLEDLCD.print(":");
printDigits(tm.Second);
// Show Temperature at the bottom
float temp = myRTC.temperature() / 4.0;
OLEDLCD.setTextSize(1);
OLEDLCD.setCursor(35, 22); // Adjusted slightly to the left
OLEDLCD.print(temp);
// Add Degree Symbol and 'C'
OLEDLCD.write(247); // Extended ASCII code for the degree symbol
OLEDLCD.print("C");
OLEDLCD.display();
}
delay(1000);
}
void printDigits(int digits) {
if (digits < 10) OLEDLCD.print('0');
OLEDLCD.print(digits);
}
void setRTCfromPC() {
time_t t = processSyncMessage();
if (t != 0) {
myRTC.set(t);
setTime(t);
}
}
time_t processSyncMessage() {
const char *monthNames = "JanFebMarAprMayJunJulAugSepOctNovDec";
char monthStr[4];
int hour, minute, second, day, year;
uint8_t month;
sscanf(__TIME__, "%d:%d:%d", &hour, &minute, &second);
sscanf(__DATE__, "%s %d %d", monthStr, &day, &year);
month = (strstr(monthNames, monthStr) - monthNames) / 3 + 1;
tmElements_t tm;
tm.Hour = hour;
tm.Minute = minute;
tm.Second = second;
tm.Day = day;
tm.Month = month;
tm.Year = CalendarYrToTm(year);
return makeTime(tm);
}
To drive this hardware, I used the following libraries:
DS3232RTC.h&TimeLib.h: These handle the time retrieval, synchronization with your PC, and access to the RTC’s temperature sensor.Adafruit_SSD1306.h&Adafruit_GFX.h: These libraries manage the OLED’s pixels, allowing us to display custom text, large numbers, and special characters like the degree ($^\circ$) symbol.
This project provides a robust, professional-grade timekeeping solution that is easy to implement in any desktop or industrial application.
Video demonstration is shown below:
Related tutorials: