DEV Community

Hedy
Hedy

Posted on

How to make a clock in Arduino?

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
}

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
  • 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);
  }
}

Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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)