mehrere Tatsten an einem Interrupt

Hallo Zusammen,

momentan beschäftige ich mich mit mehreren Tastern die auf einen Interrupt Pin angeschlossen sind. Dazu hab ich eine Schaltung mit 3 Tastern und 3 Dioden nach einer Anleitung gelötet (hier der Link). 3 Eingänge (Pin 24-26) und der Interrupt 0 an Pin 2. Bei allen Pins ist der Pull-up-Widerstand aktiviert. Die Schaltung scheint auch zu funktionieren. Jetzt möchte ich aber möglichst elegant abfragen welcher Taster gedrückt wurde und die Tasten später noch entprellen. Dazu habe ich folgenden Code geschrieben:

const int button[3]={24, 25, 26};

char bName[5];


void setup() {
  attachInterrupt(0, pressedBottom, HIGH );
  digitalWrite(2, HIGH);
  Serial.begin(9600);
  pinMode(button, INPUT);
  digitalWrite(button, HIGH);
  

}

void loop() {

}

void pressedBottom()
{
  switch (button[0]) {
    case 24:
      bName[2]="Play";
      break;
    case 25:
      bName[2]="back";
      break;
    case 26:
      bName[2]="next";
      break;
  }
  Serial.println(bName);

}

Kann mir jemand sagen ob dieser Ansatz richitg ist?

Gruß Michael

Nein, ist er nicht. Es fehlen z.B. die zugehörigen digitalRead(). Auch sind serielle Ausgaben in einer ISR eine tödliche Falle.

Und überhaupt, ist das so ziemlich die verrückteste Tastenabfrage, welche mir bisher unter gekommen ist. Mein Tipp: Ganz schnell wieder vergessen.

Hallo,

"verrückt" ersetze ich mit "total abgefahren" im negativen Sinne. Mehr Aufwand mit weniger Nutzen. :)

Die Tasten hängen schon je an einem Pin und dann noch einen Interrupt. Geiler gehts nicht. Das Problem ist, der Erfinder hat nur an Interrupts gedacht und kam wahrscheinlich gedanklich nicht der weg. In den meisten Fällen wird für Tastenabfragen kein Interrupt benötigt. Nennt sich Polling. Blockierfrei programmieren und das paßt.

Wenn du gleich was passendes haben möchtest, probiere die "Bounce2" Library und gehe die Bsp. durch

Danke für die schnellen Antworten. Ich schätze mal das mit dem Interrupt lass ich mal lieber und probiere morgen die Bounce2 Library aus.

hallo, da bin ich wieder mit meinen Tastern.

hab mich die letzten Tage mit der Bounce2 Libary beschäftigt und bin jetzt fast an meinem Ziehl.
Nur der Code ist recht umfangreich geworden:

#include <Bounce2.h>

#define BUTTON_PIN_1 22
#define BUTTON_PIN_2 24
#define BUTTON_PIN_3 26
#define BUTTON_PIN_4 28
// Instantiate a Bounce objects
Bounce debouncer1 = Bounce(); 
Bounce debouncer2 = Bounce(); 
Bounce debouncer3 = Bounce(); 
Bounce debouncer4 = Bounce(); 

unsigned long buttonPressTimeStamp;
int ledState, buttonState;

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

}

void initButtons(){
  // Setup the first button with an internal pull-up :
  pinMode(BUTTON_PIN_1,INPUT_PULLUP);
  // After setting up the button, setup the Bounce instance :
  debouncer1.attach(BUTTON_PIN_1);
  debouncer1.interval(50); // interval in ms
  
   // Setup the second button with an internal pull-up :
  pinMode(BUTTON_PIN_2,INPUT_PULLUP);
  // After setting up the button, setup the Bounce instance :
  debouncer2.attach(BUTTON_PIN_2);
  debouncer2.interval(50); // interval in ms

   // Setup the second button with an internal pull-up :
  pinMode(BUTTON_PIN_3,INPUT_PULLUP);
  // After setting up the button, setup the Bounce instance :
  debouncer3.attach(BUTTON_PIN_3);
  debouncer3.interval(50); // interval in ms
  
  pinMode(BUTTON_PIN_4,INPUT_PULLUP);
  // After setting up the button, setup the Bounce instance :
  debouncer4.attach(BUTTON_PIN_4);
  debouncer4.interval(50); // interval in ms
}

void loop() {
  pressedButton();                    //Abfrage Bedienknöpfe
  long upTime=millis()-buttonPressTimeStamp;
  if ( debouncer1.fell() || debouncer2.fell() || debouncer3.fell()|| debouncer4.fell()) {;
    //Serial.println( upTime);
    buttonPressTimeStamp = millis(); 
  }
//  if (upTime == 4000 ) Serial.println("turn OFF");    //Aktion bein nicht benutzen


}

void pressedButton(){

  boolean changed =  debouncer1.update() || debouncer2.update() || debouncer3.update()|| debouncer4.update();

  int value1 = debouncer1.read();
  int value2 = debouncer2.read();
  int value3 = debouncer3.read();
  int value4 = debouncer4.read();

  if ( changed ) {
    //erster Knopf auswerten
    if ( value1 == HIGH) {
       ledState = LOW;
       buttonState = 0;
       Serial.println("Auswahl released (state 0)");
   
   } else {
       ledState = HIGH;      
       buttonState = 1;
       Serial.println("Auswahl pressed (state 1)");
       buttonPressTimeStamp = millis();   
   }
  }
  if  ( buttonState == 1 ) {
    if ( millis() - buttonPressTimeStamp >= 500 ) {
         buttonPressTimeStamp = millis();
         if ( ledState == HIGH ) ledState = LOW;
         else if ( ledState == LOW ) ledState = HIGH;
        Serial.println("Retriggering button");
    }
  }
  //zweiter Knopf auswerten
  if ( changed ) {
    //erster Knopf auswerten
    if ( value2 == HIGH) {
       ledState = LOW;
       buttonState = 0;
       Serial.println("Play/Pause released (state 0)");
   
   } else {
       ledState = HIGH;      
       buttonState = 1;
       Serial.println("Play/Pause pressed (state 1)");
       buttonPressTimeStamp = millis();   
   }
  }
  if  ( buttonState == 1 ) {
    if ( millis() - buttonPressTimeStamp >= 500 ) {
         buttonPressTimeStamp = millis();
         if ( ledState == HIGH ) ledState = LOW;
         else if ( ledState == LOW ) ledState = HIGH;
        Serial.println("Retriggering button");
    }
  }
   //dritter Knopf auswerten
  if ( changed ) {
    //erster Knopf auswerten
    if ( value3 == HIGH) {
       ledState = LOW;
       buttonState = 0;
       Serial.println("Vor released (state 0)");
   
   } else {
       ledState = HIGH;      
       buttonState = 1;
       Serial.println("Vor pressed (state 1)");
       buttonPressTimeStamp = millis();   
   }
  }
  if  ( buttonState == 1 ) {
    if ( millis() - buttonPressTimeStamp >= 500 ) {
         buttonPressTimeStamp = millis();
         if ( ledState == HIGH ) ledState = LOW;
         else if ( ledState == LOW ) ledState = HIGH;
        Serial.println("Retriggering button");
    }
  }
   //vierter Knopf auswerten
  if ( changed ) {
    //erster Knopf auswerten
    if ( value4 == HIGH) {
       ledState = LOW;
       buttonState = 0;
       Serial.println("zurück released (state 0)");
   
   } else {
       ledState = HIGH;      
       buttonState = 1;
       Serial.println("zurück pressed (state 1)");
       buttonPressTimeStamp = millis();   
   }
  }
  if  ( buttonState == 1 ) {
    if ( millis() - buttonPressTimeStamp >= 500 ) {
         buttonPressTimeStamp = millis();
         if ( ledState == HIGH ) ledState = LOW;
         else if ( ledState == LOW ) ledState = HIGH;
        Serial.println("Retriggering button");
    }
  }
}

Das ist bestimmt sehr umständlich geschrieben. Kann mir jemand Tips geben wie man den Code vereinacht?

Mehrfache Codeduplizierung ist immer fehlerträchtig. Und Arbeitsintensiv.

Mein Tipp: Arrays und Schleifen.

wie könnte denn so eine Array aussehen?

Ungetestet.

#include <Bounce2.h>

const char tName1[] PROGMEM = "Auswahl";
const char tName2[] PROGMEM = "Play/Pause";
const char tName3[] PROGMEM = "Vor";
const char tName4[] PROGMEM = "Zurueck";

PGM_P const name_table[] PROGMEM = {
  tName1,
  tName2,
  tName3,
  tName4
};

const byte pinArray[4] = { 22, 24, 26, 28 };
Bounce Taste[4];

unsigned long buttonPressTimeStamp;
byte ledState, buttonState;

void setup() {
  Serial.begin(9600);
  for (byte i = 0; i < sizeof(Taste) / sizeof(Taste[0]); i++) {
    Taste[i].attach(pinArray[i], INPUT_PULLUP);
    Taste[i].interval(50);
  }
}

void loop() {
  for (byte i = 0; i < sizeof(Taste) / sizeof(Taste[0]); i++) {
    if (Taste[i].update()) {
      bool state = Taste[i].read();
      Serial.print((__FlashStringHelper*)pgm_read_word(&(name_table[i])));
      ledState = buttonState = !state;
      if (state) {
        Serial.println(F(" released (state 0)"));
      } else {
        Serial.println(F(" pressed (state 1)"));
        buttonPressTimeStamp = millis();
      }
    }
  }
  if (buttonState) {
    if ( millis() - buttonPressTimeStamp >= 500 ) {
      buttonPressTimeStamp = millis();
      ledState = !ledState;
      Serial.println(F("Retriggering button"));
    }
  }
  long upTime = millis() - buttonPressTimeStamp;
  if ( Taste[0].fell() || Taste[1].fell() || Taste[2].fell() || Taste[3].fell()) {
    //Serial.println( upTime);
    buttonPressTimeStamp = millis();
  }
}
Der Sketch verwendet 2.560 Bytes (8%) des Programmspeicherplatzes. Das Maximum sind 30.720 Bytes.
Globale Variablen verwenden 228 Bytes (11%) des dynamischen Speichers, 1.820 Bytes für lokale Variablen verbleiben. Das Maximum sind 2.048 Bytes.

Das Original

Der Sketch verwendet 3.398 Bytes (11%) des Programmspeicherplatzes. Das Maximum sind 30.720 Bytes.
Globale Variablen verwenden 456 Bytes (22%) des dynamischen Speichers, 1.592 Bytes für lokale Variablen verbleiben. Das Maximum sind 2.048 Bytes.

wow, danke für den kompakten code.

kannst du mir dazu noch etwas erklären?
die Stelle:

for (byte i = 0; i < sizeof(Taste) / sizeof(Taste[0]); i++) {

hierzählst du von 0 bis (4/?)

oder hier:

ledState = buttonState = !state;

was bedeutet diese Zeile mit 2 = ?

sizeof(ArrayObject)/sizeof(ArrayObject[0])

ist ein üblicher Ausdruck um die Anzahl der Arrayelemente zu ermitteln (Gesamtlänge des Arrays / Länge des ersten Arrayelements).

ledState = buttonState = !state;

Die Auswertung erfolgt von rechts nach links. Zuweisungen haben den zugewiesenen Wert als "Rückgabewert".

ledState = (buttonState = !state);

Ist vielleicht deutlicher, aber ich bin schreifaul. ;)

Eine andere Variante
(stark gekürzt)

#include <Bounce2.h>


struct Button
{
  byte pin;
  Bounce debouncer;
};

const byte AnzahlButton = 4;


Button MeineButton[AnzahlButton] =
{
  {22,Bounce(),},  
  {24,Bounce(),},  
  {26,Bounce(),},  
  {28,Bounce(),},  
};





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

void initButtons()
{
  for(int i = 0;i<AnzahlButton;i++)
  {
     pinMode(MeineButton[i].pin,INPUT_PULLUP);
     MeineButton[i].debouncer.attach(MeineButton[i].pin);
     MeineButton[i].debouncer.interval(50);
  }  
}


void updateButtons()
{
  for(int i = 0;i<AnzahlButton;i++)
     MeineButton[i].debouncer.update();
}

void loop() 
{
  updateButtons();
}

ich hab den Code etwas erweitert um Funktionen auf die Tasten zu bringen.

#include <Bounce2.h>

const char tName1[] PROGMEM = "Auswahl";
const char tName2[] PROGMEM = "Play/Pause";
const char tName3[] PROGMEM = "Vor";
const char tName4[] PROGMEM = "Zurueck";

PGM_P const name_table[] PROGMEM = {
  tName1,
  tName2,
  tName3,
  tName4
};

const byte pinArray[4] = { 22, 24, 26, 28 };
Bounce Taste[4];

unsigned long buttonPressTimeStamp;
byte ledState, buttonState;
bool retrigger = false;

void setup() {
  Serial.begin(9600);
  for (byte i = 0; i < sizeof(Taste) / sizeof(Taste[0]); i++) {
    Taste[i].attach(pinArray[i], INPUT_PULLUP);
    Taste[i].interval(50);
  }
}

void loop() {
  pressedButton();
  long upTime=millis()-buttonPressTimeStamp;
  //if (upTime == 4000 ) Serial.println("turn OFF");    //Aktion bein nicht benutzen
}

void pressedButton(){
  byte buttonNum = 5;
  for (byte i = 0; i < sizeof(Taste) / sizeof(Taste[0]); i++) {
    if (Taste[i].update()) {
      bool state = Taste[i].read();
      //Serial.print((__FlashStringHelper*)pgm_read_word(&(name_table[i])));
      ledState = buttonState = !state;
      if (state) {
        //Serial.println(F(" released (state 0)"));
        buttonNum = i;
      } else {
        //Serial.println(F(" pressed (state 1)"));
        buttonPressTimeStamp = millis();
      }
      switch (buttonNum){
        case 0: auswahl();
                break;
        case 1: play();
                break;
        case 2: next();
                break;        
        case 3: last();
                break;
      }
    }
  }
  if (buttonState) {
    if ( millis() - buttonPressTimeStamp >= 500 ) {
      buttonPressTimeStamp = millis();
      ledState = !ledState;
      retrigger = true;
      //Serial.println(F("Retriggering button"));
    }
    else retrigger = false;
  }
  long upTime = millis() - buttonPressTimeStamp;
  if ( Taste[0].fell() || Taste[1].fell() || Taste[2].fell() || Taste[3].fell()) {
    buttonPressTimeStamp = millis();
  }
}

void auswahl(){
  Serial.println("Auswahl");  
}
void play(){
  Serial.println("Play/Pause");
}
void next(){
  if (retrigger= true){
    Serial.print("schnell ");
  }
  Serial.println("Vor");
}
void last(){
  if (retrigger = true){
    Serial.print("schnell ");
  }
  Serial.println("Zurück");
}

aber wie bekomm ich es hin das beim lange drücken eine andere Funktion ausgeführt wird?

Indem du für jede Taste den Zeitpunkt der Drückens festhältst (bei .fell()), die Aktion aber erst startest wenn die Taste wieder losgelassen wird (bei .rose()). Du kannst dann eine Aktion für verschiedene Tastendruck-Längen auswählen.

Zeitpunkt(rose) - Zeitpunkt(fell)l = Dauer.

ich verstehe diese for-schleife noch nicht so ganz:

  for (byte i = 0; i < sizeof(Taste) / sizeof(Taste[0]); i++) {
    if (Taste[i].update()) {
      bool state = Taste[i].read();
      //Serial.print((__FlashStringHelper*)pgm_read_word(&(name_table[i])));
      ledState = buttonState = !state;
      if (state) {
        //Serial.println(F(" released (state 0)"));
        buttonNum = i;
      } else {
        //Serial.println(F(" pressed (state 1)"));
        buttonPressTimeStamp = millis();
      }
    }

was macht if (state)?
hier kann ich nicht die gedrückte taste erhalten?

mire: was macht if (state)?

wertet den aktuellen Tastenzustand aus. In diesem Fall nur bei einem Statechange (if(...update())), ist also fast ein fell/rose.

Etwas wie buttonPressTimeStamp sollte für jede Taste existieren, dann kannst du im anderen Teil des if's entscheiden ob es ein langer oder kurzer Druck war.

dieser Teil erkennt ja ob eine Taste lange gedrückt wird aber nicht welche Taste.

  if (buttonState) {
    if ( millis() - buttonPressTimeStamp >= 500 ) {
      buttonPressTimeStamp = millis();
      ledState = !ledState;
      retrigger = true;
      //Serial.println(F("Retriggering button"));
      if (buttonNum = 2) schnellVor();
      if (buttonNum = 3) schnellrw();
    }
    else retrigger = false;
  }

Wenn ich im oberen Teil die gedrückte Taste erfahre und im unteren Teil ob sie lange gedrückt ist würde es ja funktionieren. oder?

mire: Wenn ich im oberen Teil die gedrückte Taste erfahre und im unteren Teil ob sie lange gedrückt ist würde es ja funktionieren. oder?

Oder.

Das von dir Gezeigte ist nur die alte sinnlose "wenn die Abstände zwischen Tasten 500ms überschreiten, drucke 'Retriggering button'" Aktion aus deinem Originalkode.

Ich habe dir genau beschrieben wie man es machen könnte.

nun hab ich die Auswertung der Knöpfe so wie ich es brauche.
Nach einigen Versuchen sieht der Code nun so aus:

#include <Bounce2.h>

const byte pinArray[4] = { 22, 24, 26, 28 };
Bounce Taste[4];

unsigned long buttonPressTimeStamp;
byte ledState, buttonState;
bool retrigger;
byte lastButton;

void setup() {
  Serial.begin(9600);
  for (byte i = 0; i < sizeof(Taste) / sizeof(Taste[0]); i++) {
    Taste[i].attach(pinArray[i], INPUT_PULLUP);
    Taste[i].interval(50);
  }
}

void loop() {
  pressedButton();
  long upTime=millis()-buttonPressTimeStamp;
  //if (upTime == 4000 ) Serial.println("turn OFF");    //Aktion bein nicht benutzen
}

void pressedButton(){
  for (byte i = 0; i < sizeof(Taste) / sizeof(Taste[0]); i++) {
    if (Taste[i].update()) {
      lastButton=i;
      bool state = Taste[i].read();
      ledState = buttonState = !state;
      if (state && !retrigger) {
        switch (i){
          case 0: {
            auswahl();
            break;
          }
          case 1: {
            play();
            break;
          }
          case 2: {
            next();
            break;
          }
          case 3: {
            last();
            break;
          }
        }
      } else {
        buttonPressTimeStamp = millis();
        retrigger=false;
      }
    }
  }
  if (buttonState) {
    if ( millis() - buttonPressTimeStamp >= 500 ) {
      buttonPressTimeStamp = millis();
      ledState = !ledState;
      retrigger = true;
      switch (lastButton){
        case 2: {
          schnellVor();
          break;
        }
        case 3: {
          schnellRw();
          break;
        }
      }
    }
  }
  long upTime = millis() - buttonPressTimeStamp;
  if ( Taste[0].fell() || Taste[1].fell() || Taste[2].fell() || Taste[3].fell()) {
    buttonPressTimeStamp = millis();
  }
}

void auswahl(){
  Serial.println("Auswahl"); 
}
void play(){
  Serial.println("Play/Pause");
}
void next(){
  Serial.println("Vor");
}
void last(){
  Serial.println("Zurueck");
}
void schnellVor(){
  Serial.println("schnell vor");
}
void schnellRw(){
  Serial.println("schnell zurück");
}

danke fur Unterstüzung :slight_smile: