Frage der Umsetzbarkeit mit Taster und onebutton.h

Guten Abend Zusammen,

ich versuche mein Grundwissen (schon leicht übertrieben) mit einem eigenen Projekt jetzt endlich einmal zu erweitern.

Aus einem dummen Gespräch entwickelte sich das folgende „Projekt“.

Es geht darum, dass ich mit einem Taster mehrere Funktionen steuern will.

Grundzustand: LED1 - aus; LED2 - aus;
Erster Klick (1): LED1 - an, LED2 - aus;
Nächster Klick (+1): LED1 - aus; LED2 - an;
Nächster Klick (+1): LED1 - an; LED2 - an;
Doppelklick: alles wieder aus.

oder

Taster zum ersten Mal lang drücken (1): LED1 - an, blinkt; LED2 - aus;
erneut Taster lang drücken (+1): LED1 - aus; LED2 - an, blinkt;
wieder Taster lang drücken (+1): LED1 - an, blinkt; LED2 - an, blinkt;
Doppelklick: alles wieder aus.

Ich habe mir jetzt die Library „OneButton.h“ nach einigem suchen als aussichtsreichste Herangehensweise ausgeguckt. Aber ich find den Anfang nicht. Auch ein ähnliches Projekt, an dem ich mal im Code eine Inspiration holen kann, finde ich nicht.

Frage 1. Ist das Projekt an sich umsetzbar?
Frage 2. Ist die Library OneButton.h dafür geeignet

Danke für die Hilfe

Der Rhöner

Ich denke, das Projekt geht auch ohne eine Library.
Du has zwei LED und einen Taster. Da langweilt sich sogar ein Attiny85 mit 1MHz Taktfrequenz.
Du kannst sogar die normalen Arduinofunktionen nutzen, weil du nichts zeitkritisches machen musst.
Hechel einfach mal die Adafruit Lessons durch und du bekommst das ohne Problem selber hin.

Aus den Beispielen von OneButton zusammengestellt könnte es zum Beispiel so aussehen:

/*                    LED1   LED2
    Grundzustand:     aus    aus
    Klick 1:          an     aus
    Klick 2:          aus    an
    Klick 3:          an     an
    Doppelklick:      aus    aus

Button (Taster) nach GND
*/

#include "OneButton.h"

const byte buttonPin = 12;   // den eigenen Gegebeheiten anpassen
const byte led1pin   =  6;   // den eigenen Gegebeheiten anpassen
const byte led2pin   =  7;   // den eigenen Gegebeheiten anpassen
byte myLedState;

// Setup a new OneButton
// The 2. parameter activeLOW is true, because external wiring sets the button to LOW when pressed.
OneButton button(buttonPin, true);

// In case the momentary button puts the input to HIGH when pressed:
// The 2. parameter activeLOW is false when the external wiring sets the button to HIGH when pressed.
// The 3. parameter can be used to disable the PullUp .
// OneButton button(PIN_INPUT, false, false);


void setup() {
  Serial.begin(9600);

  // enable the leds
  pinMode(led1pin, OUTPUT);
  pinMode(led2pin, OUTPUT);

  // link the singleclick function to be called on a single click event.
  button.attachClick(click1);

  // link the doubleclick function to be called on a doubleclick event.
  button.attachDoubleClick(doubleclick);
}


void loop() {
  // keep watching the push button:
  button.tick();

  switch (myLedState) {
    case 0:
      digitalWrite(led1pin, LOW);
      digitalWrite(led2pin, LOW);
      break;
    case 1:
      digitalWrite(led1pin, HIGH);
      digitalWrite(led2pin, LOW);
      break;
    case 2:
      digitalWrite(led1pin, LOW);
      digitalWrite(led2pin, HIGH);
      break;
    case 3:
      digitalWrite(led1pin, HIGH);
      digitalWrite(led2pin, HIGH);
      break;
  }
}


// this function will be called when the button was pressed 1 time
void click1() {
  myLedState++;
  if (myLedState > 3) myLedState = 3;
  Serial.print("click  ");
  Serial.println(myLedState);
}


// this function will be called when the button was pressed 2 times in a short timeframe.
void doubleclick() {
  myLedState = 0;
  Serial.println("doubleclick");
}

Hallo Rhoendrache

Hier kommt ein einfaches Beispiel ohne Bibliothek und Doppelklick für´s Studium.

constexpr byte ButtonPin {A0};
enum LedName {One,Two};
constexpr byte LedPins[] {9, 10};
void setup()
{
  pinMode(ButtonPin, INPUT_PULLUP);
  for (auto LedPin : LedPins) pinMode(LedPin, OUTPUT);
}
void loop()
{
  int buttonRead = !digitalRead(ButtonPin);
  delay (20); // QAD debounce
  if (buttonRead == !digitalRead(ButtonPin))
  {
    static int buttonReadOld = false;
    if (buttonReadOld != buttonRead)
    {
      buttonReadOld = buttonRead;
      if (buttonRead)
      {
        static int counter = 0;
        counter++;
        digitalWrite(LedPins[One], counter & 1);
        digitalWrite(LedPins[Two], counter & 2);
      }
    }
  }
}

An sich schon, allerdings ist die Aufgabenbeschreibung das eigentliche Problem.

Ich nehme mal an, es gilt immer:
doppelklick : -> Grundstellung (Beide LED aus)

Aber was soll passieren, wenn nach einem oder mehreren kurzen Klicks ein langer kommt? Oder umgekehrt?
Was soll beim vierten gleichartigen (lang oder kurz) Klick passieren?
Was bedeutet "blinkt" in deiner Aufgabenbeschreibung?
Da "blinkt" wohl auf jeden Fall eine gewisse Zeit dauert, was soll passieren, wenn währenddessen ein Tastendruck passiert?

Nachtrag: (Eher eine Pingeligkeit)
Soll schon etwas passieren, wenn erkannt wurde dass der Tastendruck "lang" ist, oder erst, wenn danach die Taste wieder losgelassen wurde ? (Wenn es lange Tastendrücke gibt, kann ein kurzer erst beim Loslassen erkannt werden.)

Allerdings könnte die lang/kurz Unterscheidung und die Blinkdauer auch zusammenhängen: dann ginge die Led sofort beim Drücken an, und wenn die lang-Dauer erreicht ist, geht die Led (blinkend) wieder aus und blinkt weiter, egal wann der Taster losgelassen wird. Wird die Taste vorher losgelassen, bleibt die Led im Dauer-An Zustand.

Du siehst, eine vollständige Aufgabenstellung ist nicht ohne.
Und ob Taster-Bibliotheken genau machen was du dir vorstellst, käme auch auf einen Versuch (oder genaue Analyse) an.

Oder du schaust dir die Beispiele einer Bibliothek an und freust dich daran, was für Funktionen sie bietet. (Oft mehr aber anders als du dir gewünscht hättest.)

mal ganz unbefangen von dem, was vorher schon geantwortet wurde:
die oneButton.h ist schon eine praktische Sache. ich würde die Aufgabenstellung, auch, wenn sie ziemlich klein ist, strukturiert angehen und sie aufteilen.

Zuerst würde ich einen globalen Zähler, der zum Programmstart auf 0 gesetzt ist, in "Clicked" mit jedem Tastendruck um 1 erhöhen. Das heißt, der Zähler kann von 0 bis xx laufen.
Um den Wert des Zählers zu begrenzen gibt es mehrere Möglichkeiten. Entweder mit constrain oder mit einer einfachen if-Struktur. (constrain wird wohl intern nichts anderes machen, als man selbst mit einer if-Struktur machen würde)

Dann würde ich in "DoubleClicked" bei einem Doppelklick den Zähler wieder auf null setzen.

Als zweites würde ich einer switch/case Struktur festlegen, was bei jedem möglichen Zählerstand (hier 0 ... 3) passieren soll.

  • 0 = LED1 aus, LED2 aus
  • 1 = LED1 an, LED2 aus
  • 2 = LED1 aus, LED2 an
  • 3 = LED1 an, LED2 an

Mit so einem getrennten Vorgehen kann man in größeren Projekten die Übersichtlichkeit verbessern und gegebenenfalls später einfach das Ganze erweitern.

Das Ganze nennt sich endlicher Automat oder finite state machine und ist in vielen Fällen eine wichtige Grundlage der Programmierung.

Zum beispiel kann man auch mehrere solcher endlichen Automaten in einem Programm verwenden und gegebenenfalls Abhängigkeiten zwischen diesen Automaten herstellen, indem man die Zählvariable abhängig vom Zustand des einen Automaten und gegebenenfalls weiterer Bedingungen einfach ändert.

Das setzt natürlich voraus, daß man nicht blockierend programmiert, also kein delay() verwendet.

Hallo und guten Abend,

sorry, dass ich mich erst jetzt melde, aber wie immer ist es vor Weihnachten und auch noch zum Jahresende immer hektischer als sonst. Aber jetzt ist erst einmal Urlaub.
Ich gehe Eure Antworten durch und melde mich dann an den Feiertagen.
Vielen Dank für die Unterstützung und Euch schöne Feiertage

Hallo und guten Abend,

vorab noch einmal vielen Dank für die Unterstützung.
Ich hatte mich mit beiden Methoden einmal auseinandergesetzt und hat mich mit dem Sketch von uxomm mal beschäftigt, weil ich es einfach verstehen will.

Angepasst an meinen Aufbau hat die Variante mit dem Dauerlicht auch hervorragende funktioniert.

Dann dachte ich in meiner Naivität, dass ich die Blinkfunktion mal schnell einpflege und fertig. Naja, dachte ich.

Ich bekomme jetzt bei dem void langerDruckStopp() { bei jedem „break“ einen Meckerbalken und Void doubleclick ebenfalls.

Ich komme hier nicht mehr weiter.
Habt Ihr einen Tipp, wo ich so kapital versage?

Danke im Voraus…

/*                    LED1   LED2
    Grundzustand:     aus    aus
    Klick 1:          an     aus
    Klick 2:          aus    an
    Klick 3:          an     an
    Doppelklick:      aus    aus

Button (Taster) nach GND
*/

#include "OneButton.h"

const byte buttonPin = A5;   // den eigenen Gegebeheiten anpassen
const byte led1pin   =  8;   // den eigenen Gegebeheiten anpassen
const byte led2pin   =  12;   // den eigenen Gegebeheiten anpassen
byte myLedState;

// Setup a new OneButton
// The 2. parameter activeLOW is true, because external wiring sets the button to LOW when pressed.
OneButton button(buttonPin, true);

// In case the momentary button puts the input to HIGH when pressed:
// The 2. parameter activeLOW is false when the external wiring sets the button to HIGH when pressed.
// The 3. parameter can be used to disable the PullUp .
// OneButton button(PIN_INPUT, false, false);


// Timer Rückstellung
unsigned long timer = 0;

void setup() {
  Serial.begin(9600);

  // enable the leds
  pinMode(led1pin, OUTPUT);
  pinMode(led2pin, OUTPUT);

  // link the singleclick function to be called on a single click event.
  button.attachClick(click1);

  // Funktion bei langen Drückendes Taters
  button.attachLongPressStart(langerDruckStart);
  //button.attachLongPressStop(langerDruckStopp);

  // link the doubleclick function to be called on a doubleclick event.
  button.attachDoubleClick(doubleclick);
}


void loop() {
  // Abfrage Taster:
  button.tick();
  delay(10);

  switch (myLedState) {
    case 0:
      digitalWrite(led1pin, LOW);
      digitalWrite(led2pin, LOW);
      break;
    case 1:
      digitalWrite(led1pin, HIGH);
      digitalWrite(led2pin, LOW);
      break;
    case 2:
      digitalWrite(led1pin, LOW);
      digitalWrite(led2pin, HIGH);
      break;
    case 3:
      digitalWrite(led1pin, HIGH);
      digitalWrite(led2pin, HIGH);
      break;
  }
}


// this function will be called when the button was pressed 1 time
void click1() {
  myLedState++;
  if (myLedState > 3) myLedState = 3;
  Serial.print("click  ");
  Serial.println(myLedState);
}

void langerDruckStart() {
// warten bis die LED 1 oder 2 dauerhaft leuchtet
int i = 0;
// zweimal blinken, danach LED 1 und/oder2 blinken bis doubleclick
// bis der Taster losgelassen wurde
while (i < 2)
{
  digitalWrite(led1pin, HIGH);
  delay(50);
  digitalWrite(led1pin, LOW);
  delay(200);;
  i ++;
}
}

void langerDruckStopp() {

  switch (myLedState) {
      case 0:
      if(millis()-timer > 500){
      digitalWrite(led1pin, HIGH);
      digitalWrite(led2pin, LOW);
      }
      
      if(millis()-timer > 1000){
      digitalWrite(led1pin, LOW);
      digitalWrite(led2pin, LOW);
      timer=millis();
      }

      if(timer>millis()){
        timer=0      
      break;

      case 1:
      if(millis()-timer > 500){
      digitalWrite(led1pin, LOW);
      digitalWrite(led2pin, HIGH);
      }
      
      if(millis()-timer > 1000){
      digitalWrite(led1pin, LOW);
      digitalWrite(led2pin, LOW);
      timer=millis();
      }

      if(timer>millis()){
        timer=0
      break;

      case 2:
      if(millis()-timer > 500){
      digitalWrite(led1pin, HIGH);
      digitalWrite(led2pin, HIGH);
      }
      
      if(millis()-timer > 1000){
      digitalWrite(led1pin, LOW);
      digitalWrite(led2pin, LOW);
      timer=millis();
      }

      if(timer>millis()){
        timer=0      
      break;
}
}

// this function will be called when the button was pressed 2 times in a short timeframe.
void doubleclick() {
  myLedState = 0;
  Serial.println("doubleclick");
}

Im Code fehlen Semikolons und geschwungene Klammern.
Die Klammern müssen immer paarweise vorhanden sein, das sind sie aber nicht.
Speziell in Funktion langerDruckStopp()
gibt es mehrmals Codezeilen, die diese Probleme haben:

  if(timer>millis()){
    timer=0

Richtig(er) müsste es wohl so aussehen:

  if (timer > millis()) {
    timer = 0;          // Semikolon ergänzt
  }                     // Klammer ergänzt

Oder diese Variante würde formal auch funktionieren (ganz ohne Klammern):

 if (timer > millis())
    timer = 0;       // Semikolon ergänzt

Das kompiliert zumindest ohne Fehlermeldungen.
Ob es auch tut was es soll, kann ich im Moment nicht beurteilen, weil ich keine Hardware (Arduino, LEDs u.s.w.) zur Hand habe.

Ein Programm mit "Blinken" könnte eventuell so aussehen:

/*                    LED1   LED2
    Grundzustand:     aus    aus
    Lang Drücken 1:   blink  aus
    Lang Drücken 2:   aus    blink
    Lang Drücken 3:   blink  blink
    Doppelklick:      aus    aus

  Button (Taster) nach GND
*/

#include "OneButton.h"

const byte buttonPin = 12;   // den eigenen Gegebeheiten anpassen
const byte led1pin   =  6;   // den eigenen Gegebeheiten anpassen
const byte led2pin   =  7;   // den eigenen Gegebeheiten anpassen
byte myLedState;
const unsigned long myBlinkDauer = 200;     // milliseconds
unsigned long startMillis;

// Setup a new OneButton
// The 2. parameter activeLOW is true, because external wiring sets the button to LOW when pressed.
OneButton button(buttonPin, true);

// In case the momentary button puts the input to HIGH when pressed:
// The 2. parameter activeLOW is false when the external wiring sets the button to HIGH when pressed.
// The 3. parameter can be used to disable the PullUp .
// OneButton button(PIN_INPUT, false, false);


void setup() {
  Serial.begin(9600);

  // enable the leds
  pinMode(led1pin, OUTPUT);
  pinMode(led2pin, OUTPUT);

  // link the button functions.
  button.attachClick(click1);
  button.attachLongPressStart(longPressStart);
  button.attachDoubleClick(doubleclick);

  startMillis = millis();
}


void loop() {
  // keep watching the push button:
  button.tick();

  switch (myLedState) {
    case 0:
      digitalWrite(led1pin, LOW);
      digitalWrite(led2pin, LOW);
      break;
    case 1:
      if (millis() - startMillis >= myBlinkDauer) {
        digitalWrite(led1pin, !digitalRead(led1pin));   // toggle LEDstate
        startMillis = millis();
      }
      digitalWrite(led2pin, LOW);
      break;
    case 2:
      digitalWrite(led1pin, LOW);
      if (millis() - startMillis >= myBlinkDauer) {
        digitalWrite(led2pin, !digitalRead(led2pin));    // toggle LEDstate
        startMillis = millis();
      }
      break;
    case 3:
      if (millis() - startMillis >= myBlinkDauer) {
        digitalWrite(led1pin, !digitalRead(led1pin));
        digitalWrite(led2pin, !digitalRead(led1pin));
        startMillis = millis();
      }
      break;
  }
}


// this function will be called when the button was pressed 1 time
void click1() {
  myLedState++;
  if (myLedState > 3) myLedState = 3;
  Serial.print("click  ");
  Serial.println(myLedState);
}


// This function will be called once, when the button is pressed for a long time.
void longPressStart() {
  myLedState++;
  if (myLedState > 3) myLedState = 3;
  Serial.print("click  ");
  Serial.println(myLedState);
}


// this function will be called when the button was pressed 2 times in a short timeframe.
void doubleclick() {
  myLedState = 0;
  Serial.println("doubleclick");
}

AAAAhhhh....
ich bin echt durch...
Oh wie peinlich.
Ich denke, ich sollte heute erst einmal Schlussmachen. Vielen Dank für die Hilfe.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.