Toilettenampel mit Tasterhaltung

Na das ist ja nun nichts mit Sicherheitsschaltung, das ist nur die Unterbrechung der StateMachine mit Rückkehr an einen definierten Punkt.

// basiert auf https://forum.arduino.cc/t/toilettenampel-mit-tasterhaltung/914301/45?u=my_xy_projekt
// erweitert um eine Abfragebedingung in ST_REDyellow
const byte    PinLed  [] = { 5, 7, 9 };
const byte    PinBut     =  11;
enum { Off, On };
enum { ST_IDLE, ST_YELLOW, ST_RED, ST_REDwait, ST_REDYellow };  // Das ist eine Aufzaehlung der Stati
byte  state = ST_IDLE;                                          // Erster Status mit Programmstart

const unsigned long PeriodYellow = 1000;                        // Zeit in ms
unsigned long yellowPlus = 0;                                   // Variable zur Berechnung der Verlaengerung der Gelbphase
unsigned long msecLst;                                          // Merker für letzte Zeit
unsigned long msec;                                             // Merker für aktuelle Zeit

// -----------------------------------------------------------------------------
void setLeds ( const bool green,          // Funktion zur Ausgabe der Zustände
               const bool yellow,
               const bool red )
{
  digitalWrite (PinLed [0], green);
  digitalWrite (PinLed [1], yellow);
  digitalWrite (PinLed [2], red);
}

// -----------------------------------------------------------------------------
void kontrol()
{
  byte x = 200;
  static byte y = 0;
  x = (x + digitalRead(5)) << 1;
  x = (x + digitalRead(7)) << 1;
  x = (x + digitalRead(9));
  if (y != x)
  {
    y = x;
    Serial.println(y, BIN);
  }
}
void loop ()
{
  kontrol();
  msec = millis ();                         // merkt sich die aktuelle Zeit
  switch (state)                            // verzweige je nach Zustand
  {
    case ST_YELLOW:                         // Wenn Status gelb
      setLeds (Off, On, Off);               // stelle die Ampel
      if ((msec - msecLst) > PeriodYellow)  // wenn Gelbzeit abgelaufen
        state = ST_RED;                     // wechsle zu rot
      break;
    case ST_RED:                            // wenn Status rot
      setLeds (Off, Off, On);               // stelle Ampel
      msecLst = msec;                       // merke die aktuelle Zeit
      state = ST_REDwait;                   // wechsel Status zu rot_warten
      break;
    case ST_REDwait:                        // wenn Status rot_warten
      if (digitalRead (PinBut))             // wenn Schloss geöffnet
      {
        yellowPlus = (msec - msecLst);      // ermittle die Zeit, die das Schloß zu war
        if (yellowPlus < 60000) yellowPlus = 1000;  // und setze passend dazu die Verlängerungszeit
        if (yellowPlus > 119900) yellowPlus = 119900;
        msecLst = msec;                     // merke die Zeit
        state = ST_REDYellow;               // wechsel Status zu rot_gelb
      }
      break;
    case ST_REDYellow:                      // wenn Status rot_gelb
      if (!digitalRead (PinBut))            // wenn Schloss wieder geschlossen
      {
        state = ST_RED;
      }
      else
      {
        setLeds (Off, On, On);              // stelle die Ampel
        if ((msec - msecLst) > (PeriodYellow + yellowPlus)) // Wenn Zeit abgelaufen
        {
          state = ST_IDLE;                  // wechsel Status zu gruen
        }
      }
      break;
    case ST_IDLE:                           // Wenn Status gruen
    default:                                // oder Status unbekannt
      setLeds (On, Off, Off);               // stelle Ampel
      if (!digitalRead (PinBut))            // Wenn Schloss zu
      {
        state = ST_YELLOW;                  // wechsel zu Status gelb
        msecLst = msec;                     // merke die Zeit
      }
      break;
  }
}
void setup()
{
  Serial.begin (115200);
  Serial.println(F("Start..."));
  for (unsigned n = 0; n < sizeof(PinLed); n++) // Setze alle Pins
  {
    digitalWrite (PinLed [n], Off);             // aus
    pinMode      (PinLed [n], OUTPUT);          // auf Output
  }
  pinMode (PinBut, INPUT_PULLUP);
}