Meine Teemaschine debounce und counter wollen noch nicht

Hallo liebe Community,

ich möchte eine Teemaschine bauen.

An 3 Buttons soll mann die Zeit eintellen bzw. starten.
Ein counter soll sie haben.
Button1: +1Minute, wenn über 10 Minuten wieder bei 0 anfangen
Button2: -1Minute, wenn unter null bei 10 beginnen
Button3 Start/Stop

Auf dem Display (16/2) wird oben der Name angezeigt unten dann “Minuten:”
Ein kleiner Motor zieht an einem Faden zeitgesteuert.
Mit einem 2Kanal Relais ändere ich die polarität vom Motor, da er vor und zurück laufen soll.

Ich glaube das war es soweit zu den Funktionen, ich will ja nicht direkt so ausflippen :stuck_out_tongue:

Bis jetzt habe ich auf dem Display stehen was ich oben beschrieben habe.
Jetzt hänge ich am counter.
Wenn ich Button1 drücke tickern jedes mal die Zahlen ordentlich hoch, nicht nur 1.
Dafür müsste ich warscheinlich ein debounce einbauen, puhhhh
Kann mir da jemand weiterhelfen?

Mein Code bis jetzt:

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display

const int BUTTON1 = 2;// the number of the pushbutton pin 
const int BUTTON2 = 3;// the number of the pushbutton pin
const int BUTTON3 = 4;// the number of the pushbutton pin
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState2 = 0;// current state of the button 
int buttonState3 = 0;// current state of the button
int buttonState4 = 0;// current state of the button
int lastButtonState = 0;     // previous state of the button

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.setCursor(3,0);
  lcd.print("TeaMyTron");
  lcd.setCursor(0,1);
  lcd.print("Minuten: 0");
  
pinMode(BUTTON1, INPUT);
pinMode(BUTTON2, INPUT);   
pinMode(BUTTON3, INPUT);
 }

void loop() {
 
   buttonState2 = digitalRead(BUTTON1);
   
   if (buttonState2 != lastButtonState) {
    
     if (buttonState2 == HIGH)
     {
      buttonPushCounter++;
      lcd.setCursor(9,1);
      lcd.print(buttonPushCounter);
     }
   }
}

Irgendwo haperts, verschiedene Szenarien schon durch, mhhhh

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display

const int BUTTON1 = 2;// the number of the pushbutton pin 
const int BUTTON2 = 3;// the number of the pushbutton pin
const int BUTTON3 = 4;// the number of the pushbutton pin
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState2 = 0;// current state of the button 
int buttonState3 = 0;// current state of the button
int buttonState4 = 0;// current state of the button
boolean lastButtonState = LOW;     // previous state of the button
boolean currentButtonState = LOW;

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.setCursor(3,0);
  lcd.print("TeaMyTron");
  lcd.setCursor(0,1);
  lcd.print("Minuten: 0");
  
pinMode(BUTTON1, INPUT);
pinMode(BUTTON2, INPUT);   
pinMode(BUTTON3, INPUT);
 }
boolean debounce(boolean last)
{
  boolean current = digitalRead(BUTTON1);
  if(last != current){
    
    delay(5);
    current = digitalRead(BUTTON1);
  }
  return current;
}
void loop() {

  currentButtonState = debounce(lastButtonState);
  if(lastButtonState == LOW && currentButtonState ==HIGH)

  //lastButtonState = currentButtonState;
  
   //buttonState2 = digitalRead(BUTTON1);
   
   //if (buttonState2 != lastButtonState) {
    
     //if (buttonState2 == HIGH)
     {
      buttonPushCounter++;
      lcd.setCursor(9,1);
      lcd.print(buttonPushCounter);
     }
   //}
}

Ich würde Dir zu INPUT_PULLUP raten, dann hast Du einen definierten Zustand des nicht gedrückten Buttons und dafür LOW abfragen:

...

pinMode(BUTTON1, INPUT_PULLUP);
...
void loop() {

   buttonState2 = digitalRead(BUTTON1);
   
   if (buttonState2 != lastButtonState2) {  // Jeder Button braucht ein Last
     lastButtonState2 = buttonState2;  // last merken
     if (buttonState2 == LOW)  // wegin INPUT_PULLUP
     {
      buttonPushCounter++;
      lcd.setCursor(9,1);
      lcd.print(buttonPushCounter);
     }
   }
}

Debouncen oder bei den 3 Buttons kannst Du evtl. auch ein delay(50) am Ende vom Loop probieren, wenn Du keine weiteren Funktionen einbauen willst.

ButtonState2 = digitalRead(BUTTON1); ist ein schlechter Stil, der Dich irgendwann zur Verzweiflung treiben wird. Nimm besser gleiche Nummerierungen.

Gruß Tommy

Nimm besser gleiche Nummerierungen.

Oder noch besser: Verzichte gänzlich darauf Variablen durchzunummerieren. Denn dafür wurden die Arrays erfunden!

...

pinMode(UpButton, INPUT_PULLUP);
...
void loop() {

   UpButtonState = digitalRead(UpButton);

Benenne die Dinge, nach dem, was sie sind, oder tun sollen.

Der Zähler wird nicht wegen des Prellens schnell hochgezählt sondern weil der Taster oft abgefragt wird. Wenn Du pro Tastendruck nur um 1 weiterzählen willlst mußt Du auf den Pegelwechsel triggern. Dazu brauchst Du eine Statusvariable.

TasterZustand = digitalRead(Taste);
if (TasterZustand == 1 && AltZustand == 0)
{
Zähler ++;
delay(50);                                    // Entprellen
} 
AltZustand = TasterZustand;

Grüße Uwe

@uwefed
Ein saftiges Delay von 250 macht die Eingabe sehr schön auch ohne zusätzliche Statusvariable.
Ein bisschen was formatiert habe ich auch, hast recht so ist es übersichtlicher. :wink:

@Tommy56
INPUT_PULLUP erfüllt auch seinen Zweck wenn ich die ButtonStates auf -1 setze.

Hatte auch noch ein kleines Problem mit der Ausgabe wenn ich über 10 Zähle, konnte aber mit blanks gelöst werden.
Über 10 und unter 0 habe ich auch gelöst.
Fängt dann halt wieder bei 0 oder bei 10 an.

Soweit sogut, vielen Dank erstmal.

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display

const int UpButton = 2;// the number of the pushbutton pin
const int DownButton = 3;// the number of the pushbutton pin
const int StartStopButton = 4;// the number of the pushbutton pin

int buttonPushCounter = 0;   // counter for the number of button presses
int UpButtonState = -1;// current state of the button
int DownButtonState = -1;// current state of the button
int StartStopButtonState = -1;// current state of the button

boolean lastButtonState = LOW;
boolean lastUpButtonState = LOW;
boolean lastDownButtonState = LOW;// previous state of the button
boolean currentButtonState = LOW;


void setup() {
  lcd.init();
  lcd.backlight();
  lcd.setCursor(3, 0);
  lcd.print("TeaMyTron");
  lcd.setCursor(0, 1);
  lcd.print("Minuten: 0");

  pinMode(UpButton, INPUT_PULLUP);
  pinMode(DownButton, INPUT_PULLUP);
  pinMode(StartStopButton, INPUT_PULLUP);
}


void loop() {

  UpButtonState = digitalRead(UpButton);

  if (UpButtonState != lastButtonState) {  // Jeder Button braucht ein Last
    lastButtonState = UpButtonState;  // last merken
    if (UpButtonState == LOW)  // wegin INPUT_PULLUP
    {
      buttonPushCounter++;
      delay(250);
      lcd.setCursor(9, 1);
      lcd.print(buttonPushCounter);
    }
  }
  
  DownButtonState = digitalRead(DownButton);

  if (DownButtonState != lastUpButtonState) {  // Jeder Button braucht ein Last
    lastUpButtonState = DownButtonState;  // last merken
    if (DownButtonState == LOW)  // wegin INPUT_PULLUP
    {
      lcd.setCursor(9, 1);
      lcd.print("        ");
      buttonPushCounter--;
      delay(250);
      lcd.setCursor(9, 1);
      lcd.print(buttonPushCounter);
    }
  }

  if (buttonPushCounter > 10) {
    buttonPushCounter = 0;
    lcd.setCursor(9, 1);
    lcd.print("0        ");
  }
  
  if (buttonPushCounter < 0) {
    buttonPushCounter = 10;
    lcd.setCursor(9, 1);
    lcd.print("10       ");
  }
}

Jetzt zwirbelt mein Kopf vor dem nächsten Problem.
Nachdem ich die Minuten eingestellt habe soll, bei drücken von StartStopButton, ein Timer runterlaufen (mm:ss).
Alle 30 Sekunden bzw bei 0 soll ein Relais angesprochen werden.

Ein saftiges Delay von 250 macht die Eingabe sehr schön

Stimmt eigentlich, kann man auch pragmatisch sehen: Die Maschine gewöhnt einem zu kurze Tastendrücke eben ab. Und durch die ordentliche Zustandswechsel-Erfassung kann man auch gerne deutlich langsamer sein.

  if (UpButtonState != lastButtonState) {  
    lastButtonState = UpButtonState; 
    delay(10); // das würde auch die Loslassen-Richtung ausreichend entprellen.
    if (UpButtonState == LOW) {
       // Zähler erhöhen und anzeigen
    }
  }

das delay muss gar nicht so saftig sein

Jetzt zwirbelt mein Kopf vor dem nächsten Problem.
Nachdem ich die Minuten eingestellt habe soll, bei drücken von StartStopButton, ein Timer runterlaufen (mm:ss).
Alle 30 Sekunden bzw bei 0 soll ein Relais angesprochen werden.

Brauchst du einen Merker, ob grade Start oder Stop ist und die aktuelle Zeit, die runtergezählt wird
(oder eben nicht). Seh ich kein echtes Problem, bei deinen Fähigkeiten :wink:

michael_x:
Stimmt eigentlich, kann man auch pragmatisch sehen: Die Maschine gewöhnt einem zu kurze Tastendrücke eben ab. Und durch die ordentliche Zustandswechsel-Erfassung kann man auch gerne deutlich langsamer sein.

  if (UpButtonState != lastButtonState) {  

lastButtonState = UpButtonState;
    delay(10); // das würde auch die Loslassen-Richtung ausreichend entprellen.
    if (UpButtonState == LOW) {
      // Zähler erhöhen und anzeigen
    }
  }


<sup>das delay muss gar nicht so saftig sein</sup> 

Brauchst du einen Merker, ob grade Start oder Stop ist und die aktuelle Zeit, die runtergezählt wird 
(oder eben nicht). Seh ich kein echtes Problem, bei deinen Fähigkeiten ;)

Hast recht, das delay umsetzen und auf 10 verkürzen erfüllt den selben Zweck :slight_smile:

Muss ich für jeden Zustand 1-9 einzeln definieren, oder gibt es eine elegantere Lösung`?

Muss ich für jeden Zustand 1-9 einzeln definieren, oder gibt es eine elegantere Lösung`?

Was, wieso?

uwefed: Was, wieso?

Na irgendwie sowas:

StartStopButtonState = digitalRead(StartStopButton);

  if ((buttonPushCounter =1) && (StartStopButtonState =-1)){
    lcd.setCursor(9, 1);
    lcd.print("TIMER       ");
  }
  if ((buttonPushCounter =2) && (StartStopButtonState =-1)){
    lcd.setCursor(9, 1);
    lcd.print("TIMER       ");
  }

Aber dann wird immer TIMER, der gute alte Platzhalter, angezeigt.

Muss ich für jeden Zustand 1-9 einzeln definieren, oder gibt es eine elegantere Lösung`?

Verstehe ich nicht. Mit den Tastern willst du im Stop-Zustand eine Zahl einstellen, die du dann im Lauf-Zustand langsam runterzählst. ( Und wohl vorher noch von Minuten auf Sekunden oder Millisekunden umrechnest ) oder ?

michael_x: Verstehe ich nicht. Mit den Tastern willst du im Stop-Zustand eine Zahl einstellen, die du dann im Lauf-Zustand langsam runterzählst. ( Und wohl vorher noch von Minuten auf Sekunden oder Millisekunden umrechnest ) oder ?

Das wäre sehr elegant. Und wie gesagt es soll dann, bei egal wie viel Minuten ich eingestellt habe, alle 30 Sekunden ein Relais schalten bzw wenn die Zeit abgelaufen ist. Nochmaliges Drücken von Start/Stop im Laufmodus soll den Timer sofort beenden.

ChrisBoy: Und wie gesagt es soll dann, bei egal wie viel Minuten ich eingestellt habe, alle 30 Sekunden ein Relais schalten bzw wenn die Zeit abgelaufen ist.

Das solltest Du evtl. noch mal genauer erklären, für was das gut ist - besonders wofür alle 30 Sekunden.

Gruß Tommy

Tommy56: Das solltest Du evtl. noch mal genauer erklären, für was das gut ist - besonders wofür alle 30 Sekunden.

Gruß Tommy

Na der Teebeutel, der an einem Arm über der Tasse hängt, soll alle 30 Sekunden einmal hoch und runter gezogen werden. Dafür nehme ich ein umgebautes Servo, dessen polarität und damit der Richtungswechsel über ein Relais geändert wird. Ein kleines Bänchen mit einer Wäscheklammer am Ende erledigt den mechanischen Part ;)

Natürlich werde ich noch ein Bild posten wenn alles fertig ist :D

Ah, verstanden. Du müsstest dann ermitteln, wie lange der Teebeutel hoch und wieder runter laufen muss. Am Ende soll er dann wohl nur hoch gezogen werden.

Gruß Tommy

Tommy56: Ah, verstanden. Du müsstest dann ermitteln, wie lange der Teebeutel hoch und wieder runter laufen muss. Am Ende soll er dann wohl nur hoch gezogen werden.

Gruß Tommy

Und was sagst du nun zu meinen Fragen? :P

ChrisBoy: Und was sagst du nun zu meinen Fragen? :P

Ich sehe noch keinen Code für den Motor. Was soll ich also dazu sagen?

Ich würde an Deiner Stelle eine Funktion BeutelHoch und eine BeutelRunter bauen. In den 30Sekunden eine Funktion Schwenken, die BeutelHoch und BeutelRunter nacheinander aufruft und am Ende einmal BeutelHoch.

Gruß Tommy

Hallo Chris,

ich habe mir auch so einen Heber gebaut. Momentan aber nur mit einem SG90 Servo. Funktioniert aber super. Code habe ich aus Zeit und Erfolgsdruck in 10 Minuten mit delay geschrieben.

Momentan stelle ich den Code aber auf Echtzeit um. Im selben Zug kommt ein 8x2 LCD zum Einsatz. Als Zeitvorgabe finde ich ein Poti ausreichend. Der Heber startet mit anlegen der Spannung und kann über das Poti jederzeit verändert/abgebrochen werden.

[u]ChrisBoy, hättest du Interesse, dann schreib mir an was genau...[/u]

Ich finde einen Servo als einfachste Lösung des Problems. Der hat die Leistungselektronik eingebaut und das Gewicht eines nassen Teebeutels ist kein Problem für ihn. Als Eingabe sehe ich einen Encoder als optimale Lösung.

https://www.heise.de/select/make/2017/1/1488464563901699 https://www.heise.de/make/projekte/Tee-Timing-Maschine-3057233.html

Grüße Uwe

Ich sehe bei mir die Gefahr, dass wenn ein Encoder dran ist, ich auch ein Menü bastle :confused:

Mit einem Poti bin ich dieser Gefahr nicht ausgesetzt. Und man muss die letzte Zeit nicht im EEPROM Speichern ;D

Teeheber.jpg

Hier hats vielleicht nicht jemanden der Zeit, Lust und Bedarf hat und so einen Heber für sich gerne in 3D zeichnen möchte und einen Plotter besitzt??? Mal ganz frech gefragt...

Ich würde dann auch Platinen erstellen und bestücken.

Sorry für den Thread mis_brauch...