Taster entprellen an einem konkreten Beispiel

Hallo zusammen.
Ich habe eine konkrete frage zum entprellen eines Tasters. Wir machen gerade in der Schule ein Programm für ein “Parkhaus” (10. Klasse Realschule und unser Lehrer hat selber kaum Ahnung vom programmieren). Das Programm soll kurz gesagt mit einer roten und einer grünen LED anzeigen, ob es noch freie Parkplätze gibt. Ich denke, dass ich das Programm prinzipiell richtig habe, allerdings kapiere ich das ganze mit dem entprellen des Tasters nicht. Ich habe dazu schon viel hier im Forum gelesen, kapiere aber nicht, wie ich das genau in meinem Programm einfügen muss. Ich hänge das Programm hier einfach mal an. Vielleicht kann mir ja jemand helfen und mich auch noch auf weitere Probleme in meinem Programm hinweisen :wink: Danke schonmal im Vorraus
LG Elias

int Ausfahrt=7;
int Einfahrt=2;
int LEDgruen=4;
int LEDrot=8;
int Zaehler;

void setup() {
  pinMode (Ausfahrt,INPUT);
  pinMode (Einfahrt, INPUT);
  pinMode (LEDgruen, OUTPUT);
  pinMode (LEDrot, OUTPUT);
  Zaehler=10;
}

void loop() {
if(digitalRead(Einfahrt)==HIGH){                            //Der Knopf bei der Einfahrt wird gedrückt => dann passiert folgendes:
  (Zaehler=Zaehler-1);}                                     //Der Zähler zählt eins runter.
   else{                                                    //Wenn der Knopf nicht gedrückt wird, passiert folgendes:
      if (digitalRead(Ausfahrt)==HIGH){                     //Es wird abgefragt, ob der Knopf von der Ausfahrt gedrückt wird. Wenn dies so ist passiert folgendes:
         (Zaehler=Zaehler+1);}                              //Der Zähler zählt eins hoch.
         else{                                              //Wenn der Knopf nicht gedrückt wird, passiert folgendes.
            if (Zaehler==0){                                //Es wird abgefragt, ob der Zähler im Moment 0 entspricht. Wenn dies so ist passiert folgendes:
               digitalWrite(LEDgruen, LOW);                 //Die grüne LED geht aus, weil keine freien Parkplätze mehr vorhanden sind.
               digitalWrite(LEDrot, HIGH);}                 //Die rote LED geht an, wegen des oben genannten Zustandes.
               else{                                        //Falls das alles nicht passieren sollte, passiert folgendes:
                   if (Zaehler>0){                          //Es wird geschaut, ob der Zähler einer Zahl größer als 0 entspricht. Ist dies der Fall, passiert folgendes:
                      digitalWrite(LEDrot, LOW);            //Die rote LED geht/bleibt aus, weil Parkplätze vorhanden sind.
                      digitalWrite(LEDgruen, HIGH);}        //Die grüne LED geht/bleibt an, weil Parkplätze vorhanden sind.
                      else{                                 //Der folgende Schritt wird ausgeführt
                          if (Zaehler<0){                   //Es wird geschaut, ob der Zähler einer Zahl kleiner als 0 entspricht. Wenn dies so ist passiert folgendes:
                             (Zaehler=0);}                  //Der Zähler wird auf 0 gestellt
                             else{                          //Der ganze Ablauf beginnt von vorne.
                                        }
                                 }
                          }                                 //Die folgenden geschweiften Klammern beenden die verschiedenen Aufgaben.
                  }
            }
      }

Arduino_neu_Parkhaus.ino (2.61 KB)

im einfachsten Fall mit einem delay(10) nach dem Einlesen des Tasters.
Besser den Status des Taters erfassen und nur wenn er von low nach high wechselt ein delay(10) einfügen. Ansonsten mit millis() die Zeit erfassen und nach Ablauf von der Entprellzeit ein erneutes Einlesen des Tasters zulassen.
Ich habe dir mal ein ähnliches Programm eingefügt, vlt. kannst du es auf deine Bedürfnisse anpassen.

/*
 *© Ardubu Nov. 2017
 *Taster wird zwischen GND und pin_x angeschlossen
 *interner Pullup Widerstand aktiviert
 *der counter zählt von 0 bis 3 jeden Tastendruck
*/

#define DEBUG //Nur zur Fehlersuche aktivieren
#define tasterHoch 2   //Taster an D2 und GND
#define tasterRunter 3 //Taster an D3 und GND
#define ledPin1 10     // LED an D11
#define ledPin2 11     // LED an D12
#define ledPin3 12     // LED an D13

#define debounce_delay 15 //Entprellzeit für den Taster in ms
  bool tasterHochState, tasterRunterState, tasterHochState_alt,  tasterRunterState_alt;// Variablendeklaration (global)
  uint8_t counter; //Zählt wie oft die Taste gedrückt wurde
void setup() {
  #ifdef DEBUG
  Serial.begin(115200);
  Serial.println("Setup");
  #endif
  pinMode(tasterHoch,   INPUT_PULLUP);
  pinMode(tasterRunter, INPUT_PULLUP);
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT);
 }

void loop() {

 static uint32_t debounce_time;
 if (millis()-debounce_time>debounce_delay)tasterHochState = digitalRead(tasterHoch); //einlesen des Tasters
    
 if (tasterHochState != tasterHochState_alt) // bei Pegelwechsel 
    {
     debounce_time=millis();
     #ifdef DEBUG
               Serial.println(counter);
     #endif
     if(!tasterHochState)//wenn Taster gedrückt
       {counter++;
        counter   = min (3 , counter  );
       }
        tasterHochState_alt = tasterHochState; // state aktualisieren
     }
 if (millis()-debounce_time>debounce_delay)tasterRunterState = digitalRead(tasterRunter); //einlesen des Tasters   
   
 if (tasterRunterState != tasterRunterState_alt) // bei Pegelwechsel 
    {
     debounce_time=millis();
     #ifdef DEBUG
               Serial.println(counter);
     #endif
     if(!tasterRunterState)//wenn Taster gedrückt
       {counter--;
        if(counter<1||counter>250) counter=0;
       }
        tasterRunterState_alt = tasterRunterState; // state aktualisieren
     }  

// *********************************************************** counter   = 0 ****************************       
          if (counter   == 0) {
          digitalWrite (ledPin1, LOW);
          digitalWrite (ledPin2, LOW);
          digitalWrite (ledPin3, LOW);
           }
// *********************************************************** counter   = 1 ****************************       
          if (counter   == 1) {
          digitalWrite (ledPin1, HIGH);
          digitalWrite (ledPin2, LOW);
          digitalWrite (ledPin3, LOW);
          }
 // *********************************************************** counter   = 2 ****************************       
          if (counter   == 2) {
          digitalWrite (ledPin1, HIGH);
          digitalWrite (ledPin2, HIGH);
          digitalWrite (ledPin3, LOW);
          }
 // *********************************************************** counter   = 3 ****************************       
          if (counter   == 3) {
          digitalWrite (ledPin1, HIGH);
          digitalWrite (ledPin2, HIGH);
          digitalWrite (ledPin3, HIGH);
          }        
}//Ende loop

Hi

So manch ein Lehrer ist hobbymäßig ebenfalls hier unterwegs und wenn's neben Spaß auch noch eine Weiterbildung 'in eigener Sache' gibt, muß Das ja nicht schlecht sein.

Zumindest ich hatte das Glück, daß meine Lehrer der technischen Fächer 'nicht ganz ohne' waren. Klar: Mir Jungspund (zumindest damals g) mit 'Rechner' als Hobby machte 'der alte Mann' in DOS Nichts vor - und (GW-)Basic sprach ich besser als meine Muttersprache ;). Aber Er wusste, Was Wie geht, konnte Helfen und auch verstehen, was 'unsereins' zusammen programmiert hat. ... ähnliches Glück hatte ich auch mit Mathe, Physik und Chemie! ... und PC, Basic UND Mathe ... Herz, was willst Du mehr?? Mit Physik konnte man 'Ballerburg' nachschreiben (ballistischer Wurf) - Chemie war halt außen vor, für Atom-Bindungen waren meine 'Progger-Skills' zu 'lame' ;)

MfG

Edit Anmerkungen zum Lehrer wurden verstanden, deshalb auch hier wieder entfernt. Danke schon Mal dafür.

Hallo ardubu,

das mit dem delay(10); hat leider nicht funktioniert. Habe ich da einfach etwas falsch gemacht? Das andere, wo du beschrieben hast, habe ich jetzt 30 Minuten versucht zu verstehen. Ich verstehe das irgendwie gar nicht.

LG Elias

Hi

'Hat nicht funktioniert' ist keine adäquate Fehlerbeschreibung. WO hattest Du das delay(10); verbaut, waren Veränderungen spürbar?

Wenn Du zum Endprellen auch eine Lib nehmen darfst, suche nach 'debounce' - dazu müsste es auch ein Beispiel in der IDE geben. Wenn Du KEINE Lib nehmen darfst, darfst Du Diese aber 'abkupfern' - also in die Lib rein schauen und den Kram nachgeschrieben (böse Zungen würden 'abgeschrieben' schreiben). Das 'fremder Leute Libs lesen' fördert auch das Verständnis. was Da nun gemacht wird. Wenn Du Das 'gefressen' hast, ist das Nachschreiben zwar immer noch nicht aus dem Ärmel rausgeschüttelt, aber Du verstehst Deinen Sketch am Schluß.

Zu 'millis()' und der 'Nachtwächter-Erklärung': Combies Übersicht zu diesem Thema, 'Wachmann' heißt der Link bei Ihm Die anderen Links sind aber auch einen Blick wert.

MfG

... wieder Abschicken statt Vorschau geklickt ...

Ich würde das Debouncen und die State Change Detection Bounce2 überlassen.

#include <Bounce2.h>
const byte pinAusfahrt = 7;  // Tasten schließen gegen GND
const byte pinEinfahrt = 2;  // Tasten schließen gegen GND
const byte pinLEDgruen = 4;
const byte pinLEDrot = 8;

int freiePlaetze = 10;
Bounce einfahrt, ausfahrt;

void setup() {
  einfahrt.attach(pinEinfahrt, INPUT_PULLUP);
  ausfahrt.attach(pinAusfahrt, INPUT_PULLUP);
  pinMode(pinLEDgruen, OUTPUT);
  pinMode(pinLEDrot, OUTPUT);
}

void loop() {
  if (einfahrt.update() && einfahrt.fell()) {
    if (--freiePlaetze < 0) {
      freiePlaetze = 0;
    }
  }
  if (ausfahrt.update() && ausfahrt.fell()) {
    freiePlaetze++;
  }
  digitalWrite(pinLEDgruen, freiePlaetze > 0);
  digitalWrite(pinLEDrot, freiePlaetze <= 0);
}

'Hat nicht funktioniert' ist keine adäquate Fehlerbeschreibung. WO hattest Du das delay(10); verbaut, waren Veränderungen spürbar?

Ich habe es beim ersten Mal nach (Zaehler=Zaehler-1); und (Zaehler=Zaehler+1); eingefügt. Da dort keine Veränderungen zu sehen waren, habe ich es danach nochmal nach den jeweiligen if-Abfragen eingefügt also nach if(digitalRead(Einfahrt)==HIGH) und dementsprechend auch nach 'Ausfahrt'. Dort hatte ich dann die Veränderung, dass ich, wenn ich den Einfahrt Button gedrückt habe, für eine Sekunde nur die grüne LED geleuchtet hat.

Hallo,

Dein Sketch aus #1 ist ja nicht so falsch. Eigendlich hast du zunächst kein Problem mit dem prellen der Taster, sonder solange ein Taster gedrückt wird wird auch immer weiter gezählt. Wenn Du lange drückst wir eben viel gezählt.

Du darfst also nur dann einmal zählen wenn der Taster den Zustand von “nicht gedrückt” auf “gedrückt” wechselt. Dazu must du dir den Zustand in einer Variablen speichern. Wenn der aktuelle Zustand gedrückt ist , der vom letzten mal aber “ungedrückt” war dann muss gezählt werden.

Hier mal nur ein Ansatz dazu. Das delay zum entprellen ist unten mit drin. Damit wird hier erreicht das eine Signalwechsel < 10ms nicht erkannt wird. Besser wäre noch den Zustand der Taster nur an einer Stelle , oben im loop , einzulesen und in einer bool Variablen abzulegen. Dann nur noch mit dieser Variablen arbeiten.

die Variablen letzeEinfahrt, letzteAusfahrt must Du natürlich noch deklarieren, in deinem Fall mit int.
(nicht getestet)

if (digitalRead(Einfahrt) == HIGH && letzeEinfahrt == LOW) {
  letzteEinfahrt = HIGH;
  Zaehler = Zaehler - 1;
  delay(10);
}
if (digilaRead(Einfahrt) == LOW)letzteEinfahrt = LOW;


if (digitalRead(Ausfahrt) == HIGH && letzteAusfart == LOW) {
  letzteAusfahrt = HIGH;
  Zaehler = Zaehler + 1;
  delay(10);
}
if (digitalRead(Ausfahrt == LOW) letzteAusfahrt = LOW;

Du kannst auch die meisten else weglassen die Abfragen sind ja eigendlich unabhängig voneinander. Wenn eine Einfahrt und einen Ausfahr wirklich mal gleichzeitig kommen muss ja doch in beide Richtungen gezählt werden können, mit else würde ja nur die erste Bedingung bearbeitet.

Zur Hardware gibts auch noch was zu sagen. Du verwendest positive logik damit benötigen Deine Taster einen Pull down Widerstand, oder sie schalten eindeutig auf H und L Signal. Ein offener Schalter geht nur mit einem Pull down.

Heinz