Logik/Code-Problem bei einem etwas komplexeren Sketch

So könnte es mit den neuen Tasten funktionieren.
Die LEDs der Tasten werden noch nicht angesteuert.

#include <Bounce2.h>

const byte relaisPin_Pumpe =  8;
const byte relaisPin_Reinstwasser =  7;
const byte relaisPin_Leitungswasser =  6;
const byte relaisPin_SpuelVorMembran3 = 5;
const byte relaisPin_SpuelVorMembran2 = 4;
const byte relaisPin_SpuelVorMembran1 = 3;
const byte relaisPin_SpuelNachMembran = 2;

// LED Ausgänge

const byte LED_rot_aus = 28;
const byte LED_gelb_wenig = 29;
const byte LED_gruen_mittel = 30;
const byte LED_blau_viel = 31;

// Taster Eingänge

const byte tasterPin1 = 24;    // Eingang Taster abbruch / Stop
const byte tasterPin2 = 25;    // Eingang Taster wenig
const byte tasterPin3 = 26;    // Eingang Taster mittel
const byte tasterPin4 = 27;    // Eingang Taster viel

const unsigned long zeit6H = 21600000UL;

const byte relayPins[] = {
  relaisPin_SpuelNachMembran, relaisPin_SpuelVorMembran1,
  relaisPin_SpuelVorMembran2, relaisPin_SpuelVorMembran3,
  relaisPin_Leitungswasser, relaisPin_Reinstwasser,
  relaisPin_Pumpe
};

const byte butLedPins[] = { LED_rot_aus, LED_gelb_wenig, LED_gruen_mittel, LED_blau_viel };
const byte buttonPins[] = { tasterPin1, tasterPin2, tasterPin3, tasterPin4 };
#define NUMBUTTONS sizeof(buttonPins)
enum sels {
  selStop, selWenig, selMittel, selViel,
};

enum Zustaende {
  unbeschaeftigt,
  stopped,
  spuelStart,   spuelPhase1,  spuelPause,  spuelPhase2,
  shortStart,   shortPhase1,  shortPause,  shortPhase2,
  doubleStart,  doublePhase1, doublePause, doublePhase2,
  longStart,    longPhase1,   longPause,   longPhase2,
};

Bounce key[NUMBUTTONS];

byte aktuellerZustand = unbeschaeftigt;

unsigned long currentMillis;
unsigned long lastTransition;
unsigned long letzteSpuelung;

void setup() {
  Serial.begin(250000);
  Serial.println(F("Button test"));
  for (byte i = 0; i < NUMBUTTONS; i++) {
    pinMode(butLedPins[i], OUTPUT);
    key[i].attach(buttonPins[i], INPUT_PULLUP);
  }
  for (byte i = 0; i < sizeof(relayPins); i++) {
    digitalWrite(relayPins[i], HIGH);
    pinMode(relayPins[i], OUTPUT);
  }
}

void loop() {
  currentMillis = millis();
  for (byte i = 0; i < NUMBUTTONS; i++) {
    key[i].update();
  }
  if (aktuellerZustand != unbeschaeftigt) {
    if (key[selStop].fell()) {
      if (aktuellerZustand != stopped) {
        aktuellerZustand = stopped;
      } else {
        aktuellerZustand = unbeschaeftigt;
      }
    }
  } else {
    if (key[selWenig].fell()) {
      aktuellerZustand = shortStart;
    } else if (key[selMittel].fell()) {
      aktuellerZustand = doubleStart;
    } else if (key[selViel].fell()) {
      aktuellerZustand = longStart;
    }
  }
  switch (aktuellerZustand) {
    case unbeschaeftigt:
      if (currentMillis - letzteSpuelung >= zeit6H) {
        letzteSpuelung = currentMillis;
        aktuellerZustand = spuelStart;
      }
      break;

    case stopped:
      break;

    case spuelStart:
      setupAndGoToState(0b0001111, true, spuelPhase1, PSTR("Test")); // mit 8 0b0101111
      break;
    case spuelPhase1:
      switchAndNewStateAfter(0b0001111, false, spuelPause, 20000);  // mit 8 0b0101111
      break;
    case spuelPause:
      switchAndNewStateAfter(0b0001001, true, spuelPhase2, 10);  // mit 8 0b0101001
      break;
    case spuelPhase2:
      switchAndNewStateAfter(0b0001001, false, unbeschaeftigt, 15000);  // mit 8 0b0101001
      break;

    case shortStart:
      setupAndGoToState(0b0101001, true, shortPhase1, PSTR("300 ml"));
      break;
    case shortPhase1:
      switchAndNewStateAfter(0b0101001, false, shortPause, 15000);
      break;
    case shortPause:
      switchAndNewStateAfter(0b0111000, true, shortPhase2, 500);
      break;
    case shortPhase2:
      switchAndNewStateAfter(0b0111000, false, unbeschaeftigt, 20000);
      break;

    case doubleStart:
      setupAndGoToState(0b0101001, true, doublePhase1, PSTR("1000 ml"));
      break;
    case doublePhase1:
      switchAndNewStateAfter(0b0101001, false, doublePause, 15000);
      break;
    case doublePause:
      switchAndNewStateAfter(0b0111000, true, shortPhase2, 500);
      break;
    case doublePhase2:
      switchAndNewStateAfter(0b0111000, false, unbeschaeftigt, 60000UL);
      break;

    case longStart:
      setupAndGoToState(0b0101001, true, longPhase1, PSTR("8000 ml"));
      break;
    case longPhase1:
      switchAndNewStateAfter(0b0101001, false, longPause, 15000);
      break;
    case longPause:
      switchAndNewStateAfter(0b0111000, true, longPhase2, 500);
      break;
    case longPhase2:
      switchAndNewStateAfter(0b0111000, false, unbeschaeftigt, 480000UL);
      break;
  }
  benchmark();
}

void switchRelaisSet(byte mask, bool toWhat) {
  for (byte idx = 1; mask; idx++, mask >>= 1) {
    if (mask & 1) {
      digitalWrite(relayPins[idx], toWhat ? LOW : HIGH);
    }
  }
}

void setupAndGoToState(byte mask, bool toWhat, byte newState, char* txt) {
  switchRelaisSet(mask, toWhat);
  lastTransition = currentMillis;
  aktuellerZustand = newState;
  Serial.print(F("  "));
  Serial.print((__FlashStringHelper*)txt);
  Serial.write(' ');
  Serial.println(currentMillis);
}

void switchAndNewStateAfter(byte mask, bool toWhat, byte newState, unsigned long duration) {
  if (currentMillis - lastTransition >= duration) {
    switchRelaisSet(mask, toWhat);
    Serial.print(F("  "));
    Serial.print(aktuellerZustand);
    Serial.print(F(" -> "));
    Serial.print(newState);
    Serial.print(F(" nach "));
    Serial.print(currentMillis - lastTransition);
    Serial.println();
    lastTransition = currentMillis;
    aktuellerZustand = newState;
  }
}

void benchmark() {
  static unsigned long counterStartTime;
  static unsigned long counter;
  if (++counter >= 1000000L) {
    Serial.print(F("Average Time per loop(): "));
    Serial.print((micros() - counterStartTime) / 1000000.0);
    Serial.println(F(" microseconds"));
    counter = 0;
    counterStartTime = micros();
  }
}

Und nun mit Leds.

Gehen einfach nur an, kein Blinken oder so.

#include <Bounce2.h>

const byte relaisPin_Pumpe =  8;
const byte relaisPin_Reinstwasser =  7;
const byte relaisPin_Leitungswasser =  6;
const byte relaisPin_SpuelVorMembran3 = 5;
const byte relaisPin_SpuelVorMembran2 = 4;
const byte relaisPin_SpuelVorMembran1 = 3;
const byte relaisPin_SpuelNachMembran = 2;

// LED Ausgänge

const byte LED_rot_aus = 28;
const byte LED_gelb_wenig = 29;
const byte LED_gruen_mittel = 30;
const byte LED_blau_viel = 31;

// Taster Eingänge

const byte tasterPin_Stop = 24;
const byte tasterPin_Wenig = 25;
const byte tasterPin_Mittel = 26;
const byte tasterPin_Viel = 27;

const unsigned long zeit6H = 21600000UL;

const byte relayPins[] = {
  relaisPin_SpuelNachMembran, relaisPin_SpuelVorMembran1,
  relaisPin_SpuelVorMembran2, relaisPin_SpuelVorMembran3,
  relaisPin_Leitungswasser, relaisPin_Reinstwasser,
  relaisPin_Pumpe
};

const byte butLedPins[] = { LED_rot_aus, LED_gelb_wenig, LED_gruen_mittel, LED_blau_viel };
const byte buttonPins[] = { tasterPin_Stop, tasterPin_Wenig, tasterPin_Mittel, tasterPin_Viel };
#define NUMBUTTONS sizeof(buttonPins)
enum sels {
  selStop, selWenig, selMittel, selViel,
};

enum Zustaende {
  unbeschaeftigt,
  stopped,
  spuelStart,   spuelPhase1,  spuelPause,  spuelPhase2,
  shortStart,   shortPhase1,  shortPause,  shortPhase2,
  doubleStart,  doublePhase1, doublePause, doublePhase2,
  longStart,    longPhase1,   longPause,   longPhase2,
};

Bounce key[NUMBUTTONS];

byte aktuellerZustand = unbeschaeftigt;

unsigned long currentMillis;
unsigned long lastTransition;
unsigned long letzteSpuelung;

void setup() {
  Serial.begin(250000);
  Serial.println(F("Button test"));
  for (byte i = 0; i < NUMBUTTONS; i++) {
    pinMode(butLedPins[i], OUTPUT);
    key[i].attach(buttonPins[i], INPUT_PULLUP);
  }
  for (byte i = 0; i < sizeof(relayPins); i++) {
    digitalWrite(relayPins[i], HIGH);
    pinMode(relayPins[i], OUTPUT);
  }
}

void loop() {
  currentMillis = millis();
  for (byte i = 0; i < NUMBUTTONS; i++) {
    key[i].update();
  }
  if (aktuellerZustand != unbeschaeftigt) {
    if (key[selStop].fell()) {
      if (aktuellerZustand != stopped) {
        switchRelaisSet(0b01111111, false);
        setKeyLeds(0b0001);
        aktuellerZustand = stopped;
      } else {
        aktuellerZustand = unbeschaeftigt;
        setKeyLeds(0b0000);
      }
    }
  } else {
    if (key[selWenig].fell()) {
      aktuellerZustand = shortStart;
      setKeyLeds(0b0011);
    } else if (key[selMittel].fell()) {
      aktuellerZustand = doubleStart;
      setKeyLeds(0b0101);
    } else if (key[selViel].fell()) {
      aktuellerZustand = longStart;
      setKeyLeds(0b1001);
    }
  }
  switch (aktuellerZustand) {
    case unbeschaeftigt:
      if (currentMillis - letzteSpuelung >= zeit6H) {
        letzteSpuelung = currentMillis;
        aktuellerZustand = spuelStart;
      }
      break;

    case stopped:
      break;

    case spuelStart:
      setupAndGoToState(0b0001111, true, spuelPhase1, PSTR("Test")); // mit 8 0b0101111
      break;
    case spuelPhase1:
      switchAndNewStateAfter(0b0001111, false, spuelPause, 20000);  // mit 8 0b0101111
      break;
    case spuelPause:
      switchAndNewStateAfter(0b0001001, true, spuelPhase2, 10);  // mit 8 0b0101001
      break;
    case spuelPhase2:
      switchAndNewStateAfter(0b0001001, false, unbeschaeftigt, 15000);  // mit 8 0b0101001
      break;

    case shortStart:
      setupAndGoToState(0b0101001, true, shortPhase1, PSTR("300 ml"));
      break;
    case shortPhase1:
      switchAndNewStateAfter(0b0101001, false, shortPause, 15000);
      break;
    case shortPause:
      switchAndNewStateAfter(0b0111000, true, shortPhase2, 500);
      break;
    case shortPhase2:
      switchAndNewStateAfter(0b0111000, false, unbeschaeftigt, 20000);
      break;

    case doubleStart:
      setupAndGoToState(0b0101001, true, doublePhase1, PSTR("1000 ml"));
      break;
    case doublePhase1:
      switchAndNewStateAfter(0b0101001, false, doublePause, 15000);
      break;
    case doublePause:
      switchAndNewStateAfter(0b0111000, true, shortPhase2, 500);
      break;
    case doublePhase2:
      switchAndNewStateAfter(0b0111000, false, unbeschaeftigt, 60000UL);
      break;

    case longStart:
      setupAndGoToState(0b0101001, true, longPhase1, PSTR("8000 ml"));
      break;
    case longPhase1:
      switchAndNewStateAfter(0b0101001, false, longPause, 15000);
      break;
    case longPause:
      switchAndNewStateAfter(0b0111000, true, longPhase2, 500);
      break;
    case longPhase2:
      switchAndNewStateAfter(0b0111000, false, unbeschaeftigt, 480000UL);
      break;
  }
  benchmark();
}

void switchRelaisSet(byte mask, bool toWhat) {
  for (byte idx = 1; mask; idx++, mask >>= 1) {
    if (mask & 1) {
      digitalWrite(relayPins[idx], toWhat);
    }
  }
}

void setKeyLeds(byte mask) {
  for (byte idx = 0; mask; idx++, mask >>= 1) {
    digitalWrite(butLedPins[idx], mask & 1);
  }
}

void setupAndGoToState(byte mask, bool toWhat, byte newState, char* txt) {
  switchRelaisSet(mask, toWhat);
  lastTransition = currentMillis;
  aktuellerZustand = newState;
  Serial.print(F("  "));
  Serial.print((__FlashStringHelper*)txt);
  Serial.write(' ');
  Serial.println(currentMillis);
}

void switchAndNewStateAfter(byte mask, bool toWhat, byte newState, unsigned long duration) {
  if (currentMillis - lastTransition >= duration) {
    switchRelaisSet(mask, toWhat);
    Serial.print(F("  "));
    Serial.print(aktuellerZustand);
    Serial.print(F(" -> "));
    Serial.print(newState);
    Serial.print(F(" nach "));
    Serial.print(currentMillis - lastTransition);
    Serial.println();
    lastTransition = currentMillis;
    aktuellerZustand = newState;
    if (newState == unbeschaeftigt) {
      setKeyLeds(0b0000);
    }
  }
}

void benchmark() {
  static unsigned long counterStartTime;
  static unsigned long counter;
  if (++counter >= 1000000L) {
    Serial.print(F("Average Time per loop(): "));
    Serial.print((micros() - counterStartTime) / 1000000.0);
    Serial.println(F(" microseconds"));
    counter = 0;
    counterStartTime = micros();
  }
}

Etwas weiter zusammengefasst.

#include <Bounce2.h>

const byte relaisPin_Pumpe =  8;
const byte relaisPin_Reinstwasser =  7;
const byte relaisPin_Leitungswasser =  6;
const byte relaisPin_SpuelVorMembran3 = 5;
const byte relaisPin_SpuelVorMembran2 = 4;
const byte relaisPin_SpuelVorMembran1 = 3;
const byte relaisPin_SpuelNachMembran = 2;

// LED Ausgänge

const byte LED_rot_aus = 28;
const byte LED_gelb_wenig = 29;
const byte LED_gruen_mittel = 30;
const byte LED_blau_viel = 31;

// Taster Eingänge

const byte tasterPin_Stop = 24;
const byte tasterPin_Wenig = 25;
const byte tasterPin_Mittel = 26;
const byte tasterPin_Viel = 27;

const unsigned long zeit6H = 21600000UL;

const byte relayPins[] = {
  relaisPin_SpuelNachMembran, relaisPin_SpuelVorMembran1,
  relaisPin_SpuelVorMembran2, relaisPin_SpuelVorMembran3,
  relaisPin_Leitungswasser, relaisPin_Reinstwasser,
  relaisPin_Pumpe
};

const byte butLedPins[] = { LED_rot_aus, LED_gelb_wenig, LED_gruen_mittel, LED_blau_viel };
const byte buttonPins[] = { tasterPin_Stop, tasterPin_Wenig, tasterPin_Mittel, tasterPin_Viel };
#define NUMBUTTONS sizeof(buttonPins)
enum sels {
  selStop, selWenig, selMittel, selViel,
};

enum Zustaende {
  unbeschaeftigt,
  stopped,
  spuelStart,   spuelPhase1,  spuelPause,  spuelPhase2,
  shortStart,   shortPhase1,  shortPause,  shortPhase2,
  doubleStart,  doublePhase1, doublePause, doublePhase2,
  longStart,    longPhase1,   longPause,   longPhase2,
};

Bounce key[NUMBUTTONS];

byte aktuellerZustand = unbeschaeftigt;

unsigned long currentMillis;
unsigned long lastTransition;
unsigned long letzteSpuelung;

void setup() {
  Serial.begin(250000);
  Serial.println(F("Button test"));
  for (byte i = 0; i < NUMBUTTONS; i++) {
    pinMode(butLedPins[i], OUTPUT);
    key[i].attach(buttonPins[i], INPUT_PULLUP);
  }
  for (byte i = 0; i < sizeof(relayPins); i++) {
    digitalWrite(relayPins[i], HIGH);
    pinMode(relayPins[i], OUTPUT);
  }
}

void loop() {
  currentMillis = millis();
  for (byte i = 0; i < NUMBUTTONS; i++) {
    key[i].update();
  }
  if (aktuellerZustand != unbeschaeftigt) {
    if (key[selStop].fell()) {
      if (aktuellerZustand != stopped) {
        setupAndGoToState(0b0001, 0b01111111, false, stopped, PSTR("Stopped"));
      } else {
        setKeyLeds(0b0000);
        aktuellerZustand = unbeschaeftigt;
      }
    }
  } else {
    if (key[selWenig].fell()) {
      aktuellerZustand = shortStart;
    } else if (key[selMittel].fell()) {
      aktuellerZustand = doubleStart;
    } else if (key[selViel].fell()) {
      aktuellerZustand = longStart;
    }
  }
  switch (aktuellerZustand) {
    case unbeschaeftigt:
      if (currentMillis - letzteSpuelung >= zeit6H) {
        letzteSpuelung = currentMillis;
        aktuellerZustand = spuelStart;
      }
      break;

    case stopped:
      break;

    case spuelStart:
      setupAndGoToState(0b0001, 0b0001111, true, spuelPhase1, PSTR("Test")); // mit 8 0b0101111
      break;
    case spuelPhase1:
      switchAndNewStateAfter(0b0001111, false, spuelPause, 20000);  // mit 8 0b0101111
      break;
    case spuelPause:
      switchAndNewStateAfter(0b0001001, true, spuelPhase2, 10);  // mit 8 0b0101001
      break;
    case spuelPhase2:
      switchAndNewStateAfter(0b0001001, false, unbeschaeftigt, 15000);  // mit 8 0b0101001
      break;

    case shortStart:
      setupAndGoToState(0b0011, 0b0101001, true, shortPhase1, PSTR("300 ml"));
      break;
    case shortPhase1:
      switchAndNewStateAfter(0b0101001, false, shortPause, 15000);
      break;
    case shortPause:
      switchAndNewStateAfter(0b0111000, true, shortPhase2, 500);
      break;
    case shortPhase2:
      switchAndNewStateAfter(0b0111000, false, unbeschaeftigt, 20000);
      break;

    case doubleStart:
      setupAndGoToState(0b0101, 0b0101001, true, doublePhase1, PSTR("1000 ml"));
      break;
    case doublePhase1:
      switchAndNewStateAfter(0b0101001, false, doublePause, 15000);
      break;
    case doublePause:
      switchAndNewStateAfter(0b0111000, true, shortPhase2, 500);
      break;
    case doublePhase2:
      switchAndNewStateAfter(0b0111000, false, unbeschaeftigt, 60000UL);
      break;

    case longStart:
      setupAndGoToState(0b1001, 0b0101001, true, longPhase1, PSTR("8000 ml"));
      break;
    case longPhase1:
      switchAndNewStateAfter(0b0101001, false, longPause, 15000);
      break;
    case longPause:
      switchAndNewStateAfter(0b0111000, true, longPhase2, 500);
      break;
    case longPhase2:
      switchAndNewStateAfter(0b0111000, false, unbeschaeftigt, 480000UL);
      break;
  }
  benchmark();
}

void switchRelaisSet(byte mask, bool toWhat) {
  for (byte idx = 1; mask; idx++, mask >>= 1) {
    if (mask & 1) {
      digitalWrite(relayPins[idx], toWhat);
    }
  }
}

void setKeyLeds(byte mask) {
  for (byte idx = 0; mask; idx++, mask >>= 1) {
    digitalWrite(butLedPins[idx], mask & 1);
  }
}

void setupAndGoToState(byte ledMask, byte mask, bool toWhat, byte newState, char* txt) {
  setKeyLeds(ledMask);
  switchRelaisSet(mask, toWhat);
  lastTransition = currentMillis;
  aktuellerZustand = newState;
  Serial.print(F("  "));
  Serial.print((__FlashStringHelper*)txt);
  Serial.write(' ');
  Serial.println(currentMillis);
}

void switchAndNewStateAfter(byte mask, bool toWhat, byte newState, unsigned long duration) {
  if (currentMillis - lastTransition >= duration) {
    switchRelaisSet(mask, toWhat);
    Serial.print(F("  "));
    Serial.print(aktuellerZustand);
    Serial.print(F(" -> "));
    Serial.print(newState);
    Serial.print(F(" nach "));
    Serial.print(currentMillis - lastTransition);
    Serial.println();
    lastTransition = currentMillis;
    aktuellerZustand = newState;
    if (newState == unbeschaeftigt) {
      setKeyLeds(0b0000);
    }
  }
}

void benchmark() {
  static unsigned long counterStartTime;
  static unsigned long counter;
  ++counter;
  if (micros() - counterStartTime >= 5000000) {
    Serial.print(F("Average Time per loop(): "));
    Serial.print((micros() - counterStartTime) / counter);
    Serial.println(F(" microseconds"));
    counter = 0;
    counterStartTime = micros();
  }
}

Versuche nun seit Stunden den letzten Sketch zu verstehen.

Leider mit nur mäßigem Erfolg.
Ein Bild meines Anlagensimulators folgt.

Die Eingabe der Taster funktioniert zu 95 % gut (Kontrolle über den Serial-Monitor). Leider machen die Leds nicht ganz das was sie sollen, und die Zustände der angesteuerten Relais sind unplausibl.

Ich habe mir überlegt, ich beginne damit die Funktion der Leds zu korrigieren.

der_anfaenger:
Die Eingabe der Taster funktioniert zu 95 % gut (Kontrolle über den Serial-Monitor). Leider machen die Leds nicht ganz das was sie sollen, und die Zustände der angesteuerten Relais sind unplausibl.

Sorry wegen der Relais, ersetze

     digitalWrite(relayPins[idx], toWhat);

durch

     digitalWrite(relayPins[idx], !toWhat);

Die Endebedingung der for-Schleife für die Leds war schlecht, versuche mal

void setKeyLeds(byte mask) {
  for (byte idx = 0; idx<NUMBUTTONS; idx++, mask >>= 1) {
    digitalWrite(butLedPins[idx], mask & 1);
  }
}

Leds und Relais werden über die Bitmasken gesteuert,
bei den Relais werden alle ausgewählten ein oder ausgestellt,
bei den Leds wird die Bitmaske auf die Leds übertragen.

Guten Abend,

Vielen Dank Whandall!

Jetzt Funktionieren die Leds schon sehr gut und die Taster auch. Die Relais lassen sich auch wunderbar an und ausschalten über den Binärcode. Es passiert fast genau das was ich möchte.

Warum fast. Die Leds leuchten dann, wenn sie aus sein sollen und sind an, wenn Sie aus sein sollen.

Ich habe bis jetzt die Stelle zum Invertieren noch nicht gefunden.

Und der relaisPin_SpuelNachMembran = 2 wird einfach nicht angesteuert warum verstehe ich leider nicht.

Ist die Anzahl der Zeichen der Maske ausgereizt? Wird die Feldlänge der Maske irgendwo definiert? Oder gibt es da eine Standardfeldlänge?

Bin schon voll glücklich mit eurer besonders mit der Hilfe von Whandall bis hier gekommen zu sein.

Wenn du jetzt noch deine aktuelle Version posten würdest, könnte man dir sogar weiter helfen. :wink:

der_anfaenger:
Warum fast. Die Leds leuchten dann, wenn sie aus sein sollen und sind an, wenn Sie aus sein sollen.

Das könnte auch an deiner Beschaltung liegen, mein Kode ging von normalen Leds aus, d.h. HIGH = an.
Kann man natürlich leicht ändern.

Guten Tag,

Vielen Dank noch mal Whandall,

ich habe nun fast alle Probleme des Sketch behoben.

Es ist jetzt ein Luxus-Problem geblieben.

Ich habe in den Ablauf noch den relaisPin_test hinzugefügt, dadurch wird jetzt Auch der relaisPin_SpuelNachMembran 2 richtig abgefragt. Ich weiß so macht man es bestimmt nicht, aber es funktioniert.

const byte relayPins[] = {
  relaisPin_test, relaisPin_SpuelVorMembran3,
  relaisPin_SpuelVorMembran2, relaisPin_SpuelVorMembran1, relaisPin_SpuelNachMembran,
  relaisPin_Leitungswasser, relaisPin_Reinstwasser,
  relaisPin_Pumpe,

Außerdem habe ich die Leds in der Schaltung von Masse geschaltet zu Plus geschaltet umgeklemmt. =>
Alle Leds funktionieren super.

Ich habe ebenfalls noch "Arbeitszustande" druckabbauan* und druckabbauaus* hinzugefügt. Diese "Entlasten" die Anlage in dem sie den relaisPin_SpuelNachMembran 2 für 2 Sekunden ansteuert.

enum Zustaende {
  unbeschaeftigt,
  stopped,
  spuelStart,   spuelPhase1,  spuelPause,  spuelPhase2, druckabbauan1, druckabbauaus1,
  shortStart,   shortPhase1,  shortPause,  shortPhase2, druckabbauan2, druckabbauaus2,
  doubleStart,  doublePhase1, doublePause, doublePhase2, druckabbauan3, druckabbauaus3,
  longStart,    longPhase1,   longPause,   longPhase2, druckabbauan4, druckabbauaus4,
  druckabbauan5, druckabbauaus5,
};

Dies funktioniert auch super, doch leider nicht bei der Abbruchfunktion. Ich habe die Funktion von

if (aktuellerZustand != unbeschaeftigt) {
    if (key[selStop].fell()) {
      if (aktuellerZustand != stopped) {
        setupAndGoToState(0b0001, 0b01111111, false, stopped, PSTR("Stopped"));
      } else{
        setKeyLeds(0b0000);
        aktuellerZustand = unbeschaeftigt;
      }
    }
  } else {
    if (key[selWenig].fell()) {
      aktuellerZustand = shortStart;
    } else if (key[selMittel].fell()) {
      aktuellerZustand = doubleStart;
    } else if (key[selViel].fell()) {
      aktuellerZustand = longStart;
    }
  }

zu

if (aktuellerZustand != unbeschaeftigt) {
    if (key[selStop].fell()) {
      if (aktuellerZustand != stopped) {
        setupAndGoToState(0b0001, 0b01111111, false, stopped, PSTR("Stopped"));
        setupAndGoToState(0b0001, 0b00001000, true, druckabbauan5, 10, PSTR("Druckabbauan"));
        setupAndGoToState(0b0001, 0b00001000, false, druckabbauaus5, 2000, PSTR("Druckabbauaus"));
        setKeyLeds(0b0000);
        aktuellerZustand = unbeschaeftigt;

      } else{
        setKeyLeds(0b0000);
        aktuellerZustand = unbeschaeftigt;
      }
    }
  } else {
    if (key[selWenig].fell()) {
      aktuellerZustand = shortStart;
    } else if (key[selMittel].fell()) {
      aktuellerZustand = doubleStart;
    } else if (key[selViel].fell()) {
      aktuellerZustand = longStart;
    }
  }

geändert. Doch dieser Code lässt sich nicht einmal kompilieren. Was habe ich falsch gemacht?

Im nächsten Post füge ich noch den kompletten Code mit an.

Kompletter Code:

#include <Bounce2.h>

const byte relaisPin_test =  9;
const byte relaisPin_Pumpe =  8;
const byte relaisPin_Reinstwasser =  7;
const byte relaisPin_Leitungswasser =  6;
const byte relaisPin_SpuelVorMembran3 = 5;
const byte relaisPin_SpuelVorMembran2 = 4;
const byte relaisPin_SpuelVorMembran1 = 3;
const byte relaisPin_SpuelNachMembran = 2;

// LED Ausgänge

const byte LED_rot_aus = 28;
const byte LED_gelb_wenig = 29;
const byte LED_gruen_mittel = 30;
const byte LED_blau_viel = 31;

// Taster Eingänge

const byte tasterPin_Stop = 24;
const byte tasterPin_Wenig = 25;
const byte tasterPin_Mittel = 26;
const byte tasterPin_Viel = 27;

const unsigned long zeit6H = 21600000UL;

const byte relayPins[] = {
  relaisPin_test, relaisPin_SpuelVorMembran3,
  relaisPin_SpuelVorMembran2, relaisPin_SpuelVorMembran1, relaisPin_SpuelNachMembran,
  relaisPin_Leitungswasser, relaisPin_Reinstwasser,
  relaisPin_Pumpe,
};

const byte butLedPins[] = { LED_rot_aus, LED_gelb_wenig, LED_gruen_mittel, LED_blau_viel };
const byte buttonPins[] = { tasterPin_Stop, tasterPin_Wenig, tasterPin_Mittel, tasterPin_Viel };
#define NUMBUTTONS sizeof(buttonPins)
enum sels {
  selStop, selWenig, selMittel, selViel,
};

enum Zustaende {
  unbeschaeftigt,
  stopped,
  spuelStart,   spuelPhase1,  spuelPause,  spuelPhase2, druckabbauan1, druckabbauaus1,
  shortStart,   shortPhase1,  shortPause,  shortPhase2, druckabbauan2, druckabbauaus2,
  doubleStart,  doublePhase1, doublePause, doublePhase2, druckabbauan3, druckabbauaus3,
  longStart,    longPhase1,   longPause,   longPhase2, druckabbauan4, druckabbauaus4,
  druckabbauan5, druckabbauaus5,
};

Bounce key[NUMBUTTONS];

byte aktuellerZustand = unbeschaeftigt;

unsigned long currentMillis;
unsigned long lastTransition;
unsigned long letzteSpuelung;

void setup() {
  Serial.begin(250000);
  Serial.println(F("Button test"));
  for (byte i = 0; i < NUMBUTTONS; i++) {
    pinMode(butLedPins[i], OUTPUT);
    key[i].attach(buttonPins[i], INPUT_PULLUP);
  }
  for (byte i = 0; i < sizeof(relayPins); i++) {
    digitalWrite(relayPins[i], HIGH);
    pinMode(relayPins[i], OUTPUT);
  }
}

void loop() {
  currentMillis = millis();
  for (byte i = 0; i < NUMBUTTONS; i++) {
    key[i].update();
  }
  if (aktuellerZustand != unbeschaeftigt) {
    if (key[selStop].fell()) {
      if (aktuellerZustand != stopped) {
        setupAndGoToState(0b0001, 0b01111111, false, stopped, PSTR("Stopped"));
//        setupAndGoToState(0b0001, 0b00001000, true, druckabbauan5, 10, PSTR("Druckabbauan"));
//        setupAndGoToState(0b0001, 0b00001000, false, druckabbauaus5, 2000, PSTR("Druckabbauaus"));
        setKeyLeds(0b0000);
        aktuellerZustand = unbeschaeftigt;

      } else{
        setKeyLeds(0b0000);
        aktuellerZustand = unbeschaeftigt;
      }
    }
  } else {
    if (key[selWenig].fell()) {
      aktuellerZustand = shortStart;
    } else if (key[selMittel].fell()) {
      aktuellerZustand = doubleStart;
    } else if (key[selViel].fell()) {
      aktuellerZustand = longStart;
    }
  }
  switch (aktuellerZustand) {
    case unbeschaeftigt:
      if (currentMillis - letzteSpuelung >= zeit6H) {
        letzteSpuelung = currentMillis;
        aktuellerZustand = spuelStart;
      }
      break;

    case stopped:
      break;

    case spuelStart:
      setupAndGoToState(0b0001, 0b00010111, true, spuelPhase1, PSTR("Test")); // mit 8 0b0101111
      break;
    case spuelPhase1:
      switchAndNewStateAfter(0b00010111, false, spuelPause, 30000);  // mit 8 0b0101111
      break;
    case spuelPause:
      switchAndNewStateAfter(0b00011000, true, spuelPhase2, 10);  // mit 8 0b0101001
      break;
    case spuelPhase2:
      switchAndNewStateAfter(0b00011000, false, druckabbauan1, 15000);  // mit 8 0b0101001
      break;
    case druckabbauan1:
      switchAndNewStateAfter(0b00001000, true, druckabbauaus1, 10);
      break;
    case druckabbauaus1:
      switchAndNewStateAfter(0b00001000, false, unbeschaeftigt, 2000);
      break;

    case shortStart:
      setupAndGoToState(0b0011, 0b01011000, true, shortPhase1, PSTR("300 ml"));//0b01011000
      break;
    case shortPhase1:
      switchAndNewStateAfter(0b01011000, false, shortPause, 10000);
      break;
    case shortPause:
      switchAndNewStateAfter(0b01110000, true, shortPhase2, 10);
      break;
    case shortPhase2:
      switchAndNewStateAfter(0b01110000, false, druckabbauan2, 20000);
      break;
       case druckabbauan2:
      switchAndNewStateAfter(0b00001000, true, druckabbauaus2, 10);
      break;
    case druckabbauaus2:
      switchAndNewStateAfter(0b00001000, false, unbeschaeftigt, 2000);
      break;

    case doubleStart:
      setupAndGoToState(0b0101, 0b00011000, true, doublePhase1, PSTR("1000 ml"));
      break;
    case doublePhase1:
      switchAndNewStateAfter(0b00011000, false, doublePause, 10000);
      break;
    case doublePause:
      switchAndNewStateAfter(0b01110000, true, shortPhase2, 10);
      break;
    case doublePhase2:
      switchAndNewStateAfter(0b01110000, false, druckabbauan3, 60000UL);
      break;
        case druckabbauan3:
      switchAndNewStateAfter(0b00001000, true, druckabbauaus3, 10);
      break;
    case druckabbauaus3:
      switchAndNewStateAfter(0b00001000, false, unbeschaeftigt, 2000);
      break;

    case longStart:
      setupAndGoToState(0b1001, 0b00011000, true, longPhase1, PSTR("8000 ml"));
      break;
    case longPhase1:
      switchAndNewStateAfter(0b00011000, false, longPause, 10000);
      break;
    case longPause:
      switchAndNewStateAfter(0b01110000, true, longPhase2, 10);
      break;
    case longPhase2:
      switchAndNewStateAfter(0b01110000, false, druckabbauan4, 600000UL);
      break;
    case druckabbauan4:
      switchAndNewStateAfter(0b00001000, true, druckabbauaus4, 10);
      break;
    case druckabbauaus4:
      switchAndNewStateAfter(0b00001000, false, unbeschaeftigt, 2000);
      break;
      
  }
  benchmark();
}

void switchRelaisSet(byte mask, bool toWhat) {
  for (byte idx = 1; mask; idx++, mask >>= 1) {
    if (mask & 1) {
      digitalWrite(relayPins[idx], !toWhat);
    }
  }
}

void setKeyLeds(byte mask) {
  for (byte idx = 0; idx<NUMBUTTONS; idx++, mask >>= 1) {
    digitalWrite(butLedPins[idx], mask & 1);
  }
}

void setupAndGoToState(byte ledMask, byte mask, bool toWhat, byte newState, char* txt) {
  setKeyLeds(ledMask);
  switchRelaisSet(mask, toWhat);
  lastTransition = currentMillis;
  aktuellerZustand = newState;
  Serial.print(F("  "));
  Serial.print((__FlashStringHelper*)txt);
  Serial.write(' ');
  Serial.println(currentMillis);
}

void switchAndNewStateAfter(byte mask, bool toWhat, byte newState, unsigned long duration) {
  if (currentMillis - lastTransition >= duration) {
    switchRelaisSet(mask, toWhat);
    Serial.print(F("  "));
    Serial.print(aktuellerZustand);
    Serial.print(F(" -> "));
    Serial.print(newState);
    Serial.print(F(" nach "));
    Serial.print(currentMillis - lastTransition);
    Serial.println();
    lastTransition = currentMillis;
    aktuellerZustand = newState;
    if (newState == unbeschaeftigt) {
      setKeyLeds(0b0000);
    }
  }
}

void benchmark() {
  static unsigned long counterStartTime;
  static unsigned long counter;
  ++counter;
  if (micros() - counterStartTime >= 5000000) {
    Serial.print(F("Average Time per loop(): "));
    Serial.print((micros() - counterStartTime) / counter);
    Serial.println(F(" microseconds"));
    counter = 0;
    counterStartTime = micros();
  }
}

Ich habe eben noch zwei Case's (druckabbauan5 und druckabbauaus5) in den Switch eingefügt

case druckabbauan5:
      switchAndNewStateAfter(0b00001000, true, druckabbauaus5, 10);
      break;
    case druckabbauaus5:
      switchAndNewStateAfter(0b00001000, false, unbeschaeftigt, 2000);
      break;

und diesen mit der Stop Funktion gestartet (druckabbauan5 anstelle von stopped).

if (aktuellerZustand != druckabbauan5) {
        setupAndGoToState(0b0001, 0b01111111, false, druckabbauan5, PSTR("Stopped"));
      } else{

Es funktioniert.

kann es damit Probleme geben?

Da der Druckabbau bei allen der gleiche Vorgang zu sein scheint,
könntest du dir die Vervielfachung sparen und einen gemeinsamen Abschluss benutzen.

//        setupAndGoToState(0b0001, 0b00001000, true, druckabbauan5, 10, PSTR("Druckabbauan"));
//        setupAndGoToState(0b0001, 0b00001000, false, druckabbauaus5, 2000, PSTR("Druckabbauaus"));
        setKeyLeds(0b0000);
        aktuellerZustand = unbeschaeftigt;

Diese Zeilen sind Quatsch, entferne die wieder.

Ungetesteter leicht überarbeiteter Vorschlag:

#include <Bounce2.h>

const byte relaisPin_Pumpe =  8;
const byte relaisPin_Reinstwasser =  7;
const byte relaisPin_Leitungswasser =  6;
const byte relaisPin_SpuelVorMembran3 = 5;
const byte relaisPin_SpuelVorMembran2 = 4;
const byte relaisPin_SpuelVorMembran1 = 3;
const byte relaisPin_SpuelNachMembran = 2;

// LED Ausgänge

const byte LED_rot_aus = 28;
const byte LED_gelb_wenig = 29;
const byte LED_gruen_mittel = 30;
const byte LED_blau_viel = 31;

// Taster Eingänge

const byte tasterPin_Stop = 24;
const byte tasterPin_Wenig = 25;
const byte tasterPin_Mittel = 26;
const byte tasterPin_Viel = 27;

const unsigned long zeit6H = 21600000UL;

const byte relayPins[] = {
  relaisPin_SpuelVorMembran3, relaisPin_SpuelVorMembran2, relaisPin_SpuelVorMembran1,
  relaisPin_SpuelNachMembran,  relaisPin_Leitungswasser, relaisPin_Reinstwasser,
  relaisPin_Pumpe,
};

const char rn0[] PROGMEM = "SpuelVorMembran3";
const char rn1[] PROGMEM = "SpuelVorMembran2";
const char rn2[] PROGMEM = "SpuelVorMembran1";
const char rn3[] PROGMEM = "SpuelNachMembran";
const char rn4[] PROGMEM = "Leitungswasser";
const char rn5[] PROGMEM = "Reinstwasser";
const char rn6[] PROGMEM = "Pumpe";

const char * const relaisNamen[] PROGMEM { rn0, rn1, rn2, rn3, rn4, rn5, rn6 };

const byte butLedPins[] = { LED_rot_aus, LED_gelb_wenig, LED_gruen_mittel, LED_blau_viel };
const byte buttonPins[] = { tasterPin_Stop, tasterPin_Wenig, tasterPin_Mittel, tasterPin_Viel };
#define NUMBUTTONS sizeof(buttonPins)
enum sels {
  selStop, selWenig, selMittel, selViel,
};

enum Zustaende {
  unbeschaeftigt,
  stopped,
  spuelStart,   spuelPhase1,  spuelPause,  spuelPhase2,
  shortStart,   shortPhase1,  shortPause,  shortPhase2,
  doubleStart,  doublePhase1, doublePause, doublePhase2,
  longStart,    longPhase1,   longPause,   longPhase2,
  druckAbbauEin, druckAbbauAus,
};

Bounce key[NUMBUTTONS];

byte aktuellerZustand = unbeschaeftigt;

unsigned long currentMillis;
unsigned long lastTransition;
unsigned long letzteSpuelung;

void setup() {
  Serial.begin(250000);
  Serial.println(F("Button test"));
  for (byte i = 0; i < NUMBUTTONS; i++) {
    pinMode(butLedPins[i], OUTPUT);
    key[i].attach(buttonPins[i], INPUT_PULLUP);
  }
  for (byte i = 0; i < sizeof(relayPins); i++) {
    digitalWrite(relayPins[i], HIGH);
    pinMode(relayPins[i], OUTPUT);
  }
}

void loop() {
  currentMillis = millis();
  for (byte i = 0; i < NUMBUTTONS; i++) {
    key[i].update();
  }
  if (aktuellerZustand != unbeschaeftigt) {
    if (key[selStop].fell()) {
      if (aktuellerZustand != stopped) {
        setupAndGoToState(0b0001, 0b01111111, false, stopped, PSTR("Stopped"));
      } else {
        setKeyLeds(0b0000);
        aktuellerZustand = unbeschaeftigt; // u.U. druckAbbauEin?
      }
    }
  } else {
    if (key[selWenig].fell()) {
      aktuellerZustand = shortStart;
    } else if (key[selMittel].fell()) {
      aktuellerZustand = doubleStart;
    } else if (key[selViel].fell()) {
      aktuellerZustand = longStart;
    }
  }
  switch (aktuellerZustand) {
    case unbeschaeftigt:
      if (currentMillis - letzteSpuelung >= zeit6H) {
        letzteSpuelung = currentMillis;
        aktuellerZustand = spuelStart;
      }
      break;

    case stopped:
      break;

    case spuelStart:
      setupAndGoToState(0b0001, 0b00010111, true, spuelPhase1, PSTR("Test")); // mit 8 0b0101111
      break;
    case spuelPhase1:
      switchAndNewStateAfter(0b00010111, false, spuelPause, 30000);  // mit 8 0b0101111
      break;
    case spuelPause:
      switchAndNewStateAfter(0b00011000, true, spuelPhase2, 10);  // mit 8 0b0101001
      break;
    case spuelPhase2:
      switchAndNewStateAfter(0b00011000, false, druckAbbauEin, 15000);  // mit 8 0b0101001
      break;

    case shortStart:
      setupAndGoToState(0b0011, 0b01011000, true, shortPhase1, PSTR("300 ml"));//0b01011000
      break;
    case shortPhase1:
      switchAndNewStateAfter(0b01011000, false, shortPause, 10000);
      break;
    case shortPause:
      switchAndNewStateAfter(0b01110000, true, shortPhase2, 10);
      break;
    case shortPhase2:
      switchAndNewStateAfter(0b01110000, false, druckAbbauEin, 20000);

    case doubleStart:
      setupAndGoToState(0b0101, 0b00011000, true, doublePhase1, PSTR("1000 ml"));
      break;
    case doublePhase1:
      switchAndNewStateAfter(0b00011000, false, doublePause, 10000);
      break;
    case doublePause:
      switchAndNewStateAfter(0b01110000, true, shortPhase2, 10);
      break;
    case doublePhase2:
      switchAndNewStateAfter(0b01110000, false, druckAbbauEin, 60000UL);
      break;

    case longStart:
      setupAndGoToState(0b1001, 0b00011000, true, longPhase1, PSTR("8000 ml"));
      break;
    case longPhase1:
      switchAndNewStateAfter(0b00011000, false, longPause, 10000);
      break;
    case longPause:
      switchAndNewStateAfter(0b01110000, true, longPhase2, 10);
      break;
    case longPhase2:
      switchAndNewStateAfter(0b01110000, false, druckAbbauEin, 600000UL);
      break;

    case druckAbbauEin:
      switchAndNewStateAfter(0b00001000, true, druckAbbauAus, 10);
      break;
    case druckAbbauAus:
      switchAndNewStateAfter(0b00001000, false, unbeschaeftigt, 2000);
      break;
  }
  benchmark();
}

void switchRelaisSet(byte mask, bool toWhat) {
  Serial.print(F("Schalte Relais "));
  for (byte idx = 0; mask; idx++, mask >>= 1) {
    if (mask & 1) {
      digitalWrite(relayPins[idx], !toWhat);
      Serial.print((__FlashStringHelper*)pgm_read_word(relaisNamen[idx]));
      if (mask != 1) {
        Serial.print(F(", "));
      }
    }
  }
  Serial.print(toWhat ? F(" EIN ") : F(" AUS "));
}

void setKeyLeds(byte mask) {
  for (byte idx = 0; idx < NUMBUTTONS; idx++, mask >>= 1) {
    digitalWrite(butLedPins[idx], mask & 1);
  }
}

void setupAndGoToState(byte ledMask, byte mask, bool toWhat, byte newState, char* txt) {
  setKeyLeds(ledMask);
  switchRelaisSet(mask, toWhat);
  lastTransition = currentMillis;
  aktuellerZustand = newState;
  Serial.print(F("  "));
  Serial.print((__FlashStringHelper*)txt);
  Serial.write(' ');
  Serial.println(currentMillis);
}

void switchAndNewStateAfter(byte mask, bool toWhat, byte newState, unsigned long duration) {
  if (currentMillis - lastTransition >= duration) {
    switchRelaisSet(mask, toWhat);
    Serial.print(F("  "));
    Serial.print(aktuellerZustand);
    Serial.print(F(" -> "));
    Serial.print(newState);
    Serial.print(F(" nach "));
    Serial.print(currentMillis - lastTransition);
    Serial.println();
    lastTransition = currentMillis;
    aktuellerZustand = newState;
    if (newState == unbeschaeftigt) {
      setKeyLeds(0b0000);
    }
  }
}

void benchmark() {
  static unsigned long counterStartTime;
  static unsigned long counter;
  ++counter;
  if (micros() - counterStartTime >= 5000000) {
    Serial.print(F("Average Time per loop(): "));
    Serial.print((micros() - counterStartTime) / counter);
    Serial.println(F(" microseconds"));
    counter = 0;
    counterStartTime = micros();
  }
}

Ich habe etwas Kode hinzugefügt der bei jedesmal ausgibt welche Relais wie geschaltet werden.
Das könnte dir bei der Beantwortung von "könnte das Probleme geben" helfen.
Ansonsten testen wie ein Anwender. jederzeit auf allen Knöfen rumdrücken, auch gleichzeigt etc.

Die Tasten sind mit der Library doch wirklich einfach zu beherrschen, findest du nicht?

Guten Abend Whandall,

boa krass. Schon wieder eine neue Version des Codes. Danke, dass du mir die Freude am "Programmieren" gezeigt hast. Vielen, vielen Dank für deine Hilfe.

Ich habe die letzten zwei Tage gebaut, gelötet, gesteckt, kompeliert, hochgeladen, getestet und den Code angepasst.

Fazit: Ich habe, zwei Wasserfilteranlagen umgebaut. Diese laufen jetzt nahezu perfekt mit dem "alten" leicht angepassten Code.

Code folgt im nächsten Post (zu viel Zeichen).

Einziger "Fehler". Man kann, während die Stop-Taste aktiv ist, die Stop-Funktion immer wieder erneut starten.

Damit kann ich leben, da dadurch keine Einschränkungen entstehen. Die Anlagen laufen super.

Ein weiteres Problem: Jetzt sind beide Mega's verbaut und nun habe ich keinen mehr für den Simulator. Behelfe mir nun für den Übergang mit einem der alten UNO's. Ein weiterer Mega ist schon bestellt und auf dem Weg zu mir. Überlege mir gerade, ob ich mir das passende Kabel-Krimp-Equipment zulege.

Mein Ziel ist es noch, in der nächsten Zeit die Wasserstop-Funktion einzubauen und den Hochdruck- und den Niederdruckschalter einzubauen. Da weiß ich aber noch nicht, wie die geschaltet sein sollen. Ich habe dafür auch noch nicht die passende Hardware. Ein Blinken der Leds als Fehlermeldung wäre schön.

Außerdem überlege ich über eine Wasserqualitätsmessung und über ein Display, welches Betriebszustände und Details anzeigt.

Eine Filterwechselintervall -und Membran-Zustands-Anzeige wäre eventuell eine Option.

Aber dafür muss ich mir noch Gedanken machen, wie ich diese Spielereien realisiere.

Ich habe eben deinen neusten Code-Vorschlag für den UNO umgeschrieben.
Der Code funktioniert nicht wie gewünscht. Schön wie subtil du mir immer wieder neue Möglichkeiten der Programmierung zeigst. Werde mich morgen mal an den neuen Code wagen und versuchen den zum "Rennen" zu bekommen.

So hier nun der Code:

 #include <Bounce2.h>

const byte relaisPin_test =  9;
const byte relaisPin_Pumpe =  8;
const byte relaisPin_Reinstwasser =  7;
const byte relaisPin_Leitungswasser =  6;
const byte relaisPin_SpuelVorMembran3 = 5;
const byte relaisPin_SpuelVorMembran2 = 4;
const byte relaisPin_SpuelVorMembran1 = 3;
const byte relaisPin_SpuelNachMembran = 2;

// LED Ausgänge

const byte LED_rot_aus = 28;
const byte LED_gelb_wenig = 29;
const byte LED_gruen_mittel = 30;
const byte LED_blau_viel = 31;

// Taster Eingänge

const byte tasterPin_Stop = 24;
const byte tasterPin_Wenig = 25;
const byte tasterPin_Mittel = 26;
const byte tasterPin_Viel = 27;

const unsigned long zeit6H = 14400000UL; //21600000UL 14400000UL

const byte relayPins[] = {
  relaisPin_test, relaisPin_SpuelVorMembran3,
  relaisPin_SpuelVorMembran2, relaisPin_SpuelVorMembran1, relaisPin_SpuelNachMembran,
  relaisPin_Leitungswasser, relaisPin_Reinstwasser,
  relaisPin_Pumpe,
};

const byte butLedPins[] = { LED_rot_aus, LED_gelb_wenig, LED_gruen_mittel, LED_blau_viel };
const byte buttonPins[] = { tasterPin_Stop, tasterPin_Wenig, tasterPin_Mittel, tasterPin_Viel };
#define NUMBUTTONS sizeof(buttonPins)
enum sels {
  selStop, selWenig, selMittel, selViel,
};

enum Zustaende {
  unbeschaeftigt,
  stopped,
  spuelStart,   spuelPhase1,  spuelPause,   spuelPhase2,  druckabbauan1, druckabbauaus1,
  shortStart,   shortPhase1,  shortPause1,  shortPhase2,  shortPause2,   shortPhase3,
  doubleStart,  doublePhase1, doublePause1, doublePhase2, doublePause2,  doublePhase3,
  longStart,    longPhase1,   longPause1,   longPhase2,   longPause2,    longPhase3,
 
};

Bounce key[NUMBUTTONS];

byte aktuellerZustand = unbeschaeftigt;

unsigned long currentMillis;
unsigned long lastTransition;
unsigned long letzteSpuelung;

void setup() {
  Serial.begin(250000);
  Serial.println(F("Button test"));
  for (byte i = 0; i < NUMBUTTONS; i++) {
    pinMode(butLedPins[i], OUTPUT);
    key[i].attach(buttonPins[i], INPUT_PULLUP);
  }
  for (byte i = 0; i < sizeof(relayPins); i++) {
    digitalWrite(relayPins[i], HIGH);
    pinMode(relayPins[i], OUTPUT);
  }
}

void loop() {
  currentMillis = millis();
  for (byte i = 0; i < NUMBUTTONS; i++) {
    key[i].update();
  }
  if (aktuellerZustand != unbeschaeftigt) {
    if (key[selStop].fell()) {
      if (aktuellerZustand != druckabbauan1) {
        setupAndGoToState(0b0001, 0b01111111, false, druckabbauan1, PSTR("Stopped"));
      } else{
        setKeyLeds(0b0000);
        aktuellerZustand = unbeschaeftigt;
      }
    }
  } else {
    if (key[selWenig].fell()) {
      aktuellerZustand = shortStart;
    } else if (key[selMittel].fell()) {
      aktuellerZustand = doubleStart;
    } else if (key[selViel].fell()) {
      aktuellerZustand = longStart;
    }
  }
  switch (aktuellerZustand) {
    case unbeschaeftigt:
      if (currentMillis - letzteSpuelung >= zeit6H) {
        letzteSpuelung = currentMillis;
        aktuellerZustand = spuelStart;
      }
      break;

    case stopped:
      break;

    case spuelStart:
      setupAndGoToState(0b1111, 0b00010111, true, spuelPhase1, PSTR("Test")); // mit 8 0b0101111
      break;
    case spuelPhase1:
      switchAndNewStateAfter(0b00010111, false, spuelPause, 30000);  // mit 8 0b0101111
      break;
    case spuelPause:
      switchAndNewStateAfter(0b00011000, true, spuelPhase2, 10);  // mit 8 0b0101001
      break;
    case spuelPhase2:
      switchAndNewStateAfter(0b00011000, false, druckabbauan1, 20000);  // mit 8 0b0101001
      break;
    case druckabbauan1:
      switchAndNewStateAfter(0b00001000, true, druckabbauaus1, 10);
      break;
    case druckabbauaus1:
      switchAndNewStateAfter(0b00001000, false, unbeschaeftigt, 15000);
      break;

    case shortStart:
      setupAndGoToState(0b0011, 0b01010111, true, shortPhase1, PSTR("300 ml"));//0b01011000
      break;
    case shortPhase1:
      switchAndNewStateAfter(0b01010111, false, shortPause1, 7000);
      break;
    case shortPause1:
      setupAndGoToState(0b0011, 0b01011000, true, shortPhase2,10);
      break;
    case shortPhase2:
      switchAndNewStateAfter(0b01011000, false, shortPause2, 7000);
      break;
    case shortPause2:
      switchAndNewStateAfter(0b01110000, true, shortPhase3, 10);
      break;
    case shortPhase3:
      switchAndNewStateAfter(0b01110000, false, druckabbauan1, 20000);
      break;
       
    case doubleStart:
      setupAndGoToState(0b0101, 0b01010111, true, doublePhase1, PSTR("1000 ml"));
      break;
    case doublePhase1:
      switchAndNewStateAfter(0b001010111, false, doublePause1, 7000);
      break;
    case doublePause1:
      setupAndGoToState(0b0101, 0b01011000, true, doublePhase2, 10);
      break;
    case doublePhase2:
      switchAndNewStateAfter(0b001011000, false, doublePause2, 7000);
      break;
    case doublePause2:
      switchAndNewStateAfter(0b01110000, true, shortPhase3, 10);
      break;
    case doublePhase3:
      switchAndNewStateAfter(0b01110000, false, druckabbauan1, 60000UL);
      break;
        
    case longStart:
      setupAndGoToState(0b1001, 0b01010111, true, longPhase1, PSTR("8000 ml"));
      break;
    case longPhase1:
      switchAndNewStateAfter(0b01010111, false, longPause1, 7000);
      break;
    case longPause1:
      setupAndGoToState(0b1001, 0b01011000, true, longPhase2, 10);
      break;
    case longPhase2:
      switchAndNewStateAfter(0b01011000, false, longPause2, 7000);
      break;
    case longPause2:
      switchAndNewStateAfter(0b01110000, true, longPhase3, 10);
      break;
    case longPhase3:
      switchAndNewStateAfter(0b01110000, false, druckabbauan1, 600000UL);
      break;
          
  }
  benchmark();
}

void switchRelaisSet(byte mask, bool toWhat) {
  for (byte idx = 1; mask; idx++, mask >>= 1) {
    if (mask & 1) {
      digitalWrite(relayPins[idx], !toWhat);
    }
  }
}

void setKeyLeds(byte mask) {
  for (byte idx = 0; idx<NUMBUTTONS; idx++, mask >>= 1) {
    digitalWrite(butLedPins[idx], mask & 1);
  }
}

void setupAndGoToState(byte ledMask, byte mask, bool toWhat, byte newState, char* txt) {
  setKeyLeds(ledMask);
  switchRelaisSet(mask, toWhat);
  lastTransition = currentMillis;
  aktuellerZustand = newState;
  Serial.print(F("  "));
  Serial.print((__FlashStringHelper*)txt);
  Serial.write(' ');
  Serial.println(currentMillis);
}

void switchAndNewStateAfter(byte mask, bool toWhat, byte newState, unsigned long duration) {
  if (currentMillis - lastTransition >= duration) {
    switchRelaisSet(mask, toWhat);
    Serial.print(F("  "));
    Serial.print(aktuellerZustand);
    Serial.print(F(" -> "));
    Serial.print(newState);
    Serial.print(F(" nach "));
    Serial.print(currentMillis - lastTransition);
    Serial.println();
    lastTransition = currentMillis;
    aktuellerZustand = newState;
    if (newState == unbeschaeftigt) {
      setKeyLeds(0b0000);
    }
  }
}

void benchmark() {
  static unsigned long counterStartTime;
  static unsigned long counter;
  ++counter;
  if (micros() - counterStartTime >= 5000000) {
    Serial.print(F("Average Time per loop(): "));
    Serial.print((micros() - counterStartTime) / counter);
    Serial.println(F(" microseconds"));
    counter = 0;
    counterStartTime = micros();
  }
}

Vielen Dank für deine Hilfe.

der_anfaenger:
Schon wieder eine neue Version des Codes.

Na ja, war schon einen guten Tag alt als du das entdeckt hast.

der_anfaenger:
Einziger "Fehler". Man kann, während die Stop-Taste aktiv ist, die Stop-Funktion immer wieder erneut starten.

Du hast ja auch den State stopped wegoptimiert.

der_anfaenger:
Mein Ziel ist es noch, in der nächsten Zeit die Wasserstop-Funktion einzubauen und den Hochdruck- und den Niederdruckschalter einzubauen. Da weiß ich aber noch nicht, wie die geschaltet sein sollen. Ich habe dafür auch noch nicht die passende Hardware. Ein Blinken der Leds als Fehlermeldung wäre schön.

Außerdem überlege ich über eine Wasserqualitätsmessung und über ein Display, welches Betriebszustände und Details anzeigt.

Eine Filterwechselintervall -und Membran-Zustands-Anzeige wäre eventuell eine Option.

Wenn du genau definierst was wann passieren soll, kann man dir da helfen.

Wenn du ein schönes Display haben willst, solltest du dir mal die Nextion Displays ansehen.
Da du Megas benutzt, kannst du die zusätzliche(n) seriellen Schnittstellen sinnvoll einsetzen.