Dauer eines Tastendrucks auswerten

Moin Forum,

ich habe eine Funktion, die die dauer eines Tastendrucks auswertet und daraufhin etwas tut. Das Problem ist jetzt, wenn ich z.B. den Taster 5 Sekunde gedückt halte werden bei meinem Code auch alle anderen dinge getan, die bei 1 - 4 Sekunden gedückten Taster passieren sollen. Jetzt will ich aber natürlich, dass nur die eine Funktion ausgeführt werden soll. Ich hab überlegt, dass ich erst eine gewisse Zeit warte und dann erst die entsprechenden Befehle ausführe. Finde aber ich eher unschön, wenn ich jetzt Beispielsweise den Taster 1 Sekunde drücke und dann erst 10 Sekunden warte, bevor ich das passiert, was bei 1 Sekunde gedückten Taster passieren soll.

Hat jemand da eine Idee, wie ich das lösen kann?
Mfg

int8_t Taster_alt;

#define TASTER_GEDRUECKT 1
#define TASTER_NICHT_GEDRUECKT 2
#define TASTER_LOSGELASSEN 3
#define TASTER_1SEK_GEDRUECKT 4
#define TASTER_2SEK_GEDRUECKT 5
#define TASTER_3SEK_GEDRUECKT 6
#define TASTER_4SEK_GEDRUECKT 7
#define TASTER_5SEK_GEDRUECKT 8

void Tasterabfrage()
{
  // == Tasterauswertung ==
  byte Bla = Taster();

  if (Taster_alt != Bla)
  {
    if (Bla == 5) // tu was

      if (Bla == 6) // tu was

        if (Bla == 7) // tu was

          if (Bla == 8) // tu was
          }
  Taster_alt = Bla; // Aktuellen Wert abspeichern
}

byte Taster() //== Tasterabfrage ==
{
  static unsigned long startzeit;
  static bool Taster_status;

  bool Taster_gedrueckt = !digitalRead(D4); // Taster nach GND geschaltet

  if ((Taster_gedrueckt) && (! Taster_status))
  {
    startzeit = millis();
    Taster_status = true;
    delay(5); // entprellen
    return TASTER_GEDRUECKT;
  }

  if ((Taster_gedrueckt) && (Taster_status))
  {

    if (((millis() - startzeit) >= 1000) && ((millis() - startzeit) <= 2000))
      return TASTER_1SEK_GEDRUECKT;

    else if (((millis() - startzeit) >= 2000) && ((millis() - startzeit) <= 3000))
      return TASTER_2SEK_GEDRUECKT;

    else if (((millis() - startzeit) >= 3000) && ((millis() - startzeit) <= 4000))
      return TASTER_3SEK_GEDRUECKT;

    else if (((millis() - startzeit) >= 4000) && ((millis() - startzeit) <= 5000))
      return TASTER_4SEK_GEDRUECKT;

    else if (((millis() - startzeit) >= 5000) && ((millis() - startzeit) <= 6000))
      return TASTER_5SEK_GEDRUECKT;

    else
      return false;

  }

  if ((!Taster_gedrueckt && Taster_status))
  {
    Taster_status = false;
    delay(5);
    return TASTER_LOSGELASSEN;
  }
  return TASTER_NICHT_GEDRUECKT;
}

Erfasse das Loslassen und dann werte die Zeit aus (von lang nach kurz)

Gruß Tommy

1 Like

könnte man dafür auch pulsein() benutzen?

Du hast nicht nur ein Problem.
Warum machst Du das:

void Tasterabfrage()
{
  // == Tasterauswertung ==
  byte Bla = Taster();

  if (Taster_alt != Bla)
  {
    if (Bla == 5) // tu was

      if (Bla == 6) // tu was

        if (Bla == 7) // tu was

          if (Bla == 8) // tu was
          }
  Taster_alt = Bla; // Aktuellen Wert abspeichern
}

neu:

  if (Taster_alt != Bla)
  {
    switch (bla)
    {
      case 5:
      break;
      case 6:
      break;
      case 7:
      break;
      case 8:
      break;
      default:
      break:
    }
  Taster_alt = Bla; // Aktuellen Wert abspeichern
}

Und dann am Beispiel:

    if (((millis() - startzeit) >= 1000) && ((millis() - startzeit) <= 2000))
      return TASTER_1SEK_GEDRUECKT;
    else if (((millis() - startzeit) >= 2000) && ((millis() - startzeit) <= 3000))
      return TASTER_2SEK_GEDRUECKT;

Wenn Du 2000 ms gedrückt hast, darf sich ausgesucht werden, was da ausgegeben wird!
Das zieht sich dann auch so durch.

Davon abgesehen,. das ich den Codeschnipsel für nicht zielführend halte....
Da wird sicher noch mehr kommen...

  if ((Taster_gedrueckt) && (Taster_status))
  {
    if (millis() - startzeit > 6000)
    {
      Serial.println(F("zu lange gedrückt"));
    }
    else if (((millis() - startzeit) >= 5000) && ((millis() - startzeit) <= 6000))
      return TASTER_5SEK_GEDRUECKT;
    else if (((millis() - startzeit) >= 4000) && ((millis() - startzeit) <= 5999))
      return TASTER_4SEK_GEDRUECKT;
    else if (((millis() - startzeit) >= 3000) && ((millis() - startzeit) <= 3999))
      return TASTER_3SEK_GEDRUECKT;
    else if (((millis() - startzeit) >= 2000) && ((millis() - startzeit) <= 2999))
      return TASTER_2SEK_GEDRUECKT;
    else if (((millis() - startzeit) >= 1000) && ((millis() - startzeit) <= 1999))
      return TASTER_1SEK_GEDRUECKT;
    else
      return false;
  }

Hallo,
ich habe deinen Sketch als Pseudocode angenommen und einen gestesten Sketch erstellt. Probier mal aus ob diese Lösung zu deinem Projekt passt.

// timer für die Tasterabfrage
struct TIMER {
  unsigned long stamp;
  unsigned long duration;
};
TIMER buttonScan {0, 20}; // alle 20 msec wird auf eine Änderung geschaut

// Datenstruktur für den Taster
struct INPUT_ {
  int pin;
  int state;
  unsigned long time01;
};
INPUT_ button {A0, 0, 0};

void setup() {
  pinMode (button.pin, INPUT_PULLUP);
  Serial.begin(9600);
}
void loop() {
  Tasterabfrage();
}
void Tasterabfrage() {
  if (millis() - buttonScan.stamp >= buttonScan.duration) {
    buttonScan.stamp = millis();
    // ist der Taster gedrückt worden?
    bool state = !digitalRead(button.pin);
    if (button.state != state) {
      // den aktuellen Status speichern
      button.state = state;
      // wenn der Taster losgelassen worden ist, dann mit der Zeitdifferenz in die Auswertung
      if (!state) makeTime(((int)millis() - button.time01) / 100);
      // wenn der Taster gedrückt worden ist, dann die Zeit speichern
      else button.time01 = millis();
    }
  }
}
void makeTime (int time) {
    switch (time) {
    case 0 ... 9: Serial.println(F("1. Sekunde")); break;
    case 10 ... 19: Serial.println(F("2. Sekunde")); break;
    case 20 ... 29: Serial.println(F("3. Sekunde")); break;
    case 30 ... 39: Serial.println(F("4. Sekunde")); break;
    case 40 ... 49: Serial.println(F("5. Sekunde")); break;
    case 50 ... 59: Serial.println(F("6. Sekunde")); break;
    case 60 ... 69: Serial.println(F("7. Sekunde")); break;
    default: Serial.println(F("größer als 7 Sekunden")); break;
  }
}

Davon abgesehen, das der TO noch am Anfang vom Verständis von if / if else / else und scope steht

Hm....

Hi,

danke für die vielen antworten und die Hinweise bezüglich meines Codes. Der Sketch von @paulpaulson hat gut funktioniert danke :slight_smile:

Du hast nicht zufällig Lesestoff (?)

Mfg

Hi,

eine Frage hab ich noch. Wo wäre der Unterschied, wenn ich vor dem struct ein typedef hinzufüge?

// Datenstruktur für den Taster
struct INPUT_ {
  int pin;
  int state;
  unsigned long time01;
};
INPUT_ button {A0, 0, 0};

Bedeutet das „Hm….“ weil wegen INT für time nicht unsingned long ist ? :face_with_monocle:

Danke euch :slight_smile:

Das dort Beschriebene gilt für C. Für C++ ist typedef für struct nicht notwendig.

Gruß Tommy

Ne.
Weil int AN DER STELLE Unsinn ist.

Der Code krankt auch sonst - Es war nur ein gut gemeinter Hinweis.
Ungehört. Nu gut...

Hier gehört ein Byte rein für den PIN und ein bool für den state.

zu dem int:

makeTime(((int)millis() - button.time01) / 100);

Das halte ich für kreuzgefährlich, denn mit jedem Mal, wo millis() am int überläuft, kommt es zu einem negativen Vorzeichen....

Probier es aus:

unsigned long x = 0;
int y=0;

void setup() {
  Serial.begin(115200);
  Serial.println(F("Start..."));

  for (uint8_t i=0; i<10; i++)
  {
    x+=32767;
    y=(int)x;
    Serial.print(x);
    Serial.print("\t");    
    Serial.println(y);
  }
  
}

void loop() {
  // put your main code here, to run repeatedly:

}

Was darüber hinaus passiert, las ich mal so stehen,...

Ach, Du wollstest ja noch Lit.

:wink: Beste Grüße!

Ja das meinte ich: Für Zeiten immer unsigned long!

Nur als Info: Ich bin nicht der TO, ich hatte nur interessehalber eine Frage gestellt :grinning:

Das macht er ja eigentlich.
Das casten auf (signed) int ist falsch und an der Stelle wo es jetzt steht auch.
Man könnte jetzt drüber nachdenken, ob die Typumwandlung nach der Subtraktion und vor der Division oder erst nach der Division erfolgen soll.
Ich würde definitiv zu letzterem tendieren.

Mit der expliziten Typumwandlung soll ja der Bereich fürs case abgedeckt werden. Das geht auch. nur eben nicht da :wink:

Ja, hab ich übersehen...

Danke dir :grinning:

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