Forum: Mikrocontroller und Digitale Elektronik Entprellungsfunktion arbeitet nicht zuverlässig


von Johannes (menschenskind)


Lesenswert?

Hallo

Ich habe diese Entprellungsroutine 
https://www.mikrocontroller.net/articles/Entprellung#Flankenerkennung 
für einen "Active HIGH"-Taster umgebaut:
1
#include <avr/io.h>
2
3
#define BUTTONPORT PIND
4
#define BUTTONPIN PD2
5
 
6
char debounce(void)
7
{
8
    static unsigned char state;
9
    char rw = 0;
10
 
11
    if(state == 0 && (BUTTONPORT & (1<<BUTTONPIN)))   //Taster wird gedrueckt (steigende Flanke)
12
    {
13
        state = 1;
14
        rw = 1;
15
    }
16
    else if (state == 1 && (BUTTONPORT & (1<<BUTTONPIN)))   //Taster wird gehalten
17
    {
18
         state = 2;
19
         rw = 0;
20
    }
21
    else if (state == 2 && !(BUTTONPORT & (1<<BUTTONPIN)))   //Taster wird losgelassen (fallende Flanke)
22
    {
23
        state = 3;
24
        rw = 0;
25
    }
26
    else if (state == 3 && !(BUTTONPORT & (1<<BUTTONPIN)))   //Taster losgelassen
27
    {
28
        state = 0;
29
        rw = 0;
30
    }
31
 
32
    return rw;
33
}

Über
1
while(1){
2
    
3
    if(debounce() == 1)  LED_EVENT(LED2,2);
4
}
lasse ich eine LED blinken, wenn "rw" 1 ist.
Leider klappt das aber irgendwie nur bei jedem 2. Mal (selten auch erst 
beim 3. Drücken)
Woran kann das liegen?

Der µC läuft mit 16 MHz und nebenbei (in der While-Schleife) wird noch 
ein NeoPixelRing angesteuert.

Danke
Hannes

von Peter D. (peda)


Lesenswert?

Johannes H. schrieb:
> Ich habe diese Entprellungsroutine
> https://www.mikrocontroller.net/articles/Entprellung#Flankenerkennung

Drüber steht ja "Flankenerkennung", da wird also gar nichts entprellt.

Weiter steht "Die Entprellung geschieht dabei durch die ganze Laufzeit 
des Programms.", was ganz großer Bockmist ist.

von Joe F. (easylife)


Lesenswert?

Du könntest statt
1
    else if (state == 1 && (BUTTONPORT & (1<<BUTTONPIN)))   //Taster wird gehalten
2
    {
3
         state = 2;
4
         rw = 0;
5
    }

folgendes machen:
1
    else if (state == 1 && (BUTTONPORT & (1<<BUTTONPIN)))   //Taster wird gehalten
2
    {
3
         state = 2;
4
         rw = 1;
5
    }

Dadurch wird dir zumindest beim Halten des Tasters auch eine 1 
zurückgeliefert.
Was macht denn deine Funktion "LED_EVENT(LED2,2)" genau?
Du müsstest die LED ja auch irgendwo wieder ausschalten...?

Insgesamt ist diese Entprell-Funktion nicht so super.
Sie geht davon aus, dass der Taster beim Prellen bei jedem 
Funktionsaufruf seinen Zustand geändert hat.
Wenn er "langsamer" prellt (also 2 Funktionsaufrufe den gleichen Wert 
liefert) steigt diese Funktion schon aus.

Ich würde es eher über ein Timeout machen.
Also nach der Flankenerkennung (in beiden Richtungen) eine gewisse Zeit 
lang (ein paar ms) den Taster nicht abfragen.
Das kann man z.B. über einen Counter in debounce() realisieren.

Also so:
1
#define DEBOUNCE_DELAY (100)    // <--- entsprechend anpassen
2
3
char debounce(void)
4
{
5
    static unsigned char state = 0;
6
    static unsigned int  delay = 0;
7
    
8
    if (delay > 0)
9
    {
10
      delay--;
11
    }
12
    else
13
    {
14
      if(state == 0 && (BUTTONPORT & (1<<BUTTONPIN)))   //Taster wird gedrueckt (steigende Flanke)
15
      {
16
          state = 1;
17
          delay = DEBOUNCE_DELAY;
18
      }
19
      else if (state == 1 && !(BUTTONPORT & (1<<BUTTONPIN)))   //Taster losgelassen
20
      {
21
          state = 0;
22
          delay = DEBOUNCE_DELAY;
23
      }
24
    }
25
26
    return state;
27
}

: Bearbeitet durch User
von Johannes (menschenskind)


Lesenswert?

@Peter
Ach so! Hm, ja diesen einen Satz hatte ich dann in der Tat nicht richtig 
verstanden.

@Joe
Wie Peter schon sagte, ist das also keine Entprellfunktion. Die stand 
nur in der Liste ganz oben, deswegen hab ich die zuerst ausprobiert.
Die Timeoutvariante ist auch in dem Tutorial enthalten, wenn auch in 
anderer Form.
"LED_EVENT" schaltet die LED kurz ein und dann wieder aus.

von Johannes (menschenskind)


Lesenswert?

Hi Peter,

Ich habe Deinen Code (Komfortroutine) jetzt integriert.
Woran ich aber gerade grüble ist, dass das "get_key_long" bereits nach
sehr kurzem "Lang-Drücken" des Tasters registriert wird.

Ich habe in den Defines diesen Wert von 50 auf 100 geändert "#define
REPEAT_START    100 "
Da sich das Verhalten aber nicht ändert, nehme ich also an, dass ich an
der falschen Stelle gedreht habe.
Ebenso habe ich den Vorteilquotienten von 1024 auf 1600 gesetzt da ich 
mit einem höheren Takt als in Deinem Beispiel arbeite.

Mein Ziel ist es, ein Lang-Drücken von etwa 2 Sekunden zu detektieren.

von Route_66 (Gast)


Lesenswert?

Johannes H. schrieb:
> Ebenso habe ich den Vorteilquotienten von 1024 auf 1600 gesetzt da ich
> mit einem höheren Takt als in Deinem Beispiel arbeite.

Du kannst doch nur Vorteiler wählen, die in Deiner Hardware auch 
vorhanden sind!?

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.