While - Schleife wird manchmal zu früh beendet

Hallo,

ich möchte ein Arduino Nano in meinen Kaffeeautomaten setzen, sodass dieser dann nicht nur Kaffeetassen befüllen kann, sondern auch ganze Kaffeekannen. Dazu soll es für jede Tasse (bis zu 8), die in die Kanne gefüllt werden soll, eine LED geben.
Über einen Button wählt man die Anzahl der Tassen aus - die Auswahl wird entsprechend an den LED´s angezeigt. Wählt man jetzt für eine Zeit X nichts weiter aus, so soll ein Relais zwei mal angezogen werden. Dieses Relais "drückt" dann einfach die Kaffeetaste am Kaffeeautomat, wartet einen definierten Zeitraum X ab, und drückt dann je nach Auswahl nochmal.

In meinem Sketch klappt das auch alles schon wie gewünscht.
Manchmal springt der Code aber schon bei der Auswahl in die Funktion kaffeekochen.
Über einen Hinweis warum, wäre ich sehr dankbar :slight_smile:

int led1 = 2;       //pin led1
int led2 = 3;       //pin led2
int led3 = 4;       //pin led3
int led4 = 5;       //pin led4
int led5 = 6;       //pin led5
int led6 = 7;       //pin led6
int led7 = 8;       //pin led7
int led8 = 9;       //pin led8
double startzeit = 136; //Laufzeit Maschinen-Start in s
double auswahlzeit = 4; //Auswahlzeit für Tassenwahl per Taster in s
double bruehzeit = 89; //Brühzeit für eine Tasse in s
const int button1 = 12; //pin für button
int rel1 = 11;          //pin für relais

double laufzeit = 0;
int zaehler = 99; 
int tmp2 = 0;
double tmp = 0;
void setup() {                
  pinMode(led1, OUTPUT);   
  pinMode(led2, OUTPUT);  
  pinMode(led3, OUTPUT); 
  pinMode(led4, OUTPUT);
  pinMode(led5, OUTPUT);
  pinMode(led6, OUTPUT);
  pinMode(led7, OUTPUT);
  pinMode(led8, OUTPUT);
  pinMode(rel1, OUTPUT);   
  pinMode(button1, INPUT); 
  Serial.begin(9600);
}


void loop() {
  
  Serial.println(zaehler);
  delay(200);
      
      if (zaehler == 99){ //Maschinenstart LED Startsequenz ausführen
        zaehler = 0;
        tmp = laufzeit + startzeit * 1000;
        while ((digitalRead(button1) == LOW) && laufzeit < tmp) {
          laufzeit=millis();  
          digitalWrite(led1, HIGH);
          delay(80);
          digitalWrite(led1, LOW);
          digitalWrite(led2, HIGH);
          delay(80);
          digitalWrite(led2, LOW);
          digitalWrite(led3, HIGH);
          ...
          }
       }
       
       if (digitalRead(button1) == HIGH){
        zaehler ++;
        delay(200);
        }
        
       if (zaehler > 8){ //Anzeige zurücksetzen
        zaehler = 0;
        digitalWrite(led8, LOW);
        delay(80);
        digitalWrite(led7, LOW);
        delay(80);
        digitalWrite(led6, LOW);
        delay(80);
        digitalWrite(led5, LOW);
        delay(80);
        digitalWrite(led4, LOW);
        delay(80);
        digitalWrite(led3, LOW);
        delay(80);
        digitalWrite(led2, LOW);
        delay(80);
        digitalWrite(led1, LOW);
        delay(80);
        }
  
  if (zaehler == 1){
digitalWrite(led1, HIGH);

tmp = laufzeit + auswahlzeit * 1000;

tmp2 = 0;
  while ((digitalRead(button1) == LOW) && laufzeit < tmp ){
    laufzeit=millis();  
  digitalWrite(led1, HIGH);
  
  if (digitalRead(button1) == HIGH){
 zaehler = 2;
  Serial.println("Zähler++"); }
  delay(80);
  tmp2 = 1;
   if (digitalRead(button1) == HIGH){
 zaehler = 2;
  }
  
}
if (zaehler == 1 && tmp2 == 1)
kaffeekochen(led1); 
  }
  
    if (zaehler == 2){
digitalWrite(led1, HIGH);
digitalWrite(led2, HIGH);

Serial.print("laufzeit vor rechnung");
Serial.println(laufzeit);
tmp = laufzeit + auswahlzeit * 1000;
Serial.print("tmp nach rechnung");
Serial.println(tmp);
Serial.print("auswahlzeit nach rechnung");
Serial.println(auswahlzeit);
tmp2 = 0;
  while ((digitalRead(button1) == LOW) && laufzeit < tmp ){
    laufzeit=millis();  
    Serial.print("laufzeit");
    Serial.println(laufzeit);
  digitalWrite(led2, HIGH);
  
  if (digitalRead(button1) == HIGH){
 zaehler = 3;
  Serial.println("Zähler++"); }
  delay(80);
  tmp2 = 1;
   if (digitalRead(button1) == HIGH){
 zaehler = 3;
  }
  
}
if (zaehler == 2 && tmp2 == 1)
kaffeekochen(led2); 
  }

      if (zaehler == 3){
digitalWrite(led1, HIGH);
digitalWrite(led2, HIGH);
digitalWrite(led3, HIGH);

Serial.print("laufzeit vor rechnung");
Serial.println(laufzeit);
tmp = laufzeit + auswahlzeit * 1000;
tmp2 = 0;
  while ((digitalRead(button1) == LOW) && laufzeit < tmp ){
    laufzeit=millis();  
  digitalWrite(led3, HIGH);
  
  if (digitalRead(button1) == HIGH){
 zaehler = 4;
 }
  delay(80);
  tmp2 = 1;
   if (digitalRead(button1) == HIGH){
 zaehler = 4;
  }
  
}
if (zaehler == 3 && tmp2 == 1)
kaffeekochen(led3); 
  }

        if (zaehler == 4){
digitalWrite(led1, HIGH);
digitalWrite(led2, HIGH);
digitalWrite(led3, HIGH);
digitalWrite(led4, HIGH);
tmp = laufzeit + auswahlzeit * 1000;

tmp2 = 0;
  while ((digitalRead(button1) == LOW) && laufzeit < tmp ){
    laufzeit=millis();  

  digitalWrite(led4, HIGH);
  
  if (digitalRead(button1) == HIGH){
 zaehler = 5;
  Serial.println("Zähler++"); }
  delay(80);
  tmp2 = 1;
   if (digitalRead(button1) == HIGH){
 zaehler = 5;
  }
  
}
if (zaehler == 4 && tmp2 == 1)
kaffeekochen(led4); 
  }

          if (zaehler == 5){
digitalWrite(led1, HIGH);
digitalWrite(led2, HIGH);
digitalWrite(led3, HIGH);
digitalWrite(led4, HIGH);
digitalWrite(led5, HIGH);
tmp = laufzeit + auswahlzeit * 1000;
tmp2 = 0;
  while ((digitalRead(button1) == LOW) && laufzeit < tmp ){
    laufzeit=millis();  
  digitalWrite(led5, HIGH);
  
  if (digitalRead(button1) == HIGH){
 zaehler = 6;
 }
  delay(80);
  tmp2 = 1;
   if (digitalRead(button1) == HIGH){
 zaehler = 6;
  }
  
}
if (zaehler == 5 && tmp2 == 1)
kaffeekochen(led5); 
  }
            if (zaehler == 6){
digitalWrite(led1, HIGH);
digitalWrite(led2, HIGH);
digitalWrite(led3, HIGH);
digitalWrite(led4, HIGH);
digitalWrite(led5, HIGH);
digitalWrite(led6, HIGH);

Serial.print("laufzeit vor rechnung");
Serial.println(laufzeit);
tmp = laufzeit + auswahlzeit * 1000;
tmp2 = 0;
  while ((digitalRead(button1) == LOW) && laufzeit < tmp ){
    laufzeit=millis();  

  digitalWrite(led6, HIGH);
  
  if (digitalRead(button1) == HIGH){
 zaehler = 7;
  Serial.println("Zähler++"); }
  delay(80);
  tmp2 = 1;
   if (digitalRead(button1) == HIGH){
 zaehler = 7;
  }
  
}
if (zaehler == 6 && tmp2 == 1)
kaffeekochen(led6); 
  }


              if (zaehler == 7){
digitalWrite(led1, HIGH);
digitalWrite(led2, HIGH);
digitalWrite(led3, HIGH);
digitalWrite(led4, HIGH);
digitalWrite(led5, HIGH);
digitalWrite(led6, HIGH);
digitalWrite(led7, HIGH);

tmp = laufzeit + auswahlzeit * 1000;
tmp2 = 0;
  while ((digitalRead(button1) == LOW) && laufzeit < tmp ){
    laufzeit=millis();  
  digitalWrite(led7, HIGH);
  
  if (digitalRead(button1) == HIGH){
 zaehler = 8;
 }
  delay(80);
  tmp2 = 1;
   if (digitalRead(button1) == HIGH){
 zaehler = 8;
  }
}
if (zaehler == 7 && tmp2 == 1)
kaffeekochen(led7); 
  }
                if (zaehler == 8){
digitalWrite(led1, HIGH);
digitalWrite(led2, HIGH);
digitalWrite(led3, HIGH);
digitalWrite(led4, HIGH);
digitalWrite(led5, HIGH);
digitalWrite(led6, HIGH);
digitalWrite(led7, HIGH);
digitalWrite(led8, HIGH);
tmp = laufzeit + auswahlzeit * 1000;
tmp2 = 0;
  while ((digitalRead(button1) == LOW) && laufzeit < tmp ){
    laufzeit=millis();  
  digitalWrite(led8, HIGH);
  
  if (digitalRead(button1) == HIGH){
 zaehler = 9;
  Serial.println("Zähler++"); }
  delay(80);
  tmp2 = 1;
   if (digitalRead(button1) == HIGH){
 zaehler = 9;
  }
  
}
if (zaehler == 8 && tmp2 == 1)
kaffeekochen(led8); 
  }
} //EndLoop

int kaffeekochen(char lednr) {
  digitalWrite(rel1, HIGH);
  delay(280);
  digitalWrite(rel1, LOW);
  delay(280);
  digitalWrite(rel1, HIGH);
  delay(280);
  digitalWrite(rel1, LOW);
 
  zaehler = zaehler - 1;

  tmp = laufzeit + bruehzeit * 1000;
 
  while ((digitalRead(button1) == LOW) && laufzeit < tmp ){
    laufzeit=millis();  
    digitalWrite(lednr, LOW);
    if (digitalRead(button1) == HIGH){
      zaehler = 9;
 }
    delay(80);
     if (digitalRead(button1) == HIGH){
        zaehler = 9;}
    digitalWrite(lednr, HIGH);
    delay(80);
    tmp2 = 1;
    if (digitalRead(button1) == HIGH){
        zaehler = 9;}
    }
    Serial.print("zaehler in kaffeekochen am ende:");
  digitalWrite(lednr, LOW);
  return 0;
  exit;
}

Wechselt Dein Kafeeautomat automatisch das Kafeepulver?

Grüße Uwe

Hab den Code wirklich nur sehr oberflächlich überflogen: ich tippe auf Problem beim Erkennen von Tastendruck/loslassen.

Was passiert, wenn Du die Taste gedrückt hälst?

Mann muss vor Benutzung dafür sorgen dass Wasser und Bohnen ausreichend befüllt sind und der Satzbehälter geleert ist.

Wenn ich die Taste länger drücke, wechselt die Auswahl wie gewünscht im 200ms Rhythmus.

Dein Code hat sehr viele While-Schleifen; werden die Schleifen in immer den gleichen Zuständen vorzeitig verlassen oder kommt das Verhalten bei jedem Zustand von Zaehler vor?

Warum setzt Du bei einer erkannten Eingabe je Zählerzustand den Zähler immer 2x auf die jeweilige Zahl?

Ich habe Schwierigkeiten, deinem Code zu folgen. Du kannst ihn immens vereinfachen, indem du die Aufgaben mit einer Sammlung globaler Variablen zur Speicherung der Zustände bearbeitest (letzter Input, is exklusiver Input etc.) und Ausgaben (wie die LEDs) durch for-Schleifen realisierst (zumindest ist das mein Eindruck nach dem ersten Überfliegen :wink: ).

Eine weitere Tugent ist es, den Code nicht so "lange gefangen" zu halten, bis er Loop einmal komplett durchläuft. Das erreichst Du unter anderem auch durch den vorangegangenen Tipp :slight_smile:

Delays sind sowieso böse.

Hast Du einen Widerstand am Taster?

laufzeit muß ein unsigned long sein.

Was ist "exit" ?

delay(280); Ein Relais schaltet nicht so schnell.

while ((digitalRead(button1) == LOW) && laufzeit < tmp ){
    laufzeit=millis();  
    digitalWrite(lednr, LOW);
    if (digitalRead(button1) == HIGH){
      zaehler = 9;
 }
    delay(80);
     if (digitalRead(button1) == HIGH){
        zaehler = 9;}
    digitalWrite(lednr, HIGH);
    delay(80);
    tmp2 = 1;
    if (digitalRead(button1) == HIGH){
        zaehler = 9;}
    }

Die Tasterabfrage ist konfus. Es können zufällig keine bis alle 3 if ausgeführt werde je nachdem in welchen Moment relativ zur while Schleife der Taster betätigt/losgelassen wird.

Grüße Uwe

Hallo,

ich habe dir mal eine Zustandssteuerung mit combies aktueller "Timer" Lib programmiert. Die wollte ich auch einmal ausprobieren. Die LEDs dienen nur zur Anzeige des aktuellen Zustandes. Was du mit dem oder in dem Zustand machst, ist dir überlassen. Auf alle Fälle haste saubere Entprellung und kannst damit ohne Probleme weiter schalten oder weiß der Geier ...

combies Lib: [Projekt] INTERVAL Ersatzstoff - #28 by combie - Deutsch - Arduino Forum

alle 4 enthaltenen Ordner nach C:\Users\name\Documents\Arduino\libraries\ entpacken.

/*
  Doc_Arduino - german Arduino Forum
  combies Timer Lib
  IDE v1.8.5
  27.12.2017
  Tastendruck erkennen
*/

#include "CombieTimer.h"
using Combie::Timer::EntprellTimer;

EntprellTimer entprellen(60);                         // Entprellzeit

typedef enum {AUS, EINS, ZWEI, DREI, VIER} state_t;    // Steuerzustände
state_t modus = AUS;

const byte _Taster = 2;
const byte _LED1 = 30;
const byte _LED2 = 31;
const byte _LED3 = 32;
const byte _LED4 = 33;

void setup() {
  
  Serial.begin(500000);
  pinMode(_Taster, INPUT_PULLUP);     // mit INPUT_PULLUP invertierte Logik
  pinMode(_LED1, OUTPUT);               
  pinMode(_LED2, OUTPUT);  
  pinMode(_LED3, OUTPUT); 
  pinMode(_LED4, OUTPUT);   
}

void loop() {

  Taster();
  LED();

}


void Taster ()
{ 
  
  static bool modi = false;
  static bool last_state = false;
  
  bool state_Taster = entprellen(digitalRead(_Taster)); 

  if (state_Taster != last_state) {   // wenn Tasterstatus verschieden zu vorher 
    last_state = state_Taster;
    if (state_Taster == LOW) {        // wenn wirklich gedrückt wurde
      modi = true;                    // Änderung zum Schalter
    }
  }  
  
  if (modi == true) {             
    modi = false;    
    switch (modus) {
      case AUS:  modus = EINS;  break;
      case EINS: modus = ZWEI;  break;
      case ZWEI: modus = DREI;  break;
      case DREI: modus = VIER;  break;
      case VIER: modus = EINS;  break;
      default:  modus = AUS;    break;
    }
}
}


void LED ()
{ 
  static state_t last_modi = AUS;

  if (modus != last_modi ) {
    last_modi = modus;
    switch (modus) {
      case AUS:   digitalWrite(_LED1, LOW);  
                  digitalWrite(_LED2, LOW);  
                  digitalWrite(_LED3, LOW);  
                  digitalWrite(_LED4, LOW);  
                  break;
      case EINS:  digitalWrite(_LED1, HIGH);  
                  digitalWrite(_LED2, LOW);  
                  digitalWrite(_LED3, LOW);  
                  digitalWrite(_LED4, LOW);  
                  break;
      case ZWEI:  digitalWrite(_LED1, LOW);  
                  digitalWrite(_LED2, HIGH);  
                  digitalWrite(_LED3, LOW);  
                  digitalWrite(_LED4, LOW);  
                  break;
      case DREI:  digitalWrite(_LED1, LOW);  
                  digitalWrite(_LED2, LOW);  
                  digitalWrite(_LED3, HIGH);  
                  digitalWrite(_LED4, LOW);  
                  break;
      case VIER:  digitalWrite(_LED1, LOW);  
                  digitalWrite(_LED2, LOW);  
                  digitalWrite(_LED3, LOW);  
                  digitalWrite(_LED4, HIGH);  
                  break;
      default:  modus = AUS; 
                break;
    }
  }  
}

Hi!

Schön, dass du dich daran versuchst.
Es ist mir eine Ehre.

  bool state_Taster = entprellen(digitalRead(_Taster)); 

if (state_Taster != last_state) {  // wenn Tasterstatus verschieden zu vorher
    last_state = state_Taster;
    if (state_Taster == LOW) {        // wenn wirklich gedrückt wurde
      modi = true;                    // Änderung zum Schalter
    }
  }

Wenn ich den Code richtig verstanden habe, dann kann man ihn abkürzen, wenn man die FlankenErkennung aus der Combie::Tools Lib nutzt.

z.B. so:

bool modi = flankenerkennung = entprellen = digitalRead(_Taster);

oder so:

bool modi = flankenerkennung(entprellen(digitalRead(_Taster)));

Oder eine Mischform.
Ganz nach gut dünken.
Wie es einem am besten schmeckt.

 if (modi == true) {             
    modi = false;

wird dann zu:

 if (modi) {

Hallo,

die Flankenabfrage geht auch. Es kommt nur darauf an das sich der Steuerzustand nur einmal pro Tastendruck ändert, egal wie lange der Taster gedrück wird. Sonst rasselt permanent switch durch.

Haste fein gemacht. :slight_smile:

Vielen Dank, den Code probiere ich morgen aus.
Mein Problem konnte ich dank der Hinweise mit folgender Änderung in der Schleife lösen:

//while ((digitalRead(button1) == LOW) && laufzeit < tmp ){
  while (zaehler == 1 && laufzeit < tmp ){
    laufzeit=millis();  
    //Serial.print("laufzeit");
    //Serial.println(laufzeit);
    if (digitalRead(button1) == HIGH){
      zaehler = 2;
      delay(200); }
    tmp2 = 1;
  }
  if (zaehler == 1 && tmp2 == 1) {
    kaffeekochen(led1); }
  }

Hier auch mal ein Video vom Projekt:Delonghi EAM Umbau Kannenbrüh - Funktion - YouTube

laufzeit < tmp

Wer ist tmp?
Da steckt ein Überlauf drin!
Welcher dir nach ca 49 Tagen auf die Füße fällt.
Oder?

combie:
Wer ist tmp?
Da steckt ein Überlauf drin!
Welcher dir nach ca 49 Tagen auf die Füße fällt.
Oder?

Eigentlich nicht, tmp wird vor der Schleife gesetzt:

tmp = laufzeit + auswahlzeit * 1000;

Man hätte es sicher auch mit in die Schleife packen können aber c war noch nie meine Stärke :o

Eigentlich nicht,

Aber sicherlich!

laufzeit=millis(); 
//---
tmp = laufzeit + auswahlzeit * 1000; //<<-- fataler Überlauf.

Man hätte es sicher auch mit in die Schleife packen können

Das ist nicht das Problem

combie:
Aber sicherlich!

laufzeit=millis(); 

//---
tmp = laufzeit + auswahlzeit * 1000; //<<-- fataler Überlauf.




Das ist nicht das Problem

Stimmt, wenn das ende von double erreicht ist.
Wie kann ich das umgehen?
Vermutlich wird es nicht auffallen, der der Kaffeeautomat nie länger als 30min. eingeschaltet ist.

Wie kann ich das umgehen?

Hier wird es richtig gemacht:
Blinken ohne "delay()"