#include <LiquidCrystal.h> //Header file for LCD from https://www.arduino.cc/en/Reference/LiquidCrystal
#include <RotaryEncoder.h>
#define BTN 11
#define PIN_IN1 12
#define PIN_IN2 13
const int rs = 2, en = 3, d4 = 4, d5 = 5, d6 = 6, d7 = 7; //Pins to which LCD is connected
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
// IN PROGRESS - Function to print on LCD to reduce clutter
// Can add a mode variable to choose what its printing (time, date, etc.)
// IN PROGRESS - Encoder
// Years get messed up when changing to a value less than the previous one
// Store previous values of encoder to provide easier access
// Flash current selection?
// When clicking button to lock in date, tracked as another button press and messes up other values - Made an extra state as a buffer, better way to do this?
//
int day = 1;
int hours = 12;
int milHour = 0;
int min = 0;
int sec = 0;
bool aPm = true; // true if AM, false if PM
int currMonth = 0;
char* months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
int year = 2024;
bool btn_pressed = false;
bool long_press = true;
int btn_num = 0;
uint32_t mdelay = 0;
uint32_t loopDelay = 0;
uint16_t duty = 0;
int newEncoderValue = 0, oldEncoderVlue = 0;
// Initialize rotary encoder
RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::FOUR3);
// Collect encoder value and return it - This may need to be edited to save the previous time values
int getEncoderChanges() {
int retVal = 0;
newEncoderValue = encoder.getPosition();
if(newEncoderValue != oldEncoderVlue){
if(oldEncoderVlue > newEncoderValue){
retVal = 1;
}else{
retVal = -1;
}
oldEncoderVlue = newEncoderValue;
}
return retVal;
}
// Change date and time by counting button presses and using encoder
void changeDateTime(int btn_num) {
// Use button presses to choose unit of time to change w/ encoder
switch(btn_num) {
case(0): // Change month
currMonth += getEncoderChanges();
if(currMonth > 11) {
currMonth = 11;
}
break;
case(1): // Change day
day += getEncoderChanges();
if(day < 1) {
day = 1;
}
if(currMonth==3 || currMonth==5 || currMonth==8 || currMonth==10) {
if(day > 30) {
day = 30;
}
}
else if(currMonth==1) {
if(day > 28) {
day = 28;
}
}
else {
if(day > 31) {
day = 31;
}
}
break;
case(2): // Change year
year += getEncoderChanges();
break;
case(3): // Change hours
hours += getEncoderChanges();
if(hours > 12) {
hours = 12;
}
if(hours < 1) {
hours = 1;
}
break;
case(4): // Change minutes
min += getEncoderChanges();
if(min > 59) {
min = 59;
}
break;
case(5): // Change seconds
sec += getEncoderChanges();
if(sec > 59) {
sec = 59;
}
break;
case(6): // Change AM PM
if(encoder.getPosition() % 2 == 0) {
aPm = true;
milHour = hours;
}
else {
aPm = false;
milHour = 12 + hours;
}
break;
case(7):
// Buffer state - enter when done setting clock
break;
} // switch
}
// Cursor to flash currently selected time unit
void cursor_flash(uint16_t duty) {
if(duty == 10) {
lcd.clear();
duty = 0;
}
}
// Check button return to see if it was pressed/held/released
int check_btn_status() {
int bs = 0;
// Tracking a button press or long press
if(digitalRead(BTN) == LOW && !btn_pressed) {
mdelay = millis(); // Important to set this here for long button press
btn_pressed = true;
}
else if(digitalRead(BTN) == LOW && btn_pressed) {
if(millis() - mdelay > 2000) {
mdelay = millis();
long_press = true;
bs = 2;
}
}
else if(digitalRead(BTN) == HIGH && btn_pressed) {
btn_pressed = false;
if(millis() - mdelay < 300 && millis() - mdelay > 100) {
bs = 1;
}
}
return bs;
}
void setup() {
Serial.begin(115200);
lcd.begin(16, 2); //We are using a 16*2 LCD display
pinMode(BTN, INPUT_PULLUP); // Intialize button
}
void loop() {
if(long_press) {
// Start encoder
encoder.tick();
int bs = check_btn_status();
Serial.print("Button Staus>> ");
Serial.println(bs);
if(bs == 1) {
btn_num++;
// Wrap back to setting month if btn_num > 7
if(btn_num == 7) {
btn_num = 0;
}
}else if(bs == 2) {
long_press = false;
}
// Change date and time using encoder and number of button presses to determine what
// unit of time being changed
changeDateTime(btn_num);
// Print Date
lcd.setCursor(0, 0);
lcd.print(months[currMonth]);
lcd.print(" ");
lcd.print(day);
lcd.print(", ");
lcd.print(year);
// Print time
lcd.setCursor(0,1);
if(hours < 10){
lcd.print(0);
lcd.print(hours);
}
else{
lcd.print(hours);
}
lcd.print(":");
// Set minutes
if(min < 10) {
lcd.print(0);
lcd.print(min);
}
else{
lcd.print(min);
}
lcd.print(":");
// Set seconds
if(sec < 10) {
lcd.print(0);
lcd.print(sec);
}
else{
lcd.print(sec);
}
// Print AM or PM
if(aPm == true){
lcd.print(" AM");
}
else{
lcd.print(" PM");
}
// Call flash cursor function
cursor_flash(duty);
duty++;
} // if long press false
else
{
if(check_btn_status() == 2){
long_press = true;
btn_num = 0;
}
if(millis() - loopDelay >= 1000) {
loopDelay = millis();
// Normal clock functionality
// Reset second and minute count
if(sec >= 60) {
min++;
sec = 0;
}
if(min >= 60) {
hours++;
milHour++;
min = 0;
}
// Flipping AM and PM, resetting 12 hour count
if(hours == 12 && sec == 0 && min == 0){
aPm = !aPm;
}
if(hours > 12) {
hours = 1;
}
// Incrementing day, resetting 24 hour count
if(milHour == 24 && sec == 0 && min == 0) {
day++;
}
if(milHour > 24){
milHour = 0;
}
// Make correct number of days for current month, reset when new month
if(currMonth==3 || currMonth==5 || currMonth==8 || currMonth==10) {
if(day > 30) {
day = 0;
currMonth++;
}
}
else if(currMonth==1) {
if(day > 28) {
day = 0;
currMonth++;
}
}
else {
if(day > 31) {
day = 0;
currMonth++;
}
}
// Reset month count
if(currMonth > 12) {
currMonth = 0;
year++;
}
// Print Date
lcd.setCursor(0, 0);
lcd.print(months[currMonth]);
lcd.print(" ");
lcd.print(day);
lcd.print(", ");
lcd.print(year);
// Print time on line below, insert placeholder 0 when values < 10
lcd.setCursor(0,1);
if(hours < 10){
lcd.print(0);
lcd.print(hours);
}
else{
lcd.print(hours);
}
lcd.print(":");
// Set minutes
if(min < 10) {
lcd.print(0);
lcd.print(min);
}
else{
lcd.print(min);
}
// Set seconds
lcd.print(":");
if(sec < 10) {
lcd.print(0);
lcd.print(sec);
}
else{
lcd.print(sec);
}
// Print AM or PM
if(aPm == true){
lcd.print(" AM");
}
else{
lcd.print(" PM");
}
// Increment seconds after every loop
sec++;
} // if(millis() - loopDelay >= 1000)
} // else long press is true
}