#include <Wire.h>
#include "RTClib.h"
#include <LiquidCrystal.h>
#define DOWN_BUTTON 3
#define UP_BUTTON 2
#define RIGHT_BUTTON 4
#define LEFT_BUTTON 5
int buttons[] = {DOWN_BUTTON, UP_BUTTON, RIGHT_BUTTON, LEFT_BUTTON};
int countdown = 0;
unsigned long milisBreakdown = 0;
RTC_DS1307 rtc;
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);
void setup() {
lcd.begin(16, 2);
lcd.print("hello world");
Serial.begin(9600);
for (int btn : buttons) {
pinMode(btn, INPUT_PULLUP);
}
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
abort();
}
}
int getButtonPress() {
return getButtonPress(false);
}
int getButtonPress(bool onlyOnce) {
return getButtonPress(onlyOnce, false);
}
int getButtonPress(bool onlyOnce, bool holdIn) {
if (onlyOnce) {
for (int btn : buttons) {
if (digitalRead(btn) == LOW) {
while (digitalRead(btn) == LOW && holdIn)delay(10);
return btn;
}
}
return 0;
}
while (true) {
for (int btn : buttons) {
if (digitalRead(btn) == LOW) {
while (digitalRead(btn) == LOW && holdIn) {};
return btn;
}
}
}
}
char *menu(char *menus[255], int menu_length) {
int selectedItems = 0;
while (true) {
lcd.clear();
lcd.print(">");
lcd.print(menus[selectedItems]);
lcd.setCursor(0, 1);
if (selectedItems != (menu_length - 1)) lcd.print(menus[selectedItems + 1]);
else lcd.print(menus[0]);
delay(400);
switch (getButtonPress(false, true)) {
case UP_BUTTON :
// selectedItems = (selectedItems - 1) % menu_length;
if (selectedItems <= 0) selectedItems = menu_length - 1;
else selectedItems--;
break;
case DOWN_BUTTON :
selectedItems = (selectedItems + 1) % menu_length;
break;
case RIGHT_BUTTON :
lcd.clear();
return menus[selectedItems];
case LEFT_BUTTON :
lcd.clear();
return "";
}
}
}
// todo: give this proper name
int intSelector(int minimal, int maximal) {
int value = minimal;
while (true) {
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(value);
delay(100);
switch (getButtonPress()) {
case UP_BUTTON :
if (value != maximal) value++;
break;
case DOWN_BUTTON :
if (value != minimal) value--;
break;
case RIGHT_BUTTON :
lcd.setCursor(0, 1);
lcd.print(" ");
delay(400);
return value;
case LEFT_BUTTON :
break;
}
}
}
void configRTC() {
int year = 2000,
month = 1,
day = 1,
hour = 0,
miniute = 0,
second = 0;
lcd.print("RTC config..");
delay(700);
lcd.clear();
lcd.print("tahun?");
year = intSelector(2000, 4000);
lcd.clear();
lcd.print("bulan?");
month = intSelector(1, 12);
lcd.clear();
lcd.print("tanggal?");
int maxDay = 31;
if (month == 4 || month == 6 || month == 9 || month == 11) maxDay = 30;
else if (month == 2) {
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) maxDay = 29;
else maxDay = 28;
}
day = intSelector(1, maxDay);
lcd.clear();
lcd.print("jam berapa?");
hour = intSelector(0, 24);
lcd.clear();
lcd.print("kalau menit?");
miniute = intSelector(0, 60);
lcd.clear();
lcd.print("ok, detik?");
second = intSelector(0, 60);
}
int getTimeInput() {
int state = 1;
int add_input_value = 1;
unsigned long input_value = 0;
delay(500);
while (true) {
lcd.clear();
int second = input_value;
int hour = second / 3600;
second = second % 3600;
int miniute = second / 60;
second = second % 60;
lcd.setCursor(0, 0);
lcd.print(hour);
lcd.print(":");
if (miniute < 10) {
lcd.print("0");
}
lcd.print(miniute);
lcd.print(":");
if (second < 10) {
lcd.print("0");
}
lcd.print(second);
lcd.setCursor(0, 1);
lcd.print("+/-");
lcd.print(add_input_value);
lcd.print("s");
delay(400);
switch (getButtonPress(false)) {
case UP_BUTTON :
input_value = input_value + add_input_value;
break;
case DOWN_BUTTON :
if ( (input_value - add_input_value) >= 0) input_value = input_value - add_input_value;
break;
case RIGHT_BUTTON :
lcd.clear();
Serial.println(input_value);
return input_value;
case LEFT_BUTTON :
state = (state + 1) % 6;
switch (state) {
case 1:
add_input_value = 1;
break;
case 2:
add_input_value = 10;
break;
case 3:
add_input_value = 60;
break;
case 4:
add_input_value = 600;
break;
case 5:
add_input_value = 3600;
break;
}
break;
}
}
}
void loop() {
DateTime date = rtc.now();
char *DateFormat = "DD/MM/YYYY ";
char *TimeFormat = "hh:mm";
// lcd.clear();
lcd.setCursor(0, 0);
lcd.print(date.toString(DateFormat));
lcd.setCursor(11, 0);
lcd.print(date.toString(TimeFormat));
delay(100);
if (countdown != 0) {
int second = countdown - ((millis() - milisBreakdown) / 1000);
if (second <= 0) {
lcd.clear();
lcd.print("HITUNG MUNDUR");
lcd.setCursor(0, 1);
lcd.println("SELESAI");
getButtonPress(false);
lcd.clear();
countdown = 0;
milisBreakdown = 0;
delay(400);
return;
}
int hour = second / 3600;
second = second % 3600;
int miniute = second / 60;
second = second % 60;
lcd.setCursor(0, 1);
lcd.print(hour);
lcd.print(":");
if (miniute < 10) {
lcd.print("0");
}
lcd.print(miniute);
lcd.print(":");
if (second < 10) {
lcd.print("0");
}
lcd.print(second);
}
if (getButtonPress(true, true)) {
delay(400);
char *menuItems[] = {"Setel Alarm", "Hitung Waktu", "Hitung Mundur", "config RTC", "credit"};
char *respons = menu(menuItems, 5);
if (respons == "config RTC") configRTC();
else if (respons == "Hitung Mundur") {
int input = getTimeInput();
if (input){
countdown = input;
milisBreakdown = millis();
}
} else if (respons == "Hitung Waktu") {
delay(400);
lcd.clear();
milisBreakdown = millis();
while (true) {
unsigned long time = (millis() - milisBreakdown);
int second = time / 1000;
int hour = second / 3600;
second = second % 3600;
int miniute = second / 60;
second = second % 60;
lcd.setCursor(0, 1);
lcd.print(hour);
lcd.print(":");
if (miniute < 10) {
lcd.print("0");
}
lcd.print(miniute);
lcd.print(":");
if (second < 10) {
lcd.print("0");
}
lcd.print(second);
lcd.print(".");
lcd.print(time - ((time / 1000) * 1000));
if (getButtonPress(true, false) == RIGHT_BUTTON) {
delay(400);
unsigned long jedaAwal = millis();
bool wait = true;
while (wait) {
switch (getButtonPress(false, true)) {
case UP_BUTTON :
case DOWN_BUTTON :
//
break;
case RIGHT_BUTTON :
milisBreakdown += millis() - jedaAwal;
wait = false;
break;
case LEFT_BUTTON :
milisBreakdown = 0;
return;
}
}
delay(100);
}
// delay(400);
}
}
else lcd.print(respons);
// delay(700);
lcd.clear();
// lcd.print(respons);
delay(1000);
}
}