/*
Arduino RTC Clock
3/1/26
Encoder library:
https://github.com/mathertel/RotaryEncoder/tree/master
TO DO: Add code to set time / date via rotary encoder
*/
#include <LiquidCrystal.h>
#include <RotaryEncoder.h>
#include <RTClib.h>
const int RS = 12, EN = 11, D4 = 10, D5 = 9, D6 = 8, D7 = 7;
const int CK_PIN = 3;
const int DT_PIN = 2;
const int SW_PIN = 4;
const char daysOfTheWeek[7][4] = {
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat"
};
const unsigned long ONE_SEC = 1000;
bool isMDY = true;
bool is12Hour = true;
unsigned long prevTime = 0;
LiquidCrystal lcd(RS, EN, D4, D5, D6, D7);
RotaryEncoder *encoder = nullptr;
RTC_DS1307 rtc;
void checkPosition() {
encoder->tick(); // just call tick() to check the state.
}
void showSplash() {
lcd.setCursor(1, 0);
lcd.print("Arduino Clock");
lcd.setCursor(5, 1);
lcd.print("V1.00");
delay(2000);
lcd.clear();
}
void setup() {
Serial.begin(115200);
lcd.begin(16, 2);
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (true);
}
// setup the rotary encoder functionality
// use FOUR3 mode when CK_PIN, DT_PIN signals are always HIGH in latch position.
encoder = new RotaryEncoder(CK_PIN, DT_PIN, RotaryEncoder::LatchMode::FOUR3);
attachInterrupt(digitalPinToInterrupt(CK_PIN), checkPosition, CHANGE);
attachInterrupt(digitalPinToInterrupt(DT_PIN), checkPosition, CHANGE);
pinMode(SW_PIN, INPUT_PULLUP);
showSplash();
}
void loop() {
char dateBuffer[16];
char timeBuffer[16];
static int pos = 0;
encoder->tick(); // just call tick() to check the state.
int newPos = encoder->getPosition();
if (pos != newPos) {
Serial.print("pos:");
Serial.print(newPos);
Serial.print(" dir:");
Serial.println((int)(encoder->getDirection()));
pos = newPos;
}
if (millis() - prevTime >= ONE_SEC) {
prevTime = millis();
DateTime now = rtc.now();
if (is12Hour) {
snprintf(timeBuffer, 16, "%2d:%02d:%02d %s",
now.twelveHour(),
now.minute(),
now.second(),
now.isPM() ? "PM" : "AM"
);
lcd.setCursor(2, 0);
} else {
snprintf(timeBuffer, 16, "%2d:%02d:%02d",
now.hour(),
now.minute(),
now.second()
);
lcd.setCursor(4, 0);
}
lcd.print(timeBuffer);
Serial.print(timeBuffer);
Serial.print("\t");
if (isMDY) {
snprintf(dateBuffer, 16, "%s %2d/%2d/%4d",
daysOfTheWeek[now.dayOfTheWeek()],
now.month(),
now.day(),
now.year()
);
} else {
snprintf(dateBuffer, 16, "%s %2d/%2d/%4d",
daysOfTheWeek[now.dayOfTheWeek()],
now.day(),
now.month(),
now.year()
);
}
lcd.setCursor(1, 1);
lcd.print(dateBuffer);
Serial.println(dateBuffer);
}
}