Wie ist dieser Pushbutton Debounce-Code?

Ich überwache einen Taster mit einem Mikrocontroller, wo ich versuche, vier Dinge zusammen zu erledigen:

  1. 50-ms-Entprellzeit bei Druckbeginn und 25-ms-Entprellzeit bei Druckfreigabe
  2. Identifizieren eines kurzen Drückens, definiert als das Loslassen der Taste innerhalb von < 1 Sekunde
  3. Identifizieren Sie ein langes Halten, definiert als wenn 1 Sekunde seit dem Beginn des Tastendrucks vergangen ist
  4. schlafen Sie so viel wie möglich, wenn Sie nichts anderes tun

Unten ist ein kurzer Pseudocode dessen, was ich bisher implementiert habe. Ich denke, es deckt alle diese Fälle ab.

Sehen Sie mögliche Verbesserungen oder potenzielle Probleme? (Zum Beispiel interessiere ich mich für alle subtilen Fälle, die blinde Flecken für meinen Ansatz sein könnten.)

Pseudocode:

Main loop {
  Sleep
}

Falling-Interrupt {
  Disable Falling-Interrupt
  Enable 50-millisecond-Debounce-Timer-Interrupt
}

50-millisecond-Debounce-Timer-Interrupt {
  if PushButton state is still LOW {
    Enable Rising-Interrupt
    Enable 1000-millisecond-Hold-Timer-Interrupt
  }
}

1000-millisecond-Hold-Timer-Interrupt {
  Register as Pushbutton long-hold
}

Rising-Interrupt {
  if (Time since Falling-Interrupt < 1000 millisecond) {
    Register as Button Short-press
  }
  Disable 1000-millisecond-Hold-Timer-Interrupt
  Enable 25-millisecond-Debounce-Timer-Interrupt
}

25-millisecond-Debounce-Timer-Interrupt {
   Enable Falling-Interrupt
} 
Persönlich vermeide ich Unterbrechungen von Serviceroutinen, wann immer ich kann. Ich würde einen 50-ms-Interrupt einrichten und die gesamte Verarbeitung nach dem Ruhezustand durchführen. 25 ms: warum nicht 50 ms? Kein Benutzer wird es bemerken.
@WoutervanOoijen: Wie kann ich ein Drucktastenereignis im Schlaf erkennen, wenn ich die Verwendung von Interrupts vermeide? Oder meinst du, ich sollte den eigentlichen Code in der ISR minimieren? [Und die 25 vs. 50 ms waren willkürlich; Ich habe es nur verwendet, um es dem Leser einfacher zu machen, zwischen dem Entprell-Timer beim Beginn und dem Entprell-Timer beim Loslassen zu unterscheiden]
@Inga re: how can I detect a pushbutton event amidst sleep?Du kannst nur einen (1) Interrupt verwenden: den Falling-Interrupt. Wachen Sie bei diesem Interrupt auf und erledigen Sie den Rest der Entprellung in der Hauptschleife. Schlafen Sie wieder ein, wenn der Code anzeigt, dass der Tastendruck nicht "echt" war.

Antworten (1)

Ich kann keinen Code in einen Kommentar einfügen, daher eine Antwort. Mein 'Framework' für einfache eingebettete Systeme ist die Hauptschleife mit Polling. Um den Stromverbrauch zu minimieren, kann die Hauptschleife beispielsweise 50 ms im Ruhemodus warten. Ich weiß nicht, welches uC Sie verwenden, ich kenne PICs, die durch einen Interrupt aus dem Schlaf geweckt werden können.

 set up an interrupt to wake me from sleep each 50 ms
 down_counter = 0
 for(;;){
    sleep();
    if( key down ){
       down_counter++;
       if( down_counter == 20 ){
          (start of) long_down detected
       }
    } else {
       if( down_counter > 1 && down_counter < 20 ){
          (end of) short press detected
       }
       down_counter = 0;
    }
 }
Das ist sehr elegant! Die einzige kleine Schwäche, die ich sehe, ist, dass Sie bei Ihrem Ansatz den Mikrocontroller 20 Mal aufwecken würden, also möglicherweise etwas mehr Stromverbrauch (während bei mir der uC nur 2 oder 3 Mal aufwacht). Mich würde dein Kommentar zu diesem Aspekt interessieren, denn alles andere gefällt mir an diesem Main-Loop-Fokus.
(Aber ich nehme an, es ist sehr wenig Strom, da Sie meistens nur zwei Anweisungen bei jedem Aufwachen ausführen.)
Eine der Grundregeln der Informatik lautet „Optimieren Sie nicht, wenn Sie nicht wissen, dass Sie einen Engpass haben“. Nicht raten, rechnen oder messen. Ich denke, das aktive Schlafverhältnis meines Ansatzes beträgt weniger als 1: 1000 (vielleicht viel viel weniger, aber das ist eine weniger sichere Schätzung). Wie ist das Verhältnis von aktivem zu Schlafstrom für Ihren uC? Wenn es viel mehr als 1:1000 ist, werden Sie den Unterschied nicht bemerken.
Es ist ein Atmega1280, und das Verhältnis zwischen aktivem und schlafendem Strom liegt tatsächlich bei etwa 1000: 1. Ich werde diesen Ansatz ausprobieren und meine Frage basierend auf dem Ergebnis aktualisieren.
Denke auf jeden Fall, dass dies der richtige Weg ist. Die einzige Verbesserung, die ich mir vorstellen kann, wäre, beim Erkennen des ersten Tastendrucks zunächst aus dem Schlaf aufzuwachen und dann zum Aufwachen durch den Timer zu wechseln. Nachdem der Tastendruck vollständig dekodiert wurde, schalten Sie zurück auf Wake on Button.
@rocketmagnet: warum? um ein paar % Strom gegenüber einer einfacheren Lösung zu sparen?
@WoutervanOoijen - Ja, das ist so ziemlich alles. Es ist keine große Verbesserung, aber das war irgendwie der Punkt. An deinem Vorschlag kann man nicht viel verbessern.