#include <Wire.h>
#include <U8g2lib.h>
#include <EEPROM.h>
#define ENCODER_CLK 3
#define ENCODER_DT 4
#define ENCODER_SW 5
#define TRIGGER_PIN 2
#define BUZZER_PIN 6
#define OUTPUT1 7
#define OUTPUT2 8
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
volatile int currentTime = 30; // Default countdown time
volatile int setTime = 30;
volatile bool timerRunning = false;
volatile bool soundOn = true;
volatile bool inMenu = false;
volatile bool lastTriggerState = HIGH;
volatile int menuPage = 0; // 0 for set time, 1 for sound option
unsigned long lastInteractionTime = 0;
unsigned long lastEncoderToggleTime = 0; // To handle debounce for the encoder rotation
void setup() {
pinMode(ENCODER_CLK, INPUT);
pinMode(ENCODER_DT, INPUT);
pinMode(ENCODER_SW, INPUT_PULLUP);
pinMode(TRIGGER_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(OUTPUT1, OUTPUT);
pinMode(OUTPUT2, OUTPUT);
attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), readEncoder, CHANGE);
u8g2.begin();
u8g2.setFont(u8g2_font_ncenB08_tr);
// Startup beep tone (tick tick tick)
for (int i = 0; i < 2; i++) {
tone(BUZZER_PIN, 1100, 500);
delay(100);
tone(BUZZER_PIN, 1300, 500);
delay(100);
tone(BUZZER_PIN, 1500, 500);
delay(100);
tone(BUZZER_PIN, 1700, 500);
delay(100);
tone(BUZZER_PIN, 1900, 500);
delay(100);
tone(BUZZER_PIN, 2100, 500);
delay(100);
tone(BUZZER_PIN, 2300, 500);
delay(100);
tone(BUZZER_PIN, 2500, 500);
delay(100);
}
// Display splash screen
displaySplashScreen();
delay(3000); // Show splash screen for 3 seconds
// Read set time from EEPROM
EEPROM.get(0, setTime);
if (setTime < 0 || setTime > 300) {
setTime = 30;
}
currentTime = setTime;
}
void loop() {
bool triggerState = digitalRead(TRIGGER_PIN);
if (triggerState == LOW && !timerRunning && !inMenu) {
digitalWrite(OUTPUT1, HIGH);
digitalWrite(OUTPUT2, HIGH);
startTimer();
}
if (triggerState == HIGH && lastTriggerState == LOW) {
resetTimer();
}
if (digitalRead(ENCODER_SW) == LOW) {
delay(50); // Debounce delay
if (digitalRead(ENCODER_SW) == LOW) {
while (digitalRead(ENCODER_SW) == LOW); // Wait for button release
lastInteractionTime = millis();
if (!inMenu) {
inMenu = true;
menuPage = 0;
} else {
menuPage = (menuPage + 1) % 2; // Toggle between menu pages
if (menuPage == 0) { // If it cycles back to the first page, exit menu
inMenu = false;
EEPROM.put(0, setTime); // Save set time to EEPROM
}
}
delay(200); // Debounce delay
}
}
if (inMenu && (millis() - lastInteractionTime > 5000)) {
inMenu = false;
EEPROM.put(0, setTime); // Save set time to EEPROM
}
if (!inMenu) {
updateDisplay(triggerState);
} else {
enterMenu();
}
lastTriggerState = triggerState;
}
void readEncoder() {
static unsigned long lastInterruptTime = 0;
unsigned long interruptTime = millis();
if (interruptTime - lastInterruptTime > 200) { // Increased debounce time to reduce sensitivity
if (inMenu) {
if (menuPage == 0) {
if (digitalRead(ENCODER_DT) == HIGH) {
setTime++;
} else {
setTime--;
}
setTime = constrain(setTime, 0, 300);
tone(BUZZER_PIN, 2500, 100); // Beep sound when changing set time
} else if (menuPage == 1 && (millis() - lastEncoderToggleTime) > 500) { // Debounce time for sound toggle
soundOn = !soundOn;
lastEncoderToggleTime = millis();
tone(BUZZER_PIN, 1000, 100); // Beep sound when toggling sound
}
lastInteractionTime = interruptTime;
}
lastInterruptTime = interruptTime;
}
}
void startTimer() {
currentTime = setTime;
timerRunning = true;
while (currentTime > 0) {
if (digitalRead(TRIGGER_PIN) == HIGH) { // Stop if trigger pin goes HIGH
break;
}
delay(1000);
currentTime--;
updateDisplay(LOW);
if (soundOn) {
tone(BUZZER_PIN, 2500, 500);
delay(100);
tone(BUZZER_PIN, 1500, 300);
delay(100);
noTone(BUZZER_PIN);
}
}
if (currentTime == 0) {
if (soundOn) {
tone(BUZZER_PIN, 2500, 500);
delay(100);
tone(BUZZER_PIN, 2300, 500);
delay(100);
tone(BUZZER_PIN, 2100, 500);
delay(100);
tone(BUZZER_PIN, 1900, 500);
delay(100);
tone(BUZZER_PIN, 1700, 500);
delay(100);
tone(BUZZER_PIN, 1500, 500);
delay(100);
tone(BUZZER_PIN, 1300, 500);
delay(100);
tone(BUZZER_PIN, 1100, 500);
delay(100);
// tone(BUZZER_PIN, 1000, 2000);
// delay(2000);
noTone(BUZZER_PIN);
}
digitalWrite(OUTPUT1, LOW);
digitalWrite(OUTPUT2, LOW);
delay(1000);
}
timerRunning = false;
}
void resetTimer() {
timerRunning = false;
currentTime = setTime;
noTone(BUZZER_PIN);
digitalWrite(OUTPUT1, LOW);
digitalWrite(OUTPUT2, LOW);
}
void enterMenu() {
u8g2.clearBuffer();
if (menuPage == 0) {
u8g2.setCursor(0, 10);
u8g2.print("Set Time: ");
u8g2.print(setTime);
u8g2.print(" s");
} else if (menuPage == 1) {
u8g2.setCursor(0, 10);
u8g2.print("Sound: ");
u8g2.print(soundOn ? "ON" : "OFF");
}
u8g2.sendBuffer();
}
void updateDisplay(bool triggerState) {
u8g2.clearBuffer();
u8g2.setCursor(0, 10);
u8g2.print("Cool Down : ");
u8g2.print(triggerState == HIGH ? setTime : currentTime);
u8g2.print(" s");
int barLength = map(triggerState == HIGH ? setTime : currentTime, 0, setTime, 0, 128);
u8g2.drawBox(0, 30, barLength, 30);
u8g2.sendBuffer();
}
void displaySplashScreen() {
u8g2.clearBuffer();
// Replace this with the actual drawing commands for your logo
// Example placeholder: draw a simple shape representing the logo
u8g2.drawStr(2, 32, "RE1M Development"); // Placeholder: Draw text
u8g2.sendBuffer();
}