LED´s Individuell über EINEN Taster ansteuern

Hallo Zusammen,

ich bin neu im Forum und kann auch schon einige Erfolge mit meinem UNO verbuchen.
Allerdings stoße ich so langsam an meine Konw-How Grenzen.

Ich möchte 5 LED´s und eine "Kontroll-LED" individuell durch einen Taster Ansprechen z.B.:

  • Taster 3x hintereinander drücken -> LED 3 geht (und bleibt) an + "Kontroll-LED" an Taster Blinkt 3x

oder

  • Taster 3 Sekunden gedrückt halten -> LED´s 1-3 gehen aus bzw. an + "Kontroll-LED" blinkt nun einmal länger

Leider komme ich nicht über den void setup Teil hinaus, ich hoffe mir kann jemand helfen.

Vielen Dank
Hubbert90

Hubbert90:
... ich hoffe mir kann jemand helfen.

Willkommen im Forum!

Bitte schreibe einen Sketch, wie Du Dir das so vorstellst. Dann sehen die vielen, die Dir hier im Forum helfen können, wo Du hinsichtlich Deiner Kenntnisse stehst und wie Dir am besten zu helfen wäre.

Danke für die schnelle Antwort.

der Sketch ist ja mein Problem, das ist mein aktueller Stand:

#define Taster      2
#define Taster_LED  3
#define LED_1       4
#define LED_2       5
#define LED_3       6
#define LED_4       7
#define LED_5       8


void setup() {
  
  pinMode(Taster, INPUT);

  pinMode(Taster_LED, OUTPUT);
  pinMode(LED_1, OUTPUT);
  pinMode(LED_2, OUTPUT);
  pinMode(LED_3, OUTPUT);
  pinMode(LED_4, OUTPUT);
  pinMode(LED_5, OUTPUT);

}

void loop() {


}

Ich nehme an man könnte einen Counter und Cases verwenden ich weiß allerdings nicht wie... :frowning:

Hubbert90:
Danke für die schnelle Antwort.

der Sketch ist ja mein Problem, das ist mein aktueller Stand:

Du solltest erst mal üben, wie ein Taster abgefragt wird.

Beispiele findest du dazu in der IDE.
Damit kannst du dann einzelne Leds zum leuchten bringen.

Das klingt nach einem Automaten (state machine), und zwar nach einem ziemlich komplexen. Schau erst mal nach, was Du dazu findest, und versuche zu verstehen, wie so ein Automat funktioniert.

Vor allem brauchst Du eine Debounce Funktion, die das Prellen des Tasters eliminiert. Dazu gibt's diverse Beispiele (IDE Examples...). Diese Funktion kann (zum Testen) gleich die LED im/am Taster ansteuern, damit man sehen kann, was als Eingabe vom Programm erkannt wurde.

Danach könnte man sowas wie einen Morse-Code definieren, mit kurzen und langen Tastendrücken bzw. Pausen, und den dazu gehörenden Baum zeichnen. Der Automat muß dann erkennen, welchen Ast er durchwandern soll, je nachdem ob die Taste kurz oder lang gedrückt gehalten oder losgelassen wurde. Am Ende von jedem Ast steht dann, was mit den LEDs oder sonstigen Gerätschaften passieren soll.

DrDiettrich:
Das klingt nach einem Automaten (state machine), und zwar nach einem ziemlich komplexen. Schau erst mal nach, was Du dazu findest, und versuche zu verstehen, wie so ein Automat funktioniert.

Vor allem brauchst Du eine Debounce Funktion, die das Prellen des Tasters eliminiert. Dazu gibt's diverse Beispiele (IDE Examples...). Diese Funktion kann (zum Testen) gleich die LED im/am Taster ansteuern, damit man sehen kann, was als Eingabe vom Programm erkannt wurde.

Danach könnte man sowas wie einen Morse-Code definieren, mit kurzen und langen Tastendrücken bzw. Pausen, und den dazu gehörenden Baum zeichnen. Der Automat muß dann erkennen, welchen Ast er durchwandern soll, je nachdem ob die Taste kurz oder lang gedrückt gehalten oder losgelassen wurde. Am Ende von jedem Ast steht dann, was mit den LEDs oder sonstigen Gerätschaften passieren soll.

Oha, du fährst ja gleich richtige Geschütze auf. :wink:
Ich befürchte, der TO sollte erst mal die Basics lernen.
Aber das mit dem Entprellen der Taster sollte er schon im Hinterkopf behalten.

HotSystems:
Du solltest erst mal üben, wie ein Taster abgefragt wird.

Wie ein Taster abgefragt wird, ist mir schon klar und die Debounce Funktion ist auch kein Neuland für mich.

Allerdings habe ich noch wenig/keine Erfahrung mit Countern, Case oder "Morse-Code".

Könne mir nicht jemand einen kurzen Beispiel-Sketch schreiben, bei dem ein Taster abgefragt wird und dann je nach Counter-Ergebnis auf einen Case verweist?
Oder is das der falsche Lösungsansatz?

Das klingt nach einem Automaten (state machine), und zwar nach einem ziemlich komplexen

Da kann ich nur "stimmt 100%" zu sagen... Hier müssen in der Tat mehrere Ebenen zusammenspielen. Debouncing, Timer, Counter... Der Hinweis auf Morse-Code war auch goldrichtig. Da beißt man sich gerne mal die Zähne dran aus weil auch noch "Pausen" in dieser Sache berücksichtigt werden müssen. Auch wenn der Wunsch von Hubbert90 vielleicht gar nix damit zu tun hat.

Oder is das der falsche Lösungsansatz?

Ich denke JA, denn im Grunde wäre das ein geeignetes Ding für OOP mit ein paar passenden Methoden - aber darauf will ich hier jetzt erstmal gar nicht eingehen...

vielleicht hilft dir die Funktion pulseIn(pin, state) etwas, mit state HIGH, LOW usw. Wenn du den Taster entprellst (z.B. mit Widerständen und Kondensator) und die richtige Schaltung wählst, bekommst du mit dem pulseIn Befehl eine Zeit, wie lange das state zutrifft. z.B. wenn du den Taster 2 s drückst bekommst du eine bestimmte Zeitzahl, die du dann einfach in einen Integer schreiben kannst. Den Integer kannst du dann mit einer if-clause vergleichen.
dasselbe wendest du dann zum zählen an, erst mit pulseIn messen, prüfen wie lang es ist, dann entscheiden ob da mehr klicks kommen können und einfach nen Integer hochzählen lassen. Wieder mit if prüfen ob die Integervariable größergleich 3 ist und du kannst deine Befehle dahinter schreiben.

Hubbert90:
Wie ein Taster abgefragt wird, ist mir schon klar und die Debounce Funktion ist auch kein Neuland für mich.

Hört sich für mich an, als wenn Du mit simplen mechanischen Tastern noch total auf Kriegsfuß stehst.

Kennst Du den Unterschied in der "Tasterschaltung mit PullUp-Widerstand" und "Tasterschaltung mit PullDown-Widerstand" und kannst Du erklären, ob Du für diese Codezeile im setup()

pinMode(Taster, INPUT);

einen PullUp- oder PullDown-Widerstand in Deiner Schaltung benötigst und auch tatsächlich verbaut hast?

Jurs bringt es auf den Punkt.
Wenn du mit der Tasterabfrage soweit klar kommst, wie du schreibst, warum bringst du das nicht in deinem Sketch.

Wir helfen dir ja, aber du musst auch dein Teil beitragen.
Das Entprellen kannst du ja, wie schon geschrieben, per Hardware losen und später optimieren.

Den Einstieg würde ich etwas anders machen:

const byte tasterPin = 2, ledPin[] = {3, 4, 5, 6, 7, 8};
bool status, aktTaster, altTaster;

void setup() {
  pinMode(tasterPin, INPUT_PULLUP);
  for (byte j = 0; j < sizeof(ledPin); j++) {
    pinMode(ledPin[j], OUTPUT);
  }
  aktTaster = digitalRead(tasterPin);
  altTaster = aktTaster;
}

void loop() {
...
    for (byte j = 0; j < sizeof(ledPin); j++) {  // Ausgaenge loeschen
      digitalWrite(ledPin[j], LOW);
    }
...
}

Gibt's keinen fertigen Code für ein Morse-Programm, das Morsezeichen lesen kann? Dann wäre dreimal kurz ein "S", einmal lang ein "T". Den Rest kann man in einen großen switch packen, der die Aktionen zu den empfangenen Zeichen ausführt.

Soooo, ich konnte mein Problem nun fast komplett mit der ClickButton Library lösen.

Allerdings will ich nun die erste 3 LEDs gemeinsam an oder aus schalten wenn ich den Taster 1 Sekunde lang drücke, jedoch springen die LEDs beim aktuellen Code nur in den jeweils anderen Zustand um.
Hier der Sketch:

#include "ClickButton.h"

int Taster = 2;

int TasterLED = 3;

int LED1 = 4;
int LED2 = 5;
int LED3 = 6;
int LED4 = 7;
int LED5 = 8;

int counter1 = 0;
int counter2 = 0;
int counter3 = 0;
int counter4 = 0;
int counter5 = 0;

ClickButton button1(Taster, LOW, CLICKBTN_PULLUP);


void setup() {
  
  pinMode(TasterLED, OUTPUT); 
  pinMode(LED1, OUTPUT); 
  pinMode(LED2, OUTPUT); 
  pinMode(LED3, OUTPUT); 
  pinMode(LED4, OUTPUT); 
  pinMode(LED5, OUTPUT); 
     
  button1.maxPresses     = 6;    // max button multiclick count
  button1.debounceTime   = 50;   // Debounce timer in ms
  button1.multiclickTime = 350;  // Time limit for multi clicks
  button1.heldDownTime   = 1000; // time until "held-down clicks" register
}

void BlinkenKurz() {
  digitalWrite(TasterLED, HIGH);
  delay(200);
  digitalWrite(TasterLED, LOW);
  delay(200);
}

void BlinkenNormal() {
  digitalWrite(TasterLED, HIGH);
  delay(750);
  digitalWrite(TasterLED, LOW);
  delay(750);
}

void BlinkenLang() {
  digitalWrite(TasterLED, HIGH);
  delay(1200);
  digitalWrite(TasterLED, LOW);
  delay(1200);
}


void loop() {
  button1.Update();

  
 if(button1.click ==  -1) {  // 1 sek druecken
  
   BlinkenLang(); 
   counter1++;
   counter2++;
   counter3++;
 
   if (counter1 % 2 == 0) 
    digitalWrite(LED1, LOW);
   else 
    digitalWrite(LED1, HIGH);

   if (counter2 % 2 == 0) 
    digitalWrite(LED2, LOW);
   else 
    digitalWrite(LED2, HIGH);
    
   if (counter3 % 2 == 0) 
    digitalWrite(LED3, LOW);
   else 
    digitalWrite(LED3, HIGH);
  }



  if(button1.click == 1) {    // 1x druecken
   
    BlinkenKurz();
    counter1++;
    
       if (counter1 % 2 == 0) 
        digitalWrite(LED1, LOW);
       else 
        digitalWrite(LED1, HIGH);
   }


  if(button1.click ==  2) {   // 2x druecken

    BlinkenKurz();
    BlinkenKurz();
    counter2++;
    
       if (counter2 % 2 == 0) 
        digitalWrite(LED2, LOW);
       else 
        digitalWrite(LED2, HIGH);
   }
    

  if(button1.click ==  3) {   // 3x druecken
  
    BlinkenKurz();
    BlinkenKurz();
    BlinkenKurz();
    counter3++;
    
       if (counter3 % 2 == 0) 
        digitalWrite(LED3, LOW);
       else 
        digitalWrite(LED3, HIGH);
   }


  if(button1.click ==  4) {   // 4x druecken
    
    BlinkenNormal();
    counter4++;
    
       if (counter4 % 2 == 0) 
        digitalWrite(LED4, LOW);
       else 
        digitalWrite(LED4, HIGH);
   }


  if(button1.click == 5) {  // 5x druecken
  
    BlinkenNormal();
    BlinkenNormal();
    counter5++;
    
       if (counter5 % 2 == 0) 
        digitalWrite(LED5, LOW);
       else 
        digitalWrite(LED5, HIGH);
   }

}

Allerdings will ich nun die erste 3 LEDs gemeinsam an oder aus schalten wenn ich den Taster 1 Sekunde lang drücke, jedoch springen die LEDs beim aktuellen Code nur in den jeweils anderen Zustand um.

if(button1.click ==  -1) {  // 1 sek druecken
    BlinkenLang();
   ...

Wenn der Kommentar halbwegs zutreffend ist (ich kenne "ClickButton" natürlich nicht),
hast du da was anderes programmiert.

Das haut schon hin.

Es passiert auch was, das 1200 ms lange blinken. Ich glaube bei den Countern stimmt was nicht.

Das "-" bezieht sich bei dieser Library darauf, das der Taster gedrückt gehalten wird.

also... eine Lösung "auf die Schnelle" habe ich leider keine - aber mich irritiert an deinem Code so einiges:

In den Unterprogrammen "BlinkKurz()" usw. sehe ich eine Menge "delay(...)". Hiermit blockierts du dir schon jegliche Reaktionen auf irgendwelche Eingaben. Heißt, dass im Moment des Blinkens absolut nix mehr geschehen kann, keine Counter-Increments, keine Tastenabfragen, keine (vielleicht notwendige) parallele Weiterverarbeitung von irgendwas, rein gar nix. Alles wäre absolut "gegen" die von "DrDittrich" angesprochene "State Machine" und seinen Morsezeichen. Hierzu wäre aber ein Code notwendig, der vollkommen frei von jeglichen Blockierungen ist.

Vielleicht wäre es für die Community (und für dich) hilfreich, wenn du mal "genau" auflistest, was du eigentlich "wirklich" mit welchen Eingaben erreichen möchtest (ich selbst steige da noch nicht wirklich hinter). Eventuell findet man im Laufe der Zeit gemeinsam eine perfekte Lösung.

Dein Code sieht aus wie "Die Lösung haben wir schon, nun fehlt uns nur noch das dazu passende Problem" :-]

Woran willst Du z.B. festmachen, ob bei langem Drücken alle LED ein- oder ausgeschaltet werden sollen? Wenn LED1 an ist, und LED2 aus, sollen dann alle ein oder aus geschaltet werden?

Daß delay() jedes Timing durcheinanderbringt, wurde ja schon erwähnt. Schau Dir mal BlinkWithoutDelay an, wie man sowas richtig implementiert. Statt Deiner Funktionen BlinkenKurz usw. brauchst Du einen Automaten, der im Laufe der Zeit seinen Zustand und ändert, und entsprechend die LED blinken läßt. Diesen Automaten packst Du in eine Funktion, die bei jedem Durchlauf von loop() aufgerufen wird, so wie jetzt schon button1.Update().

Der Automat könnte dann z.B. einen Zähler enthalten, der angibt, wie oft geblinkt werden soll. Nach jedem einzelnen Blinken wird der Zähler heruntergezählt, bis er 0 ist. Zusätzlich ein Intervall, das die Länge des Blinkens angibt. Das läßt sich mitsamt dieser Variablen auch in eine Klasse packen, so wie für ClickButton.

Bei den anderen LEDs kann der Code auch vereinfacht bzw. übersichtlicher gemacht werden. Bislang würde es zumindest reichen, statt der Zähler nur bool Variablen zu nehmen, die mit var=!var getoggelt werden, und mit digitalWrite(LED, var) ohne ein if und %2 direkt ausgegeben werden können.

DrDiettrich:
Dein Code sieht aus wie "Die Lösung haben wir schon, nun fehlt uns nur noch das dazu passende Problem" :-]

Woran willst Du z.B. festmachen, ob bei langem Drücken alle LED ein- oder ausgeschaltet werden sollen? Wenn LED1 an ist, und LED2 aus, sollen dann alle ein oder aus geschaltet werden?

Man weiß es nicht so genau, aber in einer Demokratie müßte wohl die Mehrheit entscheiden, und bei 3 LEDs gibt es ja immer eine Mehrheit von mindestens zwei-zu-eins.

D.h. wenn LED1 an ist, und LED2 aus, dann kommt es drauf an, welchen Schaltstatus LED3 hat. D.h. wenn LED3 an ist, steht es zwei-zu-eins für "derzeitig sind die LEDs an", also alle drei ausschalten.

Aber wenn LED3 aus ist, stünde es zwei-zu-eins für "derzeitig sind die LEDs aus", also in dem Fall alle drei einschalten.

Oder so. ;D