Hi,
dem Wiki-Eintrag zum Thema "Entprellen" folgend bin ich auf folgende
Seite gestoßen (http://www.ganssle.com/debouncing.pdf). Diese ist recht
informatik und bietet im zweiten Teil auch einige Beispiele für eine
Debounce-Routine.
Allerdings habe ich da so meine Verständnisprobleme mit. Vielleicht kann
mir ja einer von euch auf die Sprünge helfen.
Konkret geht es um Folgenden Code:
1
bool_tDebounceSwitch2(){
2
3
staticuint16_tstate=0;
4
5
state=(state<<1)|!RawKeyPressed()|0xE000;
6
7
if(state==0xF0000){
8
9
returntrue;
10
11
}
12
13
returnfalse;
14
15
}
Ich bin mir nicht sicher wie ich diesen Code anwenden muss. Zum Einen
gibt es ja das Problem, dass die Funktion über einen Timer aufgerufen
wird (in meinem Fall alle 10 ms). Demnach macht ja ein Rückgabewert
nicht wirklich Sinn. Hierfür habe ich eine weitere Variable eingeführt
(und als volatile gekennzeichnet).
Das weitaus größere Problem ist aber, dass die Funktion ja nur einmalig
true zurückliefert und nicht beständig, solange die Taste gedrückt
bleibt. Wie würde ich das nun ändern?
Mir ist durchaus klar, dass es hier im Forum zig Entprell-Routinen gibt.
Aber diese erscheinen mir für meinen Anwendungsfall zu komplex und
bieten mehr als ich benötige. Ich habe nur einen Taster, welchen ich
entprellen möchte. Außerdem befinde ich mich noch am Anfang und würde
das auch gerne nutzen, um selbst nachzudenken und dabei vielleicht etwas
lernen ;).
Mit freundlichen Grüßen,
Unlucky2012
Unlucky2012 schrieb:> Hierfür habe ich eine weitere Variable eingeführt> (und als volatile gekennzeichnet)
Wo?
10ms sind für Tasterprellen schon eine recht lange Zeit, aber angesichts
der Qualität von diesen Printtastern...
Die einfachste Methode ist, einen Zähler zu verwenden. Bei "Taste unten"
wird der Zähler inkrementiert, bei "Taste oben" auf 0 zurückgesetzt. Nun
kann man
1. zu kurze Tastendrücke erkennen: Zähler bleibt unter einem gewissen
Schwellwert
2. gültige Tastendrücke erkennen: Zähler überschreitet diesen
Schwellwert
3. längere Tastendrücke erkennen: Zähler überschreitet einen noch
größeren Schwellwert
Was sich hier im Forum sehr bewährt hat, sind Peter Danneggers
"Bulletproof"-Entprellroutinen.
mfg mf
Mini Float schrieb:> Wo?
Außerhalb der ISR, sodass ich dann in meiner Endlosschleife Zugriff
darauf habe.
Mini Float schrieb:> 10ms sind für Tasterprellen schon eine recht lange Zeit, aber angesichts> der Qualität von diesen Printtastern...
Naja, ich habe 10ms mal als Mittelwert aufgefasst. Unter anderem findet
man ja aussagen wie die Folgende:
> Most switches seem to exhibit under 10 msec bounce rates. Coupled with my> observation that a 50 msec response seems instantaneous, it seems> reasonable to pick a debounce period in the 20 to 50 msec range.
siehe: http://www.ganssle.com/debouncing-pt2.htm
Wenn ich mir andere Debounce-Routinen anschaue, dann spielen die in der
gleichen Liga (+/- ein paar Millisekunden).
Mini Float schrieb:> Die einfachste Methode ist, einen Zähler zu verwenden. Bei "Taste unten"> wird der Zähler inkrementiert, bei "Taste oben" auf 0 zurückgesetzt.
Dieser Ansatz ist mir durchaus bekannt, aber irgendwie hat mir der
andere (aufgrund der kürzeren Implementierung) besser gefallen.
Mini Float schrieb:> Was sich hier im Forum sehr bewährt hat, sind Peter Danneggers> "Bulletproof"-Entprellroutinen.
Wie gesagt: Halte ich für das Entprellen von nur einem Taster fast für
ein wenig Overkill. Vor allem, weil ich keine Doppel-Belegung
(kurz/lang) und auch keine Wiederholfunktionen brauche. Außerdem habe
ich bloß ein einzigen Taster und würde auch noch ganz gerne etwas
lernen, anstatt fertigen Code zu nehmen ;).
Unlucky2012 schrieb:> Mini Float schrieb:>> Die einfachste Methode ist, einen Zähler zu verwenden. Bei "Taste unten">> wird der Zähler inkrementiert, bei "Taste oben" auf 0 zurückgesetzt.> Dieser Ansatz ist mir durchaus bekannt, aber irgendwie hat mir der> andere (aufgrund der kürzeren Implementierung) besser gefallen.
Naja, hier ist es auch ein Zähler. Nur dass da Bits "von hinten nach
vorne" rein geschoben werden.
Was hier noch zusätzlich gemacht wird: eine Fensterung. Vermute ich.
Das hier:
Unlucky2012 schrieb:> uint16_t state
Und das:
Unlucky2012 schrieb:> if (state == 0xF0000)
passen nicht zusammen. Vier Bit zuviel...
Angenommen, es heißt...
1
if(state==0xF000){<...>}
...wird bei jedem Aufruf erstmal nachgesehen, ob der Taster einen Druck
abliefert. Wenn...
Unlucky2012 schrieb:> !RawKeyPressed()
...einen Wert von 0xFF bei gedrücktem Taster zurückgibt, wird der bei
folgenden erkannten Tastendrücken "nach vorne" geschoben, bis in "state"
die vier MSB gesetzt sind. Dann wird true zurückgegeben. Wenn er einfach
unten rausfällt, eben "false".
mfg mf
Unlucky2012 schrieb:> Das weitaus größere Problem ist aber, dass die Funktion ja nur einmalig> true zurückliefert und nicht beständig, solange die Taste gedrückt> bleibt. Wie würde ich das nun ändern?
Schreib dir deine eigene.
Eine Funktion, die eine Variable so lange auf true hält, wie eine Taste
gedrückt IST, ist schnell geschrieben.
Viel interessanter ist der Fall: Bei einmaligem Niederdrücken soll die
Funktion auch nur ein einziges mal true liefern. Und zwar auch dann,
wenn zwischen Tastendruck und Abfrage 5 Stunden liegen. Da wirds dann
interessant.
Aber ein 'true solange gedrückt' ist nicht wirklich schwer. Das schaffst
du alleine. Überhaupt dann, wenn du sowieso schon einen Timer am laufen
hast mit 10ms. In der Interrupt Routine einfach den Tastenzustand mit
einem gespeicherten Tastenzustand von vor 10ms vergleichen.
Unterscheiden sich die beiden, dann kannst du keine Aussage darüber
machen ob die Taste gedrückt ist oder nicht. Sind die beiden aber
gleich, dann sagt dir der Zustand ob die Taste gedrückt ist oder nicht.
Sprich: das was du vom Port eingelesen hast, gilt. Das sind 1
Portabfrage, 3 Zuweisung und 1 Vergleich. Fertig.
Unlucky2012 schrieb:> Das weitaus größere Problem ist aber, dass die Funktion ja nur einmalig> true zurückliefert und nicht beständig, solange die Taste gedrückt> bleibt. Wie würde ich das nun ändern?
Das ist genau der Sinn einer Entprellung, daß man pro Drücken garantiert
nur ein Ereignis kriegt.
Willst Du etwas machen, solange man drückt, dann braucht man kein
Entprellen.
Die Routine ist auf nem 8Bitter sehr ineffektiv, da man umständlich 2
Bytes zu 16Bit zusammen kleistern muß.
Bis 16 kann man mit nur einem Byte zählen, das ist schneller und
kleiner.
Gerade bei dem erwähnten 8051 ist das besonders krass. Zählen kann der
nämlich direkt im SRAM, schieben aber nur im ACC-Register. 16Bit
schieben sind dann schon 6 Befehle, INC aber nur einer.
Peter
Peter Dannegger schrieb:> Das ist genau der Sinn einer Entprellung, daß man pro Drücken garantiert> nur ein Ereignis kriegt.
Ok, das sehe ich ein. Aber wie wäre dann eine solche Funktion
aufzurufen? Der oben skizzierte Ansatz liefert ja nur zu einem Zeitpunkt
"true" zurück, nämlich wenn die letzte 1 durchgeschoben wird.
Da das Ganze aber in einer ISR läuft, und die eigentliche Verarbeitung
normalerweise woanders (in einer Endlosschleife) statt findet, kann es
doch passieren, dass ich den Druck verpasse, weil die ISR nochmal
aufgerufen worden ist und jetzt false liefert?
Peter Dannegger schrieb:> Die Routine ist auf nem 8Bitter sehr ineffektiv, da man umständlich 2> Bytes zu 16Bit zusammen kleistern muß.> Bis 16 kann man mit nur einem Byte zählen, das ist schneller und> kleiner.
Naja, man könnte ja 8 Bits nehmen anstatt der 16 und dann eben nur bis 8
"zählen" bzw. schieben. Auf einem "modernen" AVR müsste es genau dafür
doch dann auch die "Doppelregister" geben, oder?
Der Code kann schon sinn machen, und nähmlich:
state = (state<<1) | !RawKeyPressed() | 0xE000;
if (state == 0xF0000) {
return true;
}
ist irgendwie dasselbe wie
static unsigned char debounce=14;
if(debounce>22) debounce=22; // repeat rate
if(!RawKeyPressed()) debounce=14;
if(!debounce--) return true;
return false;
Aber, beim zweiten Code wird der Tastendruck nach X Durchläufen wieder
gemeldet, kommt ein repeat gleich, hingegen beim obigen Code wird er nur
einmal gemeldet, und zwar nach exact 120mS. Oft wird auch ein repeat
verlangt, es kommt auf die Specs an. Oft wird auch so ein code
verwendet:
static unsigned char debounce=14;
if(!RawKeyPressed()) debounce=14;
if(debounce==-22) debounce=0; // repeat rate
if(!debounce--) return true;
return false;
Hiermit kann dann unterschieden werden, ob es ein einmaliger Tastendruck
ist oder ein automatisch wiederholter, dank bit7 von debounce.
Chris schrieb:> und zwar nach exact 120mS.
120milli Siemens?
mS sind ein Leitwert und keine Zeit. 1/R.
Du meinst wohl 120ms.
Bitte die Einheiten beachten.
exact-> exakt.
Gruß