Multifunktionstaster - Abfrage eines Status für eine Bestimmte Zeit?!

steview_de:
Die LED Lampe ist "dimmbar", allerdings in drei Stufen. Jede Stufe hat einen eigenen Eingang.
Also:

  • erster Klick "LED, dunkel" an, andere LEDS aus
  • zweiter Klick "LED, mittel" an, andere LEDs aus
  • dritter Klick "LED, hell" an, andere LEDs aus
  • vierter Klick, wie erster Klick
  • fünfter Klick, wie zweiter Klick
  • usw.

... das ist für mich "toggeln".

Und weil die ja immer durchgetoggelt werden, möchte ich beim langen Drücken des Tasters alle LEDs ausschalten.

Bei der Lampe mußt Du dann aber eine Bedienungsanleitung beilegen! Wenn jemand die Lampe sonst aus Versehen mit einem kurzen Klick einschaltet, ohne das Bedienkonzept zu kennen, bekommt er sie intuitiv sonst durch noch so häufiges Klicken nicht mehr ausgeschaltet.

Hier ist ein Code, der drei Funktionen unterscheiden kann: Click, Doubleclick und LongClick:

// Tastenerkennung SHORTCLICK, DOUBLECLICK, LONGCLICK
#define INPUTMODE INPUT_PULLUP  // INPUT oder INPUT_PULLUP
#define PRELLZEIT 5             // Prellzeit in Millisekunden
// #define SHORTCLICKTIME 250      // Längste Zeit für einen SHORTCLICK
#define DOUBLECLICKTIME 400     // Längste Zeit für den zweiten Klick beim DOUBLECLICK
#define LONGCLICKTIME 600       // Mindestzeit für einen LONGGLICK
byte buttonPins[]={2,3,A3}; // Arduino Pins (mehrere als Array möglich)
#define NUMBUTTONS sizeof(buttonPins)
byte buttonState[NUMBUTTONS];  // Aktueller Status des Buttons HIGH/LOW
enum {NONE, FIRSTDOWN, FIRSTUP, SHORTCLICK, DOUBLECLICK, LONGCLICK}; 
byte buttonResult[NUMBUTTONS]; // Aktueller Klickstatus der Buttons NONE/SHORTCLICK/LONGCLICK

void setup() {
  Serial.begin(9600);
  Serial.println("Button test");
  for (int i=0;i<NUMBUTTONS;i++) pinMode(buttonPins[i],INPUTMODE);
}

boolean eingabe()
// Rückgabewert false ==> Prellzeit läuft, Taster wurden nicht abgefragt
// Rückgabewert true ==> Taster wurden abgefragt und Status gesetzt
{
  static unsigned long lastRunTime;
  static unsigned long buttonDownTime[NUMBUTTONS];
  unsigned long now=millis();
  if (now-lastRunTime<PRELLZEIT) return false; // Prellzeit läuft noch
  lastRunTime=now;
  for (int i=0;i<NUMBUTTONS;i++)
  {
    byte curState=digitalRead(buttonPins[i]); 
    if (INPUTMODE==INPUT_PULLUP) curState=!curState; // Vertauschte Logik bei INPPUT_PULLUP
    if (buttonResult[i]>=SHORTCLICK) buttonResult[i]=NONE; // Letztes buttonResult löschen
    if (curState!=buttonState[i]) // Flankenwechsel am Button festgestellt
    {
      if (curState)   // Taster wird gedrückt, Zeit merken
      {
        if (buttonResult[i]==FIRSTUP && now-buttonDownTime[i]<DOUBLECLICKTIME)
          buttonResult[i]=DOUBLECLICK;
        else
        {  
          buttonDownTime[i]=now; 
          buttonResult[i]=FIRSTDOWN;
        } 
      }
      else  // Taster wird losgelassen
      {
        if (buttonResult[i]==FIRSTDOWN) buttonResult[i]=FIRSTUP;
        if (now-buttonDownTime[i]>=LONGCLICKTIME) buttonResult[i]=LONGCLICK;
      }
    }
    else // kein Flankenwechsel, Up/Down Status ist unverändert
    {
      if (buttonResult[i]==FIRSTUP && now-buttonDownTime[i]>DOUBLECLICKTIME) 
        buttonResult[i]=SHORTCLICK;
    }
    buttonState[i]=curState;
  } // for
  return true;
}


void verarbeitung()
{
  // dummy function 
}


void ausgabe()
// Klickstatus von geklickten Buttons mit Zeitstempel ausgeben
{
  for (int i=0;i<NUMBUTTONS;i++)
  {
    if (buttonResult[i]>=SHORTCLICK) // Ein Button wurde geklickt
    {
      Serial.print(millis()/1000.0,3); // Zeitstempel mit Millisekundenauflösung
      Serial.print("\tPin-");Serial.print(buttonPins[i]);
      if (buttonResult[i]==SHORTCLICK) Serial.println(" CLICK");
      else if(buttonResult[i]==DOUBLECLICK) Serial.println(" DOUBLE CLICK");
      else if(buttonResult[i]==LONGCLICK) Serial.println(" LONG CLICK");
    }
  }
}

void benchmark() {
  static unsigned long counterStartTime;
  static unsigned long counter;
  counter++;
  if (counter>=1000000L)
  {
    Serial.print("Average Time per loop(): ");
    Serial.print((micros()-counterStartTime)/1000000.0);
    Serial.println(" microseconds");
    counter=0;
    counterStartTime=micros();
  }
}


void loop() {
  if (eingabe())
  {
    verarbeitung();
    ausgabe();
  }
  benchmark();
}

Die Zeiten sind im Code frei konfigurierbar.

Wenn Du auf den "Doubleclick" verzichten möchtest, setzt Du die DOUBLECLICKTIME am besten auf eine Zeit, die niedriger als die PRELLZEIT ist, zum Beispiel:

#define DOUBLECLICKTIME 4

Dann werden keine Doppelklicks mehr ausgewertet.

Die "eingabe()" Funktion wertet übrigens ein ganzes Array von Button-Pins aus, falls Du nicht nur einen Schalter mit zwei oder drei Funktionen haben möchtest, sondern "viele Schalter mit mehreren Funktionen".

1 Like