Mit einem Taster mehrere Funktionen ausführen

Hallo

Ich habe nochmals ein kleines Problem. Ich habe jetzt die letzten Tage versucht (blutiger Anfänger) einen Taster mit mehreren Funktionen zu belegen. Das Onlinebeispiel habe ich als Hilfe genommen, aber irgendwie gehts nicht so wie ich will.
Ich möchte einen Taster, der wenn einmal gedrückt, Funktion A ausführt. Bei zweimal drücken Funktion B und bei dreimal drücken Funktion C.
Nun habe ich versucht mit einer Variablen die Tastendrücke zu zählen, und dann je nach dem, die Funktionen auszuführen. Nun zählt er aber nicht immer. Manchmal überhaupt nicht und manchmal nur einmal. Ich habe den Sketch mal unten angehängt. Google und das Forum bringen keine wirkliche Lösungen - vielleicht verstehe ich auch den einen oder andern Sketch nicht richtig. Die Funktion millis() soll ja irgendwie für solche Zwecke geeignet sein, doch die verstehe ich überhaupt nicht. Kann mir da einer weiterhelfen?
Die LED an Pin 13 ist nur ein Platzhalter um die eigentliche Funktion des Tasterzählens zum laufen zu bringen.

int buttonPin = 2; //Taster "buttonPin" an Pin 2 angeschlossen
int ledPin = 13; //LED "ledPin" an Pin 13 angeschlossen

//Variablen des Zwischenspeichers:
int buttonPushCounter = 0;   //Zählt Tastendrücke
int buttonState = 0;         //Aktueller Tastenstatus
int lastButtonState = 0;     //Vorheriger Tastenstatus

void setup() {
  
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  
  buttonState = digitalRead(buttonPin); //Taster an buttonPin wird gelesen und in Zwischenspeicher buttonState gespeichert

  if (buttonState != lastButtonState) { //Wenn buttonState nicht gleich lastButtonState, dann...
    
    if (buttonState == LOW) { //Wenn buttonState gleich gedrückt, dann...
      buttonPushCounter++; //buttonPushCounter +1
      lastButtonState = buttonState; //Speichert buttonState in lastButtonState

      delay(50);

    buttonState = digitalRead(buttonPin);
    if (buttonState == LOW) { //Wenn buttonState gleich gedrückt, dann...
      buttonPushCounter++; //buttonPushCounter +1
      lastButtonState = buttonState; //Speichert buttonState in lastButtonState

      delay(50); 
    }
    buttonState = digitalRead(buttonPin);
    if (buttonState == LOW) { //Wenn buttonState gleich gedrückt, dann...
      buttonPushCounter++; //buttonPushCounter +1
      lastButtonState = buttonState; //Speichert buttonState in lastButtonState

      delay(50); 
    }
    buttonState = digitalRead(buttonPin);
    if (buttonState == LOW) { //Wenn buttonState gleich gedrückt, dann...
      buttonPushCounter++; //buttonPushCounter +1
      lastButtonState = buttonState; //Speichert buttonState in lastButtonState

      delay(50); 
    }
    } else {
      lastButtonState = buttonState;
    }
  }

  //Taster wird 1 Mal gedrückt:
  if (buttonPushCounter == 1) { //Wenn buttonPushCounter gleich 1, dann...
    digitalWrite(ledPin, HIGH); //Schalte ledPin an
  } else {
    digitalWrite(ledPin, LOW); //Sonst schalte ledPin aus
  }

  //Taster wird 2 Mal gedrückt:
  if (buttonPushCounter == 2) { //Wenn buttonPushCounter gleich 2, dann...
    digitalWrite(ledPin, HIGH); //Schalte ledPin an
  } else {
    digitalWrite(ledPin, LOW); //Sonst schalte ledPin aus
  }

  //Taster wird 3 Mal gedrückt:
  if (buttonPushCounter == 3) { //Wenn buttonPushCounter gleich 3, dann...
    digitalWrite(ledPin, HIGH); //Schalte ledPin an
  } else {
    digitalWrite(ledPin, LOW); //Sonst schalte ledPin aus
  }

  //Taster wird 4 Mal gedrückt:
  if (buttonPushCounter == 4) { //Wenn buttonPushCounter gleich 4, dann...
    digitalWrite(ledPin, HIGH); //Schalte ledPin an
  } else {
    digitalWrite(ledPin, LOW); //Sonst schalte ledPin aus
  }

buttonPushCounter = 0;

}

Grüsse

Stef

stef308:
Die Funktion millis() soll ja irgendwie für solche Zwecke geeignet sein, doch die verstehe ich überhaupt nicht. Kann mir da einer weiterhelfen?

Das BlinkWithoutDelay Beispiel ist ein MUSS um sinnvoll arbeiten zu können.

Welche Frage hast du konkret zu dem Beispiel?

Ansonsten würde ich dir nur die Library "OneButton" empfehlen, denn die kennt bereits einen Klick und einen Doppelklick. Nur bin ich der Meinung, dass der Umgang mit Millis einfach geübt werden muss.

Dieses Beispiel habe ich auch schon gesehen, aber ich hab da keine Ahnung wie ich das auf meinen Taster anwenden kann. Das Beispiel zählt ja die Millisekunden während des Betriebs und sobald die laufenden Millisekunden minus den vorherigen Millisekunden gleich einer Sekunde entspricht, blinkt die LED auf.
Wie soll ich das aber auf einen Taster umnutzen? :confused:

Die Library "OneButton" habe ich ebenfalls gefunden, aber da dort nur bis zum Doppelklick vorhanden ist und ich bei der überhaupt nichts verstehe habe ich die mal auf der Seite gelassen.

Dann hast Du BlinkWithoutDelay nicht wirklich verstanden.
Dass da eine LED blinkt ist nur ein Beispiel. Abstrahiere das Vorgehen von der LED.
Suche mal nach der Nachtwächtererklärung.
Wenn Du den Sinn dahinter nicht verstehst, bist Du in einer Sackgasse, denn diese Zeitsteuerung braucht man immer wieder.

Gruß Tommy

Hi

Dein Ansatz, einzelne Tastendrücke mittels delay(50); auseinander halten zu können, deutet auf einen schnellen Klick-Finger hin.

Dein Sketch entprellt den Taster 50 ms, um dann einen erneuten Versuch zu starten, ob der Taster gedrückt ist.
Das machst Du 4 Mal? (bei identischem Code kann man eine Funktion bauen)

Ist Dir bewusst, wie kurz 50ms sind? Das sind 20 mögliche Tastendrücke in der Sekunde - DAS nenne ich sportlich.

Du möchtest eher die Flanken des Taster erkennen.
Ein Entprellen via delay(20...50); kann man noch machen, drüber solltest Du wirklich millis() verinnerlicht haben.
Dann brauchst Du auch millis() um zu entscheiden, ob die Drückerei vorbei ist - nach welcher Zeit 'kommt kein Tastendruck mehr'?

MfG

So wie ich das verstehe, kann ich da nur die Differenz der Gesamtzeit für die vier Tastendrücke eingeben und wenn innerhalb dieser Zeit einmal gedrückt wurde, dann mach das, wenn zweimal gedrückt, dann jenes, etc.
Das wäre aber schätzungsweise bei einer Sekunde die ich für vier Tastendrücke benötigen würde und da...... Ach, das Programm läuft ja trotzdem weiter und bleibt nicht stehen! Dann bedeutet dies nur, dass es innerhalb dieser Zeitspanne die Tastendrücke aufnimmt, korrekt so?
Muss mir das nochmals durchlesen, bin verwirrt.

Ja, stimmt, ist bisschen sportlich :grinning: Hab ich mir nicht so kurz vorgestellt, da verschätzt man sich recht leicht. Pro Sekunde ca. vier Klicks sind akzeptabel denke ich.
Ja ich dachte ich machs viermal, weil ich ja maximal viermal den Taster drücken mag um Funktionen auszuführen. Stimmt schon, aber für den Anfang lass ich das lieber ein bisschen einfacher stehen.

Überlege mal was "Taste mehrmals gedrückt" überhaupt heißt !
Das heißt doch das man sie drückt (und das fehlt in deinem Code komplett) und wieder loslässt.
Wo ist der Test auf "Loslassen" ?

Dein Programm testet nur ob zu vier festen Zeitpunkten die Taste "noch" gedrückt ist.
Eigentlich testest du einen Zeitraum.

Das es bei bestimmten (schnellen) Tastentackern eventuell auch 1 - 4 mal gedrückt detektiert ist ein Seiteneffekt.

Du musst dir auch Gedanken machen in welchen Zeitraum das 1 - 4 mal drücken gilt und ab wann wieder
neu gezählt wird.

All das fehlt in deinem Programm.

  1. Problem in Teilprobleme zerlegen.
  2. Diese einzeln in "Flußdiagrammen" lösen.
  3. Einzelteile implementieren und testen (z.b. Funktion "CountKeyPresses")
  4. Einzelteile zusammenbauen und testen.

Ulli

Hallo,

na ja , die Frage ist ja eigendlich wie lange willst Du warten bevor Du die eingabe als beendet betrachtest und den Zählerstand auswertest.

Also nimm erst mal nur den Tatste und zähle mit Ihm hoch bis zu einem maximal wert z.B 4. Wenn Du bei 4 angekommen bist setzt Du den Zähler wieder auf 0. Damit kannst Du dann 4 Werte. 0-1-2-3 erhalten. Damit das nicht prellt kannst Du delay() verwenden. z.B delay(50).

wenn das sauber klappt musst Du wie bereits geschrieben den Umgang mit millis() lernen. Wenn Du das kannst gehts dann weiter. Dazu gibts Beispiele BlinkWithoutDelay.

Erfolgte kein Tastendruck zum Beispiel innerhalb 1 sekunde kannst Du den Zählerstand auswerten und den Zähler wieder auf Null setzten. Das kannst Du nicht mit delay machen, da wenn delay läuft das Program angehalten wird und wartet bis delay abgelaufen ist und Du somit nicht mehr mitbekommst ob der Taster nochmals gedrückt wurde.

eigendlich macht es für Anfänger Sinn die Aufgabe erst mal grob zu gliedern , keine Bange ist eigendlich ganz einfach auf einem Zettel. Anschliessend setzt man das dann in ausführbaren code um.

Taster erkennen
entprellen z.B mit delay geht aber auch mit millis()
wartezeit=millis()
counter++
wenn counter =4 dann counter=0

wenn millis() - wartezeit > 1000
auswerten
bei 0 nix machen
bei 1 funktion 1
bei 2 funktion 2
bei 3 funktion 3
Zählerstand =0 setzten

Hallo zusammen

Vielen Dank für die ganzen Hinweise!
Speziell ein grosses Dankeschön an Rentner! Die Liste hat mir wirklich sehr geholfen gestern noch den Taster zum Laufen zu bringen. Über Nacht ist mir dann aber noch eingefallen wie ich den Taster direkt nach dem loslassen messen kann. Habe zuerst die gesamte Zeit gemessen, indem man maximal viermal drücken kann. Das hat aber zu lange gedauert bis die Aktion ausgeführt wurde und in dem Fall, wenn die Zeitperiode abgelaufen ist und ich ganz wenig vorher gedrückt habe, hat er logischerweise statt zum Beispiel dreimal drücken nur einmal oder zweimal registriert.
Nun habe ich den Sketch soweit angepasst, dass er funktioniert:

int buttonPin = 2; //Taster "buttonPin" an Pin 2 angeschlossen
int ledPin = 13; //LED "ledPin" an Pin 13 angeschlossen

//Variablen des Zwischenspeichers:
int buttonPushCounter = 0;   //Zählt Tastendrücke
int buttonState = 0;         //Aktueller Tastenstatus
int lastButtonState = 0;     //Vorheriger Tastenstatus
unsigned long previousMillis = 0; //Speichert vergangene Zeit
const long interval = 500; //Intervall wo Tasterdrücke registriert wurden

void setup() {
  
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
}

void loop() {

  unsigned long currentMillis = millis(); //Zählt Millisekunden
  buttonState = digitalRead(buttonPin); //Taster an buttonPin wird gelesen und in Zwischenspeicher buttonState gespeichert
 
  if (buttonState != lastButtonState) { //Wenn buttonState nicht gleich lastButtonState, dann...
    
    if (buttonState == LOW) { //Wenn buttonState gleich gedrückt, dann...
      buttonPushCounter ++; //buttonPushCounter +1
      lastButtonState = buttonState; //Speichert buttonState in lastButtonState
      previousMillis = currentMillis; //Speichere jetzige Millisekunden in previousMillis
      delay(50);
    }
  else {
      lastButtonState = buttonState;
    }
  }

  if (currentMillis - previousMillis >= interval && buttonState == lastButtonState) { //Wenn gezählte Millisekunden minus vorherige Millisekunden (gespeicherte, vergangene Zeit) grösser/gleich interval ist und buttonState gleich lastButtonState ist, dann...

    //Taster wird 1 Mal gedrückt:
    if (buttonPushCounter == 1) { //Wenn buttonPushCounter gleich 1, dann...
      digitalWrite(ledPin, HIGH); //Schalte ledPin an
      delay(200);
      digitalWrite(ledPin, LOW);
    }

    //Taster wird 2 Mal gedrückt:
    if (buttonPushCounter == 2) { //Wenn buttonPushCounter gleich 2, dann...
      digitalWrite(ledPin, HIGH); //Schalte ledPin an
      delay(200);
      digitalWrite(ledPin, LOW);
      delay(200);
      digitalWrite(ledPin, HIGH);
      delay(200);
      digitalWrite(ledPin, LOW);
    }

    //Taster wird 3 Mal gedrückt:
    if (buttonPushCounter == 3) { //Wenn buttonPushCounter gleich 3, dann...
      digitalWrite(ledPin, HIGH); //Schalte ledPin an
      delay(200);
      digitalWrite(ledPin, LOW);
      delay(200);
      digitalWrite(ledPin, HIGH);
      delay(200);
      digitalWrite(ledPin, LOW);
      delay(200);
      digitalWrite(ledPin, HIGH);
      delay(200);
      digitalWrite(ledPin, LOW);
    }

    //Taster wird 4 Mal gedrückt:
    if (buttonPushCounter == 4) { //Wenn buttonPushCounter gleich 4, dann...
      digitalWrite(ledPin, HIGH); //Schalte ledPin an
      delay(200);
      digitalWrite(ledPin, LOW);
      delay(200);
      digitalWrite(ledPin, HIGH);
      delay(200);
      digitalWrite(ledPin, LOW);
      delay(200);
      digitalWrite(ledPin, HIGH);
      delay(200);
      digitalWrite(ledPin, LOW);
      delay(200);
      digitalWrite(ledPin, HIGH);
      delay(200);
      digitalWrite(ledPin, LOW);
    }

    buttonPushCounter = 0; //Setze buttonPushCounter auf 0

  }
}

Nun möchte ich das ganze mit zwei unabhängigen Arduinos steuern. Also einem Sender und Empfänger. Da habe ich den Sketch oben angepasst und das ist bei rausgekommen:

//Sender:

int buttonPin = 2; //Taster "buttonPin" an Pin 2 angeschlossen

//Variablen des Zwischenspeichers:
int buttonPushCounter = 0;   //Zählt Tastendrücke
int memoryButtonPushCounter = 0; //Speicher Tastendrücke
int buttonState = 0;         //Aktueller Tastenstatus
int lastButtonState = 0;     //Vorheriger Tastenstatus
unsigned long previousMillis = 0; //Speichert vergangene Zeit
const long interval = 500; //Intervall wo Tasterdrücke registriert wurden

void setup() {
  Serial.begin(38400);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop() {

  unsigned long currentMillis = millis(); //Zählt Millisekunden
  buttonState = digitalRead(buttonPin); //Taster an buttonPin wird gelesen und in Zwischenspeicher buttonState gespeichert
 
  if (buttonState != lastButtonState) { //Wenn buttonState nicht gleich lastButtonState, dann...
    
    if (buttonState == LOW) { //Wenn buttonState gleich gedrückt, dann...
      buttonPushCounter ++; //buttonPushCounter +1
      lastButtonState = buttonState; //Speichert buttonState in lastButtonState
      previousMillis = currentMillis; //Speichere jetzige Millisekunden in previousMillis
      delay(50); //Entprellen des Tasters
    }
  else {
      lastButtonState = buttonState;
    }
  }

  if (currentMillis - previousMillis >= interval && buttonState == lastButtonState) { //Wenn gezählte Millisekunden minus vorherige Millisekunden (gespeicherte, vergangene Zeit) grösser/gleich interval ist und buttonState gleich lastButtonState ist, dann...
    memoryButtonPushCounter = buttonPushCounter;
    buttonPushCounter = 0; //Setze buttonPushCounter auf 0
  }

  Serial.write(',');
  Serial.write(memoryButtonPushCounter);

}

------------------------------------------------------------------------------------------------
//Empfänger:

int buttonPushCounter;

int ledPin = 13; //LED "ledPin" an Pin 13 angeschlossen


void setup() {

  Serial.begin(38400);

  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

}

void loop() {

  if(Serial.read() == ','){
    buttonPushCounter = Serial.read();
  }

    //Taster wird 1 Mal gedrückt:
    if (buttonPushCounter == 1) { //Wenn buttonPushCounter gleich 1, dann...
      digitalWrite(ledPin, HIGH); //Schalte ledPin an
      delay(200);
      digitalWrite(ledPin, LOW);
    }

    //Taster wird 2 Mal gedrückt:
    if (buttonPushCounter == 2) { //Wenn buttonPushCounter gleich 2, dann...
      digitalWrite(ledPin, HIGH); //Schalte ledPin an
      delay(200);
      digitalWrite(ledPin, LOW);
      delay(200);
      digitalWrite(ledPin, HIGH);
      delay(200);
      digitalWrite(ledPin, LOW);
    }

    //Taster wird 3 Mal gedrückt:
    if (buttonPushCounter == 3) { //Wenn buttonPushCounter gleich 3, dann...
      digitalWrite(ledPin, HIGH); //Schalte ledPin an
      delay(200);
      digitalWrite(ledPin, LOW);
      delay(200);
      digitalWrite(ledPin, HIGH);
      delay(200);
      digitalWrite(ledPin, LOW);
      delay(200);
      digitalWrite(ledPin, HIGH);
      delay(200);
      digitalWrite(ledPin, LOW);
    }

    //Taster wird 4 Mal gedrückt:
    if (buttonPushCounter == 4) { //Wenn buttonPushCounter gleich 4, dann...
      digitalWrite(ledPin, HIGH); //Schalte ledPin an
      delay(200);
      digitalWrite(ledPin, LOW);
      delay(200);
      digitalWrite(ledPin, HIGH);
      delay(200);
      digitalWrite(ledPin, LOW);
      delay(200);
      digitalWrite(ledPin, HIGH);
      delay(200);
      digitalWrite(ledPin, LOW);
      delay(200);
      digitalWrite(ledPin, HIGH);
      delay(200);
      digitalWrite(ledPin, LOW);
    }

}

Ich frage mich jetzt, was ist, wenn ich noch andere Knöpfe, Taster und Joysticks in den Sketch vom Sender, "void loop()", z.B. zwischen der Zeile "buttonState = digitalRead(buttonPin);" und "if(buttonState != lastButtonState){..." packe. Wird dann dieser Taster trotzdem immer registriert oder ist da ein Problem weil der Arduino zu lange braucht um den "loop" zu wiederholen und alle verschiedenen Tasterdrücke zu registrieren? Das Sendermodul soll mit einem Arduino Mini Pro laufen.

Grüsse und danke bis hierhin nochmals

Stef

P.S. Ich weiss, der Sketch könnte man sicher noch irgendwie vereinfachen, aber zum besseren Nachvollziehen und Verständnis wollte ich ihn so belassen.

Eigentlich willst du eine Statemachine haben, die ungefähr so aussieht:

TO -> Zeit nach der die Eingabe beendet ist
BTO -> Zeit für das debouncen des Tasters

Über den Pfeilen steht die Bedingung, die erfüllt sein muss, damit man den Pfeil gehen darf.
Unter dem Pfeil stehen die Aktionen, die man beim gehen ausführen muss.

Hallo,
danke für die Bumen,
Eigendlich kannst du so viele Taste einbauen wie Du willst, bzw anschliessen kannst. Wenn Du ein Gefühl dafür bekommen willst wie Lange die Zeit für einen Umlauf ist dann lass Dir das Doch einfach irgendwo im Loop anzeigen, z.B ganz oben.Wenn Du keine delay mit langen Zeiten ständig abarbeitest wirst Du dich wundern wie schnell das geht. Wobei die Serielle Ausgabe sicher ebenfalls viel Zeit benötigt, aber auch das kann man messen. Wenn Du dann immer noch irgendwo delays drin hast die ständig zu stark bremsen kannst Du die auch noch durch millis() ersetzen. Natürlich sollte man aufpassen mit Schleifenkonstukten im Program z.B for , do , while usw.

Serial.println (millis()-lastmillis());
lastmillis=millis();

lastmillis global als unsigned long, aber das kennst Du ja schon.

da Du ja anscheinend was lernen willst, mach doch mal ein Programm mit mit einer Schleife z.B 1000 Integer Multiplikationen und mess die Zeit wie lang das dauert. Oder 1000 mal Seriell.print(einen Integer) und mess die Zeit dazu. Hier wieder für den Zettel für Dich, weil Dir das so gut gefallen hat :wink:

startzeit setzen
schleife bilden
was in der schleife bearbeite
Messzeitt =aktuelle Zeit - startzeit
Messzeit ausgeben

übrigens es gibt auch noch micros()

Heinz