Überlaufsicheren Timer - etwas alle x Sekunden machen

Hallo
Ich habe auch noch Einen :nerd_face:
Deine Aufgabenstellung kann man super für die Anwendung der OOP verwenden, ohne Class-Defintion, es geht auch ohne Extras!
Aber nun zum Eingemachten:
Der Sketch hat drei Timer-Objekte:

enum {Alarm, Blink, BlinkBlink}; // timer names

Diese Objekte werden über diese Methode abgefackelt:

bool checkTimer(TIMER &time_) {
  return ((currentTime - time_.stamp >= time_.duration && time_.control_) ? true : false);

Den Rest dazu findest Du im Sketch, der auf einem Arduino UNO getestet worden ist.

// BLOCK COMMENT
// https://www.learncpp.com/cpp-tutorial/
// https://forum.arduino.cc/t/uberlaufsicheren-timer-etwas-alle-x-sekunden-machen/903257
#define ProjectName "Überlaufsicheren Timer - etwas alle x Sekunden machen"
// CONSTANT DEFINITION
// you may need to change these constants to your needs
constexpr unsigned long AlarmTime {20000};
constexpr unsigned long BlinkTime {10000};
constexpr unsigned long BlinkBlinkTime {1000};

// VARIABLE DECLARATION AND DEFINTION
enum {Alarm, Blink, BlinkBlink}; // timer names
unsigned long currentTime;
struct TIMER {
  int name_;
  unsigned long duration;
  bool control_;
  unsigned long stamp;
};
TIMER alarms [] {
  {Alarm, AlarmTime,  true,  0},
  {Blink, BlinkTime, false,  0},
  {BlinkBlink, BlinkBlinkTime, false,  0},
};
// FUNCTIONs
bool checkTimer(TIMER &time_) {
  return ((currentTime - time_.stamp >= time_.duration && time_.control_) ? true : false);
}
void setup() {
  Serial.begin(9600);
  Serial.println(F("."));
  Serial.print(F("File   : ")), Serial.println(__FILE__);
  Serial.print(F("Date   : ")), Serial.println(__DATE__);
  Serial.print(F("Project: ")), Serial.println(ProjectName);
  pinMode (LED_BUILTIN, OUTPUT);
   alarms[Alarm].stamp = alarms[Alarm].duration; // start condition 
}
void loop () {
  currentTime = millis();
  digitalWrite(LED_BUILTIN, (currentTime / 500) % 2);
  for (auto &alarm : alarms) {
    if (checkTimer(alarm)) {
      switch (alarm.name_) {
        case Alarm:
          alarms[Alarm].control_ = false;
          alarms[Blink].stamp = currentTime;
          alarms[Blink].control_ = true;
          alarms[BlinkBlink].control_ = true;
          Serial.println(F("start beep"));
          break;
        case Blink:
          alarms[Alarm].stamp = currentTime;
          alarms[Alarm].control_ = true;
          alarms[Blink].control_ = false;
          alarms[BlinkBlink].control_ = false;
          Serial.println(F("\nstopp beep"));
          break;
        case BlinkBlink:
          alarms[BlinkBlink].stamp = currentTime;
          Serial.print(F("Beep"));
          break;
      }
    }
  }
}

Viel Spass beim Studium der Möglichkeiten, die die OOP bietet.