Verständnissfrage zu Button_SL

Hallo,
ich habe irgendwie eine Verständnissfrage oder stehe auf dem Schlauch.
Wollte eigentlich nur mal das entdeckte Wokwi mit dem Button_SL testen.
ich sehe aber seit 2 Tagen den Fehler nicht. Ich in noch Anfänger und ich weis, das mein Code
sehr "unelegant" ist, aber mir geht es um die Funktion.

Erklärung:
Drücke ich den Taster kurz, soll LED 1 kurz aufleuchten (das klappt)
Drücke ich den Taster länger (3s) soll LED2 blinken, solange ich auf dem Taster bleibe,
das Ding blinkt einmal und das wars. Ich habe schon alles Mögliche probiert aber irgendwie fällt der immer wieder aus der IF-Schleife raus ??

Kann mir jemand helfen, mich vom "Schlauch" runterzuschubbsen?
Danke.

Code:

// Blink...BlinkBlink

#include <Button_SL.hpp>

// Globale Variable
constexpr uint8_t Taster{2};
constexpr uint8_t LED1{4};
constexpr uint8_t LED2{6};

using namespace Btn;
ButtonSL btn{Taster, 3000}; // 3s für langes Drücken

int var,x=0;

//////////////////////////////////////////////////////////////////////////////
void setup() {
Serial.begin(115200);
pinMode(LED1,OUTPUT);
pinMode(LED2,OUTPUT);

btn.begin();
btn.setDebounceTime_ms(20);
btn.releaseOn();
}

//////////////////////////////////////////////////////////////////////////////
void loop() {

switch (btn.tick()) {
case ButtonState::shortPressed:
if (digitalRead(LED1) == LOW && x==0) {
digitalWrite(LED1,HIGH);
x=1;
Serial.println("> X=1, LED an");
}
if (digitalRead(LED1) == HIGH && x==1) {
digitalWrite(LED1,LOW);
x=0;
Serial.println("> X=0, LED aus");
}

  Serial.println("Tastzeit: ");
  Serial.print(btn.getDuration_ms());
  Serial.println(" ms");
  break;


case ButtonState::longPressed:
 if (digitalRead (Taster) == LOW) {
 
    if (digitalRead(LED2) == LOW && x==0) {
        digitalWrite(LED2,HIGH);
       x=1;
    }
    delay(100);

    if (digitalRead(LED2) == HIGH && x==1) {
        digitalWrite(LED2,LOW);
       x=0;
   }
   delay(100);
 }

  Serial.print("Tastzeit: ");
  Serial.print(btn.getDuration_ms());
  Serial.println(" ms");
  break;

default: break;

}

}

Ich würde nicht die Bibliothek Button_SL benutzen sondern das erkennen der Tastenlänge selbst programmieren. Darum kann ich Dir nicht helfen.

Wenn Du schon eine Schrittekette verwendest dann solltest Du Zeiten nicht mit delay() machen, sondern mit millis(). Du solltest lernen nicht blockierend zu programmieren.

grüße Uwe

1 Like

"Ich würde nicht die Bibliothek Button_SL benutzen sondern das erkennen der Tastenlänge selbst programmieren. Darum kann ich Dir nicht helfen."

Öha, da bin ich leider noch weit davon entfernt, hoffe aber das wird noch :slight_smile:

"Wenn Du schon eine Schrittekette verwendest dann solltest Du Zeiten nicht mit delay() machen, sondern mit millis(). Du solltest lernen nicht blockierend zu programmieren."

Danke, die hatte ich nur eingefügt, da ich vermutete, das ich das "Blinken" nicht sehe weil zu schnell geschalten wird, war eine "schnelle" Kontrolle, die allerdings nichts gebracht hat.

Wenn Du Beitrag #1 editierst, so daß Dein Programm richtig formatiert und damit lesbar dargestellt wird, könnte man sich das mal ansehen :wink:

Um andere Beiträge zu zitieren, gibt es hier extra eine Funktion, die dabei hilft.
Einfach mal hier nachlesen.
Verstehe nicht warum das ignoriert wird.

So wäre z.B. eine Möglichkeit:

#include <Button_SL.hpp>

// Globale Variable
constexpr uint8_t Taster {2};
constexpr uint8_t LED1 {4};
constexpr uint8_t LED2 {6};

using namespace Btn;
ButtonSL btn {Taster, 3000};   // 3s für langes Drücken

int var, x = 0;

//////////////////////////////////////////////////////////////////////////////
void setup() {
  Serial.begin(115200);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);

  btn.begin();
  btn.setDebounceTime_ms(20);
  btn.releaseOn();
}

//////////////////////////////////////////////////////////////////////////////
void loop() {

  switch (btn.tick()) {
    case ButtonState::shortPressed:
      digitalWrite(LED1, HIGH);
      Serial.println("Tastzeit: ");
      Serial.print(btn.getDuration_ms());
      Serial.println(" ms");
      delay(100);
      break;

    case ButtonState::longPressed:
      digitalWrite(LED2, HIGH);
      Serial.print("Tastzeit: ");
      Serial.print(btn.getDuration_ms());
      Serial.println(" ms");
      break;

    default:
      if (digitalRead(LED1)) { digitalWrite(LED1, LOW); }
      if (digitalRead(LED2) && digitalRead(Taster)) { digitalWrite(LED2, LOW); }
      break;
  }
}

Oder, um das Delay zu vermeiden:

#include <Button_SL.hpp>

// Globale Variable
constexpr uint8_t Taster {2};
constexpr uint8_t LED1 {4};
constexpr uint8_t LED2 {6};
constexpr unsigned long duration {1000};

class Timer {
public:
  void start() { timeStamp = millis(); }
  bool operator()(const unsigned long duration) const { return (millis() - timeStamp >= duration) ? true : false; }

private:
  unsigned long timeStamp {0};
};

using namespace Btn;
ButtonSL btn {Taster, 3000};   // 3s für langes Drücken
Timer wait;

//////////////////////////////////////////////////////////////////////////////
void setup() {
  Serial.begin(115200);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);

  btn.begin();
  btn.setDebounceTime_ms(20);
  btn.releaseOn();
}

//////////////////////////////////////////////////////////////////////////////
void loop() {

  switch (btn.tick()) {
    case ButtonState::shortPressed:
      digitalWrite(LED1, HIGH);
      wait.start();
      Serial.println("Tastzeit: ");
      Serial.print(btn.getDuration_ms());
      Serial.println(" ms");
      break;

    case ButtonState::longPressed:
      digitalWrite(LED2, HIGH);
      Serial.print("Tastzeit: ");
      Serial.print(btn.getDuration_ms());
      Serial.println(" ms");
      break;

    default:
      if (digitalRead(LED1) && wait(duration)) { digitalWrite(LED1, LOW); }
      if (digitalRead(LED2) && digitalRead(Taster)) { digitalWrite(LED2, LOW); }
      break;
  }
}

1 Like

Ich werf mal einen rein, ganz ohne extern.
Ob der funktioniert, weiss ich nicht, aber es sollte erklärend sein.


// Globale Variable
constexpr uint8_t Taster{2};
constexpr uint8_t LED1{4};
constexpr uint8_t LED2{6};

constexpr uint32_t debounceTime {20}; // Zeit in ms
constexpr uint32_t longHoldTime {3000};

bool isPress;
uint32_t pressStart;

const uint32_t ledOnTime {500};
uint32_t ledStartTime;

enum {RELAESE, SHORTPRESS, LONGPRESS};
uint8_t pressState;
uint8_t lastState;

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start.... "));
  pinMode(Taster, INPUT_PULLUP);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
}

void loop()
{
  getTaster();
  setLed();
}

uint8_t getTaster()
{
  uint32_t myMillis = millis();

  if (!digitalRead(Taster))                                 // Taste gedrückt!
  {
    if (isPress == false)                                   // Taste vorher nciht gedrückt?
    {
      pressStart = myMillis;                                // Auslösezeit merken
      isPress = true;                                       // Zustand merken
    }
    else                                                    // Taste vorher schon gedrückt
    {
      if (myMillis - pressStart > longHoldTime)             // UND Zeit abgelaufen
      {
        return (LONGPRESS); //
      }
    }
  }
  else                                                     // Taste NICHT (mehr) gedrückt
  {
    if (isPress &&                                         // UND vorher gedrückt
        myMillis - pressStart > debounceTime &&            // UND DebounceTime abgelaufen
        myMillis - pressStart < longHoldTime )             // UND NICHT lange gedrückt
    {
      isPress = false;                                     // Merker löschen
      return SHORTPRESS; //
    }
  }

  return RELAESE;                                          // Wenn nix passiert ist....
}

void setLed()
{
  switch (pressState)
  {
    case SHORTPRESS:
      digitalWrite(LED1, HIGH);
      ledStartTime = millis();
      lastState = SHORTPRESS;
      break;

    case LONGPRESS:
      if (lastState != LONGPRESS)
      {
        digitalWrite(LED2, HIGH);
        ledStartTime = millis();
        lastState = LONGPRESS;
      }
      else if (millis() - ledStartTime > ledOnTime)
      {
        digitalWrite(LED2, !digitalRead(LED2));
        ledStartTime = millis();
      }

      break;

    case RELAESE:
      if (lastState == SHORTPRESS)
      {
        if (millis() - ledStartTime > ledOnTime)
        {
          digitalWrite(LED1, LOW);
          lastState = RELAESE;
        }
      }
      else if (lastState == LONGPRESS)
      {
        digitalWrite(LED2, LOW);
        lastState == RELAESE;
      }

      break;
  }
}

Der ist nicht länger als mit der externen hpp und anpassbar wie Du es brauchst.

2 Likes

wooow....
danke an Alle die mir helfen möchten :slight_smile:
Die beiden Codes werde ich mal durcharbeiten/durchdenken/versuchen zu verstehen
Herzlichen Dank
(Dachte ich bekomme nur daueransch..., da ich noch nicht alles verstehe, wie es in anderen Foren als Neuling "üblich" ist. Man schämt sich für Unwissenheit )

Herzlichen Dank,
habe es mir angeschaut, probiert und verstanden
Das die LED2 blinkt wie ich wollte, habe ich den code dahingehend geändert:
(Ich weis, ich habe das delay verwendet, da ich aber damit nur lernen wollte und kein zeitkritisches Projekt dahintersteht, ist das denke ich ok?)

default:
      if (digitalRead(LED1) && wait(duration)) { digitalWrite(LED1, LOW); }
      if (digitalRead(LED2) && digitalRead(Taster) == LOW) { 
          delay(200);
          digitalWrite(LED2, LOW);
          delay(200);
          digitalWrite(LED2, HIGH);
         
      }
      if (digitalRead(LED2) && digitalRead(Taster)) { digitalWrite(LED2, LOW); }
      break;

Wenn Du was nicht verstehst einfach fragen.

Das ist eine Fehleinschätzung. Du wirst geteert und gefedert nur wenn Du uns keine Infos bezüglich Deines Projekts und Deines Sketches gibst und Fragen nicht beantwortest bzw Ratschläge nicht befolgst. :wink:

Ja kann ok sein. Da Dein Sketch funktioniert, könntest Du zu lernzwecken ja vesuchen das delay() nicht zu verwenden. Viele Sketche müssen nicht blockierend sein. Dann kannst Du es.

Grüße Uwe

@my_xy_projekt :
Deinen Code habe ich ausprobiert, ohne externes zu verwenden finde ich gut, aber hat leider nicht funktioniert, ich konnte den Fehler allerdings auch nicht finden da der Code zZ vom Verständniss leider meine momentanen Fähigkeiten übersteigt. Ich danke dir trotzdem für deine Mühe, werde nochmal dranrumkauen :slight_smile:

Ich schau mal drauf - das war vorhin ein Schnellschuß.
Kurze Frage: Wie ist der Taster angeschlossen? - DAS IST WICHTIG!

@uwefed,
"geteert und gefedert"....öha, dachte ich es mir doch :wink:
Es steht kein Projekt dahinter, nicht mal Hardware. Ich habe einen Arduino gekauft und auch ein Steckbrett aber bisher ist mir noch nichts wirkliches eingefallen was ich nützliches damit machen will und da meine Kenntnisse für Cpp anfänglich praktisch nicht vorhanden waren (was sich ändern will) stürze ich mich ersteinmal da drauf wobei ich festgestellt habe, das meine Konzentrationsfähigkeit zum lernen nicht mehr das sind was sie mal waren (Akzeptiere ich auch nicht!) Das Wokwi habe ich erst entdeckt und wollte mal "klein" anfangen. Sollte ich irgendwann mal soweit sein, das ich zu einem echten Projekt komme, teile ich das gerne. BTW mit den millis bin ich noch nicht ganz klar aus den Erklärungen geworden, da muß ich wohl auch mal mit code etwas probieren. Man lernt am besten durch probieren mMn :slight_smile:

Taster D2 gegen GND

1 Like

Millis() gibt nur die Millisekunden seit dem Einschalten zurück.

Wenn man jetzt in der loop() die Differenz der aktuellen millis mit denen am Startzeitpunkt macht und kontrolliert ob das Ergebnis größer als das Zeitinterwall ist, das man haben möchte dann hat man ein Zeitintervall ohne daß etwas blockiert wird.

Grüße Uwe

1 Like

Ich denke meinen Fehler gefunden zu haben.
Hab Dir ein paar serielle Ausgaben eingefügt.
Wenns nicht geht, brauch ich die.

// Globale Variable
constexpr uint8_t Taster{2};
constexpr uint8_t LED1{4};
constexpr uint8_t LED2{6};

constexpr uint32_t debounceTime {20}; // Zeit in ms
constexpr uint32_t longHoldTime {3000};

bool isPress;
uint32_t pressStart;

const uint32_t ledOnTime {500};
uint32_t ledStartTime;

enum {RELAESE, SHORTPRESS, LONGPRESS};
uint8_t pressState;
uint8_t lastState;

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start.... "));
  pinMode(Taster, INPUT_PULLUP);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
} 

void loop()
{
  pressState = getTaster();
  setLed();
}

uint8_t getTaster()
{
  uint32_t myMillis = millis();

  if (!digitalRead(Taster))                                 // Taste gedrückt!
  {
    if (isPress == false)                                   // Taste vorher nciht gedrückt?
    {
      Serial.println(F("erster Tastendruck"));
      pressStart = myMillis;                                // Auslösezeit merken
      isPress = true;                                       // Zustand merken
    }
    else                                                    // Taste vorher schon gedrückt
    {
      if (myMillis - pressStart > longHoldTime)             // UND Zeit abgelaufen
      {
        Serial.println(F("Longpress"));
        return (LONGPRESS); //
      }
    }
  }
  else if (isPress)                                         // Taste NICHT (mehr) gedrückt UND vorher gedrückt
  {
    if (myMillis - pressStart > debounceTime &&             // UND DebounceTime abgelaufen
        myMillis - pressStart < longHoldTime )              // UND NICHT lange gedrückt
    {
      Serial.println(F("Shortpress"));
      isPress = false;                                      // Merker löschen
      return SHORTPRESS; //
    }
    else                                                    // Hier war lang gedrückt...
    {
      isPress = false;
    }
  }

  return RELAESE;                                          // Wenn nix passiert ist....
}

void setLed()
{
  switch (pressState)
  {
    case SHORTPRESS:
      Serial.println(F("LED Shortpress"));
      digitalWrite(LED1, HIGH);
      ledStartTime = millis();
      lastState = SHORTPRESS;
      break;

    case LONGPRESS:
      if (lastState != LONGPRESS)
      {
        Serial.println(F("erster LED Longpress"));
        digitalWrite(LED2, HIGH);
        ledStartTime = millis();
        lastState = LONGPRESS;
      }
      else if (millis() - ledStartTime > ledOnTime)
      {
        Serial.println(F("LED Long Switch"));
        digitalWrite(LED2, !digitalRead(LED2));
        ledStartTime = millis();
      }

      break;

    case RELAESE:
      if (lastState == SHORTPRESS)
      {
        if (millis() - ledStartTime > ledOnTime)
        {
          Serial.println(F("Short Relaese"));
          digitalWrite(LED1, LOW);
          lastState = RELAESE;
        }
      }
      else if (lastState == LONGPRESS)
      {
        Serial.println(F("Long Relaese"));
        digitalWrite(LED2, LOW);
        lastState = RELAESE;
      }

      break;
  }
}
1 Like

Du kannst es mit delay machen oder dich auch in eine Menge "if (millis() - blah > blub)" ergehen, kannst es aber auch so machen:

// Blink...BlinkBlink
#include <Button_SL.hpp>

class Timer {
public:
  void start() { timeStamp = millis(); }
  bool operator()(const unsigned long duration) const { return millis() - timeStamp >= duration; }

private:
  unsigned long timeStamp {0};
};

// Globale Konstanten
constexpr uint8_t Taster {2};
constexpr uint8_t LED1 {4};
constexpr uint8_t LED2 {6};
constexpr unsigned long duration {1000};
constexpr unsigned long blink_duration {200};

// Globale Variablen
using namespace Btn;
ButtonSL btn {Taster, 3000};   // 3s für langes Drücken
Timer wait;

// Funktion(en)
void btnDuration(unsigned long time_ms) {
  Serial.println("Tastzeit: ");
  Serial.print(time_ms);
  Serial.println(" ms");
}

//////////////////////////////////////////////////////////////////////////////
void setup() {
  Serial.begin(115200);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);

  btn.begin();
  btn.setDebounceTime_ms(20);
  btn.releaseOn();
}

//////////////////////////////////////////////////////////////////////////////
void loop() {
  static bool do_blink {false};
  switch (btn.tick()) {
    case ButtonState::shortPressed:
      wait.start();
      digitalWrite(LED1, HIGH);
      btnDuration(btn.getDuration_ms());
      break;
    case ButtonState::longPressed:
      do_blink = true;
      btnDuration(btn.getDuration_ms());
      break;
    default:
      if (digitalRead(LED1) && wait(duration)) { digitalWrite(LED1, LOW); }
      if (do_blink) {
        if (wait(blink_duration)) {         // Taster noch gedrückt, Blinkinterval wartezeit abgelaufen.
          digitalWrite(LED2, !digitalRead(LED2));
          wait.start();                     // Timer auf Blinkintervall (Zeit in ms) setzen.
        } else if (digitalRead(Taster)) {   // Taster nicht mehr gedrückt. Blinken stoppen.
          digitalWrite(LED2, LOW);
          do_blink = false;
        }
      }
      break;
  }
}

Es gibt natürlich auch noch viele andere Möglichkeiten...

1 Like

Ich versteh noch nicht, warum die gedrückte Taste ausgelagert wird, aber eine losgelassene Taste nicht.

Weil die Bibliothek (Methode tick()) den gedrückten Status nicht mehr zurückgibt, wenn die vorgegebene Drückzeit "Lang" abgelaufen ist. Durch das Setzen von releaseOn().
Wird releaseOn() nicht gesetzt, wird der Status (shortPressed/longPressed) erst zurückgegeben, wenn der Taster losgelassen wird.

Wenn einem das nicht gefällt, muss man das halt von Hand machen oder eine andere der massig vorhandenen Taster / Debounce Bibliotheken verwenden...