#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <TimerOne.h>
#include <RTClib.h>
#define NOTE_B0 31
#define NOTE_C1 33
#define NOTE_CS1 35
#define NOTE_D1 37
#define NOTE_DS1 39
#define NOTE_E1 41
#define NOTE_F1 44
#define NOTE_FS1 46
#define NOTE_G1 49
#define NOTE_GS1 52
#define NOTE_A1 55
#define NOTE_AS1 58
#define NOTE_B1 62
#define NOTE_C2 65
#define NOTE_CS2 69
#define NOTE_D2 73
#define NOTE_DS2 78
#define NOTE_E2 82
#define NOTE_F2 87
#define NOTE_FS2 93
#define NOTE_G2 98
#define NOTE_GS2 104
#define NOTE_A2 110
#define NOTE_AS2 117
#define NOTE_B2 123
#define NOTE_C3 131
#define NOTE_CS3 139
#define NOTE_D3 147
#define NOTE_DS3 156
#define NOTE_E3 165
#define NOTE_F3 175
#define NOTE_FS3 185
#define NOTE_G3 196
#define NOTE_GS3 208
#define NOTE_A3 220
#define NOTE_AS3 233
#define NOTE_B3 247
#define NOTE_C4 262
#define NOTE_CS4 277
#define NOTE_D4 294
#define NOTE_DS4 311
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_FS4 370
#define NOTE_G4 392
#define NOTE_GS4 415
#define NOTE_A4 440
#define NOTE_AS4 466
#define NOTE_B4 494
#define NOTE_C5 523
#define NOTE_CS5 554
#define NOTE_D5 587
#define NOTE_DS5 622
#define NOTE_E5 659
#define NOTE_F5 698
#define NOTE_FS5 740
#define NOTE_G5 784
#define NOTE_GS5 831
#define NOTE_A5 880
#define NOTE_AS5 932
#define NOTE_B5 988
#define NOTE_C6 1047
#define NOTE_CS6 1109
#define NOTE_D6 1175
#define NOTE_DS6 1245
#define NOTE_E6 1319
#define NOTE_F6 1397
#define NOTE_FS6 1480
#define NOTE_G6 1568
#define NOTE_GS6 1661
#define NOTE_A6 1760
#define NOTE_AS6 1865
#define NOTE_B6 1976
#define NOTE_C7 2093
#define NOTE_CS7 2217
#define NOTE_D7 2349
#define NOTE_DS7 2489
#define NOTE_E7 2637
#define NOTE_F7 2794
#define NOTE_FS7 2960
#define NOTE_G7 3136
#define NOTE_GS7 3322
#define NOTE_A7 3520
#define NOTE_AS7 3729
#define NOTE_B7 3951
#define NOTE_C8 4186
#define NOTE_CS8 4435
#define NOTE_D8 4699
#define NOTE_DS8 4978
#define buzzer_pin 8
RTC_DS1307 rtc;
char daysOfTheWeek[7][12] = {"Minngu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu"};
int jam, minute, sec, edit, stop, currentMode, counterAlarm, mode, statesw, stateAlarm = 0;
int nyala, state, hoursw, minsw, secsw, reset, hourAlarm, minAlarm, secAlarm, countersw = 0;
int counterSec = -1;
bool editingMinute, editingSecond, editingHour = false; // variables for editing clock time
bool lastButtonState = HIGH; // variable to store lastButtonState and prevent bouncing effect in stopwatch mode
unsigned long lastModeChangeTime = 0; // variable to store the time of the last mode change prevent bouncing effect in ISR function
unsigned long debounceDelay = 300;
LiquidCrystal_I2C lcd(0x27, 16, 2);
int melody[] = {
NOTE_AS4, NOTE_AS4, NOTE_AS4, NOTE_AS4,
NOTE_D5, NOTE_D5, NOTE_D5, NOTE_D5,
NOTE_C5, NOTE_C5, NOTE_C5, NOTE_C5,
NOTE_F5, NOTE_F5, NOTE_F5, NOTE_F5,
NOTE_G5, NOTE_G5, NOTE_G5, NOTE_G5,
NOTE_G5, NOTE_G5, NOTE_G5, NOTE_G5,
NOTE_G5, NOTE_G5, NOTE_G5, NOTE_G5,
NOTE_C5, NOTE_AS4, NOTE_A4, NOTE_F4,
NOTE_G4, 0, NOTE_G4, NOTE_D5,
NOTE_C5, 0, NOTE_AS4, 0,
NOTE_A4, 0, NOTE_A4, NOTE_A4,
NOTE_C5, 0, NOTE_AS4, NOTE_A4,
NOTE_G4,0, NOTE_G4, NOTE_AS5,
NOTE_A5, NOTE_AS5, NOTE_A5, NOTE_AS5,
NOTE_G4,0, NOTE_G4, NOTE_AS5,
NOTE_A5, NOTE_AS5, NOTE_A5, NOTE_AS5,
NOTE_G4, 0, NOTE_G4, NOTE_D5,
NOTE_C5, 0, NOTE_AS4, 0,
NOTE_A4, 0, NOTE_A4, NOTE_A4,
NOTE_C5, 0, NOTE_AS4, NOTE_A4,
NOTE_G4,0, NOTE_G4, NOTE_AS5,
NOTE_A5, NOTE_AS5, NOTE_A5, NOTE_AS5,
NOTE_G4,0, NOTE_G4, NOTE_AS5,
NOTE_A5, NOTE_AS5, NOTE_A5, NOTE_AS5
};
// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
4,4,4,4,
};
void setup() {
Serial.begin(9600); // Start serial communication for debugging
lcd.init();
lcd.backlight();
pinMode(2, INPUT); // Button to switch mode
pinMode(3, INPUT); // Button to switch between editing hour, minute, or time
pinMode(4, INPUT); // Button to increment time or to reset the stopwatch
Timer1.initialize(1000000);
Timer1.attachInterrupt(secIncrement);
attachInterrupt(digitalPinToInterrupt(2), ClockEdit, FALLING);
attachInterrupt(digitalPinToInterrupt(3), startMode, FALLING);
if (! rtc.begin())
{
lcd.print("Couldn't find RTC");
while (1);
}
if (! rtc.isrunning())
{
lcd.print("RTC is NOT running!");
}
//rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));//auto update from computer time
//rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));// to set the time manually
}
void loop() {
jam = counterSec / 3600;
minute = (counterSec % 3600) / 60;
sec = counterSec % 60;
hoursw = countersw / 3600;
minsw = (countersw % 3600) / 60;
secsw = countersw % 60;
hourAlarm = counterAlarm / 3600;
minAlarm = (counterAlarm % 3600) / 60;
secAlarm = counterAlarm % 60;
while (counterAlarm == 0 && stateAlarm) {
if (reset) {
noTone(buzzer_pin);
counterAlarm = 0;
stateAlarm = 0;
reset = 0;
break;
}
else {
lcd.setCursor(2, 0);
lcd.print(" Timer On ");
blinkAlarm();
}
}
if (mode == 1) {
setJam();
}
else if (mode == 2) {
setStopwatch();
}
else if (mode == 3) {
setAlarm();
}
else{
displayRTC();
}
}
void setJam() {
lcd.clear();
while (true) {
if (mode != 1) {
break;
}
displayLCD();
if (!edit) {
lcd.setCursor(0, 0);
lcd.print(" Digital Clock ");
lcd.setCursor(4, 1);
jam = counterSec / 3600;
minute = (counterSec % 3600) / 60;
sec = counterSec % 60;
displayLCD();
}
else {
if (editingHour) {
lcd.setCursor(1, 0);
lcd.print(" Atur Jam ");
if (digitalRead(4) == LOW) {
jam++;
if (jam > 23) {
jam = 0;
}
delay(150); // Debouncing delay
}
}
else if (editingMinute) {
lcd.setCursor(3, 0);
lcd.print("Atur Menit");
if (digitalRead(4) == LOW) {
minute++;
if (minute > 59) {
minute = 0;
}
delay(150); // Debouncing delay
}
}
else if (editingSecond) {
lcd.setCursor(3, 0);
lcd.print("Atur Detik");
if (digitalRead(4) == LOW) {
sec++;
if (sec > 59) {
sec = 0;
}
delay(150); // Debouncing delay
}
}
displayLCD();
counterSec = jam * 3600 + minute * 60 + sec;
}
}
}
void secIncrement() {
if (counterSec == 3600 * 24) {
counterSec = 0;
}
if (edit > 0) {
counterSec = counterSec;
}
if (statesw) {
countersw++;
}
if (counterAlarm > 0) {
stateAlarm = 1;
counterAlarm--;
}
else {
countersw = countersw;
}
counterSec++;
}
void ClockEdit() {
unsigned long currentMillis = millis();
if (currentMillis - lastModeChangeTime >= debounceDelay) {
if (mode == 2 && !statesw) {
countersw = 0;
}
if (stateAlarm && counterAlarm == 0) {
reset = 1;
}
else {
edit++;
if (edit == 1) {
editingSecond = 0;
editingHour = 1;
}
else if (edit == 2) {
editingHour = 0;
editingMinute = 1;
}
else {
editingMinute = 0;
editingSecond = 1;
}
if (edit > 3) {
edit = 0;
}
}
lastModeChangeTime = currentMillis;
}
}
String formatTime(int time) {
if (time < 10) {
return "0" + String(time);
} else {
return String(time);
}
}
void displayLCD() {
lcd.setCursor(4, 1);
lcd.print(formatTime(jam));
lcd.print(":");
lcd.print(formatTime(minute));
lcd.print(":");
lcd.print(formatTime(sec));
}
void displayLCDalarm() {
lcd.setCursor(4, 1);
lcd.print(formatTime(hourAlarm));
lcd.print(":");
lcd.print(formatTime(minAlarm));
lcd.print(":");
lcd.print(formatTime(secAlarm));
}
void displayLCDstopwatch() {
hoursw = countersw / 3600;
minsw = (countersw % 3600) / 60;
secsw = countersw % 60;
lcd.setCursor(4, 1);
lcd.print(formatTime(hoursw));
lcd.print(":");
lcd.print(formatTime(minsw));
lcd.print(":");
lcd.print(formatTime(secsw));
}
void startMode() {
unsigned long currentMillis = millis();
if (currentMillis - lastModeChangeTime >= debounceDelay) {
mode++;
if (mode > 4) {
mode = 0;
}
edit = 0;
lastModeChangeTime = currentMillis;
}
}
void setStopwatch() {
lcd.clear();
while (true) {
if (mode != 2) {
if (statesw == 1 || (statesw == 0 && countersw > 0)) {
nyala = 1; // kalo ganti mode, stopwatch masih menampilkan waktu
}
lcd.clear();
break;
}
else if (statesw == 0 && countersw == 0 || nyala) {
lcd.setCursor(0, 0);
lcd.print(" Stopwatch Mode");
}
displayLCDstopwatch();
if (digitalRead(4) == LOW && lastButtonState == HIGH && statesw == 0) {
lcd.setCursor(0, 0);
lcd.print(" Start ");
displayLCDstopwatch();
statesw = 1;
nyala = 0;
}
else if (digitalRead(4) == LOW && lastButtonState == HIGH && statesw == 1) {
lcd.clear();
lcd.setCursor(6, 0);
lcd.print("Stop");
displayLCDstopwatch();
statesw = 0;
nyala = 0;
}
lastButtonState = digitalRead(4);
}
}
void setAlarm() {
lcd.clear(); {
while (true) {
if (mode != 3) {
if (counterAlarm > 0) {
stateAlarm = 1;
}
else {
stateAlarm = 0;
}
break;
}
if (edit == 0) {
lcd.setCursor(2, 0);
lcd.print(" Timer Set ");
lcd.setCursor(4, 1);
hourAlarm = counterAlarm / 3600;
minAlarm = (counterAlarm % 3600) / 60;
secAlarm = counterAlarm % 60;
displayLCDalarm();
while (secAlarm == 0 && stateAlarm) {
blinkAlarm();
if (reset) {
noTone(7);
counterAlarm = 0;
stateAlarm = 0;
reset = 0;
break;
}
}
}
else
{
if (editingHour) {
lcd.setCursor(1, 0);
lcd.print(" Set Hour ");
if (digitalRead(4) == LOW) {
hourAlarm++;
if (hourAlarm > 23) {
hourAlarm = 0;
}
delay(150); // Debouncing delay
}
}
else if (editingMinute) {
lcd.setCursor(3, 0);
lcd.print("Set Minute");
if (digitalRead(4) == LOW) {
minAlarm++;
if (minAlarm > 59) {
minAlarm = 0;
}
delay(150); // Debouncing delay
}
}
else if (editingSecond) {
lcd.setCursor(3, 0);
lcd.print("Set Second");
if (digitalRead(4) == LOW) {
secAlarm++;
if (secAlarm > 59) {
secAlarm = 0;
}
delay(150); // Debouncing delay
}
}
displayLCDalarm();
counterAlarm = hourAlarm * 3600 + minAlarm * 60 + secAlarm;
}
}
}
}
void blinkAlarm() {
lcd.setCursor(2, 0);
lcd.print(" Timer On ");
displayLCDalarm();
for (int i = 0; i < sizeof(melody) / sizeof(melody[0]); i++) {
int noteDuration = 750 / noteDurations[i];
tone(buzzer_pin, melody[i], noteDuration);
delay(noteDuration * 1.30);
noTone(buzzer_pin);
}
}
void displayRTC() {
DateTime now = rtc.now();
lcd.setCursor(0, 1);
lcd.print("JAM :");
lcd.print(" ");
lcd.print(now.hour());
lcd.print(':');
lcd.print(now.minute());
lcd.print(':');
lcd.print(now.second());
lcd.setCursor(0, 0);
lcd.print(daysOfTheWeek[now.dayOfTheWeek()]);
lcd.print(" ");
lcd.print(now.day());
lcd.print('/');
lcd.print(now.month());
lcd.print('/');
lcd.print(now.year());
lcd.print(" ");
}