Forum: Mikrocontroller und Digitale Elektronik Long Button Press


von D a v i d K. (oekel) Benutzerseite


Lesenswert?

Hi,

ich hätte nicht gedacht, dass man sich an so einer Thematik länger als 
10min aufhalten kann, aber ich bin mit meinen Denkansätze nicht zu 
frieden.

Ich möchte gerne eine Tastendruck "nahezu" sofort auswerten aber auch 
noch die Möglichkeit haben ein langes drücken zu detektieren.

ich speichere mir den Zustand des Pins aktuell in 2 Variablen:
aktueller und letzter Zustand.

Somit habe ich das bekannte detektieren von Kanten.

nehmen wir uns nun die methode "&incrementValue()" daher, die auf einen 
Knopf/IO gemappt werden soll.

mein Timer aktualisiert "alt" & "neu" alle 10ms.
Somit habe ich also ggf. alle 10ms ein neues RISING oder FALLING.
1
if(RISING){
2
incrementValue();
3
}
Kommt überspringt manche Inputs, weil vom Timing so schnell gedrückt 
worden ist, dass bereits wieder FALLING aktiv ist.
1
if(FALLING){
2
incrementValue();
3
}
Ist da zuverlässiger, verwirrt jedoch, wenn man den Knopf fest hält.

Und nun die spannendste Frage, wie baue ich ein
1
...
2
incrementValue();
3
}
für lange Haltezeit ein ohne die anderen beiden Detektionen zu 
verlieren?


Grüße Oekel

: Bearbeitet durch User
von Klar M. (Gast)


Lesenswert?

Hallo,

schau dir die Entprell- und Auswertroutinen von Peter Dannegger (peda) 
im Leitartikel an.

Damit kann u.a. man Press, Release oder Short- oder Long-Press und 
Release auswerten.

Schöner Nebeneffekt es werden 8 Taster gleichzeitig entprellt!

von D a v i d K. (oekel) Benutzerseite


Lesenswert?

Folgendes finde ich jetzt nicht sonderlich schick:
1
    if (sw1_now) {
2
        if (!sw1_last) {
3
            SW1 = RISING;
4
            count.ms10.switch1LongPress = DETECT_LONGPRESS_BUTTON_MS10;
5
        } else if (count.ms10.switch1LongPress == 0) {
6
                SW1 = RISING_FAST;
7
        }
8
    }else if(sw1_last){
9
        SW1 = FALLING;
10
    }

von D a v i d K. (oekel) Benutzerseite


Lesenswert?

Klar M. schrieb:
> Hallo,
>
> schau dir die Entprell- und Auswertroutinen von Peter Dannegger (peda)
> im Leitartikel an.
https://www.mikrocontroller.net/articles/Entprellung ?

von Einer K. (Gast)


Angehängte Dateien:

Lesenswert?

Keine IDE genannt, kein µC genannt.

Darum ein "schönes" Arduino Beispiel im Anhang.
Die gedrückte Taste wird nach 20ms gemeldet
Der lange Druck nach 1020ms.
Mach was draus.


Die benötigten Libraries habe ich hier schon irgendwann mal gepostet.
Die findest du.

von Klar M. (Gast)


Lesenswert?

Hallo,

Hier ist noch der Link zum original Artikel "Universelle Tastenabfrage":

Beitrag "Universelle Tastenabfrage"

Weitere Referenzen wirst Du selbst finden.

von D a v i d K. (oekel) Benutzerseite


Lesenswert?

Arduino Fanboy D. schrieb:
> Die benötigten Libraries habe ich hier schon irgendwann mal gepostet.
> Die findest du.

Nur die wären interessant gewesen. Der µC ist doch für die Idee völlig 
uninteressant.

ansosten tut es mein Code hier auch: :P
1
#include "meineMagie.h"
2
3
4
int main(){
5
while(1){
6
 doMagic();
7
}

: Bearbeitet durch User
von Lisp-Fan (Gast)


Lesenswert?

In Lisp lässt sich das noch prägnanter ausdrücken:
1
(DWIM 'KEYBOARD)

von Einer K. (Gast)


Lesenswert?

D a v i d K. schrieb:
> ansosten tut es mein Code hier auch: :P

Wer nicht will, der hat schon ....

von spess53 (Gast)


Lesenswert?

HI

>Ich möchte gerne eine Tastendruck "nahezu" sofort auswerten aber auch
>noch die Möglichkeit haben ein langes drücken zu detektieren.

Na ja, da gab es mal diese Tasten mit den kleinen Kristall-Kugeln drin. 
Die haben schon bei Tastendrücken die Länge des Tastendrucks 
vorausgesehen.

MfG Spess

von Mick (Gast)


Lesenswert?

Dein Vorhaben ist überhaupt nicht einfach...

Falls Arduino oder PlatformIO im Einsatz ist, nimm diese Bibliothek: 
https://github.com/TOLDOTECHNIK/TTBOUNCE

Da kannst du die Methoden
1
attachClick()
 für einen einfachen Klick und
1
attachPress()
 für das lange Drücken verwenden.

Die Zeitfenster kannst du jeweils mit
1
setClickInterval()
und
1
setPressInterval()
festlegen.

von Quax (Gast)


Lesenswert?

D a v i d K. schrieb:
> ansosten tut es mein Code hier auch: :P

Leider nicht, Syntax error :-/ Zudem noch Schreibfehler :-/ :-/

von loeti2 (Gast)


Lesenswert?

Einfach die Aktion bei kurzem Tastendruck erst nach Loslassen starten 
lassen, ansonsten den Beginn des Tastendrucks feststellen und nach der 
gewünschten Wartezeit wenn Taste noch gedrückt die Aktion bei langem 
Tastendruck starten.
Dabei Flag setzen daß Loslassen nicht zusätzlich die Aktion bei kurzem 
Tastendruck startet.

von Philipp K. (philipp_k59)


Lesenswert?

Ich bin da auch mal drüber gestolpert..

Anbei mal ein übersichtlicher Arduino Code:
1
int pin = 6;
2
int laststate = HIGH;
3
int state = HIGH;
4
boolean debouncing = false; //Entprellt?
5
boolean minimpuls = true; //Minimale Impulslänge für Aktion
6
unsigned long lastintervallmillis = millis();
7
unsigned long changestate = millis();
8
unsigned long lastdebounce = millis();
9
unsigned long lastminpulse = millis();
10
 
11
void setup() {
12
  Serial.begin(115200);
13
}
14
 
15
//Konfiguration:
16
int Abtastrate = 5;
17
int entprellzeit = 100;
18
int minpuls = 50; //Minimale Pulslänge
19
 
20
 
21
void loop() {
22
  long tempmillis = millis();
23
  if ((tempmillis - lastintervallmillis) >=  Abtastrate ) //Frühestens nach Abtastrate überprüfen, reicht manchmal schon als kleine Entprellung
24
  {
25
    lastintervallmillis = tempmillis; //Letzte Abtastung speichern
26
    int tempstate = digitalRead(pin); //Pin einlesen
27
 
28
    if (tempstate != laststate) //Pin hat sich geändert, hier ist egal in welche Richtung, im Prinzip Low und High Entprellung.
29
    {
30
      debouncing = true; //Entprellung aktivieren
31
      minimpuls=true;
32
      laststate = tempstate; //Buffer für temporären Pinstatus
33
      changestate = tempmillis; //Änderungszeitpunkt
34
    }
35
    if (debouncing) { 
36
      if ((tempmillis - changestate) >= entprellzeit && debouncing)
37
      {
38
        debouncing = false;
39
      }
40
    }
41
    if (tempmillis - changestate >= (entprellzeit + minpuls) && !debouncing )
42
    {
43
      minimpuls=false;
44
    }
45
    if(!debouncing && !minimpuls)
46
      state = laststate;
47
      debouncing = true;
48
      minimpuls = true;
49
      if (state == HIGH) {
50
        Serial.println("Alles erfüllt!");
51
      }
52
    }
53
  }

von Frickler (Gast)


Lesenswert?

Was mich betrifft finde ich Pedas Lösung optimal weil sich alles im 
Hintergrund in einer Timer ISR abspielt. Für meine Projekte zumindest 
lässt diese Lösung keine Wünsche offen. Funktioniert absolut zuverlässig 
ohne den CPU Durchsatz nennenswert zu belasten. Auch mit Arduino 
funktioniert es ohne irgendwelche Probleme. Das Geniale an seiner Lösung 
ist, daß der Timer mit seiner ms Zeitbasis die ganze Arbeit erledigt. 
Alles andere was der CPU abarbeitet spielt keine nennenswerte Rolle und 
kann keinen Einfluß ausüben.

von Peter D. (peda)


Lesenswert?

Philipp K. schrieb:
> unsigned long lastintervallmillis = millis();
> unsigned long changestate = millis();
> unsigned long lastdebounce = millis();
> unsigned long lastminpulse = millis();

Puh, ne riesen Menge Code und riesen Variablen je Taste. Mußt Du 
wirklich einen langen Druck von 49 Tagen erkennen können?

von Einer K. (Gast)


Lesenswert?

Wenn das Programm/µC sonst nix zu tun hat....

von Crazy Harry (crazy_h)


Lesenswert?

Ich hab meine Tastaturabfrage in einen Process ausgelagert, der alle 
50ms durchlaufen wird. Bleibt eine Taste gedrückt wird eine Variable 
hoch gezählt, ist die Taste beim nächsten Processlauf nicht mehr 
gedrückt, wird die Var auf 0 gesetzt.
Bei Var>=X kann ich also ein Unterprogramm ausführen lassen ...... nur 
mal so prinzipiell.

von D a v i d K. (oekel) Benutzerseite


Lesenswert?

Crazy H. schrieb:
> Ich hab meine Tastaturabfrage in einen Process ausgelagert, der alle
> 50ms durchlaufen wird. Bleibt eine Taste gedrückt wird eine Variable
> hoch gezählt, ist die Taste beim nächsten Processlauf nicht mehr
> gedrückt, wird die Var auf 0 gesetzt.
> Bei Var>=X kann ich also ein Unterprogramm ausführen lassen ...... nur
> mal so prinzipiell.

Ich glaube, wenn ich noch mal genauer drüber nachdenke sind meine 
Anforderungen komplett unterschiedlich zu euren.

Ich möchte nicht erkennen, ob eine Taste x_sec gedrückt war und dann ein 
einzelnes event abfeuern (ich glaube genau das macht der Code von 
(peda)).

Sondern ich möchte so etwas wie ein fast_up fast_down eines Wertes 
veranlassen, der gleichzeitig "schnell" auf einer Anzeige gezeigt wird.

Also ähnlich eines (DVD)-Players, der im Play/Pause Modus ist und ein 
einzelner Druck auf die jeweilige Taste 1Sec im Film vor oder zurück 
spult, das halten der Taste jedoch schnell vorspult und gleichzeitig die 
Zeit im Display, wo man sich gerade befindet angezeigt wird.

Meine Vermutung, und nur das bitte ich kurz (falls richtig) zu 
bestätigen ist, dass ich dieses Verhalten nur darüber erzielen kann den 
jeweilen Entprell-Timer öfters als "normal" azufragen und so auch im µC 
die routinen schneller/häufiger zu durchlaufen.

Ist das korrekt, oder gibt es alternativen?

Grüße Oekel

: Bearbeitet durch User
von S. R. (svenska)


Lesenswert?

Wenn du lange Tastendrücke von kurzen Tastendrücken unterscheiden können 
willst, dann kannst du prinzipiell erst dann dein Event auslösen, wenn 
du die Taste (nach Entprellung) loslässt.

Das heißt, die Entprellroutine schaut beim Loslassen der Taste nach, wie 
lange sie gedrückt war und löst dann das passende Event aus.

Was du willst, ist eine sich wiederholende Taste. Dazu schaust du in der 
Entprellungroutine bei einer gedrückten Taste nach, wie lange sie schon 
gedrückt ist. Wenn das lange genug ist, setzt du den Zähler zurück und 
löst ein "repeat"-Event aus.

von Philipp K. (philipp_k59)


Lesenswert?

Vielleicht so.. ungetestet. Zählt hoch und wird immer schneller
1
unsigned long currentMillis=millis();
2
unsigned long previousMillis=millis();
3
int intervall= 500; //hochzählabstand
4
int intervallfest=500;
5
int count =0;
6
void loop(){
7
currentMillis=millis();
8
9
 if (digitalRead(button1) == LOW) {
10
11
      if (currentMillis - previousMillis >= intervall) {
12
        Serial.println("Button1");
13
        previousMillis = currentMillis;
14
        timerminute++;
15
        count++;
16
        if(count>=9;)
17
{
18
if(intervall>100)
19
intervall=intervall-100;
20
count=0;
21
}
22
23
}
24
    } else {
25
      previousMillis = currentMillis;
26
      intervall=intervallfest;
27
      count=0;    
28
}
29
}
30
}

: Bearbeitet durch User
von D a v i d K. (oekel) Benutzerseite


Lesenswert?

Philipp K. schrieb:
> Vielleicht so.. ungetestet. Zählt hoch und wird immer schneller

Ja so in etwa habe ich es auch gelöst. :)
Wenn das the-way-of-doing ist, bin ich bereits zufrieden.

von Philipp K. (philipp_k59)


Lesenswert?

das ist halt indirekte entprellung, das funktioniert auch so für Taster.

da brauch man keine lib oder timer.. beschäftigt ist die MCU so oder so.

von Peter D. (peda)


Lesenswert?

D a v i d K. schrieb:
> gibt es alternativen?

In dem Fall kann man mit get_key_press() der Tastendruck auswerten und 
mit  get_key_rpt() das gedrückt halten. Die Repeatfunktion kann man z.B. 
in 10-er Schritten zählen lassen. Es sind auch verschiedene Zeiten für 
den Start der Repeatfunktion und das Wiederholen definierbar.
Es wird ein Repeatzähler für alle Tasten gemeinsam verwendet, was in der 
Regel ausreichen sollte. Tasten ohne Repeat bzw. andere Pins des Ports 
sollte man daher ausmaskieren.

https://www.mikrocontroller.net/articles/Entprellung#Timer-Verfahren_.28nach_Peter_Dannegger.29

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.