#include <Wire.h> // For I2C communication
#include <LiquidCrystal_I2C.h> // For LCD
#include <RTClib.h> // For RTC
LiquidCrystal_I2C lcd(0x27, 16, 2); // Create LCD at I2C address 0x27, 16 characters by 2 lines.
RTC_DS3231 rtc; // Create RTC for the DS3231 RTC module, address is 0x68 fixed.
// Minimum and maximum values structure for each input.
typedef struct minMax_t {
int minimum;
int maximum;
};
/*
* Function to validate user input.
* Returns TRUE if value in range, FALSE otherwise.
*/
bool checkInput(const int value, const minMax_t minMax) {
if ((value >= minMax.minimum) &&
(value <= minMax.maximum))
return true;
Serial.print(value);
Serial.print(" is out of range ");
Serial.print(minMax.minimum);
Serial.print(" - ");
Serial.println(minMax.maximum);
return false;
}
/*
Function to update RTC time using user input.
*/
void updateRTC()
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Edit Mode...");
// Prompts for user input.
const char txt[6][15] = { "year [4-digit]", "month [1~12]", "day [1~31]",
"hours [0~23]", "minutes [0~59]", "seconds [0~59]"};
// Define limits for the 6 user inputs.
const minMax_t minMax[] = {
{2000, 9999}, // Year
{1, 12}, // Month
{1, 31}, // Day
{0, 23}, // Hours
{0, 59}, // Minutes
{0, 59}, // Seconds
};
String str = "";
long newDate[6];
DateTime newDateTime;
while (1) {
while (Serial.available()) {
Serial.read(); // Clear serial buffer
}
// We have 6 different user inputs to capture.
for (int i = 0; i < 6; i++) {
while (1) {
Serial.print("Enter ");
Serial.print(txt[i]);
Serial.print(" (or -1 to abort) : ");
while (!Serial.available()) {
; // Wait for user input
}
str = Serial.readString(); // Read user input
if ((str == "-1") || (str == "-1\n") ||
(str == "-1\r") || (str == "-1\r\n")) {
Serial.println("\nABORTED");
return;
}
newDate[i] = str.toInt(); // Convert user input to number and save to array
if (checkInput(newDate[i], minMax[i]))
break;
}
Serial.println(newDate[i]); // Show user their input
}
newDateTime = DateTime(newDate[0], newDate[1], newDate[2], newDate[3], newDate[4], newDate[5]);
if (newDateTime.isValid())
break;
// Otherwise, we have to do it all again.
Serial.println("Date/time entered was invalid, please try again.");
}
// Update RTC as we have a valid date & time.
rtc.adjust(newDateTime);
Serial.println("RTC Updated!");
}
void updateLCD()
{
// Get time and date from RTC.
DateTime rtcTime = rtc.now();
char dateBuffer[] = "DD-MMM-YYYY DDD";
char timeBuffer[] = "hh:mm:ss AP";
// Move LCD cursor to top line, far left position.
lcd.setCursor(0, 0);
lcd.print(rtcTime.toString(dateBuffer));
// Move LCD cursor to second line, far left position.
lcd.setCursor(0, 1);
lcd.print(rtcTime.toString(timeBuffer));
}
void setup()
{
Serial.begin(9600);
lcd.init(); // Initialize lcd
lcd.backlight(); // Switch-on lcd backlight
rtc.begin(); // Initialise RTC module.
}
void loop()
{
updateLCD();
if (Serial.available()) {
char input = Serial.read();
if (input == 'u') updateRTC();
}
}