Probleme beim durchlaufen einer if Anweisung im loop Teil

Hallo. Ich habe eine Anlage gebaut, um Getränke zu mischen. Ich habe dazu auch ein Programm geschrieben. Das Programm ergibt aus meiner Sicht auch ziemlich Sinn. Die Beleuchtung der Taster funktioniert auch super.

Nun zum Problem: Sobald der Starttaster gedrückt wurde, wird die Variable start auf true gesetzt. Im Loop-Teil springt der Compiler dann auch in die if-Anweisung, bearbeitet aber nur den Anfang der if-Anweisung. Die Systemausgaben werden auf dem seriellen Monitor ausgegeben, die Delays aber nicht ausgeführt. Das sieht man auch an der Systemausgabe, da er nach der Ausgabe von 2000 direkt wieder loop ausgibt.

Ich bedanke mich schon mal bei jedem, der sich mein Programm durchliest, da es sich aus meiner Sicht um eine knifflige Angelegenheit handelt.

//---Logische Variablen festlegen
volatile boolean starten = false;
volatile char gewaehlterAlc;
volatile char gewaehlterDrink;

double flussratePumpe = 8.333;
double flussrateVentil = 35.000;              // Muss noch genau ermittelt werden
double pumpenDelay;
double ventilDelay;
int becherInhalt = 400;
int mischVerhaeltniss; // Setze hier einen Standardwert

// Variablen für Debouncing
unsigned long lastDebounceTimeAlcA = 0;
unsigned long lastDebounceTimeAlcB = 0;
unsigned long lastDebounceTimeAlcC = 0;
unsigned long lastDebounceTimeDrinkA = 0;
unsigned long lastDebounceTimeDrinkB = 0;
unsigned long lastDebounceTimeDrinkC = 0;
unsigned long lastDebounceTimeStart = 0;
const unsigned long debounceDelay = 50;  // Debounce-Verzögerung in ms

void setup() {
  pinMode(53, INPUT); // Pin 53 als Input festlegen für PinChange Interrupt
  pinMode(22, OUTPUT);  // IN1 -> AlcButtonA
  pinMode(23, OUTPUT);  // IN2 -> AlcButtonB
  pinMode(24, OUTPUT);  // IN3 -> AlcButtonC
  pinMode(25, OUTPUT);  // IN4 -> DrinkButtonA
  pinMode(26, OUTPUT);  // IN5 -> DrinkButtonB
  pinMode(27, OUTPUT);  // IN6 -> DrinkButtonC
  pinMode(28, OUTPUT);  // IN7 -> StartButton

  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(18, OUTPUT);
  pinMode(19, OUTPUT);
  pinMode(20, OUTPUT);
  pinMode(21, OUTPUT);

  //---Externe Interrupts Festlegen
  attachInterrupt(digitalPinToInterrupt(2), isrAlcButtonA, FALLING);
  attachInterrupt(digitalPinToInterrupt(3), isrAlcButtonB, FALLING);
  attachInterrupt(digitalPinToInterrupt(18), isrAlcButtonC, FALLING);
  attachInterrupt(digitalPinToInterrupt(19), isrDrinkButtonA, FALLING);
  attachInterrupt(digitalPinToInterrupt(20), isrDrinkButtonB, FALLING);
  attachInterrupt(digitalPinToInterrupt(21), isrStartButton, FALLING);

  // Pin-change-interrupt auf Pin 53 legen
  PCICR |= (1 << PCIE0);
  PCMSK0 |= (1 << PCINT0);

  //---Pins für Hardwarekomponenten festlegen
  pinMode(38, OUTPUT);  // mVentilA
  pinMode(39, OUTPUT);  // mVentilB
  pinMode(40, OUTPUT);  // mVentilC

  pinMode(32, OUTPUT);  // pumpeA
  pinMode(33, OUTPUT);  // pumpeA
  pinMode(34, OUTPUT);  // pumpeB
  pinMode(35, OUTPUT);  // pumpeB
  pinMode(36, OUTPUT);  // pumpeC
  pinMode(37, OUTPUT);  // pumpeC

  // Potentiometer
  pinMode(A1, INPUT);

  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println("---loop---");

  if (starten == true) {
    // Interrupts vorrübergehend deaktivieren
    noInterrupts();


    mischVerhaeltniss = analogRead(A1);
    mischVerhaeltniss = map(mischVerhaeltniss, 0, 1023, 0, 100);

    Serial.println("Startenausgefühtt");

    pumpenDelay = 2000;  //(becherInhalt * mischVerhaeltniss) / flussratePumpe;
    ventilDelay = 2000;  //((becherInhalt * (1 - mischVerhaeltniss))/flussrateVentil);

    Serial.println(pumpenDelay);
    Serial.println(ventilDelay);

    pumpe_an(gewaehlterAlc);
    delay(pumpenDelay);
    pumpe_aus(gewaehlterAlc);

    magnetVentile_an(gewaehlterDrink);
    delay(ventilDelay);
    magnetVentile_aus(gewaehlterDrink);


    starten = false;

    delay(500);

    // Interrupts aktivieren
    interrupts();

  }
  delay(200);
}

//---Interrupts mit Debouncing
void isrAlcButtonA() {
  unsigned long currentTime = millis();
  if (currentTime - lastDebounceTimeAlcA > debounceDelay) {
    lastDebounceTimeAlcA = currentTime;
    digitalWrite(22, HIGH);
    digitalWrite(23, LOW);
    digitalWrite(24, LOW);
    Serial.println("alcButtonA");

    gewaehlterAlc = 'A';
  }
}

void isrAlcButtonB() {
  unsigned long currentTime = millis();
  if (currentTime - lastDebounceTimeAlcB > debounceDelay) {
    lastDebounceTimeAlcB = currentTime;
    digitalWrite(22, LOW);
    digitalWrite(23, HIGH);
    digitalWrite(24, LOW);
    Serial.println("alcButtonB");

    gewaehlterAlc = 'B';
  }
}

void isrAlcButtonC() {
  unsigned long currentTime = millis();
  if (currentTime - lastDebounceTimeAlcC > debounceDelay) {
    lastDebounceTimeAlcC = currentTime;
    digitalWrite(22, LOW);
    digitalWrite(23, LOW);
    digitalWrite(24, HIGH);
    Serial.println("alcButtonC");

    gewaehlterAlc = 'C';
  }
}

void isrDrinkButtonA() {
  unsigned long currentTime = millis();
  if (currentTime - lastDebounceTimeDrinkA > debounceDelay) {
    lastDebounceTimeDrinkA = currentTime;
    digitalWrite(25, HIGH);
    digitalWrite(26, LOW);
    digitalWrite(27, LOW);
    Serial.println("drinkButtonA");

    gewaehlterDrink = 'A';
  }
}

void isrDrinkButtonB() {
  unsigned long currentTime = millis();
  if (currentTime - lastDebounceTimeDrinkB > debounceDelay) {
    lastDebounceTimeDrinkB = currentTime;
    digitalWrite(25, LOW);
    digitalWrite(26, HIGH);
    digitalWrite(27, LOW);
    Serial.println("drinkButtonB");

    gewaehlterDrink = 'B';
  }
}

ISR(PCINT0_vect) {  // Pin-change-interrupt für DrinkButtonC
  unsigned long currentTime = millis();
  if (currentTime - lastDebounceTimeDrinkC > debounceDelay) {
    lastDebounceTimeDrinkC = currentTime;
    digitalWrite(25, LOW);
    digitalWrite(26, LOW);
    digitalWrite(27, HIGH);
    Serial.println("drinkButtonC");

    gewaehlterDrink = 'C';
  }
}

void isrStartButton() {
  unsigned long currentTime = millis();
  if (currentTime - lastDebounceTimeStart > debounceDelay) {
    lastDebounceTimeStart = currentTime;
    Serial.println("start");
    starten = true;
  }
}

//---Methoden zur Steuerung der Hardware
void pumpe_an(char pPumpe) {
  if (pPumpe == 'A') {
    digitalWrite(32, HIGH);
    digitalWrite(33, LOW);
  } else if (pPumpe == 'B') {
    digitalWrite(34, HIGH);
    digitalWrite(35, LOW);
  } else if (pPumpe == 'C') {
    digitalWrite(36, HIGH);
    digitalWrite(37, LOW);
  } else {
    digitalWrite(32, LOW);
    digitalWrite(33, LOW);
    digitalWrite(34, LOW);
    digitalWrite(35, LOW);
    digitalWrite(36, LOW);
    digitalWrite(37, LOW);
  }
}

void pumpe_aus(char pPumpe) {
  if (pPumpe == 'A') {
    digitalWrite(32, LOW);
    digitalWrite(33, LOW);
  } else if (pPumpe == 'B') {
    digitalWrite(34, LOW);
    digitalWrite(35, LOW);
  } else if (pPumpe == 'C') {
    digitalWrite(36, LOW);
    digitalWrite(37, LOW);
  }
}

void magnetVentile_an(char pVentil) {
  if (pVentil == 'A') {
    digitalWrite(38, HIGH);
  } else if (pVentil == 'B') {
    digitalWrite(39, HIGH);
  } else if (pVentil == 'C') {
    digitalWrite(40, HIGH);
  }
}

void magnetVentile_aus(char pVentil) {
  if (pVentil == 'A') {
    digitalWrite(38, LOW);
  } else if (pVentil == 'B') {
    digitalWrite(39, LOW);
  } else if (pVentil == 'C') {
    digitalWrite(40, LOW);
  }
}

Deine Interruptroutinen mit dem debounce gehen so nicht. Du musst das debounce im Loop machen. Tipp: alle delays raus und mehrere Statemaschienen bauen

Die Portpins freuen sich, wenn sie einen Namen bekommen, der ihre Aufgabe beschreibt.

Beschreibe mit einfachen Worten wie die Anlage funktionieren soll und das ganz einfach.

Das ist nicht weiter verwunderlich, denn Du hast die Interrupts gesperrt.

Eigentlich müsste Dein Programm komplett stehen bleiben, da es aber weiter loopt vermute ich, dass Du da mit was anderem unterwegs bist (ESP32?).

aus Spaß: Ich habe dazu mal ChatGPT befragt

Sperrt die nointerrupts()-Funktion beim Arduino auch den Timer für micros()?

Ja, die noInterrupts()-Funktion auf dem Arduino sperrt auch den Timer, der für die micros()-Funktion verwendet wird. Die micros()-Funktion nutzt interne Timer-Interrupts, um die Anzahl der Mikrosekunden seit dem Start des Programms zu zählen. Wenn du noInterrupts() aufrufst, werden alle Interrupts deaktiviert, einschließlich derjenigen, die den Timer aktualisieren, der von micros() verwendet wird.

Das bedeutet:

  1. Während noInterrupts() aktiv ist, bleibt die Zeitmessung der micros()-Funktion stehen, da die Timer-Interrupts nicht ausgeführt werden.
  2. Sobald du interrupts() wieder aktivierst, läuft die Zeitmessung weiter.

Wenn du also längere Zeit Interrupts deaktivierst, wird der von micros() gemeldete Wert während dieser Zeit nicht aktualisiert und bleibt konstant.

Dies kann problematisch sein, wenn du präzise Zeitmessungen durchführen möchtest, während Interrupts deaktiviert sind. Wenn du Interrupts deaktivieren musst und dennoch eine genaue Zeitmessung brauchst, könntest du versuchen, den Zustand der Timer direkt zu überwachen oder alternative Hardware-Mechanismen zu verwenden.

Welche Auswirkungen hat das auf millis()?

Die Auswirkungen von noInterrupts() auf die Funktion millis() sind ähnlich wie bei micros(), aber weniger gravierend aufgrund der unterschiedlichen Zeitauflösung.

Was passiert mit millis() bei noInterrupts()?

  1. millis() basiert ebenfalls auf einem Timer, der durch Interrupts aktualisiert wird (normalerweise der Timer0 auf den meisten Arduino-Boards wie dem Uno). Dieser Timer erzeugt alle 1,024 Millisekunden einen Interrupt, der die interne Zählvariable hochzählt, auf die sich die millis()-Funktion stützt.

  2. Wenn du noInterrupts() aufrufst, werden die Timer-Interrupts vorübergehend deaktiviert. Das bedeutet, dass während dieser Zeit keine Aktualisierung der internen Zähler für millis() stattfinden kann.

  3. Während der Zeit, in der Interrupts deaktiviert sind, bleibt die von millis() zurückgegebene Zeit stehen, genauso wie bei micros(). Der Unterschied ist, dass sich dies aufgrund der geringeren Zeitauflösung von millis() (1 Millisekunde im Vergleich zu 1 Mikrosekunde bei micros()) weniger bemerkbar macht, wenn Interrupts nur für kurze Zeit deaktiviert werden.

  4. Sobald du interrupts() wieder aktivierst, laufen die Interrupts und damit auch die Zeitmessung weiter. Allerdings wird die Zeit während der deaktivierten Interrupts nicht "nachgeholt". Das bedeutet, dass du während dieser Phase der Interrupt-Deaktivierung keine verpasste Zeit zurückbekommst – die Zeit bleibt einfach stehen.

Zusammenfassung der Auswirkungen:

  • Kurzzeitige Unterbrechungen (mit noInterrupts() für einige Mikrosekunden oder Millisekunden) haben nur einen minimalen Effekt auf millis(), da der Timer nur etwa jede Millisekunde einen Interrupt auslöst.
  • Länger andauernde Deaktivierungen von Interrupts führen jedoch zu einer spürbaren Verzögerung in der von millis() gemessenen Zeit, da die Timer-Interrupts während dieser Zeit nicht ausgeführt werden.

Wenn du Zeitmessungen mit einer hohen Genauigkeit durchführen musst, während du Interrupts deaktivierst, solltest du diese Funktion mit Vorsicht einsetzen.

Ist die Funktion delay() auch betroffen?

Ja, die Funktion delay() ist ebenfalls von der Deaktivierung der Interrupts durch noInterrupts() betroffen, da sie intern auf die Funktion millis() zugreift, um die Verzögerung zu berechnen.

Warum ist delay() betroffen?

  • Funktionsweise von delay(): Die delay()-Funktion pausiert die Ausführung des Programms für eine bestimmte Anzahl von Millisekunden, indem sie wiederholt die aktuelle Zeit mithilfe von millis() abfragt und wartet, bis die gewünschte Verzögerung vergangen ist.

  • Abhängigkeit von Interrupts: Da millis() auf Timer-Interrupts basiert, um die verstrichene Zeit zu zählen, wird die Zeitmessung in millis() während der Ausführung von noInterrupts() unterbrochen. Das bedeutet, dass während der Zeit, in der die Interrupts deaktiviert sind, auch die Zeit für delay() nicht korrekt abläuft.

Auswirkungen auf delay():

  • Während noInterrupts() aktiv ist, stoppt die Aktualisierung der Zeitmessung in millis(), was dazu führt, dass delay() scheinbar länger wartet, als es sollte. Die Verzögerung bleibt für die Dauer der Interrupt-Deaktivierung "eingefroren".

  • Wenn die Interrupts wieder aktiviert werden (durch einen Aufruf von interrupts()), läuft die Zeitmessung in millis() weiter, und die delay()-Funktion kann die verbleibende Zeit korrekt zählen. Jedoch wird die Zeit, in der die Interrupts deaktiviert waren, nicht nachgeholt, sodass die Gesamtwartezeit länger ist als ursprünglich vorgesehen.

Fazit:

  • Kurzzeitig deaktivierte Interrupts haben nur minimale Auswirkungen auf delay(), da diese Funktion mit Millisekunden arbeitet.
  • Länger andauernde Deaktivierungen führen jedoch dazu, dass die Verzögerung von delay() länger dauert als gewollt.

Wenn du also während einer delay()-Funktion Interrupts deaktivierst, verlängert sich die Verzögerung um den Zeitraum, in dem die Interrupts ausgeschaltet sind.

Wie ist das Verhalten von delay() bei gesperrten Interrupts beim ESP32?

Beim ESP32 unterscheidet sich das Verhalten der Funktion delay() im Vergleich zu AVR-basierten Arduinos (wie dem Arduino Uno), insbesondere wenn Interrupts gesperrt sind. Dies liegt daran, dass der ESP32 ein leistungsfähigeres Mikrocontroller-Modul mit einem anderen Hardware- und Software-Design ist.

Funktionsweise von delay() auf dem ESP32:

  1. FreeRTOS-basierte Architektur:

    • Der ESP32 verwendet ein Betriebssystem namens FreeRTOS, welches die Steuerung von Aufgaben (Tasks) übernimmt. Die delay()-Funktion ist auf dem ESP32 im Wesentlichen ein Aufruf zu vTaskDelay(), einer Funktion von FreeRTOS, die einen Task für eine bestimmte Anzahl von "Ticks" (Zeiteinheiten) pausiert.
    • Die Zeitmessung und das Timing (z. B. für delay() und millis()) werden in FreeRTOS durch Hardware-Timer und das Betriebssystem selbst gehandhabt, das von einem Tick-Interrupt gesteuert wird (standardmäßig etwa alle 1 ms).
  2. Abhängigkeit von Interrupts:

    • Interrupts sind auch beim ESP32 wichtig für die genaue Zeitmessung. Der FreeRTOS-Tick-Interrupt ist notwendig, um die Zeit für delay() und ähnliche Funktionen korrekt zu zählen.
    • Wenn du die Interrupts auf dem ESP32 mit noInterrupts() deaktivierst, wird der FreeRTOS-Tick-Interrupt ebenfalls blockiert. Das bedeutet, dass die Zeit für delay() nicht korrekt fortschreiten kann.

Verhalten von delay() bei gesperrten Interrupts auf dem ESP32:

  1. delay() stoppt oder verlangsamt sich:

    • Ähnlich wie bei Arduinos, wird die Zeit für die Funktion delay() nicht fortgesetzt, solange die Interrupts deaktiviert sind, weil der FreeRTOS-Tick-Interrupt nicht ausgeführt wird. Das führt dazu, dass delay() länger dauert, als erwartet.
  2. Andere Nebenwirkungen:

    • Da FreeRTOS auf dem ESP32 Multitasking ermöglicht, kann das Deaktivieren von Interrupts auch andere kritische Systemfunktionen blockieren, da der Scheduler von FreeRTOS nicht mehr funktioniert. Dies kann zu Problemen bei der Taskverwaltung oder anderen zeitkritischen Prozessen führen.
  3. Unterschiedliche Task-Prioritäten:

    • Auf dem ESP32 könnte die Verwendung von noInterrupts() (oder ähnliche Funktionen) dazu führen, dass nicht nur delay(), sondern auch andere Tasks mit niedrigerer Priorität verzögert oder blockiert werden. Dies liegt daran, dass das Betriebssystem nicht in der Lage ist, den Kontext zu wechseln oder Timer-Interrupts zu verarbeiten.

Alternative Ansätze auf dem ESP32:

Anstatt auf noInterrupts() zu setzen, ist es oft besser, auf dem ESP32 spezifischere Mechanismen zur Kontrolle von Interrupts oder zeitkritischen Funktionen zu verwenden:

  1. Port-disable Interrupts:

    • Du kannst gezielt Interrupts für bestimmte Timer oder Peripherien deaktivieren, ohne den gesamten FreeRTOS-Betrieb zu unterbrechen. Das hält den Scheduler intakt und verhindert Nebenwirkungen auf Funktionen wie delay().
  2. Critical Sections von FreeRTOS:

    • FreeRTOS bietet Critical Sections an, bei denen Interrupts nur für bestimmte Aufgaben oder Codeabschnitte deaktiviert werden, ohne dass das gesamte System blockiert wird. Dies wird durch taskENTER_CRITICAL() und taskEXIT_CRITICAL() erreicht.

Fazit:

Auf dem ESP32 wird die Funktion delay() ebenfalls beeinträchtigt, wenn du mit noInterrupts() alle Interrupts deaktivierst. Da FreeRTOS und die Tick-Interrupts für das Zeitmanagement notwendig sind, wird delay() während dieser Zeit ausgesetzt, was zu einer längeren als erwarteten Verzögerung führt. Um solche Nebenwirkungen zu vermeiden, ist es besser, Interrupts nur gezielt oder mithilfe von FreeRTOS-Funktionen zu deaktivieren.

Ich bin mir nicht sicher ob delay() funktioniert, wenn Interrupts deaktiviert sind.

Danke für die schnelle Antwort. Was genau meinst du mit Statemachiene? Soll ich die Zustände definen und dann in den loop teil eine große switch state abfrage rein machen ? Wie mache ich das debouncing im loop?

Ja!

Ist eine Variante.
Vielleicht nicht die schönste..

Ich glaube nicht. Wieso sollten dann die delays auch deaktiviert sein ?

Ich benutze ein Sunfounder "Arduino" Mega 2560. Wieso müsste mein Programm sofort stehen bleiben?

also es würde sich anbieten du definierst für welches Getränk welcher Output für wie lange High oder Low sein muss.

Das reicht zunächst in einer händisch geschriebenen Tabelle.
Dann kann man dir zeigen wie man daraus eine Daten Struktur macht.

Und dann wie man mehrere "Rezepte" (Getränke) in ein Array packt.

Danach stampft man das Program auf ca ein viertel der Zeilen ein.
Fürs Debouncen würde ich eine der verfügbaren Libraries nehmen.
Ich nehm dazu gern die OneButton Library.

Weil in der Funktion Delay ein Timer Interrupt hoch zählt. Da die die Interrupts deaktivierst, wird es nichts mit Delay und Millis.

Hoert sich gut an. Die delay zeit ist aber nicht bei jedem Getränk die selbe da es auf die Stellung des Potis ankommt. Woher hast du die Library?

fixe Zeiten kann man in einer Tabelle vermerken.
wenn etwas von einem Poti abgelesen werden soll - kann man es in einer Tabelle vermerken.

die One Button Library lässt sich über den Library Manager der Arduino IDE installieren.

Super danke. Ich habe die Lybrary installiert. Wie heissen die Methoden der Lybrary und wie muss ich sie in meinen Code einbinden? Folgendes Programm ist ganz ohne das debouncing.

//---Logische Variablen festlegen
volatile boolean starten = false; 
volatile char gewaehlterAlc;
volatile char gewaehlterDrink; 
  
double flussratePumpe = 8.333;
double flussrateVentil = 35.000;              // Muss noch genau ermittelt werden
double pumpenDelay;
double ventilDelay;
int becherInhalt = 400;
int mischVerhaeltniss; // Setze hier einen Standardwert

void setup() {
  // put your setup code here, to run once:
  pinMode(53, INPUT); // Pin 53 als Input festlegen für PinChange Interrupt
  pinMode(22, OUTPUT);  // IN1 -> AlcButtonA
  pinMode(23, OUTPUT);  // IN2 -> AlcButtonB
  pinMode(24, OUTPUT);  // IN3 -> AlcButtonC
  pinMode(25, OUTPUT);  // IN4 -> DrinkButtonA
  pinMode(26, OUTPUT);  // IN5 -> DrinkButtonB
  pinMode(27, OUTPUT);  // IN6 -> DrinkButtonC
  pinMode(28, OUTPUT);  // IN7 -> StartButton
 
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(18, OUTPUT);
  pinMode(19, OUTPUT);
  pinMode(20, OUTPUT);
  pinMode(21, OUTPUT);

  //---Externe Interrupts Festlegen
  attachInterrupt(digitalPinToInterrupt(2), isrAlcButtonA, FALLING);
  attachInterrupt(digitalPinToInterrupt(3), isrAlcButtonB, FALLING);   
  attachInterrupt(digitalPinToInterrupt(18), isrAlcButtonC, FALLING);
  attachInterrupt(digitalPinToInterrupt(19), isrDrinkButtonA, FALLING);
  attachInterrupt(digitalPinToInterrupt(20), isrDrinkButtonB, FALLING);
  attachInterrupt(digitalPinToInterrupt(21), isrStartButton, FALLING);
 
  // Pin-change-interrupt auf Pin 53 legen
  PCICR |= (1 << PCIE0);
  PCMSK0 |= (1 << PCINT0);

  //---Pins für Hardwarekomponenten festlegen
  // Magnetventile am 4x Relais
  pinMode(38, OUTPUT);  // mVentilA
  pinMode(39, OUTPUT);  // mVentilB
  pinMode(40, OUTPUT);  // mVentilC

  // L298n _1_
  pinMode(32, OUTPUT);  // pumpeA
  pinMode(33, OUTPUT);  // pumpeA
  pinMode(34, OUTPUT);  // pumpeB
  pinMode(35, OUTPUT);  // pumpeB

  // L298n _2_
  pinMode(36, OUTPUT);  // pumpeC
  pinMode(37, OUTPUT);  // pumpeC

  // Potentiometer
  pinMode(A1, INPUT);

  //---Serielle Kommunikation herstellen
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println("---loop---");

  if (starten == true){
    // Berechnungen durchführen
    pumpenDelay = (becherInhalt * mischVerhaeltniss) / flussratePumpe;
    ventilDelay = (becherInhalt * (1 - (mischVerhaeltniss / 100.0))) / flussrateVentil;     // Der potiwert muss noch *0.01 gemacht werden 

    pumpe_an(gewaehlterAlc);
    delay(pumpenDelay);
    pumpe_aus(gewaehlterAlc);

    magnetVentile_an(gewaehlterDrink);
    delay(ventilDelay);
    magnetVentile_aus(gewaehlterDrink);

    starten = false; 
  }
}

//---Interrupts
void isrAlcButtonA(){
  digitalWrite(22, HIGH);
  digitalWrite(23, LOW);
  digitalWrite(24, LOW);
  Serial.println("alcButtonA"); 

  gewaehlterAlc = 'A';
}

void isrAlcButtonB(){
  digitalWrite(22, LOW);
  digitalWrite(23, HIGH);
  digitalWrite(24, LOW); 
  Serial.println("alcButtonB"); 

  gewaehlterAlc = 'B';
}

void isrAlcButtonC(){
  digitalWrite(22, LOW);
  digitalWrite(23, LOW);
  digitalWrite(24, HIGH);
  Serial.println("alcButtonC"); 

  gewaehlterAlc = 'C';
}

void isrDrinkButtonA(){
  digitalWrite(25, HIGH);
  digitalWrite(26, LOW);
  digitalWrite(27, LOW);
  Serial.println("drinkButtonA"); 

  gewaehlterDrink = 'A';
}

void isrDrinkButtonB(){
  digitalWrite(25, LOW);
  digitalWrite(26, HIGH);
  digitalWrite(27, LOW);
  Serial.println("drinkButtonB");

  gewaehlterDrink = 'B';
}

ISR (PCINT0_vect){  // Pin-change-interrupt für DrinkButtonC
  digitalWrite(25, LOW);
  digitalWrite(26, LOW);
  digitalWrite(27, HIGH);
  Serial.println("drinkButtonC");

  gewaehlterDrink = 'C';
}

void isrStartButton(){
  Serial.println("start");
  mischVerhaeltniss = analogRead(A1);
  mischVerhaeltniss = map(mischVerhaeltniss, 0, 1023, 0, 100); 
  starten = true; 
}

//---Methoden zur Steuerung der Hardware
void pumpe_an(char pPumpe) {                // Laufrichtung noch nicht definiert
  if(pPumpe == 'A') {
    digitalWrite(32, HIGH);
    digitalWrite(33, LOW);
  } else if(pPumpe == 'B') {
    digitalWrite(34, HIGH);
    digitalWrite(35, LOW);    
  } else if(pPumpe == 'C') {
    digitalWrite(36, HIGH);
    digitalWrite(37, LOW);
  } else {
    digitalWrite(32, LOW);
    digitalWrite(33, LOW);
    digitalWrite(34, LOW);
    digitalWrite(35, LOW);
    digitalWrite(36, LOW);
    digitalWrite(37, LOW);
  }
}

void pumpe_aus(char pPumpe) {
  if(pPumpe == 'A') {
    digitalWrite(32, LOW);
    digitalWrite(33, LOW);
  } else if(pPumpe == 'B') {
    digitalWrite(34, LOW);
    digitalWrite(35, LOW);    
  } else if(pPumpe == 'C') {
    digitalWrite(36, LOW);
    digitalWrite(37, LOW);
  } else {
    digitalWrite(32, LOW);
    digitalWrite(33, LOW);
    digitalWrite(34, LOW);
    digitalWrite(35, LOW);
    digitalWrite(36, LOW);
    digitalWrite(37, LOW);
  }
}  // Korrekte Platzierung der schließenden Klammer

void magnetVentile_an(char pVentil) {
  if(pVentil == 'A'){
    digitalWrite(38, HIGH);
  } else if(pVentil == 'B'){
    digitalWrite(39, HIGH);
  } else if(pVentil == 'C'){
    digitalWrite(40, HIGH);
  } else {
    digitalWrite(38, LOW);
    digitalWrite(39, LOW);
    digitalWrite(40, LOW);
  }
}

void magnetVentile_aus(char pVentil) {
  if(pVentil == 'A'){
    digitalWrite(38, LOW);
  } else if(pVentil == 'B'){
    digitalWrite(39, LOW);
  } else if(pVentil == 'C'){
    digitalWrite(40, LOW);
  }
}

Das steht in der OneButton.h. Beispiele sind auch dabei.

Gruß Tommy

Meine Annahme war: Weil durch das Sperren der Interrupts auch der Timer stehenbleibt, auf dem micros() und millis() basiert.

Ich bin mir aber nach Blick in den Header util/delay.h nun gar nicht mehr sicher, ob das richtig ist, denn die Verzögerung wird durch den Aufruf von _delay_loop_2() erzeugt - Code dazu habe ich noch nicht gefunden; kann sein, dass das tatsächlich nicht auf millis() und Artverwandten basiert.

Es gibt hier aber Experten, die die Stelle um Arduino-Code bestimmt auswendig kennen und das besser erklären können.

Bei millis() wird der Überlauf eines Timers gezählt und das mit einem Interrupt. Bei delay() könnte ich mir ähnliches vorstellen. Hängt aber von der konkreten Implementation ab.

Wo wir schon mal dabei sind... das sieht komisch aus. Bei einem digitalWrite() solltest du wissen wann du eine fallende Flanke erzeugst. Alternativ ziehst du den Port von aussen gegen seinen Willen auf LOW. Da könnte schon was zu heiß werden...

Ein Schaltplan wäre jetzt hilfreich.

Hier mal ein Beispiel, wie man debouncing von Hand machen kann und eine Statemaschiene programmiert: Arduino: Programmiertechniken/Statemaschine – Wikibooks, Sammlung freier Lehr-, Sach- und Fachbücher


Das sind zwei Pläne die ich selbst gezeichnet habe. Im oberen ist die Schaltung für die Taster nicht drauf. deshalb hab ich unten ein Beispiel gemacht. Die taster sind ganz normal angeschlossen mit einem Pull-down Widerstand. In Meiner wirklichen Schaltung sind natürlich alle sieben Taster so angeschlossen (auch der Pin-change Interrupt). Das mit der fallenden Flanke habe ich noch nicht verstanden. Wo erzeuge ich die fallende Flanke wenn ich digital Write nutze. Erzeuge ich nicht eine fallende Flanke wen ich digitalWrite(pin, LOW) schreibe ? Falls der Plan genauer sein soll kann ich es gern nochmal zeichnen.

Nur dann, wenn pin vorher auf HIGH steht.
Siehe auch Signalflanke