Here are three solid ways to build an Arduino clock, from “works offline & keeps time” to “auto-syncs from the internet.” I’ll give you wiring, libraries, and complete example code.
Option A — Most reliable (offline): Arduino + DS3231 RTC + I²C 16×2 LCD
Parts
- Arduino Uno/Nano (or any I²C-capable board)
- DS3231 Real-Time Clock module (battery-backed, very accurate)
- 16×2 LCD with I²C backpack (PCF8574)
- 4× Dupont wires (I²C is shared)
Wiring (Uno/Nano)
On Mega: SDA=20, SCL=21. On Leonardo: SDA/SCL pins near AREF. Many DS3231 modules tolerate 3.3–5 V.
Libraries (install via Library Manager)
- RTClib (by Adafruit)
- LiquidCrystal_I2C (if your LCD backpack uses PCF8574)
Full sketch (sets RTC once, then displays date/time)
#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
RTC_DS3231 rtc;
// Change 0x27 to 0x3F if your LCD shows nothing
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup() {
Wire.begin();
lcd.init();
lcd.backlight();
Serial.begin(115200);
if (!rtc.begin()) {
lcd.print("RTC not found");
while (1);
}
// Set RTC once if it lost power (uses compile time)
if (rtc.lostPower()) {
// Sets to the time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
lcd.setCursor(0, 0); lcd.print("Clock ready");
delay(800);
lcd.clear();
}
void print2d(uint8_t v) { if (v < 10) lcd.print('0'); lcd.print(v); }
void loop() {
DateTime now = rtc.now();
// Line 1: YYYY-MM-DD
lcd.setCursor(0, 0);
lcd.print(now.year());
lcd.print('-'); print2d(now.month());
lcd.print('-'); print2d(now.day());
// Line 2: HH:MM:SS (24h)
lcd.setCursor(0, 1);
print2d(now.hour()); lcd.print(':');
print2d(now.minute()); lcd.print(':');
print2d(now.second());
delay(200); // refresh ~5x/sec; LCD is slow, keep it gentle
}
Tips
- To set a custom time once, replace the rtc.adjust(...) line with:
rtc.adjust(DateTime(2025, 9, 30, 10, 0, 0)); // YYYY,MM,DD,HH,MM,SS
- DS3231 battery keeps time when power is off.
- If the LCD is blank, try address 0x3F and contrast pot on the backpack.
Option B — No extra hardware: Software clock with millis()
Good for demos, but it will drift (±tens of seconds/day depending on the MCU clock).
unsigned long lastTick;
uint8_t hh=0, mm=0, ss=0;
void setup() { Serial.begin(115200); lastTick = millis(); }
void loop() {
unsigned long now = millis();
if (now - lastTick >= 1000) {
lastTick += 1000; // keep pace even if loop jitter occurs
if (++ss == 60) { ss = 0; if (++mm == 60) { mm = 0; if (++hh == 24) hh = 0; } }
// Print HH:MM:SS
if (hh<10) Serial.print('0'); Serial.print(hh); Serial.print(':');
if (mm<10) Serial.print('0'); Serial.print(mm); Serial.print(':');
if (ss<10) Serial.print('0'); Serial.println(ss);
}
}
You can add buttons to set hh/mm and display on an LCD/OLED. For better accuracy use Option A.
Option C — Network-synced (ESP32/ESP8266 + NTP + OLED/LCD)
Perfect if you have Wi-Fi and want auto time sync.
// Board: ESP32. Libraries: WiFi.h, time.h (built-in)
#include <WiFi.h>
#include <time.h>
const char* ssid = "YOUR_WIFI";
const char* pass = "YOUR_PASS";
// TZ string example: Singapore UTC+8 (no DST)
const char* tz = "SGT-8";
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) { delay(300); Serial.print("."); }
Serial.println("\nWiFi OK");
configTzTime(tz, "pool.ntp.org", "time.nist.gov");
}
void loop() {
struct tm t;
if (!getLocalTime(&t)) { Serial.println("NTP waiting..."); delay(500); return; }
char buf[32];
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &t);
Serial.println(buf); // Replace with OLED/LCD print if desired
delay(1000);
}
Add an SSD1306 OLED (I²C) if you want a display; the time formatting stays the same.
Common add-ons (any option)
- Alarms: compare current HH:MM to alarm time; drive a piezo on a PWM pin.
- Buttons/Encoder: set hours/minutes; debounce or use an encoder library.
- 12/24-hour toggle: simple boolean; for 12-hour, convert 0→12, 13–23 → 1–11 and add AM/PM.
- Brightness/Backlight: PWM the LCD/OLED backlight pin or use a MOSFET.
- Power loss: RTC with coin cell preserves time; ESP32 with NTP re-syncs at boot.
Top comments (0)