Long Button Press

Persönliche Seite #5920866
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
Gast #5920943
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.
#5921088
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
  }
Gast #5921091
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.
Persönliche Seite #5923296
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
#5923331
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.
#5923406
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
}
#5923714
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren