#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"
RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define encoderClk 2
#define encoderDt 4
#define encoderSw 3
int encoderPos = 0;
int encoderLast = 0;
bool encoderChanged = false;
bool encoderButtonPressed = false;
bool rotated = true; //info of the rotation
bool ButtonPressed = false; //info of the button
int ButtonCounter = 0; //counts the button clicks
int RotateCounter = 0; //counts the rotation clicks
int rotateMenuSayac = 4;
//Statuses
int CLKNow;
int CLKPrevious;
int DTNow;
int DTPrevious;
//aLARM AYAR
int alarmSaat = 0;
int alarmDakika = 0;
// Timers
float TimeNow1;
float TimeNow2;
//statuses (1/true: ON, 0/false: OFF)
bool whiteLEDStatus = false;
bool blueLEDStatus = false;
bool greenLEDStatus = false;
bool yellowLEDStatus = false;
bool redLEDStatus = false;
int saat, dakika, saniye;
unsigned long son_saniye = millis();
long bir_saniye = 1000;
bool menuAktif = false;
//https://maxpromer.github.io/LCD-Character-Creator/
byte CursorIcon[8] = {B10000, B01000, B00100, B00010, B00010, B00100, B01000, B10000}; // >
byte CheckIcon[8] = {B00000, B00000, B00001, B00011, B10110, B11100, B11000, B00000}; // ✓
byte CheckBoxIcon[8] = {B11111, B10000, B10001, B00011, B10110, B11101, B01001, B11111}; // 🗹
byte UncheckBoxIcon[8] = {B11111, B10001, B10001, B10001, B10001, B10001, B10001, B11111}; //☐
int menu = 0;
int altmenu = 0;
boolean updateScreen = false;
/*String menuItems[]={"Saat","Aile Saati","Sure","Baslat","Kapak Ac"};
String alt_menu[][3]={{"","",""},{"Bas Saat","",""},{"30","45","60"}};*/
void setup() {
Serial.begin(9600);
// RTC_DS1302.setDS1302Time(00, 32, 23, 6, 24, 01, 2023); // İlk zaman ayarı
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
abort();
}
if (! rtc.isrunning()) {
Serial.println("RTC is NOT running, let's set the time!");
// When time needs to be set on a new device, or after a power loss, the
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
Wire.begin();
lcd.begin(16, 2);
lcd.backlight();
pinMode(encoderClk, INPUT_PULLUP);
pinMode(encoderDt, INPUT_PULLUP);
pinMode(encoderSw, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(encoderClk), rotate, CHANGE);
attachInterrupt(digitalPinToInterrupt(encoderSw), buttonPressed, FALLING);
TimeNow1 = millis(); //Start timer 1
lcd.createChar(0, CursorIcon);
lcd.setCursor(12, 0);
lcd.write(byte(0));
updateMenu();
}
void loop() {
unsigned long currentTime = millis();
if ((currentTime - son_saniye > bir_saniye) && menuAktif == false) {
saatiGuncelle();
son_saniye = currentTime;
}
ButtonChecker();
}
void buttonPressed() {
//This timer is a "software debounce". It is not the most effective solution, but it works
TimeNow2 = millis();
if (TimeNow2 - TimeNow1 > 500) {
ButtonPressed = true;
}
TimeNow1 = millis(); //"reset" timer; the next 500 ms is counted from this moment
}
void rotate() {
CLKNow = digitalRead(encoderClk); //Read the state of the CLK pin
if (CLKNow != CLKPrevious && CLKNow == 1) {
if (digitalRead(encoderDt) != CLKNow) {
Yukari();
} else {
Asagi();
}
}
CLKPrevious = CLKNow; // Store last CLK state
rotated = true;
}
void Yukari() {
if (altmenu == 0) {
RotateCounter++;
if (RotateCounter > rotateMenuSayac) {
RotateCounter = 0;
}
menu = RotateCounter;
}
else if (altmenu == 1) {
alarmSaat++;
alarmSaat %= 24;
}
else if (altmenu == 2) {
alarmDakika += 5;
alarmDakika %= 60;
}
updateScreen = true;
}
void Asagi() {
if (altmenu == 0) {
RotateCounter--;
if (RotateCounter < 0) {
RotateCounter = rotateMenuSayac;
}
menu = RotateCounter;
}
else if (altmenu == 1) {
alarmSaat--;
if (alarmSaat < 0)alarmSaat += 24;
alarmSaat %= 24;
}
else if (altmenu == 2) {
alarmDakika -= 5;
if (alarmDakika < 0)alarmDakika += 60;
alarmDakika %= 60;
}
updateScreen = true;
}
void saatiGuncelle() {
DateTime time = rtc.now();
// Serial.print("Tarih: ");
// Serial.print(RTC_DS1302.dayofmonth);
// Serial.print("/");
// Serial.print(RTC_DS1302.month);
// Serial.print("/");
// Serial.print(RTC_DS1302.year);
// Serial.print(" Saat: ");
// Serial.print(RTC_DS1302.hours);
// Serial.print(":");
// Serial.print(RTC_DS1302.minutes);
// Serial.print(":");
// Serial.println(RTC_DS1302.seconds);
//Full Timestamp
//Serial.println(String("DateTime::TIMESTAMP_TIME:\t")+time.timestamp(DateTime::TIMESTAMP_TIME));
//saatiEkranaYazdir(time.timestamp(DateTime::TIMESTAMP_TIME));
saatiEkranaYazdir(time);
}
void saatiEkranaYazdir(DateTime time) {
lcd.setCursor(0, 1);
lcd.print(time.timestamp(DateTime::TIMESTAMP_TIME));
lcd.setCursor(0, 0);
lcd.print(time.timestamp(DateTime::TIMESTAMP_DATE));
}
void ButtonChecker() //this is basically the menu part. keep track of the buttonpressed and rotatecounter for navigation
{
lcd.setCursor(14, 1); // Defining positon to write from second row, first column .
lcd.print(RotateCounter);
if (updateScreen) {
updateScreen = false;
updateMenu();
}
if (ButtonPressed == true) {
Serial.print("RotateCounter: ");
Serial.println(RotateCounter);
updateScreen = true;
executeAction();
}
ButtonPressed = false; //reset this variable
}
void updateMenu() {
if (altmenu == 0) {
switch (menu) {
case 0:
menu = 0;
menuAktif = false;
lcd.clear();
lcd.print("Saat");
break;
case 1:
lcd.clear();
menuAktif = true;
lcd.print(">Aile Saati");
lcd.setCursor(0, 1);
lcd.print(" Sure");
break;
case 2:
lcd.clear();
lcd.print(" Aile Saati");
lcd.setCursor(0, 1);
lcd.print(">Sure");
break;
case 3:
lcd.clear();
lcd.print(">Kapak Ac");
lcd.setCursor(0, 1);
lcd.print(" Baslat");
break;
case 4:
menuAktif = true;
lcd.clear();
lcd.print(" Kapak Ac");
lcd.setCursor(0, 1);
lcd.print(">Baslat");
break;
case 5:
menu = rotateMenuSayac;
break;
}
}
else if (altmenu == 1 || altmenu == 2) {
Serial.print("altmenu->");
Serial.println(altmenu);
action1();
}
else if (altmenu == 3) {
menuAktif = true;
lcd.clear();
lcd.print("> Kaydet ve Cik");
lcd.setCursor(0, 1);
lcd.print(" Iptal");
}
else if (altmenu == 4) {
menuAktif = true;
lcd.clear();
lcd.print(" Kaydet ve Cik");
lcd.setCursor(0, 1);
lcd.print("> Iptal");
}
}
void executeAction() {
if (altmenu == 0) {
switch (menu) {
case 1:
altmenu = 1;
action1();
break;
case 2:
action2();
break;
case 3:
action3();
break;
case 4:
action4();
break;
}
}
else if (altmenu == 1 || altmenu == 2) {
altmenu++;
altmenu %= 4;
Serial.println(String(altmenu));
action1();
}
}
void action1() {
lcd.clear();
lcd.print("Baslangic Zamani");
altmenu == 1 ? lcd.setCursor(0, 1) : lcd.setCursor(6, 1);
altmenu == 1 ? lcd.print(">") : lcd.print("<");
lcd.setCursor(1, 1);
String saat=String(alarmSaat).length() == 1 ? "0" + String(alarmSaat) : String(alarmSaat);
String dakika=String(alarmDakika).length() == 1 ? "0" + String(alarmDakika) : String(alarmDakika);
lcd.print(saat+ ":" + dakika);
//delay(1500);
}
void action2() {
lcd.clear();
lcd.print(">Executing #2");
delay(1500);
}
void action3() {
lcd.clear();
lcd.print(">Executing #3");
delay(1500);
}
void action4() {
lcd.clear();
lcd.print(">Kapak Kapaniyor");
RotateCounter = 0;
delay(1500);
}