4 channels timer with individual alarm

Hello! I can't make the alarm to trigger at the alarm times that are stored in the eeprom.
This is the code

#include <LiquidCrystal.h>
#include <EEPROM.h>

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

// Timer variables
int hours[4] = {0, 0, 0, 0};
int minutes[4] = {0, 0, 0, 0};
int seconds[4] = {0, 0, 0, 0};
unsigned long startTime[4] = {0, 0, 0, 0};
const unsigned long updateInterval = 1000;

// Button pins
const int buttonPins[5] = {6, 7, 8, 9, 10};
int buttonStates[5] = {HIGH, HIGH, HIGH, HIGH, HIGH};

// Alarm variables
int alarmHours[4] = {0, 0, 0, 0};
int alarmMinutes[4] = {0, 0, 0, 0};
bool alarmEnabled[4] = {false, false, false, false};

// Setting mode
int settingChannel = -1;

// Buzzer pin
const int buzzerPin = 13;

unsigned long buttonPressTime[4] = {0, 0, 0, 0};
unsigned long alarmStartTime[4] = {0, 0, 0, 0};

// Global variable declaration
bool setButtonPressed = false;
bool alarmSettingMode = false;
bool displayNeedsUpdate = true;

// Function declarations
void readAlarmsFromEEPROM();
void writeAlarmsToEEPROM();
void checkAlarm(int channel);
void resetTimer(int channel);
void stopAlarm(int channel);
void displayTimers();
void updateTimer(int channel);
void printTime(int h, int m);
void readButtons();
void handleButtons();
void displayAllAlarms();
void displayAlarmSettings(int channel);

void setup() {
  lcd.begin(16, 2);
  Serial.begin(9600); // Initialize Serial communication
  for (int i = 0; i < 4; i++) {
    startTime[i] = millis();
  }
  for (int i = 0; i < 5; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }
  pinMode(buzzerPin, OUTPUT);
  readAlarmsFromEEPROM();
  displayTimers();
}

void loop() {
  unsigned long currentTime = millis();
  bool anyTimerUpdated = false;

  for (int i = 0; i < 4; i++) {
    if (currentTime - startTime[i] >= updateInterval) {
      startTime[i] += updateInterval;
      seconds[i]++;
      if (seconds[i] >= 60) {
        seconds[i] = 0;
        minutes[i]++;
        if (minutes[i] >= 60) {
          minutes[i] = 0;
          hours[i]++;
          if (hours[i] >= 100) {
            hours[i] = 0;
          }
        }
      }
      checkAlarm(i);
      startTime[i] = currentTime;
      if (!alarmSettingMode) {
        updateTimer(i);
        anyTimerUpdated = true;
      }
    }
  }

  readButtons();
  handleButtons();

  if (displayNeedsUpdate || anyTimerUpdated) {
    if (alarmSettingMode) {
      displayAllAlarms();
    } else {
      displayTimers();
    }
    displayNeedsUpdate = false;
  }
}

void displayTimers() {
  static int previousHours[4] = { -1, -1, -1, -1 };
  static int previousMinutes[4] = { -1, -1, -1, -1 };
  static int previousSeconds[4] = { -1, -1, -1, -1 };

  for (int i = 0; i < 4; i++) {
    if (hours[i] != previousHours[i] ||
        minutes[i] != previousMinutes[i] ||
        seconds[i] != previousSeconds[i]) {
      lcd.setCursor((i % 2) * 8, i / 2);
      lcd.print(i + 1);
      lcd.print("-");
      if (hours[i] > 0) {
        printTime(hours[i], minutes[i]);
      } else {
        printTime(minutes[i], seconds[i]);
      }
      lcd.print(" ");
      previousHours[i] = hours[i];
      previousMinutes[i] = minutes[i];
      previousSeconds[i] = seconds[i];
    }
  }
}

void updateTimer(int channel) {
  static int previousHours[4] = { -1, -1, -1, -1 };
  static int previousMinutes[4] = { -1, -1, -1, -1 };
  static int previousSeconds[4] = { -1, -1, -1, -1 };

  if (hours[channel] != previousHours[channel] ||
      minutes[channel] != previousMinutes[channel] ||
      seconds[channel] != previousSeconds[channel]) {
    int cursorPosition = (channel < 2) ? (channel * 8 + 2) : ((channel - 2) * 8 + 2);
    int row = (channel < 2) ? 0 : 1;
    lcd.setCursor(cursorPosition, row);
    if (hours[channel] > 0) {
      printTime(hours[channel], minutes[channel]);
    } else {
      printTime(minutes[channel], seconds[channel]);
    }
    previousHours[channel] = hours[channel];
    previousMinutes[channel] = minutes[channel];
    previousSeconds[channel] = seconds[channel];
  }
}

void printTime(int h, int m) {
  if (h < 10) lcd.print("0");
  lcd.print(h);
  lcd.print(":");
  if (m < 10) lcd.print("0");
  lcd.print(m);
}

void readButtons() {
  for (int i = 0; i < 5; i++) {
    buttonStates[i] = digitalRead(buttonPins[i]);
  }
}

void handleButtons() {
  unsigned long currentTime = millis();
  static unsigned long lastSetButtonReleaseTime = 0;

  if (buttonStates[4] == LOW) {
    if (!setButtonPressed) {
      alarmSettingMode = true;
      setButtonPressed = true;
      displayNeedsUpdate = true;
    }
    bool alarmUpdated = false;
    for (int i = 0; i < 4; i++) {
      if (buttonStates[i] == LOW) {
        alarmMinutes[i]++;
        if (alarmMinutes[i] >= 60) {
          alarmMinutes[i] = 0;
          alarmHours[i]++;
          if (alarmHours[i] >= 100) {
            alarmHours[i] = 0;
          }
        }
        alarmUpdated = true;
        delay(150);
      }
    }
    if (alarmUpdated) {
      displayNeedsUpdate = true;
    }
  } else {
    lastSetButtonReleaseTime = currentTime;
    if (alarmSettingMode) {
      writeAlarmsToEEPROM();
      for (int i = 0; i < 4; i++) {
        if (alarmHours[i] != 0 || alarmMinutes[i] != 0) {
          alarmEnabled[i] = true;
        }
      }
    }
    alarmSettingMode = false;
    setButtonPressed = false;
  }

  if (!alarmSettingMode) {
    for (int i = 0; i < 4; i++) {
      if (buttonStates[i] == LOW) {
        if (buttonPressTime[i] == 0) {
          buttonPressTime[i] = currentTime;
        }
        if (currentTime - buttonPressTime[i] > 500) {
          resetTimer(i);
          displayNeedsUpdate = true;
          buttonPressTime[i] = currentTime;
        }
      } else {
        if (buttonPressTime[i] != 0 && currentTime - buttonPressTime[i] <= 500) {
          stopAlarm(i);
          displayNeedsUpdate = true
        ;}
        buttonPressTime[i] = 0;
      }
    }
  }
}

void displayAllAlarms() {
  lcd.clear();
  for (int i = 0; i < 4; i++) {
    lcd.setCursor((i % 2) * 8, i / 2);
    lcd.print(i + 1);
    lcd.print("-");
    printTime(alarmHours[i], alarmMinutes[i]);
  }
}

void displayAlarmSettings(int channel) {
  lcd.clear();
  lcd.print("Set alarm ");
  lcd.print(channel + 1);
  lcd.setCursor(0, 1);
  lcd.print(alarmHours[channel]);
  lcd.print(":");
  lcd.print(alarmMinutes[channel]);
}

void checkAlarm(int channel) {
  static bool blinkState[4] = {false, false, false, false};
  static unsigned long previousMillis[4] = {0, 0, 0, 0};
  const int blinkInterval = 250;

  Serial.print("Channel: ");
  Serial.print(channel);
  Serial.print(", Enabled: ");
  Serial.print(alarmEnabled[channel]);
  Serial.print(", Alarm Time: ");
  Serial.print(alarmHours[channel]);
  Serial.print(":");
  Serial.print(alarmMinutes[channel]);

  if (alarmEnabled[channel] && (alarmHours[channel] != 0 && alarmMinutes[channel] != 0)) {
    unsigned long currentMillis = millis();

    unsigned long elapsedTime = hours[channel] * 60 + minutes[channel];
    unsigned long alarmTime = alarmHours[channel] * 60 + alarmMinutes[channel];

    Serial.print(", Elapsed Time: ");
    Serial.print(elapsedTime);
    Serial.print(", Alarm Time (min): ");
    Serial.println(alarmTime);

    if (elapsedTime >= alarmTime) {
      Serial.println("Alarm Triggered!"); // Debugging message

      tone(buzzerPin, 1000);

      if (alarmStartTime[channel] == 0) {
        alarmStartTime[channel] = millis();
      }

      if (millis() - alarmStartTime[channel] >= 2000) {
        noTone(buzzerPin);
        alarmStartTime[channel] = 0;
      }

      if (currentMillis - previousMillis[channel] >= blinkInterval) {
        previousMillis[channel] = currentMillis;
        blinkState[channel] = !blinkState[channel];

        lcd.setCursor((channel % 2) * 8, channel / 2);
        if (blinkState[channel]) {
          lcd.print(channel + 1);
          lcd.print("-");
          if (hours[channel] > 0) {
            printTime(hours[channel], minutes[channel]);
          } else {
            printTime(minutes[channel], seconds[channel]);
          }
          lcd.print(" ");
        } else {
          lcd.print("        ");
        }
      }
    } else {
      alarmStartTime[channel] = 0;
      noTone(buzzerPin);

      lcd.setCursor((channel % 2) * 8, channel / 2);
      lcd.print(channel + 1);
      lcd.print("-");
      if (hours[channel] > 0) {
        printTime(hours[channel], minutes[channel]);
      } else {
        printTime(minutes[channel], seconds[channel]);
      }
      lcd.print(" ");
    }
  } else {
    Serial.println(); // Just a newline for clarity
  }
}

void resetTimer(int channel) {
  hours[channel] = 0;
  minutes[channel] = 0;
  seconds[channel] = 0;
  updateTimer(channel);
}

void stopAlarm(int channel) {
  alarmEnabled[channel] = false;
  noTone(buzzerPin);
  displayTimers();
}

void readAlarmsFromEEPROM() {
  for (int i = 0; i < 4; i++) {
    int hour = EEPROM.read(i * 2);
    int minute = EEPROM.read(i * 2 + 1);

    if (hour >= 0 && hour < 100 && minute >= 0 && minute < 60) {
      alarmHours[i] = hour;
      alarmMinutes[i] = minute;
    } else {
      alarmHours[i] = 0;
      alarmMinutes[i] = 0;
    }
  }
}

void writeAlarmsToEEPROM() {
  for (int i = 0; i < 4; i++) {
    EEPROM.write(i * 2, alarmHours[i]);
    EEPROM.write(i * 2 + 1, alarmMinutes[i]);
  }
}

And this is the hardware:

{
  "version": 1,
  "editor": "wokwi",
  "parts": [
    { "type": "wokwi-arduino-nano", "id": "arduino", "top": 100, "left": 100, "attrs": {} },
    {
      "type": "wokwi-lcd1602",
      "id": "lcd",
      "top": -217.37,
      "left": 121.6,
      "attrs": { "contrast": "0.7" }
    },
    {
      "type": "wokwi-pushbutton",
      "id": "button1",
      "top": 270,
      "left": 50,
      "attrs": { "color": "red" }
    },
    {
      "type": "wokwi-pushbutton",
      "id": "button2",
      "top": 270,
      "left": 110,
      "attrs": { "color": "green" }
    },
    {
      "type": "wokwi-pushbutton",
      "id": "button3",
      "top": 270,
      "left": 170,
      "attrs": { "color": "blue" }
    },
    {
      "type": "wokwi-pushbutton",
      "id": "button4",
      "top": 270,
      "left": 230,
      "attrs": { "color": "yellow" }
    },
    {
      "type": "wokwi-pushbutton",
      "id": "setbutton",
      "top": 275,
      "left": 307.2,
      "attrs": { "color": "black" }
    },
    { "type": "wokwi-buzzer", "id": "buzzer", "top": 12, "left": 337.8, "attrs": {} }
  ],
  "connections": [
    [ "lcd:RS", "arduino:12", "green", [ "v0" ] ],
    [ "lcd:EN", "arduino:11", "green", [ "v0" ] ],
    [ "lcd:D4", "arduino:5", "green", [ "v0" ] ],
    [ "lcd:D5", "arduino:4", "green", [ "v0" ] ],
    [ "lcd:D6", "arduino:3", "green", [ "v0" ] ],
    [ "lcd:D7", "arduino:2", "green", [ "v0" ] ],
    [ "lcd:VCC", "arduino:5V", "green", [ "v0" ] ],
    [ "lcd:GND", "arduino:GND.1", "green", [ "v0" ] ],
    [ "lcd:LED+", "arduino:5V", "green", [ "v0" ] ],
    [ "lcd:LED-", "arduino:GND.1", "green", [ "v0" ] ],
    [ "lcd:VO", "arduino:GND.1", "green", [ "v0" ] ],
    [ "lcd:VSS", "arduino:GND.1", "green", [ "v0" ] ],
    [ "lcd:VDD", "arduino:5V", "green", [ "v0" ] ],
    [ "lcd:E", "arduino:11", "green", [ "v0" ] ],
    [ "button1:1", "arduino:6", "green", [ "v0" ] ],
    [ "button1:2", "arduino:GND.2", "green", [ "v0" ] ],
    [ "button2:1", "arduino:7", "green", [ "v0" ] ],
    [ "button2:2", "arduino:GND.2", "green", [ "v0" ] ],
    [ "button3:1", "arduino:8", "green", [ "v0" ] ],
    [ "button3:2", "arduino:GND.2", "green", [ "v0" ] ],
    [ "button4:1", "arduino:9", "green", [ "v0" ] ],
    [ "button4:2", "arduino:GND.2", "green", [ "v0" ] ],
    [ "setbutton:1", "arduino:10", "green", [ "v0" ] ],
    [ "setbutton:2", "arduino:GND.2", "green", [ "v0" ] ],
    [ "buzzer:1", "arduino:13", "green", [ "v0" ] ],
    [ "buzzer:2", "arduino:GND.3", "green", [ "v0" ] ]
  ],
  "dependencies": {}
}

Link to the project:

Just to specify that I have a minimum amount of programming capabilities, I made all this with chat gpt assisted by gemini ai😀. I'm struggling to get this working since 1 week now, if someone can help me will be very good for my mental sanity that is already falling apart!

Ask the robot again to find the malfunction.

I'm doing that over and over😁


There is a problem in alarm time calculation

And anyway, thanks for the helpful input. It never crossed my mind to do that😀

I added a serial output to the see the Time left to alarm but it's not working. The alarms are enabling for each channel and showing the corresponding alarm time, but they are not triggering anything.

#include <LiquidCrystal.h>
#include <EEPROM.h>

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

// Timer variables
int hours[4] = {0, 0, 0, 0};
int minutes[4] = {0, 0, 0, 0};
int seconds[4] = {0, 0, 0, 0};
unsigned long startTime[4] = {0, 0, 0, 0};
const unsigned long updateInterval = 1000;

// Button pins
const int buttonPins[5] = {6, 7, 8, 9, 10};
int buttonStates[5] = {HIGH, HIGH, HIGH, HIGH, HIGH};

// Alarm variables
int alarmHours[4] = {0, 0, 0, 0};
int alarmMinutes[4] = {0, 0, 0, 0};
bool alarmEnabled[4] = {false, false, false, false};

// Setting mode
int settingChannel = -1;

// Buzzer pin
const int buzzerPin = 13;

unsigned long buttonPressTime[4] = {0, 0, 0, 0};
unsigned long alarmStartTime[4] = {0, 0, 0, 0};

// Global variable declaration
bool setButtonPressed = false;
bool alarmSettingMode = false;
bool displayNeedsUpdate = true;

// Function declarations
void readAlarmsFromEEPROM();
void writeAlarmsToEEPROM();
void checkAlarm(int channel);
void resetTimer(int channel);
void stopAlarm(int channel);
void displayTimers();
void updateTimer(int channel);
void printTime(int h, int m);
void readButtons();
void handleButtons();
void displayAllAlarms();
void displayAlarmSettings(int channel);

void setup() {
  lcd.begin(16, 2);
  Serial.begin(9600); // Initialize Serial communication
  for (int i = 0; i < 4; i++) {
    startTime[i] = millis();
  }
  for (int i = 0; i < 5; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }
  pinMode(buzzerPin, OUTPUT);
  readAlarmsFromEEPROM();
  displayTimers();
}

void loop() {
  unsigned long currentTime = millis();
  bool anyTimerUpdated = false;

  for (int i = 0; i < 4; i++) {
    if (currentTime - startTime[i] >= updateInterval) {
      startTime[i] += updateInterval;
      seconds[i]++;
      if (seconds[i] >= 60) {
        seconds[i] = 0;
        minutes[i]++;
        if (minutes[i] >= 60) {
          minutes[i] = 0;
          hours[i]++;
          if (hours[i] >= 100) {
            hours[i] = 0;
          }
        }
      }
      checkAlarm(i);
      startTime[i] = currentTime;
      if (!alarmSettingMode) {
        updateTimer(i);
        anyTimerUpdated = true;
      }
    }
  }

  readButtons();
  handleButtons();

  if (displayNeedsUpdate || anyTimerUpdated) {
    if (alarmSettingMode) {
      displayAllAlarms();
    } else {
      displayTimers();
    }
    displayNeedsUpdate = false;
  }
}

void displayTimers() {
  static int previousHours[4] = { -1, -1, -1, -1 };
  static int previousMinutes[4] = { -1, -1, -1, -1 };
  static int previousSeconds[4] = { -1, -1, -1, -1 };

  for (int i = 0; i < 4; i++) {
    if (hours[i] != previousHours[i] ||
        minutes[i] != previousMinutes[i] ||
        seconds[i] != previousSeconds[i]) {
      lcd.setCursor((i % 2) * 8, i / 2);
      lcd.print(i + 1);
      lcd.print("-");
      if (hours[i] > 0) {
        printTime(hours[i], minutes[i]);
      } else {
        printTime(minutes[i], seconds[i]);
      }
      lcd.print(" ");
      previousHours[i] = hours[i];
      previousMinutes[i] = minutes[i];
      previousSeconds[i] = seconds[i];
    }
  }
}

void updateTimer(int channel) {
  static int previousHours[4] = { -1, -1, -1, -1 };
  static int previousMinutes[4] = { -1, -1, -1, -1 };
  static int previousSeconds[4] = { -1, -1, -1, -1 };

  if (hours[channel] != previousHours[channel] ||
      minutes[channel] != previousMinutes[channel] ||
      seconds[channel] != previousSeconds[channel]) {
    int cursorPosition = (channel < 2) ? (channel * 8 + 2) : ((channel - 2) * 8 + 2);
    int row = (channel < 2) ? 0 : 1;
    lcd.setCursor(cursorPosition, row);
    if (hours[channel] > 0) {
      printTime(hours[channel], minutes[channel]);
    } else {
      printTime(minutes[channel], seconds[channel]);
    }
    previousHours[channel] = hours[channel];
    previousMinutes[channel] = minutes[channel];
    previousSeconds[channel] = seconds[channel];
  }
}

void printTime(int h, int m) {
  if (h < 10) lcd.print("0");
  lcd.print(h);
  lcd.print(":");
  if (m < 10) lcd.print("0");
  lcd.print(m);
}

void readButtons() {
  for (int i = 0; i < 5; i++) {
    buttonStates[i] = digitalRead(buttonPins[i]);
  }
}

void handleButtons() {
  unsigned long currentTime = millis();
  static unsigned long lastSetButtonReleaseTime = 0;

  if (buttonStates[4] == LOW) {
    if (!setButtonPressed) {
      alarmSettingMode = true;
      setButtonPressed = true;
      displayNeedsUpdate = true;
    }
    bool alarmUpdated = false;
    for (int i = 0; i < 4; i++) {
      if (buttonStates[i] == LOW) {
        alarmMinutes[i]++;
        if (alarmMinutes[i] >= 60) {
          alarmMinutes[i] = 0;
          alarmHours[i]++;
          if (alarmHours[i] >= 100) {
            alarmHours[i] = 0;
          }
        }
        alarmUpdated = true;
        delay(150);
      }
    }
    if (alarmUpdated) {
      displayNeedsUpdate = true;
    }
  } else {
    lastSetButtonReleaseTime = currentTime;
    if (alarmSettingMode) {
      writeAlarmsToEEPROM();
      for (int i = 0; i < 4; i++) {
        if (alarmHours[i] != 0 || alarmMinutes[i] != 0) {
          alarmEnabled[i] = true;
        }
      }
    }
    alarmSettingMode = false;
    setButtonPressed = false;
  }

  if (!alarmSettingMode) {
    for (int i = 0; i < 4; i++) {
      if (buttonStates[i] == LOW) {
        if (buttonPressTime[i] == 0) {
          buttonPressTime[i] = currentTime;
        }
        if (currentTime - buttonPressTime[i] > 500) {
          resetTimer(i);
          displayNeedsUpdate = true;
          buttonPressTime[i] = currentTime;
        }
      } else {
        if (buttonPressTime[i] != 0 && currentTime - buttonPressTime[i] <= 500) {
          stopAlarm(i);
          displayNeedsUpdate = true
        ;
        }
        buttonPressTime[i] = 0;
      }
    }
  }
}

void displayAllAlarms() {
  lcd.clear();
  for (int i = 0; i < 4; i++) {
    lcd.setCursor((i % 2) * 8, i / 2);
    lcd.print(i + 1);
    lcd.print("-");
    printTime(alarmHours[i], alarmMinutes[i]);
  }
}

void displayAlarmSettings(int channel) {
  lcd.clear();
  lcd.print("Set alarm ");
  lcd.print(channel + 1);
  lcd.setCursor(0, 1);
  lcd.print(alarmHours[channel]);
  lcd.print(":");
  lcd.print(alarmMinutes[channel]);
}

void checkAlarm(int channel) {
  static bool blinkState[4] = {false, false, false, false};
  static unsigned long previousMillis[4] = {0, 0, 0, 0};
  const int blinkInterval = 250;

  Serial.print("Channel: ");
  Serial.print(channel);
  Serial.print(", Enabled: ");
  Serial.print(alarmEnabled[channel]);
  Serial.print(", Alarm Time: ");
  Serial.print(alarmHours[channel]);
  Serial.print(":");
  if (alarmMinutes[channel] < 10) {
    Serial.print("0");
  }
  Serial.print(alarmMinutes[channel]);

  if (alarmEnabled[channel] && (alarmHours[channel] != 0 && alarmMinutes[channel] != 0)) {
    unsigned long currentMillis = millis();

    // Calculate elapsed time in minutes
    unsigned long elapsedTime = hours[channel] * 60 + minutes[channel];

    // Calculate alarm time in minutes
    unsigned long alarmTime = alarmHours[channel] * 60 + alarmMinutes[channel];

    // Calculate time left in minutes
    long timeLeft = alarmTime - elapsedTime;

    // Print values
    Serial.print(", Elapsed Time: ");
    Serial.print(elapsedTime);
    Serial.print(", Alarm Time (min): ");
    Serial.print(alarmTime);
    Serial.print(", Time Left (min): ");
    Serial.println(timeLeft);

    if (elapsedTime >= alarmTime) {
      Serial.println("Alarm Triggered!");

      tone(buzzerPin, 1000);

      if (alarmStartTime[channel] == 0) {
        alarmStartTime[channel] = millis();
      }

      if (millis() - alarmStartTime[channel] >= 2000) {
        noTone(buzzerPin);
        alarmStartTime[channel] = 0;
      }

      if (currentMillis - previousMillis[channel] >= blinkInterval) {
        previousMillis[channel] = currentMillis;
        blinkState[channel] = !blinkState[channel];

        lcd.setCursor((channel % 2) * 8, channel / 2);
        if (blinkState[channel]) {
          lcd.print(channel + 1);
          lcd.print("-");
          if (hours[channel] > 0) {
            printTime(hours[channel], minutes[channel]);
          } else {
            printTime(minutes[channel], seconds[channel]);
          }
          lcd.print(" ");
        } else {
          lcd.print("        ");
        }
      }
    } else {
      alarmStartTime[channel] = 0;
      noTone(buzzerPin);

      lcd.setCursor((channel % 2) * 8, channel / 2);
      lcd.print(channel + 1);
      lcd.print("-");
      if (hours[channel] > 0) {
        printTime(hours[channel], minutes[channel]);
      } else {
        printTime(minutes[channel], seconds[channel]);
      }
      lcd.print(" ");
    }
  } else {
    Serial.println();
  }
}

void resetTimer(int channel) {
  hours[channel] = 0;
  minutes[channel] = 0;
  seconds[channel] = 0;
  updateTimer(channel);
}

void stopAlarm(int channel) {
  alarmEnabled[channel] = false;
  noTone(buzzerPin);
  displayTimers();
}

void readAlarmsFromEEPROM() {
  for (int i = 0; i < 4; i++) {
    int hour = EEPROM.read(i * 2);
    int minute = EEPROM.read(i * 2 + 1);

    if (hour >= 0 && hour < 100 && minute >= 0 && minute < 60) {
      alarmHours[i] = hour;
      alarmMinutes[i] = minute;
    } else {
      alarmHours[i] = 0;
      alarmMinutes[i] = 0;
    }
  }
}

void writeAlarmsToEEPROM() {
  for (int i = 0; i < 4; i++) {
    EEPROM.write(i * 2, alarmHours[i]);
    EEPROM.write(i * 2 + 1, alarmMinutes[i]);
  }
}

Thanks for using wokwi and sharing a link to your project.

What is it supposed to do? The buttons don't seem to be wired to anything.

a7

EEPROM.write() writes a single byte; an int is 2 bytes on 8-bit processors and 4 bytes on 32-bit processors.
EEPROM.read() reads a single byte.

As your variables are ints I suggest to use EEPROM.put() and EEPROM.get().

Further your code will benefit from the use of structs where you can combine hours, minutes and seconds. It would look something like

struct TIME
{
  int hour;
  int minute;
  int second;
};

TIME times[] = {
  {10, 0, 0},
  {13, 55, 0},
  {22, 00, 00},
  {23, 00, 00},
};

Nor hours nor minutes nor seconds can exceed 255 and they can also not be negative so they can also be stored in an uint8_t (aka byte).

You can use EEPROM.put() to store the complete timing in EEPROM and EEPROM.get() to read it back in one go.

Do some research on structs or ask your AI to implement your code with structs.

The buttons are wired and functional but the wires are not visible, don't know why :grinning_face:

Thanks, I'll try that!

The robot came up with this:

#include <LiquidCrystal.h>
#include <EEPROM.h>

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

// Struct for time
struct TIME {
  uint8_t hour;
  uint8_t minute;
  uint8_t second;
};

// Timer and alarm variables
TIME timers[4];
TIME alarms[4];
bool alarmEnabled[4] = {false, false, false, false};

unsigned long startTime[4] = {0, 0, 0, 0};
const unsigned long updateInterval = 1000;

// Button pins
const int buttonPins[5] = {6, 7, 8, 9, 10};
int buttonStates[5] = {HIGH, HIGH, HIGH, HIGH, HIGH};

// Setting mode
int settingChannel = -1;

// Buzzer pin
const int buzzerPin = 13;

unsigned long buttonPressTime[4] = {0, 0, 0, 0};
unsigned long alarmStartTime[4] = {0, 0, 0, 0};

// Global variable declaration
bool setButtonPressed = false;
bool alarmSettingMode = false;
bool displayNeedsUpdate = true;

// Function declarations
void readAlarmsFromEEPROM();
void writeAlarmsToEEPROM();
void checkAlarm(int channel);
void resetTimer(int channel);
void stopAlarm(int channel);
void displayTimers();
void updateTimer(int channel);
void printTime(uint8_t h, uint8_t m);
void readButtons();
void handleButtons();
void displayAllAlarms();
void displayAlarmSettings(int channel);

void setup() {
  lcd.begin(16, 2);
  Serial.begin(9600);
  for (int i = 0; i < 4; i++) {
    startTime[i] = millis();
  }
  for (int i = 0; i < 5; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }
  pinMode(buzzerPin, OUTPUT);
  readAlarmsFromEEPROM();
  displayTimers();
}

void loop() {
  unsigned long currentTime = millis();
  bool anyTimerUpdated = false;

  for (int i = 0; i < 4; i++) {
    if (currentTime - startTime[i] >= updateInterval) {
      startTime[i] += updateInterval;
      timers[i].second++;
      if (timers[i].second >= 60) {
        timers[i].second = 0;
        timers[i].minute++;
        if (timers[i].minute >= 60) {
          timers[i].minute = 0;
          timers[i].hour++;
          if (timers[i].hour >= 100) {
            timers[i].hour = 0;
          }
        }
      }
      checkAlarm(i);
      startTime[i] = currentTime;
      if (!alarmSettingMode) {
        updateTimer(i);
        anyTimerUpdated = true;
      }
    }
  }

  readButtons();
  handleButtons();

  if (displayNeedsUpdate || anyTimerUpdated) {
    if (alarmSettingMode) {
      displayAllAlarms();
    } else {
      displayTimers();
    }
    displayNeedsUpdate = false;
  }
}

void displayTimers() {
  static TIME previousTimers[4];
  for (int i = 0; i < 4; i++) {
    if (timers[i].hour != previousTimers[i].hour ||
        timers[i].minute != previousTimers[i].minute ||
        timers[i].second != previousTimers[i].second) {
      lcd.setCursor((i % 2) * 8, i / 2);
      lcd.print(i + 1);
      lcd.print("-");
      if (timers[i].hour > 0) {
        printTime(timers[i].hour, timers[i].minute);
      } else {
        printTime(timers[i].minute, timers[i].second);
      }
      lcd.print(" ");
      previousTimers[i] = timers[i];
    }
  }
}

void updateTimer(int channel) {
  static TIME previousTimers[4];
  if (timers[channel].hour != previousTimers[channel].hour ||
      timers[channel].minute != previousTimers[channel].minute ||
      timers[channel].second != previousTimers[channel].second) {
    int cursorPosition = (channel < 2) ? (channel * 8 + 2) : ((channel - 2) * 8 + 2);
    int row = (channel < 2) ? 0 : 1;
    lcd.setCursor(cursorPosition, row);
    if (timers[channel].hour > 0) {
      printTime(timers[channel].hour, timers[channel].minute);
    } else {
      printTime(timers[channel].minute, timers[channel].second);
    }
    previousTimers[channel] = timers[channel];
  }
}

void printTime(uint8_t h, uint8_t m) {
  if (h < 10) lcd.print("0");
  lcd.print(h);
  lcd.print(":");
  if (m < 10) lcd.print("0");
  lcd.print(m);
}

void readButtons() {
  for (int i = 0; i < 5; i++) {
    buttonStates[i] = digitalRead(buttonPins[i]);
  }
}

void handleButtons() {
  unsigned long currentTime = millis();
  static unsigned long lastSetButtonReleaseTime = 0;

  if (buttonStates[4] == LOW) {
    if (!setButtonPressed) {
      alarmSettingMode = true;
      setButtonPressed = true;
      displayNeedsUpdate = true;
    }
    bool alarmUpdated = false;
    for (int i = 0; i < 4; i++) {
      if (buttonStates[i] == LOW) {
        alarms[i].minute++;
        if (alarms[i].minute >= 60) {
          alarms[i].minute = 0;
          alarms[i].hour++;
          if (alarms[i].hour >= 100) {
            alarms[i].hour = 0;
          }
        }
        alarmUpdated = true;
        delay(150);
      }
    }
    if (alarmUpdated) {
      displayNeedsUpdate = true;
    }
  } else {
    lastSetButtonReleaseTime = currentTime;
    if (alarmSettingMode) {
      writeAlarmsToEEPROM();
      for (int i = 0; i < 4; i++) {
        if (alarms[i].hour != 0 || alarms[i].minute != 0) {
          alarmEnabled[i] = true;
        } else {
          alarmEnabled[i] = false;
        }
      }
    }
    alarmSettingMode = false;
    setButtonPressed = false;
  }

  if (!alarmSettingMode) {
    for (int i = 0; i < 4; i++) {
      if (buttonStates[i] == LOW) {
        if (buttonPressTime[i] == 0) {
          buttonPressTime[i] = currentTime;
        }
        if (currentTime - buttonPressTime[i] > 500) {
          resetTimer(i);
          displayNeedsUpdate = true;
          buttonPressTime[i] = currentTime;
        }
      } else {
        if (buttonPressTime[i] != 0 && currentTime - buttonPressTime[i] <= 500) {
          stopAlarm(i);
          displayNeedsUpdate = true;
        }
        buttonPressTime[i] = 0;
      }
    }
  }
}

void displayAllAlarms() {
  lcd.clear();
  for (int i = 0; i < 4; i++) {
    lcd.setCursor((i % 2) * 8, i / 2);
    lcd.print(i + 1);
    lcd.print("-");
    printTime(alarms[i].hour, alarms[i].minute);
  }
}

void displayAlarmSettings(int channel) {
  lcd;
  lcd.clear();
  lcd.print("Set alarm ");
  lcd.print(channel + 1);
  lcd.setCursor(0, 1);
  lcd.print(alarms[channel].hour);
  lcd.print(":");
  lcd.print(alarms[channel].minute);
}

void checkAlarm(int channel) {
  static bool blinkState[4] = {false, false, false, false};
  static unsigned long previousMillis[4] = {0, 0, 0, 0};
  const int blinkInterval = 250;

  Serial.print("Channel: ");
  Serial.print(channel);
  Serial.print(", Enabled: ");
  Serial.print(alarmEnabled[channel]);
  Serial.print(", Alarm Time: ");
  Serial.print(alarms[channel].hour);
  Serial.print(":");
  if (alarms[channel].minute < 10) {
    Serial.print("0");
  }
  Serial.print(alarms[channel].minute);

  if (alarmEnabled[channel] && (alarms[channel].hour != 0 || alarms[channel].minute != 0)) {
    unsigned long currentMillis = millis();

    // Calculate elapsed time in minutes
    unsigned long elapsedTime = timers[channel].hour * 60 + timers[channel].minute;

    // Calculate alarm time in minutes
    unsigned long alarmTime = alarms[channel].hour * 60 + alarms[channel].minute;

    // Calculate time left in minutes
    long timeLeft = alarmTime - elapsedTime;

    // Print values
    Serial.print(", Elapsed Time: ");
    Serial.print(elapsedTime);
    Serial.print(", Alarm Time (min): ");
    Serial.print(alarmTime);
    Serial.print(", Time Left (min): ");
    Serial.println(timeLeft);

    if (elapsedTime >= alarmTime) {
      Serial.println("Alarm Triggered!");

      tone(buzzerPin, 1000);

      if (alarmStartTime[channel] == 0) {
        alarmStartTime[channel] = millis();
      }

      if (millis() - alarmStartTime[channel] >= 2000) {
        noTone(buzzerPin);
        alarmStartTime[channel] = 0;
      }

      if (currentMillis - previousMillis[channel] >= blinkInterval) {
        previousMillis[channel] = currentMillis;
        blinkState[channel] = !blinkState[channel];

        lcd.setCursor((channel % 2) * 8, channel / 2);
        if (blinkState[channel]) {
          lcd.print(channel + 1);
          lcd.print("-");
          printTime(timers[channel].hour, timers[channel].minute);
          lcd.print(" ");
        } else {
          lcd.print("        ");
        }
      }
    } else {
      alarmStartTime[channel] = 0;
      noTone(buzzerPin);

      lcd.setCursor((channel % 2) * 8, channel / 2);
      lcd.print(channel + 1);
      lcd.print("-");
      printTime(timers[channel].hour, timers[channel].minute);
      lcd.print(" ");
    }
  } else {
    Serial.println();
  }
}

void resetTimer(int channel) {
  timers[channel].hour = 0;
  timers[channel].minute = 0;
  timers[channel].second = 0;
  updateTimer(channel);
}

void stopAlarm(int channel) {
  alarmEnabled[channel] = false;
  noTone(buzzerPin);
  displayTimers();
}

void readAlarmsFromEEPROM() {
  for (int i = 0; i < 4; i++) {
    EEPROM.get(i * sizeof(TIME), alarms[i]);
  }
}

void writeAlarmsToEEPROM() {
  for (int i = 0; i < 4; i++) {
    EEPROM.put(i * sizeof(TIME), alarms[i]);
  }
}


Now the eeprom data readings are a mess.
Here is a link to the project. Wokwi - Online ESP32, STM32, Arduino Simulator

The buttons are working.
It's supposed to do this:
After power on he have for timers starting to count.
We have Timer mode display :
1-00:00 2-00:00
3-00:00 4-00:00
Time format is MM:SS, after 1 hour it changes to HH:MM
There are 4 buttons for each channel and the 5th for setup.

Now we have alarm mode display.
Holding the 5th button enters in alarm mode:
1-HH:MM 2-HH:MM
3-HH:MM 4-HH :MM
Pressing the corresponding button for each channel the alarm time is incrementing with 5 minutes only once, pressing again another 5 minutes and so on. Long pressing channel button resets the alarm time to zero ane you can start over.
While set button is pressed and no channel buttons activity for 10 seconds, all alarms resets to zero.
Releasing the 5th button, the alarm values are saved in eeprom and display returns im Timer mode.
Now we wait for alarm to trigger accordingly to the values stored in the eeprom for each channel. When alarm kicks in, a sound is made on buzzer pin13 and the corresponding channel blinks 3 times per second.
A short press of the corresponding channel button stops the sound, blinking continues, timer continues to count. Another short press, blinking stops, timer continues. A long button press resets the timer and cancel alarm or blinking if they still exists.

I was not able to find where you setup a non-zero alarm times in your code.
The only init of alarms are:

It's a bad idea to write a large project at once. Professionals don't do that.

Now you are trying to debug the the clock, the alarms, the EEPROM and the buttons at the same time. Considering that you have little experience in writing programs, you are unlikely to success with all the tasks at once.
I would suggest to put aside the EEPROM and the buttons, set alarms directly in the code and see if they work
When everything works out, try changing alarms using the buttons.
And it's still a long way to EEPROM

IIRC, EEPROM data is not stored - there is no actual EEPROM in the WOKWI simulator.

I think you'll have to simulate the EEPROM by making a small function, which runs in setup(), to preload the setpoints so later code can read them.

But, I could be wrong.

I think that it is, some kind of emulated eeprom since after the reset the values saved are there, it remembers them. You enter the setup and what you stored it's preserved

You are very right. I took it step by step, starting with 1 channel the expanding. But the problem with the robots is that they make something and they break something else. So you have to be very explicit with them and restrict theyr enthusiasm :grin: and impose to do only little steps, even ask to judge first and only after they show you what they think to tell them what to do strictlly

You put me on the right track, now i have the alarm triggering but some other issues with the display.

#include <LiquidCrystal.h>
#include <EEPROM.h>
#include <string.h> // Include string.h for memcmp()

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

struct TIME {
  uint8_t hour;
  uint8_t minute;
  uint8_t second;
};

TIME timers[4];
TIME alarms[4];
bool alarmEnabled[4] = {false, false, false, false};

unsigned long startTime[4] = {0, 0, 0, 0};
const unsigned long updateInterval = 1000;

const int buttonPins[5] = {6, 7, 8, 9, 10};
int buttonStates[5] = {HIGH, HIGH, HIGH, HIGH, HIGH};

int settingChannel = -1;

const int buzzerPin = 13;

unsigned long buttonPressTime[4] = {0, 0, 0, 0};
unsigned long alarmStartTime[4] = {0, 0, 0, 0};

bool setButtonPressed = false;
bool alarmSettingMode = false;
bool displayNeedsUpdate = true;

#define EEPROM_SIGNATURE 0xA5

void initializeEEPROM() {
  if (EEPROM.read(0) != EEPROM_SIGNATURE) {
    TIME defaultAlarm = {0, 0, 0};
    for (int i = 0; i < 4; i++) {
      EEPROM.put(i * sizeof(TIME) + 1, defaultAlarm);
    }
    EEPROM.write(0, EEPROM_SIGNATURE);
  }
}

void readAlarmsFromEEPROM() {
  for (int i = 0; i < 4; i++) {
    EEPROM.get(i * sizeof(TIME) + 1, alarms[i]);
  }
}

void writeAlarmsToEEPROM() {
  bool changed = false;
  for (int i = 0; i < 4; i++) {
    TIME storedAlarm;
    EEPROM.get(i * sizeof(TIME) + 1, storedAlarm);

    if (memcmp(&storedAlarm, &alarms[i], sizeof(TIME)) != 0) {
      EEPROM.put(i * sizeof(TIME) + 1, alarms[i]);
      changed = true;
    }
  }
  if (changed) Serial.println("EEPROM updated with new alarm values.");
}

void checkAlarm(int channel);
void resetTimer(int channel);
void stopAlarm(int channel);
void displayTimers();
void updateTimer(int channel);
void printTime(uint8_t h, uint8_t m);
void readButtons();
void handleButtons();
void displayAllAlarms();
void displayAlarmSettings(int channel);

void setup() {
  lcd.begin(16, 2);
  Serial.begin(9600);
  initializeEEPROM();
  for (int i = 0; i < 4; i++) {
    startTime[i] = millis();
  }
  for (int i = 0; i < 5; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }
  pinMode(buzzerPin, OUTPUT);
  readAlarmsFromEEPROM();
  displayTimers();
}

void loop() {
  unsigned long currentTime = millis();
  bool anyTimerUpdated = false;

  for (int i = 0; i < 4; i++) {
    if (currentTime - startTime[i] >= updateInterval) {
      startTime[i] += updateInterval;
      timers[i].second++;
      if (timers[i].second >= 60) {
        timers[i].second = 0;
        timers[i].minute++;
        if (timers[i].minute >= 60) {
          timers[i].minute = 0;
          timers[i].hour++;
          if (timers[i].hour >= 100) {
            timers[i].hour = 0;
          }
        }
      }
      checkAlarm(i);
      startTime[i] = currentTime;
      if (!alarmSettingMode) {
        updateTimer(i);
        anyTimerUpdated = true;
      }
    }
  }

  readButtons();
  handleButtons();

  if (displayNeedsUpdate || anyTimerUpdated) {
    if (alarmSettingMode) {
      displayAllAlarms();
    } else {
      displayTimers();
    }
    displayNeedsUpdate = false;
  }
}

void displayTimers() {
  static TIME previousTimers[4];
  for (int i = 0; i < 4; i++) {
    if (timers[i].hour != previousTimers[i].hour ||
        timers[i].minute != previousTimers[i].minute ||
        timers[i].second != previousTimers[i].second) {
      lcd.setCursor((i % 2) * 8, i / 2);
      lcd.print(i + 1);
      lcd.print("-");
      if (timers[i].hour > 0) {
        printTime(timers[i].hour, timers[i].minute);
      } else {
        printTime(timers[i].minute, timers[i].second);
      }
      lcd.print(" ");
      previousTimers[i] = timers[i];
    }
  }
}

void updateTimer(int channel) {
  static TIME previousTimers[4];
  if (timers[channel].hour != previousTimers[channel].hour ||
      timers[channel].minute != previousTimers[channel].minute ||
      timers[channel].second != previousTimers[channel].second) {
    int cursorPosition = (channel < 2) ? (channel * 8 + 2) : ((channel - 2) * 8 + 2);
    int row = (channel < 2) ? 0 : 1;
    lcd.setCursor(cursorPosition, row);
    if (timers[channel].hour > 0) {
      printTime(timers[channel].hour, timers[channel].minute);
    } else {
      printTime(timers[channel].minute, timers[channel].second);
    }
    previousTimers[channel] = timers[channel];
  }
}

void printTime(uint8_t h, uint8_t m) {
  if (h < 10) lcd.print("0");
  lcd.print(h);
  lcd.print(":");
  if (m < 10) lcd.print("0");
  lcd.print(m);
}

void readButtons() {
  for (int i = 0; i < 5; i++) {
    buttonStates[i] = digitalRead(buttonPins[i]);
  }
}

void handleButtons() {
  unsigned long currentTime = millis();
  static unsigned long lastSetButtonReleaseTime = 0;

  if (buttonStates[4] == LOW) {
    if (!setButtonPressed) {
      alarmSettingMode = true;
      setButtonPressed = true;
      displayNeedsUpdate = true;
    }
    bool alarmUpdated = false;
    for (int i = 0; i < 4; i++) {
      if (buttonStates[i] == LOW) {
        alarms[i].minute++;
        if (alarms[i].minute >= 60) {
          alarms[i].minute = 0;
          alarms[i].hour++;
          if (alarms[i].hour >= 100) {
            alarms[i].hour = 0;
          }
        }
        alarmUpdated = true;
        delay(150);
      }
    }
    if (alarmUpdated) {
      displayNeedsUpdate = true;
    }
  } else {
    lastSetButtonReleaseTime = currentTime;
    if (alarmSettingMode) {
      writeAlarmsToEEPROM();
      for (int i = 0; i < 4; i++) {
        if (alarms[i].hour != 0 || alarms[i].minute != 0) {
          alarmEnabled[i] = true;
        } else {
          alarmEnabled[i] = false;
        }
      }
    }
    alarmSettingMode = false;
    setButtonPressed = false;
  }

  if (!alarmSettingMode) {
    for (int i = 0; i < 4; i++) {
      if (buttonStates[i] == LOW) {
        if (buttonPressTime[i] == 0) {
          buttonPressTime[i] = currentTime;
        }
        if (currentTime - buttonPressTime[i] > 500) {
          resetTimer(i);
          displayNeedsUpdate = true;
          buttonPressTime[i] = currentTime;
        }
      } else {
        if (buttonPressTime[i] != 0 && currentTime - buttonPressTime[i] <= 500) {
          stopAlarm(i);
          displayNeedsUpdate = true;
        }
        buttonPressTime[i] = 0;
      }
    }
  }
}

void displayAllAlarms() {
  lcd.clear();
  for (int i = 0; i < 4; i++) {
    lcd.setCursor((i % 2) * 8, i / 2);
    lcd.print(i + 1);
    lcd.print("-");
    printTime(alarms[i].hour, alarms[i].minute);
  }
}

void displayAlarmSettings(int channel) {
  lcd.clear();
  lcd.print("Set alarm ");
  lcd.print(channel + 1);
  lcd.setCursor(0, 1);
  lcd.print(alarms[channel].hour);
  lcd.print(":");
  lcd.print(alarms[channel].minute);
}

void checkAlarm(int channel) {
  static bool blinkState[4] = {false, false, false, false};
  static unsigned long previousMillis[4] = {0, 0, 0, 0};
  const int blinkInterval = 250;

  Serial.print("Channel: ");
  Serial.print(channel);
  Serial.print(", Enabled: ");
  Serial.print(alarmEnabled[channel]);
  Serial.print(", Alarm Time: ");
  Serial.print(alarms[channel].hour);
  Serial.print(":");
  if (alarms[channel].minute < 10) {
    Serial.print("0");
  }
  Serial.print(alarms[channel].minute);

  if (alarmEnabled[channel] && (alarms[channel].hour != 0 || alarms[channel].minute != 0)) {
    unsigned long currentMillis = millis();
    unsigned long elapsedTime = timers[channel].hour * 60 + timers[channel].minute;
    unsigned long alarmTime = alarms[channel].hour * 60 + alarms[channel].minute;
    long timeLeft = alarmTime - elapsedTime;

    Serial.print(", Elapsed Time: ");
    Serial.print(elapsedTime);
    Serial.print(", Alarm Time (min): ");
    Serial.print(alarmTime);
    Serial.print(", Time Left (min): ");
    Serial.println(timeLeft);

    if (elapsedTime >= alarmTime) {
      Serial.println("Alarm Triggered!");

      tone(buzzerPin, 1000);

      if (alarmStartTime[channel] == 0) {
        alarmStartTime[channel] = millis();
      }

      if (millis() - alarmStartTime[channel] >= 2000) {
        noTone(buzzerPin);
        alarmStartTime[channel] = 0;
      }

      if (currentMillis - previousMillis[channel] >= blinkInterval) {
        previousMillis[channel] = currentMillis;
        blinkState[channel] = !blinkState[channel];

        lcd.setCursor((channel % 2) * 8, channel / 2);
        if (blinkState[channel]) {
          lcd.print(channel + 1);
          lcd.print("-");
          printTime(timers[channel].hour, timers[channel].minute);
          lcd.print(" ");
        } else {
          lcd.print("        ");
        }
      }
    } else {
      alarmStartTime[channel] = 0;
      noTone(buzzerPin);

      lcd.setCursor((channel % 2) * 8, channel / 2);
      lcd.print(channel + 1);
      lcd.print("-");
      printTime(timers[channel].hour, timers[channel].minute);
      lcd.print(" ");
    }
  } else {
    Serial.println();
  }
}

void resetTimer(int channel) {
  timers[channel].hour = 0;
  timers[channel].minute = 0;
  timers[channel].second = 0;
  updateTimer(channel);
}

void stopAlarm(int channel) {
  alarmEnabled[channel] = false;
  noTone(buzzerPin);
  displayTimers();
}

It is unlikely that you could write a serious program only with the help of AI, without understanding it yourself.
Now you have an initial draft, then you need to try to write the code yourself, without the help of a robot

Yes, that's the sad truth and I was aware of that. That's why I was trying to make it in little steps to put the whole thing togheder after the little steps are completed. But it looks like i make 1 step forward and 5 steps back. So my plan now after i added comments for each step in the code it to take them one by one trying to understand what they do and what wrong or right:

#include <LiquidCrystal.h>
#include <EEPROM.h>
#include <string.h> // Include string.h for memcmp()

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

// Structure to store time (hours, minutes, seconds)
struct TIME {
  uint8_t hour;
  uint8_t minute;
  uint8_t second;
};

// Arrays to store timer and alarm values
TIME timers[4];
TIME alarms[4];
// Array to track if alarms are enabled
bool alarmEnabled[4] = {false, false, false, false};

// Array to store start times for timers
unsigned long startTime[4] = {0, 0, 0, 0};
// Interval to update timers (1 second)
const unsigned long updateInterval = 1000;

// Button pins and their states
const int buttonPins[5] = {6, 7, 8, 9, 10};
int buttonStates[5] = {HIGH, HIGH, HIGH, HIGH, HIGH};

// Variable to track which channel is being set (not used in current version)
int settingChannel = -1;

// Buzzer pin
const int buzzerPin = 13;

// Arrays to store button press times and alarm start times
unsigned long buttonPressTime[4] = {0, 0, 0, 0};
unsigned long alarmStartTime[4] = {0, 0, 0, 0};

// Flags to track set button state and alarm setting mode
bool setButtonPressed = false;
bool alarmSettingMode = false;
// Flag to indicate if the display needs to be updated
bool displayNeedsUpdate = true;

// EEPROM signature to verify initialization
#define EEPROM_SIGNATURE 0xA5

// Function to initialize EEPROM with default alarm values
void initializeEEPROM() {
  // Check if EEPROM has been initialized
  if (EEPROM.read(0) != EEPROM_SIGNATURE) {
    // Default alarm time (00:00:00)
    TIME defaultAlarm = {0, 0, 0};
    // Write default alarm values to EEPROM
    for (int i = 0; i < 4; i++) {
      EEPROM.put(i * sizeof(TIME) + 1, defaultAlarm);
    }
    // Write EEPROM signature
    EEPROM.write(0, EEPROM_SIGNATURE);
  }
}

// Function to read alarm settings from EEPROM
void readAlarmsFromEEPROM() {
  // Read alarm values from EEPROM
  for (int i = 0; i < 4; i++) {
    EEPROM.get(i * sizeof(TIME) + 1, alarms[i]);
  }
}

// Function to write alarm settings to EEPROM
void writeAlarmsToEEPROM() {
  // Flag to track if any alarm value has changed
  bool changed = false;
  // Iterate through alarms and compare with stored values
  for (int i = 0; i < 4; i++) {
    TIME storedAlarm;
    EEPROM.get(i * sizeof(TIME) + 1, storedAlarm);

    // Check if alarm values have changed using memcmp()
    if (memcmp(&storedAlarm, &alarms[i], sizeof(TIME)) != 0) {
      // Write updated alarm value to EEPROM
      EEPROM.put(i * sizeof(TIME) + 1, alarms[i]);
      changed = true;
    }
  }
  // Print message if EEPROM was updated
  if (changed) Serial.println("EEPROM updated with new alarm values.");
}

// Function to check if an alarm should be triggered
void checkAlarm(int channel);
// Function to reset a timer
void resetTimer(int channel);
// Function to stop an alarm
void stopAlarm(int channel);
// Function to display timers on LCD
void displayTimers();
// Function to update a timer display
void updateTimer(int channel);
// Function to print time in HH:MM format
void printTime(uint8_t h, uint8_t m);
// Function to read button states
void readButtons();
// Function to handle button presses
void handleButtons();
// Function to display all alarms in setting mode
void displayAllAlarms();
// Function to display alarm settings for a channel (not used in current version)
void displayAlarmSettings(int channel);

void setup() {
  // Initialize LCD and serial communication
  lcd.begin(16, 2);
  Serial.begin(9600);
  // Initialize EEPROM
  initializeEEPROM();
  // Initialize timer start times
  for (int i = 0; i < 4; i++) {
    startTime[i] = millis();
  }
  // Set button pins as input with pull-up resistors
  for (int i = 0; i < 5; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }
  // Set buzzer pin as output
  pinMode(buzzerPin, OUTPUT);
  // Read alarm settings from EEPROM
  readAlarmsFromEEPROM();
  // Display initial timer values
  displayTimers();
}

void loop() {
  // Get current time
  unsigned long currentTime = millis();
  // Flag to track if any timer has been updated
  bool anyTimerUpdated = false;

  // Iterate through timers
  for (int i = 0; i < 4; i++) {
    // Check if it's time to update the timer
    if (currentTime - startTime[i] >= updateInterval) {
      // Update timer start time
      startTime[i] += updateInterval;
      // Increment timer second
      timers[i].second++;
      // Handle timer overflow
      if (timers[i].second >= 60) {
        timers[i].second = 0;
        timers[i].minute++;
        if (timers[i].minute >= 60) {
          timers[i].minute = 0;
          timers[i].hour++;
          if (timers[i].hour >= 100) {
            timers[i].hour = 0;
          }
        }
      }
      // Check if alarm should be triggered
      checkAlarm(i);
      // Update timer start time
      startTime[i] = currentTime;
      // Update timer display if not in alarm setting mode
      if (!alarmSettingMode) {
        updateTimer(i);
        anyTimerUpdated = true;
      }
    }
  }

  // Read button states
  readButtons();
  // Handle button presses
  handleButtons();

  // Update LCD display if needed
  if (displayNeedsUpdate || anyTimerUpdated) {
    if (alarmSettingMode) {
      // Display alarm settings
      displayAllAlarms();
    } else {
      // Display timer values
      displayTimers();
    }
    // Reset display update flag
    displayNeedsUpdate = false;
  }
}

// Function to display timers on LCD
void displayTimers() {
  // Static array to store previous timer values
  static TIME previousTimers[4];
  // Iterate through timers
  for (int i = 0; i < 4; i++) {
    // Check if timer value has changed
    if (timers[i].hour != previousTimers[i].hour ||
        timers[i].minute != previousTimers[i].minute ||
        timers[i].second != previousTimers[i].second) {
      // Set LCD cursor position
      lcd.setCursor((i % 2) * 8, i / 2);
      // Print timer channel and time
      lcd.print(i + 1);
      lcd.print("-");
      if (timers[i].hour > 0) {
        printTime(timers[i].hour, timers[i].minute);
      } else {
        printTime(timers[i].minute, timers[i].second);
      }
      lcd.print(" ");
      // Update previous timer value
      previousTimers[i] = timers[i];
    }
  }
}

// Function to update a timer display
void updateTimer(int channel) {
  // Static array to store previous timer values
  static TIME previousTimers[4];
  // Check if timer value has changed
  if (timers[channel].hour != previousTimers[channel].hour ||
      timers[channel].minute != previousTimers[channel].minute ||
      timers[channel].second != previousTimers[channel].second) {
    // Calculate LCD cursor position
    int cursorPosition = (channel < 2) ? (channel *
 8 + 2) : ((channel - 2) * 8 + 2);
    int row = (channel < 2) ? 0 : 1;
    // Set LCD cursor position
    lcd.setCursor(cursorPosition, row);
    // Print timer time
    if (timers[channel].hour > 0) {
      printTime(timers[channel].hour, timers[channel].minute);
    } else {
      printTime(timers[channel].minute, timers[channel].second);
    }
    // Update previous timer value
    previousTimers[channel] = timers[channel];
  }
}

// Function to print time in HH:MM format
void printTime(uint8_t h, uint8_t m) {
  // Print hours with leading zero if needed
  if (h < 10) lcd.print("0");
  lcd.print(h);
  lcd.print(":");
  // Print minutes with leading zero if needed
  if (m < 10) lcd.print("0");
  lcd.print(m);
}

// Function to read button states
void readButtons() {
  // Read state of each button
  for (int i = 0; i < 5; i++) {
    buttonStates[i] = digitalRead(buttonPins[i]);
  }
}

// Function to handle button presses
void handleButtons() {
  // Get current time
  unsigned long currentTime = millis();
  // Static variable to store last set button release time
  static unsigned long lastSetButtonReleaseTime = 0;

  // Handle set button press
  if (buttonStates[4] == LOW) {
    // Check if set button was previously released
    if (!setButtonPressed) {
      // Enter alarm setting mode
      alarmSettingMode = true;
      setButtonPressed = true;
      displayNeedsUpdate = true;
    }
    // Flag to track if any alarm was updated
    bool alarmUpdated = false;
    // Iterate through alarms
    for (int i = 0; i < 4; i++) {
      // Check if button for alarm is pressed
      if (buttonStates[i] == LOW) {
        // Increment alarm minute
        alarms[i].minute++;
        // Handle alarm minute overflow
        if (alarms[i].minute >= 60) {
          alarms[i].minute = 0;
          alarms[i].hour++;
          // Handle alarm hour overflow
          if (alarms[i].hour >= 100) {
            alarms[i].hour = 0;
          }
        }
        // Set alarm updated flag
        alarmUpdated = true;
        // Delay to prevent rapid incrementing
        delay(150);
      }
    }
    // Update display if any alarm was updated
    if (alarmUpdated) {
      displayNeedsUpdate = true;
    }
  } else {
    // Store set button release time
    lastSetButtonReleaseTime = currentTime;
    // Check if exiting alarm setting mode
    if (alarmSettingMode) {
      // Write alarm settings to EEPROM
      writeAlarmsToEEPROM();
      // Enable alarms if they are set
      for (int i = 0; i < 4; i++) {
        if (alarms[i].hour != 0 || alarms[i].minute != 0) {
          alarmEnabled[i] = true;
        } else {
          alarmEnabled[i] = false;
        }
      }
    }
    // Exit alarm setting mode
    alarmSettingMode = false;
    setButtonPressed = false;
  }

  // Handle timer control buttons if not in alarm setting mode
  if (!alarmSettingMode) {
    // Iterate through timer buttons
    for (int i = 0; i < 4; i++) {
      // Check if button is pressed
      if (buttonStates[i] == LOW) {
        // Check if button press time is not set
        if (buttonPressTime[i] == 0) {
          // Store button press time
          buttonPressTime[i] = currentTime;
        }
        // Check if button is held for reset
        if (currentTime - buttonPressTime[i] > 500) {
          // Reset timer
          resetTimer(i);
          displayNeedsUpdate = true;
          // Update button press time
          buttonPressTime[i] = currentTime;
        }
      } else {
        // Check if button was released after a short press
        if (buttonPressTime[i] != 0 && currentTime - buttonPressTime[i] <= 500) {
          // Stop alarm
          stopAlarm(i);
          displayNeedsUpdate = true;
        }
        // Reset button press time
        buttonPressTime[i] = 0;
      }
    }
  }
}

// Function to display all alarms in setting mode
void displayAllAlarms() {
  // Clear LCD
  lcd.clear();
  // Iterate through alarms
  for (int i = 0; i < 4; i++) {
    // Set LCD cursor position
    lcd.setCursor((i % 2) * 8, i / 2);
    // Print alarm channel and time
    lcd.print(i + 1);
    lcd.print("-");
    printTime(alarms[i].hour, alarms[i].minute);
  }
}

// Function to display alarm settings for a channel (not used in current version)
void displayAlarmSettings(int channel) {
  lcd.clear();
  lcd.print("Set alarm ");
  lcd.print(channel + 1);
  lcd.setCursor(0, 1);
  lcd.print(alarms[channel].hour);
  lcd.print(":");
  lcd.print(alarms[channel].minute);
}

// Function to check if an alarm should be triggered
void checkAlarm(int channel) {
  // Static array to store blink state for each alarm
  static bool blinkState[4] = {false, false, false, false};
  // Static array to store previous millis for blinking
  static unsigned long previousMillis[4] = {0, 0, 0, 0};
  // Blink interval in milliseconds
  const int blinkInterval = 250;

  // Print debug information to serial monitor
  Serial.print("Channel: ");
  Serial.print(channel);
  Serial.print(", Enabled: ");
  Serial.print(alarmEnabled[channel]);
  Serial.print(", Alarm Time: ");
  Serial.print(alarms[channel].hour);
  Serial.print(":");
  if (alarms[channel].minute < 10) {
    Serial.print("0");
  }
  Serial.print(alarms[channel].minute);

  // Check if alarm is enabled and set
  if (alarmEnabled[channel] && (alarms[channel].hour != 0 || alarms[channel].minute != 0)) {
    // Get current time
    unsigned long currentMillis = millis();
    // Calculate elapsed time in minutes
    unsigned long elapsedTime = timers[channel].hour * 60 + timers[channel].minute;
    // Calculate alarm time in minutes
    unsigned long alarmTime = alarms[channel].hour * 60 + alarms[channel].minute;
    // Calculate time left in minutes
    long timeLeft = alarmTime - elapsedTime;

    // Print debug information to serial monitor
    Serial.print(", Elapsed Time: ");
    Serial.print(elapsedTime);
    Serial.print(", Alarm Time (min): ");
    Serial.print(alarmTime);
    Serial.print(", Time Left (min): ");
    Serial.println(timeLeft);

    // Check if alarm should be triggered
    if (elapsedTime >= alarmTime) {
      // Print alarm triggered message to serial monitor
      Serial.println("Alarm Triggered!");

      // Start buzzer tone
      tone(buzzerPin, 1000);

      // Check if alarm start time is not set
      if (alarmStartTime[channel] == 0) {
        // Store alarm start time
        alarmStartTime[channel] = millis();
      }

      // Stop buzzer tone after 2 seconds
      if (millis() - alarmStartTime[channel] >= 2000) {
        noTone(buzzerPin);
        alarmStartTime[channel] = 0;
      }

      // Blink timer display
      if (currentMillis - previousMillis[channel] >= blinkInterval) {
        previousMillis[channel] = currentMillis;
        blinkState[channel] = !blinkState[channel];

        lcd.setCursor((channel % 2) * 8, channel / 2);
        if (blinkState[channel]) {
          lcd.print(channel + 1);
          lcd.print("-");
          printTime(timers[channel].hour, timers[channel].
minute);
          lcd.print(" ");
        } else {
          lcd.print("        ");
        }
      }
    } else {
      // Reset alarm start time and stop buzzer
      alarmStartTime[channel] = 0;
      noTone(buzzerPin);

      // Update timer display without blinking
      lcd.setCursor((channel % 2) * 8, channel / 2);
      lcd.print(channel + 1);
      lcd.print("-");
      printTime(timers[channel].hour, timers[channel].minute);
      lcd.print(" ");
    }
  } else {
    // Print newline to serial monitor
    Serial.println();
  }
}

// Function to reset a timer
void resetTimer(int channel) {
  // Reset timer values
  timers[channel].hour = 0;
  timers[channel].minute = 0;
  timers[channel].second = 0;
  // Update timer display
  updateTimer(channel);
}

// Function to stop an alarm
void stopAlarm(int channel) {
  // Disable alarm
  alarmEnabled[channel] = false;
  // Stop buzzer tone
  noTone(buzzerPin);
  // Update timer display
  displayTimers();
}

This feature if it exists is new, and I suggest you to find out if it has been implemented. I found no support for that assertion.

I can't your AI code to answer this question.

If you think so, you shoukd be able to know it. And you should be able to easily write a small sketch that would prove it.

I would but I am not in the lab.

a7