Forum: Mikrocontroller und Digitale Elektronik Entprellen nach Peter Dannegger.


von Marc B. (drakenfly)


Lesenswert?

Liebe Community!

Ich habe eine Frage zur Entprellungs-"Komfort-Routine" von Peter 
Dannegger, siehe hier: 
http://www.mikrocontroller.net/articles/Entprellung#Interrupt-Verfahren_.28nach_Peter_Dannegger.29

Ich weiß, es wurde schon oft durchgekaut, jedoch konnte dass alles meine 
Fragen nicht klären. Das Hauptproblem ist, dass ich derzeit keine 
Möglichkeiten habe, auch nur irgendwas auf einem AVR zu testen.
Trotz allem muss ich mehr oder weniger bis Sonntag ein Projekt 
fertigstellen, in dem ich eine Entprellung brauche. An und für sich ist 
die Routine ja auch sehr komfortabel, und ich habe mich sehr gerne dafür 
entschieden.

Jedoch bin ich mir bis heute im Unklaren, was die einzelnen Abfragen 
GANZ GENAU machen, und welche sich stören.

Es gibt ja die 4 Abfragen:
get_key_press
get_key_short
get_key_long
get_key_rpt

Nun, kann ich denn auf einfache Weise, so wie hier
1
if (get_key_short(1<<KEY0)) {
2
    // Tue Aktion A
3
}
4
else if (get_key_short(1<<KEY0)) {
5
    // Tue Aktion B
6
}

zwischen langem Tastendruck und kurzem unterscheiden? Immerhin wartet 
die Routine ja auf das loslassen der Taste, bis ein short-press oder 
long-press erkannt wird. Bekomme ich da Probleme mit dem if/else 
if-Statement?

Und aus dem Source-Code:
// check if a key has been pressed. Each pressed key is reported
// only once

Heißt das, wenn er einmal abgefragt ist, wird er nie wieder als gedrückt 
erkannt, oder wie? Oder nur, bis der ISR-Ablauf wieder durchgerannt ist?


Bitte helft mit ein bißchen, ich komme im Moment kein Stück weiter... :(

Vielen Dank im Vorraus!
Lg Marc

von Karl H. (kbuchegg)


Lesenswert?

Marc Brexner schrieb:

> zwischen langem Tastendruck und kurzem unterscheiden? Immerhin wartet
> die Routine ja auf das loslassen der Taste, bis ein short-press oder
> long-press erkannt wird.

keine einzige der get_... Funktionen wartet auf irgendwas.

> Bekomme ich da Probleme mit dem if/else
> if-Statement?

Nein

> Und aus dem Source-Code:
> // check if a key has been pressed. Each pressed key is reported
> // only once
>
> Heißt das, wenn er einmal abgefragt ist, wird er nie wieder als gedrückt
> erkannt, oder wie?

Es heist genau das was dort steht.
Du drückst auf die Taste und get_key_press liefert für diese Taste 
einmal TRUE. Du drückst erneut auf die Taste und get_key_press liefert 
wieder nur 1mal TRUE

> Bitte helft mit ein bißchen, ich komme im Moment kein Stück weiter... :(

Du machst dir zu viele Sorgen.
Alle get_.... Funktionen liefern dir die Info ob eine Taste 
nieder-gedrückt wurde. So wie auf deinem Keyboard auch. Du drückst die 
Taste 'A' und 1 'a' erscheint in deinem Text. 1 Tastendruck - 1 Aktion.

Im Falle von get_key_short vs. get_key_long klarerweise erst dann, wenn 
die Taste wieder losgelassen wird.

von Marc B. (drakenfly)


Lesenswert?

Nunja, aber sobald einmal get_key_press abgefragt wurde, liefert mir 
get_key_short doch nur noch false?

Ich meine, kann so ein Gebilde denn noch funktionieren?
1
if (get_key_press(1<<KEY0) || get_key_press(1<<KEY0)) { // Ist mind. ein Taster gedrückt (nicht key_short, sondern key_press! siehe debounce.h)
2
        if (~clockStatus & (1<<CK3)) { // Wird die Uhr gerade nicht verstellt
3
          if (get_key_short(1<<KEY0) || get_key_short(1<<KEY1)) {
4
            if (~clockStatus & (1<<CK0)) { // Ist die Anzeige aus, die ...
5
              clockStatus |= (1<<CK0); // ... Anzeige eingeschalten
6
            }
7
            else { // Ist die Anzeige aus, die ...
8
              clockStatus &= ~(1<<CK0); // ... Anzeige ausschalten
9
            }
10
          }
11
          if (get_key_long(1<<KEY0)) { // Ist die Taste zum verstellen lange genug gedrückt...
12
            clockStatus |= (1<<CK3); // ... Modus zum verstellen der Uhr betreten
13
          }
14
        }
15
        else
16
        {
17
          if (get_key_short(1<<KEY0)) // Ist Taster 0 gedrückt, wechselt man von H auf M, von M auf S, und von S auf fertig.
18
          {
19
            if (clockStatus & (1<<CK4)) {
20
              clockStatus &= ~(1<<CK4);  // Stunde aus
21
              clockStatus |= (1<<CK4);  // Minute an
22
            }
23
            else if (clockStatus & (1<<CK5)) {
24
              clockStatus &= ~(1<<CK5);  // Minute aus
25
              clockStatus |= (1<<CK6);  // Sekunde an
26
            }
27
            else if (clockStatus & (1<<CK6))
28
            {
29
              clockStatus &= ~(1<<CK6);  // Sekunde aus
30
              clockStatus &= ~(1<<CK3);  // Bearbeitung beendet
31
              seconds = displayHours * 3600 + displayMinutes * 60 + displaySeconds;    // Neue Uhrzeit übernehmen
32
            }
33
          }
34
          else if(get_key_short(1<<KEY1) || get_key_press(1<<KEY1) || get_key_rpt(1<<KEY1)) { // Wird Taster 1 gedrückt (oder repeat)
35
            if (clockStatus & CK4) {
36
              displayHours++; // Um eine Stunde erhöhen
37
              if (displayHours == 24) { // Nur bis 23:59:59! -> Maximal 23h
38
                displayHours = 0;
39
              }
40
            }
41
            else if (clockStatus & CK5) {
42
              displayMinutes++;  // Um eine Minute erhöhen
43
              if (displayMinutes == 60) {
44
                displayMinutes = 0; // Nur bis 23:59:59! -> Maximal 59min
45
              }
46
            }
47
            else if (clockStatus & CK6) {
48
              displaySeconds++;  // Um eine Sekunde erhöhen (1s)
49
              if (displaySeconds == 60) {
50
                displaySeconds = 0; // Nur bis 23:59:59! -> Maximal 59s;
51
              }
52
            }
53
          }
54
        }
55
      }

Ich kann es mir nur schwer vorstellen...?

von Karl H. (kbuchegg)


Lesenswert?

Du sollst auch nicht get_key_press mit get_key_short an einem Portpin 
mischen.

get_key_short und get_key_long gehören zusammen.

und

get_key_press und get_key_rpt gehören zusammen.

Also schön brav immer innerhalb einer der beiden 'Familien' bleiben.

In der ISR wird in ein paar Variablen vermerkt, dass eine Taste gedrückt 
wurde. Sobald du die entsprechende Abfrage auf diese Taste machst, wird 
dieser Vermerk für diese Taste gelöscht. D.h. Nach einem get_key_press 
wird dir ein unmittelbar nachfolgender get_key_short immer ein FALSE 
liefern. So schnell kannst du eine Taste gar nicht drückn, dass du das 
in der Zeit dazwischen schaffst.

von Marc B. (drakenfly)


Lesenswert?

Aber wie kann ich denn dann meine Steuerung realisieren? Ich wollte 
Taster sparen, indem ich zwischen langen und kurzen Tastendrücken 
unterscheide. Auszug aus dem Handbuch meiner Uhr:

Bedienung:
Taster 0 -> Oberer Taster
Taster 1 -> Unterer Taster
Uhr inaktiv (keine LEDs an):
Taster 0 oder Taster 1 einmal kurz drücken -> Uhr wird eingeschalten
Uhr aktiv (LEDs an):
Taster 0 einmal lange drücken -> Uhr geht in Modus zum Einstellen
Taster 0 oder Taster 1 einmal kurz drücken -> Uhr wird ausgeschalten
Einstellungsmodus (LEDs blinken):
Stunden-anzeige blinkt: Die Stundenanzahl kann nun durch Drücken von 
Taster 1 nun verstellt werden. Wird Taster 1 lange gedrückt, geht er in 
den sogenannten „Repeat-Modus“, und signalisiert alle 200 Millisekunden 
einen Tastendruck für Sie. Durch Drücken von Taster 0 wird die Eingabe 
der Stundenanzahl gespeichert, und Sie können die Minuten einstellen. 
(Die Minuten-Anzeige beginnt zu blinken)
Minuten-Anzeige blinkt: Die Minutenanzahl kann nun durch Drücken von 
Taster 1 nun verstellt werden. Wird Taster 1 lange gedrückt, geht er in 
den sogenannten „Repeat-Modus“, und signalisiert alle 200 Millisekunden 
einen Tastendruck für Sie. Durch Drücken von Taster 0 wird die Eingabe 
der Minutenanzahl gespeichert, und Sie können die Sekunden einstellen. 
(Die Sekunden-Anzeige beginnt zu blinken)
Sekunden-Anzeige blinkt: Die Sekundennzahl kann nun durch Drücken von 
Taster 1 nun verstellt werden. Wird Taster 1 lange gedrückt, geht er in 
den sogenannten „Repeat-Modus“, und signalisiert alle 200 Millisekunden 
einen Tastendruck für Sie. Durch Drücken von Taster 0 wird die Eingabe 
der Sekunden-Anzahl gespeichert, und die von Ihnen eingestellte Uhrzeit 
übernommen.

von Karl H. (kbuchegg)


Lesenswert?

> Ich meine, kann so ein Gebilde denn noch funktionieren?

Nein. So wird das nichts.
Du gehst davon aus, dass die die get_.... Funktionen solange TRUE 
liefern, solange eine Taste gedrückt ist. Genau das tun sie aber nicht 
und genau das ist auch der Witz an der ganzen Sache.

von Marc B. (drakenfly)


Lesenswert?

Hm, okay. Jetzt verstehe ich, wie das funktioniert. Nun muss ich nur 
noch überlegen, was ich mache, um je nach aktuellem Modus auf die 
Abfragen zu reagieren...

Irgendwie macht dass das ganze jetzt um einiges schwerer... =/

von Karl H. (kbuchegg)


Lesenswert?

Marc Brexner schrieb:

> Taster 0 oder Taster 1 einmal kurz drücken -> Uhr wird eingeschalten
> Uhr aktiv (LEDs an):

  if Anzeige == aus )
  {
    if key pressed 0  or key pressed 1
      Anzeige ein
  }

  else
  {
    if key short 0   or  key short 1
      Anzeige aus

    else if key long 0
    {
      // Einstellungsmodus
      while ! key pressed 0
      {
         if  key pressed 1   or  key repeat 1
           Stunden++
      }

      while ! key pressed 0
      {
         if  key pressed 1   or  key repeat 1
           Minuten++
      }

      while ! key pressed 0
      {
         if  key pressed 1   or  key repeat 1
           Sekunden++
      }
    }
  }


> Irgendwie macht dass das ganze jetzt um einiges schwerer... =/
find ich nicht :-)
Ganz im Gegenteil

von Marc B. (drakenfly)


Lesenswert?

1
if (clockStatus & (1<<CK1)) // Tasterabfrage aktiv, mal sehen was nun zu tun ist
2
{
3
if (~TIMSK1 & (1<<OCIE1A)) { // Timer für Tastenabfrage ist inkativ, also ...
4
  TIMSK1 |= (1<<OCIE1A); // ... aktivieren
5
}
6
if (~clockStatus & (1<<CK0)) { // Uhr ist aus
7
  if (get_key_short(1<<KEY0) || get_key_short(1<<KEY1)) { // Bei kurzem Tastendruck
8
    clockStatus |= (1<<CK0); // Anzeige einschalten
9
  }
10
}
11
else {
12
  if (~clockStatus & (1<<CK3)) { // Wenn die Uhrzeit nicht bearbeitet wird
13
    if (get_key_short(1<<KEY0) || get_key_short(1<<KEY1)) { // Bei kurzem Tastendruck
14
    // TODO: ALLES AUS damit AVR wieder Energie sparen kann! Diese Anweisung schaltet nur die Anzeige aus!
15
      clockStatus &= ~(1<<CK0);
16
    }
17
    else if (get_key_long(1<<KEY0)) { // Bei langem Tastendruck von Taster 0
18
      clockStatus |= (1<<CK3); // Einstellungsmodus betreten
19
    }
20
  }
21
  else {
22
    if (get_key_short(1<<KEY0)) { // Taster 0 wird gedrückt -> Modus umschalten!
23
      if (clockStatus & (1<<CK4)) {
24
        clockStatus &= ~(1<<CK4);  // Stunde aus
25
        clockStatus |= (1<<CK4);  // Minute an
26
      }
27
      else if (clockStatus & (1<<CK5)) {
28
        clockStatus &= ~(1<<CK5);  // Minute aus
29
        clockStatus |= (1<<CK6);  // Sekunde an
30
      }
31
      else if (clockStatus & (1<<CK6)) {
32
        clockStatus &= ~(1<<CK6);  // Sekunde aus
33
        clockStatus &= ~(1<<CK3);  // Bearbeitung beendet
34
        seconds = displayHours * 3600 + displayMinutes * 60 + displaySeconds;    // Neue Uhrzeit übernehmen
35
      }
36
    }
37
    if (get_key_press(1<<KEY1) || get_key_rpt(1<<KEY1)) { // Wird Taster 1 gedrückt oder gehalten aktuelle ausgewähltes "Element" der Uhr hochzählen.
38
      if (clockStatus & CK4) {
39
        displayHours++; // Um eine Stunde erhöhen
40
        if (displayHours == 24) { // Nur bis 23:59:59! -> Maximal 23h
41
          displayHours = 0;
42
        }
43
      }
44
      else if (clockStatus & CK5) {
45
        displayMinutes++;  // Um eine Minute erhöhen
46
        if (displayMinutes == 60) {
47
          displayMinutes = 0; // Nur bis 23:59:59! -> Maximal 59min
48
        }
49
      }
50
      else if (clockStatus & CK6) {
51
        displaySeconds++;  // Um eine Sekunde erhöhen (1s)
52
        if (displaySeconds == 60) {
53
          displaySeconds = 0; // Nur bis 23:59:59! -> Maximal 59s;
54
        }
55
      }
56
    }
57
  }
58
}

Dann hat dieses Gebilde in deinen Augen schon etwas mehr 
durchsetzungskraft, oder? Danke für deinen "Prototypen"! :D

Lg Marc

von Marc B. (drakenfly)


Lesenswert?

Da ich seit gestern wieder zu Hause bin, habe ich mich gleich 
hingesetzt, und auf meinem Testboard was zusammengesteckt. Dieses von 
mir zuletzt gepostetes "Gebilde" funktioniert - Danke, für eure Hilfe!

Und ein großes Lob an Peters Entprellungs-Code, der funktioniert 
wirklich TOP

Lg Marc

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.