Hallo Leute,
habe gerade eine C-Funktion für das Entprellen eines Tasters
geschrieben.
Ich würde die "alten Hasen" im Forum bitten, sich diese einmal
anzuschauen und mir zu sagen, was sie davon halten.
Die Tests sagen: Funktioniert. Aber vielleicht gibt es daran ja etwas,
dass unter bestimmten Bedingungen Probleme verursachen kann.
Beschreibung der Parameter
1
*Port: Pointer auf Port, an dem der Taster angeschlossen ist
2
Pin: Pin(nummer) des Tasters
3
Values[3]: Array mit 3 uint-Werten, Bedeutung wie folgt.
Vom Hauptprogramm her gesehen erwartest du ja die Rückmeldung "ist
Taste(r) gedrückt?". Bei deiner Methode kommt einfach "nein", bis nach
frühestens 254 (!) Aufrufen dann "ja" kommen kann. Dasselbe dann für den
Wechsel zurück. Angenommen deine main() tut noch viel anderes
zwischenzeitlich, dann wird das nix...
Mit gefällt die Entprellung in der (timer-) ISR viel besser, weil ich
dann im Hauptprogramm jederzeit zeitnah zuverlässig weiss, ob eine Taste
gedrückt/losgelassen wurde und ggf. wie lange der Zustand schon als
stabil so erkannt wird.
> was sie davon halten
Schrott.
Nimm an, der Taster wechselt bei jeder Abfrage den Zustand
(!(*Port & (1<<Pin)))
Dann zählt munter Values[0] bis 255 und Values[1] bis 255,
jeweils abwechselnd.
Natürlich funktioniert das.
Weil ein Entprellen überhaupt nicht nötig ist.
Wenn deine Hauptschleife
while(1)
nur lang genug braucht, länger als eine Taste prellt
(also so 5 ms), dann holen Abfragen der Art
uPressedUp=(!(*Port & (1<<Pin)))
immer einen entprellten Zustand.
Es kann kein Prellen geben, Daher ist deine Funktion
(die zudem üble Paramterliste hat) überflüssig.
Das einzige, was ein
while(1)
eventuell zum erfolgreichen Entprellen braucht ist ein
_delay_ms(5);
Unnötig kompliziert, speicherhungrig, muss in der main aufgerufen
werden, damit sie reagieren kann (du musst sie ja in einer Schleife
aufrufen, damit das debouncing läuft), dadurch hast du keine feste
Zeitbasis, kein Speichern des Tastendrucks (wenn du die Methode jetzt
periodisch per Timer aufrufen würdest, könntest du Tastendrücke
verpassen, weil deine Main gerade was besseres zu tun hat als Taster
pollen).
Meine Verbesserungsvorschläge:
1.) Ab in nen periodischen Timer damit, also feste Zeitbasis.
2.) Deine Count werte können viel geringer ausfallen. Ich benutze z.b.
eine Zeitbasis von 10ms und überprüfe ob 3 aufeinanderfolgende Werte
konstant sind und benutze das als Ausgangssignal meiner entprellroutine.
3.) Speichervariable, die sich Tastendrücke merkt, die beim auslesen
dann zurückgesetzt werden
4.) Eventuell erkennung von langem Tastendruck.
Tom schrieb:> Vom Hauptprogramm her gesehen erwartest du ja die Rückmeldung "ist> Taste(r) gedrückt?". Bei deiner Methode kommt einfach "nein", bis nach> frühestens 254 (!) Aufrufen dann "ja" kommen kann. Dasselbe dann für den> Wechsel zurück. Angenommen deine main() tut noch viel anderes> zwischenzeitlich, dann wird das nix...>> Mit gefällt die Entprellung in der (timer-) ISR viel besser, weil ich> dann im Hauptprogramm jederzeit zeitnah zuverlässig weiss, ob eine Taste> gedrückt/losgelassen wurde und ggf. wie lange der Zustand schon als> stabil so erkannt wird.
Die Anzahl der Durchläufe könnte man anpassen, ist ja quasi ein
experimenteller Wert.
Der Einwand, dass das im Hinblick auf die Ausführungszeit unpraktisch
ist, ist natürlich korrekt.
MaWin schrieb:
>Nimm an, der Taster wechselt bei jeder Abfrage den Zustand>[...]>nur lang genug braucht, länger als eine Taste prellt[...]>üble Parameterliste
Ersterer Einwand ist aber sehr akademisch. Wieso sollte ein Taster (der
i.d.R. von einem Mensche betätigt wird) exakt mit einer Periodendauer
prellen, die der Ausführungszeit von main() entspricht?
Der zweite Einwand ist vollkommen logisch, hat aber mit der Lösung nix
zu tun.
Wieso ist die Parameterliste übel? Das ist ein ganz normale
Parameterliste?
@Hauke Radtki
Das ganze in den Timer zu packen klingt logisch und sinnvoll.
Wie bereits erwähnt sind die Zählwerte natürlich anpassbar, evtl. als
Parameter.
Wie ist dein 3. Vorschlag gemeint?
Du hast eine Variable (die du als bitmap nutzt), jedem Taster weist du
ein Bit zu, das gesetzt wird, wenn die entprellroutine nen Tasterdruck
feststellt. Jetzt hast du eine Methode die dir diese Variable ausliest,
und biem auslesen zurücksetzt. So hast du dein Tastenereignis sicher
abgefangen.
Hauke Radtki schrieb:> Du hast eine Variable (die du als bitmap nutzt), jedem Taster weist du> ein Bit zu, das gesetzt wird, wenn die entprellroutine nen Tasterdruck> feststellt. Jetzt hast du eine Methode die dir diese Variable ausliest,> und biem auslesen zurücksetzt. So hast du dein Tastenereignis sicher> abgefangen.
Problem dabei: wenn ich beim Auslesen des Zustands diesen zurücksetze,
dann wird dieser Zustand erst wieder gesetzt, wenn die Entprell-Routine
erneut ein sicheres Signal festgestellt hat. Also nach 20ms oder sowas.
Sven H. schrieb:> Problem dabei: wenn ich beim Auslesen des Zustands diesen zurücksetze,> dann wird dieser Zustand erst wieder gesetzt, wenn die Entprell-Routine> erneut ein sicheres Signal festgestellt hat. Also nach 20ms oder sowas.
Und wie schnell kannst du als Mensch einen Taster 2 mal hintereinander
betätigen?
Das ganze Konzept der Entprellung beruht darauf, dass echte
beabsichtigte Pegelwechsel wesentlich seltener und in größeren
zeitlichen Abständen auftreten als die Prellpulse.
Achja, hab ich vergessen zu erwähnen, ich setzte dieses Register bei
steigender Flanke, um einen Tastendruck festzustellen.
Wenn man Funktion wie "gedrückt gehalten" erfassen will muss man sich
noch was überlegen, möglich wär da eben eine Zählvariable in wievielen
intervallen der Pin nach der steigenden Flanke noch high war.
Oder einfacher (aber mit ein paar Tücken verbunden) man überprüft ob der
Pin noch high ist, während man seine Variable ausliest, und entscheidet
so ob der Pin durchgedrückt wurde. Da hängt jetzt aber das Verhalten
auch vom Timing es auslesenden Programms ab, das kann problematisch
sein.
Karl Heinz Buchegger schrieb:> Sven H. schrieb:>>> Problem dabei: wenn ich beim Auslesen des Zustands diesen zurücksetze,>> dann wird dieser Zustand erst wieder gesetzt, wenn die Entprell-Routine>> erneut ein sicheres Signal festgestellt hat. Also nach 20ms oder sowas.>> Und wie schnell kannst du als Mensch einen Taster 2 mal hintereinander> betätigen?>> Das ganze Konzept der Entprellung beruht darauf, dass echte> beabsichtigte Pegelwechsel wesentlich seltener und in größeren> zeitlichen Abständen auftreten als die Prellpulse.
Das ist mir bewusst. Es geht auch nicht darum, dass man so schnelle
Betätigungen nicht erfassen könnte sondern um - wie Hauke Radtki bereits
erwähnt hat - um die Funktion des "gedrückt haltens".
Sven H. schrieb:> Das ist mir bewusst. Es geht auch nicht darum, dass man so schnelle> Betätigungen nicht erfassen könnte sondern um - wie Hauke Radtki bereits> erwähnt hat - um die Funktion des "gedrückt haltens".
OK.
Dann musst du hier
> Problem dabei: wenn ich beim Auslesen des Zustands diesen zurücksetze,
deine Stretgie überdenken. Wenn du erfassen willst, dass ein Taster
gedrückt ist, anstelle von "ist er gedrückt worden", dann erfolgt das
Zurücksetzen eben erst wenn "Taster wurde losgelassen" detektiert wurde.
Aber eines gleich vorweg: Wensentlich häufiger benötigt man in der
Praxis das Detektieren "Taster wurde gedrückt" und an dieses
Niederdrücken ist eine Aktion gekoppelt.
"Solange ein Taster gedrückt ist" braucht man nicht so häufig und wenn
man das braucht ist eine nicht erfolgte Entprellung meist kein Problem.
Aber "SOlange Taste gedrückt" ereldigt die PeDa Entprellung nebenbei
mit. Entweder durch eine kleine Erweiterung oder aber in Form eines
Autorepeats.
Deine Enptrellung kannst du enorm vereinfachen, indem du dich von
'gedrückt' bzw. 'losgelassen' verabschiedest und statt dessen auf "hat
sich der Pin Zustand verändert" übergehst.
Das Hauptproblem der fehlenden Zeitbasis und damit der Abhängigkeit der
Entprellung vom restlichen Programm bleibt aber.
Dass in der Praxis eine Flankenerkennung wesentlich häufiger benötigt
wird, als eine dauerhafte oder längere Betätigung ist mir bewusst.
Es geht auch eigentlich eher um's Prinzip:
Wenn ich eine Entprellungs-Funktion verwende, dann erwarte ich
eigentlich, dass ich zu jedem Zeitpunkt der Abfrage exakt den Zustand
des Signals erhalte (nur eben ohne prellen).
Wenn ich eine Flanke brauche, dann nehme ich eine Funktion zur
Flankenauswertung.
Habe mich heute morgen mit der PeDa-Lösung befasst, aber Auto-Repeat ist
ja nicht "Zustand des Tasters" sondern eine Impulsfolge, wenn ich mir
das ganze richtig angeschaut habe.
Allerdings habe ich diese Variante jetzt angepasst und in eine Funktion
gepackt. Nun tut sie, was ich erwarte und dennoch ist das Signal bei
steigender und fallender Flanke entprellt.
Die Speicherausnutzung ist nämlich wirklich effizienter, wenn man den
ganzen Port entprellt und schöner ist es im Timer-Interrupt auch :-)
Insofern Danke für die Tipps. Ich steige gerade in das gante µC-Thema
ein, komme nämlich eigentlich aus der SPS-Welt, da muss man sich um
vieles dann doch nicht mehr so explizit kümmern (auch, wenn es in der
Praxis durchaus Prellvorgänge gibt, die im Bereich von einigen 100ms
liegen).