#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include <Wire.h>
#include <ss_oled.h>
#include "Font7Seg.h"
#include <EEPROM.h>
// Display configuration
#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW
#define MAX_DEVICES 4 // Number of displays
#define CLK_PIN 13
#define DATA_PIN 11
#define CS_PIN 10
#define SPEED_TIME 75
#define PAUSE_TIME 0
#define MAX_MESG 20
#define btnultra 6
// DS1307 RTC configuration
#define DS1307_ADDRESS 0x68
// Global variables
uint8_t wday, mday, month, year;
uint8_t hours, minutes, hours1,minutes1, seconds;
uint8_t alarmHours = 16, alarmMinutes = 0; // Default alarm time
// Time format selection
bool timeFormat = true; // true = 24-hour, false = 12-hour
bool alarmCheckEnabled = true; // New variable for alarmCheck state
char szTime[9]; // Time format: hh:mm
char szMesg[MAX_MESG + 1] = "";
char szMesg2[MAX_MESG + 1] = "";
uint8_t clear = 0x00;
const int trigPin = 5;
const int echoPin = 18;
//define sound speed in cm/uS
#define SOUND_SPEED 0.034
#define CM_TO_INCH 0.393701
// int distanceInch;
// Hardware SPI connection
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Button and Potentiometer configuration
#define BTN_PIN 2
#define ppin A0
#define bpin 3 // Buzzer pin for alarm
uint8_t adjustState = 8; // 0 = TH, 1 = TM, 2 = AH, 3 = AM
uint16_t lastPotValue = 0;
uint8_t melodyIndex = 0; // Default melody index (0)
// Debounce variables
uint32_t lastDebounceTime = 0;
const uint32_t debounceDelay = 50; // 50 ms debounce time
bool lastButtonState = HIGH;
bool buttonState = HIGH;
bool minuteChecked = false;
// OLED Configuration
SSOLED oled;
static bool flasher = false;
// Alarm-related variables
bool alarmTriggered = false;
uint32_t alarmStartMillis = 0;
bool snoozed = false; // Snooze active status
uint32_t snoozeEndMillis = 0; // Milliseconds when snooze ends
uint8_t snoozeDuration = 1; // Default snooze duration in minutes
void beginDS1307();
uint8_t decToBcd(uint8_t value);
uint8_t bcdToDec(uint8_t value);
void getTime(char *psz, bool alarm = false);
void adjustTime();
void updateOLED();
void updateMatrix();
void setDS1307Time(uint8_t hr, uint8_t min, uint8_t sec);
// void setDS1307Time(uint8_t hr, uint8_t min, uint8_t sec) {
// Wire.beginTransmission(DS1307_ADDRESS);
// Wire.write(0x00); // Start at register 0x00
// Wire.write(decToBcd(sec)); // Seconds
// Wire.write(decToBcd(min)); // Minutes
// Wire.write(decToBcd(hr)); // Hours
// Wire.write(0x00); // Day (Not used in DS1307)
// Wire.write(0x01); // Date
// Wire.write(0x01); // Month
// Wire.write(0x20); // Year (20xx format)
// Wire.endTransmission();
// }
void beginDS1307()
{
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(clear);
Wire.endTransmission();
Wire.requestFrom(DS1307_ADDRESS, 0x07);
seconds = bcdToDec(Wire.read());
minutes = bcdToDec(Wire.read());
hours = bcdToDec(Wire.read() & 0xff);
wday = bcdToDec(Wire.read());
mday = bcdToDec(Wire.read());
month = bcdToDec(Wire.read());
year = bcdToDec(Wire.read());
// if (hours>=23){
// hours=0;
// hours=hours+4;
// }
// hours1=hours;
// minutes1=minutes;
}
void beginDS13072()
{
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(clear);
Wire.endTransmission();
Wire.requestFrom(DS1307_ADDRESS, 0x07);
seconds = bcdToDec(Wire.read());
minutes1 = bcdToDec(Wire.read());
hours1 = bcdToDec(Wire.read() & 0xff);
wday = bcdToDec(Wire.read());
mday = bcdToDec(Wire.read());
month = bcdToDec(Wire.read());
year = bcdToDec(Wire.read());
// if (hours1>=23){
// hours1=0;
// hours1=hours1+4;
// }
}
uint8_t decToBcd(uint8_t value)
{
return ((value / 10 * 16) + (value % 10));
}
uint8_t bcdToDec(uint8_t value)
{
return ((value / 16 * 10) + (value % 10));
}
void getTime(char *psz, bool alarm)
{
uint8_t displayHours = alarm ? alarmHours : hours;
if (!timeFormat) // 12-hour format
{
bool isPM = (displayHours >= 12);
displayHours = (displayHours % 12 == 0) ? 12 : displayHours % 12; // Convert 0 and 12 to 12
sprintf(psz, "%02d%c%02d%s", displayHours,flasher ? ':' : ' ', minutes, isPM ? "pm" : "am");
}
else
{
sprintf(psz, "%02d%c%02d", displayHours,flasher ? ':' : ' ', minutes); // 24-hour format
}
}
void saveToEEPROM()
{
// EEPROM.write(0, alarmHours);
// EEPROM.write(1, alarmMinutes);
EEPROM.write(0, hours);
EEPROM.write(1, minutes);
}
void loadFromEEPROM()
{
// alarmHours = EEPROM.read(0);
// alarmMinutes = EEPROM.read(1);
hours = EEPROM.read(0);
minutes = EEPROM.read(1);
}
void setup()
{
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
Wire.begin();
pinMode(btnultra, INPUT_PULLUP);
pinMode(BTN_PIN, INPUT_PULLUP); // Button with internal pull-up
pinMode(ppin, INPUT);
pinMode(bpin, OUTPUT); // Configure buzzer pin as output
P.begin(2);
P.setInvert(false);
P.setZone(0, MAX_DEVICES - 4, MAX_DEVICES - 1);
P.setCharSpacing(0);
P.displayZoneText(0, szMesg, PA_CENTER, SPEED_TIME, PAUSE_TIME, PA_PRINT, PA_NO_EFFECT);
// OLED Initialization
int rc = oledInit(&oled, OLED_128x64, 0x3C, 0, 0, 1, -1, -1, -1, 400000L);
if (rc != OLED_NOT_FOUND) {
oledFill(&oled, 0, 1); // Clear the OLED display
}
adjustTime();
loadFromEEPROM();
beginDS1307(); // Retrieve initial time from RTC
beginDS13072(); // Retrieve initial time from RTC
updateOLED();
updateMatrix();
}
void loop()
{
static uint32_t lastTime = 0;
static uint32_t minuteTimer = 0;
static uint8_t previousMinute = 99; // Invalid value to force first check
if(digitalRead(btnultra)==LOW){
ultrasonic();
}
// P.displayAnimate();
// adjustTime();
// Update time every minute
if ((millis() - minuteTimer) >= 60000) {
minuteTimer = millis();
minutes++;
if (minutes >= 60) {
minutes = 0;
hours++;
if (hours >= 24) {
hours = 0;
}
}
}
P.displayAnimate();
adjustTime(); // Handle adjustments for time and alarm
uint32_t currentMillis = millis();
// Check if the minute has changed
if (minutes != previousMinute) {
previousMinute = minutes; // Update the previous minute tracker
minuteChecked = false; // Allow rechecking in the new minute
}
// Call the decentralized alarm system only once per minute
if (alarmCheckEnabled && !minuteChecked) {
minuteChecked = true; // Mark this minute as checked
checkAlarm(); // Check if the alarm should trigger
}
// Stop the alarm after 10 seconds
if (alarmTriggered && (currentMillis - alarmStartMillis >= 10000)) {
alarmTriggered = false; // Deactivate the alarm
noTone(bpin); // Stop the buzzer
}
// Blink display every second
if ((millis() - lastTime) >= 1000) {
lastTime = millis();
updateMatrix();
flasher = !flasher;
beginDS13072();
}
//snooze
if (alarmTriggered && buttonState == LOW && lastButtonState == HIGH) {
snoozed = true; // Activate snooze
snoozeEndMillis = millis() + (snoozeDuration * 30000); // Set snooze end time
alarmTriggered = false; // Turn off the alarm
noTone(bpin); // Stop the buzzer
}
}
void ultrasonic(){
long duration;
int distanceCm;
// char buffer[10];
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Calculate the distance
distanceCm = duration * (int)SOUND_SPEED/2;
// sprintf(buffer, "%.2f", distanceCm);
// Convert to inches
// distanceInch = distanceCm * CM_TO_INCH;
// oledWriteString(&oled, 0, 50, 0, (char *)"hshs", FONT_NORMAL, 0, 1);
}
void checkAlarm() {
uint32_t currentMillis = millis();
// If snoozed and snooze time expires
if (snoozed && (currentMillis >= snoozeEndMillis)) {
snoozed = false; // End snooze
alarmTriggered = true; // Reactivate the alarm
alarmStartMillis = currentMillis; // Reset alarm start time
}
// Normal alarm triggering
if (!snoozed && (hours == alarmHours) && (minutes == alarmMinutes)) {
if (!alarmTriggered) {
alarmTriggered = true; // Trigger the alarm
alarmStartMillis = currentMillis; // Record when the alarm started
}
}
// Handle alarm sound and timing
if (alarmTriggered) {
// Play alarm sound
static uint32_t lastToneMillis = 0;
static uint8_t toneStep = 0;
if ((currentMillis - lastToneMillis) >= 500) { // Change tone every 500ms
lastToneMillis = currentMillis;
switch (melodyIndex) {
case 0:
tone(bpin, (toneStep % 2 == 0) ? 440 : 880);
break;
case 1:
tone(bpin, (toneStep % 3 == 0) ? 330 : (toneStep % 3 == 1 ? 392 : 494));
break;
case 2:
tone(bpin, (toneStep % 3 == 0) ? 523 : (toneStep % 3 == 1 ? 659 : 784));
break;
}
toneStep++;
}
// Stop the alarm after 10 seconds
if ((currentMillis - alarmStartMillis) >= 10000) {
alarmTriggered = false; // Deactivate alarm
noTone(bpin); // Stop the buzzer
}
}
}
void adjustTime()
{
bool currentButtonState = digitalRead(BTN_PIN);
// Debounce logic
if (currentButtonState != lastButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
if (currentButtonState == LOW && buttonState == HIGH) {
adjustState = (adjustState + 1) % 9; // Include the new state (-1 or 8)
updateOLED(); // Update OLED when the state changes
updateMatrix(); // Update the matrix display for AH/AM
}
buttonState = currentButtonState;
}
lastButtonState = currentButtonState;
// Read potentiometer value
uint16_t potValue = analogRead(ppin);
if (abs(potValue - lastPotValue) > 10) { // Adjust threshold to prevent jitter
lastPotValue = potValue;
saveToEEPROM();
switch (adjustState) {
case 0: // Time Hours (TH)
hours = map(potValue, 0, 1023, 0, 23);
// setDS1307Time(hours, minutes, seconds); // Update RTC
break;
case 1: // Time Minutes (TM)
minutes = map(potValue, 0, 1023, 0, 59);
// setDS1307Time(hours, minutes, seconds); // Update RTC
break;
case 2: // Alarm Hours (AH)
alarmHours = map(potValue, 0, 1023, 0, 23);
break;
case 3: // Alarm Minutes (AM)
alarmMinutes = map(potValue, 0, 1023, 0, 59);
break;
case 4: // Alarm Minutes (AM)
timeFormat = (potValue > 512);
updateOLED();
break;
case 5: // AlarmCheck Toggle
alarmCheckEnabled = (potValue > 512); // Toggle based on potentiometer
updateOLED();
break;
case 6: // Melody Selection
melodyIndex = map(potValue, 0, 1023, 0, 3); // Map to 3 melody types
updateOLED();
break;
case 7: // Snooze Duration
snoozeDuration = map(potValue, 0, 1023, 1, 15); // Map snooze duration (1 to 15 minutes)
updateOLED();
break;
case 8:
beginDS13072();
break;
}
updateMatrix(); // Update matrix with the adjusted value
}
}
void updateOLED()
{
oledFill(&oled, 0, 1); // Clear the OLED display
// Display concise parameter label based on adjustState
switch (adjustState) {
case 0:
oledWriteString(&oled, 0, 0, 0, (char *)"TH", FONT_NORMAL, 0, 1); // Time Hours
break;
case 1:
oledWriteString(&oled, 0, 0, 0, (char *)"TM", FONT_NORMAL, 0, 1); // Time Minutes
break;
case 2:
oledWriteString(&oled, 0, 0, 0, (char *)"AH", FONT_NORMAL, 0, 1); // Alarm Hours
break;
case 3:
oledWriteString(&oled, 0, 0, 0, (char *)"AM", FONT_NORMAL, 0, 1); // Alarm Minutes
break;
case 4:
oledWriteString(&oled, 0, 0, 0, (char *)(timeFormat ? "24HR" : "12HR"), FONT_NORMAL, 0, 1); // Time Format
break;
case 5:
oledWriteString(&oled, 0, 0, 0, (char *)(alarmCheckEnabled ? "AL ON" : "AL OFF"), FONT_NORMAL, 0, 1); // AlarmCheck status
break;
case 6:
// Display the melody index
if (melodyIndex == 0) {
oledWriteString(&oled, 0, 0, 0, (char *)"MEL 1", FONT_NORMAL, 0, 1);
} else if (melodyIndex == 1) {
oledWriteString(&oled, 0, 0, 0, (char *)"MEL 2", FONT_NORMAL, 0, 1);
} else if (melodyIndex == 2) {
oledWriteString(&oled, 0, 0, 0, (char *)"MEL 3", FONT_NORMAL, 0, 1);
}
break;
case 7:
char snoozeMsg[10];
sprintf(snoozeMsg, "SNOOZE %d", snoozeDuration);
oledWriteString(&oled, 0, 0, 0, snoozeMsg, FONT_NORMAL, 0, 1);
break;
case 8:
oledWriteString(&oled, 0, 0, 0, (char *)"TIME", FONT_NORMAL, 0, 1); // Simple time display mode
break;
// case 9:
// oledWriteString(&oled, 0, 50, 0, (char *)"Tim", FONT_NORMAL, 0, 1);
// break;
}
// char* as;
// oledWriteString(&oled, 0, 50 0, (char *)"TIME", FONT_NORMAL, 0, 1);
}
void updateMatrix()
{ if (adjustState == 8) { // Show regular time for "Time Only" state
sprintf(szMesg, "%02d%c%02d", hours1,flasher ? ':' : ' ', minutes1);
}else if (adjustState == 2 || adjustState == 3) { // For Alarm Hours or Minutes
// Show Alarm time
sprintf(szMesg, "%02d%c%02d", alarmHours,flasher ? ':' : ' ', alarmMinutes);
} else {
// Show regular time
getTime(szMesg, adjustState >= 2); // Show current time or alarm time
}
P.displayText(szMesg, PA_CENTER, SPEED_TIME, PAUSE_TIME, PA_PRINT, PA_NO_EFFECT);
P.displayReset(0);
}