#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
// Pin Definitions
const int Thermostat_pin = A0; // Pin for the NTC temperature sensor output
const int buttonUp = 2; // Pin for button to go up in the menu
const int buttonDown = 3; // Pin for button to go down in the menu
const int buttonSelect = 4; // Pin for button to select menu item
// RTC Object
RTC_DS1307 rtc;
// LCD Object
LiquidCrystal_I2C lcd(0x27, 20, 4); // Change address if needed
// Menu items
String MenuItems[] = {
"Time & Date",
"Set Time & Date",
"Temperature",
"Submenu 4",
"Submenu 5",
"Submenu 6",
"Submenu 7",
"Submenu 8"
};
// Current menu state
int currentMenuItem = 0;
int selectedMenu = -1; // -1 means no menu selected
int totalMenuItems = sizeof(MenuItems) / sizeof(MenuItems[0]);
// Variables for scrolling
int firstMenuIndex = 0; // Index of the first menu item to display
// Timing for button hold detection
unsigned long buttonHoldStartTime = 0;
bool buttonHeld = false;
const unsigned long holdDuration = 2000; // 2 seconds to detect hold
void setup() {
Serial.begin(9600); // Initialize serial communication for output
// Initialize buttons
pinMode(buttonUp, INPUT_PULLUP);
pinMode(buttonDown, INPUT_PULLUP);
pinMode(buttonSelect, INPUT_PULLUP);
// Initialize RTC
if (!rtc.begin()) {
Serial.println("RTC not found!"); // Inform if RTC is not found
while (1); // Halt if RTC is not found
}
// Initialize LCD
lcd.begin(20, 4);
lcd.backlight(); // Turn on the backlight
lcd.clear();
// Welcome Animation
String welcomeMessage = " Welcome!................"; // Add spaces for smoother scrolling
int messageLength = welcomeMessage.length();
int displayWidth = 20; // Width of the display
int scrollLength = messageLength + displayWidth; // Total length to scroll
// Scroll the message across the LCD
for (int pos = 0; pos < scrollLength; pos++) {
lcd.setCursor(0, 1); // Set cursor position on the second row
lcd.print(welcomeMessage.substring(pos, pos + displayWidth));
delay(50); // Adjust delay for speed of scrolling
}
delay(1000); // Pause before proceeding
}
void loop() {
handleMenuNavigation(); // Call function to handle menu navigation
// Read and display the temperature
int Thermostat = analogRead(Thermostat_pin); // Read the NTC sensor value
float temperature = calculateTemperature(Thermostat); // Calculate temperature
// Get current time from RTC
DateTime currentTime = rtc.now();
// Clear LCD and update based on current menu or submenu
lcd.clear();
if (selectedMenu == -1) {
// Show Main Menu with cursor and scroll if needed
displayMainMenu();
} else {
// Display the selected submenu's information
lcd.setCursor(0, 0);
lcd.print(MenuItems[selectedMenu]); // Print the current submenu item
if (selectedMenu == 0) {
// Submenu 1: Display time
lcd.setCursor(0, 1);
lcd.print("Time: ");
lcd.print(currentTime.hour());
lcd.print(":");
lcd.print(currentTime.minute());
lcd.print(":");
lcd.print(currentTime.second());
lcd.setCursor(0, 2);
lcd.print("Date: ");
lcd.print(currentTime.day());
lcd.print("/");
lcd.print(currentTime.month());
lcd.print("/");
lcd.print(currentTime.year());
} else if (selectedMenu == 1) {
// Submenu 2: Set Time & Date
setTimeAndDate();
selectedMenu = -1; // Return to main menu after setting
} else if (selectedMenu == 2) {
// Submenu 3: Display temperature
lcd.setCursor(0, 1);
lcd.print("Temp: ");
lcd.print(temperature);
lcd.print(" C");
} else {
// For other submenus
lcd.setCursor(0, 1);
lcd.print("No data");
}
// Check if "select" button is held down to return to main menu
if (digitalRead(buttonSelect) == LOW) {
if (!buttonHeld) {
buttonHoldStartTime = millis(); // Start timing the button hold
buttonHeld = true;
} else if (millis() - buttonHoldStartTime > holdDuration) {
// Button held for more than 2 seconds, go back to main menu
selectedMenu = -1;
buttonHeld = false; // Reset button hold flag
}
} else {
buttonHeld = false; // Reset if the button is released
}
}
delay(1000); // Delay for 1 second before the next read
}
// Handle menu navigation with buttons and scrolling
void handleMenuNavigation() {
if (selectedMenu == -1) {
// Main Menu Navigation
if (digitalRead(buttonUp) == LOW) {
if (currentMenuItem > 0) { // Prevent moving above the first item
currentMenuItem--; // Move up in the menu
}
if (currentMenuItem < firstMenuIndex) {
firstMenuIndex = currentMenuItem; // Scroll up if necessary
}
delay(200); // Debounce delay
}
if (digitalRead(buttonDown) == LOW) {
if (currentMenuItem < totalMenuItems - 1) { // Prevent moving below the last item
currentMenuItem++; // Move down in the menu
}
if (currentMenuItem >= firstMenuIndex + 4) { // If it goes out of the display
firstMenuIndex = currentMenuItem - 3; // Scroll down
}
delay(200); // Debounce delay
}
if (digitalRead(buttonSelect) == LOW) {
selectedMenu = currentMenuItem; // Select the current menu item
delay(200); // Debounce delay
}
} else {
// In a submenu: allow the "select" button to go back to the main menu
if (digitalRead(buttonSelect) == LOW) {
selectedMenu = -1; // Go back to the main menu
delay(200); // Debounce delay
}
}
}
// Display the main menu with a cursor and handle scrolling
void displayMainMenu() {
for (int i = 0; i < 4; i++) {
lcd.setCursor(0, i); // Set cursor position on each line
int menuIndex = firstMenuIndex + i; // Adjust the menu index based on scrolling
if (menuIndex < totalMenuItems) {
if (menuIndex == currentMenuItem) {
lcd.print(">"); // Display cursor (>)
} else {
lcd.print(" "); // Blank space when not selected
}
lcd.print(MenuItems[menuIndex]); // Print menu item
}
}
}
// Thermostat to temperature
float calculateTemperature(int sensorValue) {
float resistance = (1023.0 / sensorValue) - 1.0; // Calculate resistance
resistance = 10000.0 / resistance; // Convert to temperature
return (1.0 / (log(resistance / 10000.0) / 3950 + (1.0 / 298.15))) - 273.15; // Return Celsius
}
// Function to set time and date
void setTimeAndDate() {
int newHour = rtc.now().hour();
int newMinute = rtc.now().minute();
int newDay = rtc.now().day();
int newMonth = rtc.now().month();
int newYear = rtc.now().year();
int settingMode = 0; // 0: Hour, 1: Minute, 2: Day, 3: Month, 4: Year
bool settingComplete = false;
while (!settingComplete) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Set Time & Date");
lcd.setCursor(0, 1);
lcd.print("Hour: ");
lcd.print(newHour);
lcd.setCursor(0, 2);
lcd.print("Minute: ");
lcd.print(newMinute);
lcd.setCursor(0, 3);
lcd.print("Day: ");
lcd.print(newDay);
lcd.setCursor(10, 3);
lcd.print("Month: ");
lcd.print(newMonth);
lcd.setCursor(0, 4);
lcd.print("Year: ");
lcd.print(newYear);
// Handle navigation with buttons
if (digitalRead(buttonUp) == LOW) {
if (settingMode == 0) newHour = (newHour + 1) % 24;
else if (settingMode == 1) newMinute = (newMinute + 1) % 60;
else if (settingMode == 2) newDay = (newDay % 31) + 1;
else if (settingMode == 3) newMonth = (newMonth % 12) + 1;
else if (settingMode == 4) newYear++;
delay(200); // Debounce delay
}
if (digitalRead(buttonDown) == LOW) {
if (settingMode == 0) newHour = (newHour == 0) ? 23 : newHour - 1;
else if (settingMode == 1) newMinute = (newMinute == 0) ? 59 : newMinute - 1;
else if (settingMode == 2) newDay = (newDay == 1) ? 31 : newDay - 1;
else if (settingMode == 3) newMonth = (newMonth == 1) ? 12 : newMonth - 1;
else if (settingMode == 4) newYear--;
delay(200); // Debounce delay
}
if (digitalRead(buttonSelect) == LOW) {
settingMode++;
if (settingMode > 4) {
settingMode = 0;
settingComplete = true;
}
delay(200); // Debounce delay
}
}
// Set the new time and date
rtc.adjust(DateTime(newYear, newMonth, newDay, newHour, newMinute, 0)); // Set seconds to 0
lcd.clear();
lcd.print("Time & Date Set!");
delay(1000); // Delay before returning to the menu
}