Hallo, ich benutze aus https://www.mikrocontroller.net/articles/Entprellung die Komfortroutine in c von Peter. Ich habe sie auf meinen µC portiert und sie funktioniert erst mal sehr gut. Im Moment habe ich vier Taster und einen Schalter angeschlossen. Dieser muss ja auch Entprellt werden. Kann ich die Routine auch hierzu nutzen? Wenn ja... ich bekomme es gerade nicht hin... Wenn ich es richtig verstanden habe, geht die Repeatfunktion immer nur für eine Taste gleichzeitig oder? Den Schalter habe ich aus dem Repeat rausgenommen (sonst geht nichts mehr). Dank und Gruß Jan
Wenn ich Peters Sourcen nur früher gekannt hätte...hab selbst rumprobiert und mich gequält. Habe mir eine Bitqueue überlegt, wo der Pin-Status 8x reingeschoben wird. Nur wenn alle Bits gesetzt sind oder gar keins, wir der Status 1 oder 0 übernommen. Alle anderen Werte ändern den entprellten Pin-Status nicht. Die Routine stammt aus einem Timer-Event. Bei einer Pin-Abtastrate von 160x pro Sekunde lassen sich 20 entprellte Zustände pro Sekunde einlesen. Das reicht, um sogar schnelles "DoubleClick", also Taster 2x kurz hintereinander gedrückt (sozusagen DoublePress) sicher zu identifizieren.
1 | // Pin einlesen und entprellen.
|
2 | // Das '& 1' ist nur symbolisch
|
3 | |
4 | byte iBit0 = digitalRead(iPin) & 1; // Status des digitalen Pin als Bit einlesen |
5 | iPuffer <<= 1; // Platz in der Queue schaffen |
6 | iPuffer |= iBit0; // Pin als Bit 0 übernehmen |
7 | |
8 | // Nur wenn die Queue ganz voll (255) oder ganz leer (0) ist,
|
9 | // wird der Status '1' oder '0' als 'iEntprellterPinStatus' übernommen
|
10 | |
11 | if (iPuffer == 0b11111111) // 0b11111111 = Taster gedrückt |
12 | {iEntprellterPinStatus = 1;} // dann nur Taster-Gedrückt-Bit setzen, fertig |
13 | else if (iPuffer == 0b00000000) // 0b00000000 = Taster nicht gedrückt |
14 | {iEntprellterPinStatus = 0;} // nur Taster-Gedrückt-Bits löschen, fertig |
Die Routine entprellt sogar eine rostige Büroklammer. Einen ISR-Rumpf (Timer-Interrupt) habe ich hier gerade gepostet: Beitrag "Re: delay() in Timer-Event ISR (Arduino)" In den Rumpf kannst du, statt der LED-Ansteuerung, die Pin-Abfrage mit Entprellung einbauen. Ist ganz easy und funzt sofort. Wenn du mehr als nur entprellen willst, z.B. 'Doppelter Tasterdruck' oder 'Taster gedrückt gehalten' erkennen willst, musst du sehr viel tiefer in die Materie gehen. Meine Sourcen, nach viel rumprobieren (und überlegen, wie ich doppelten und einfachen Tastendruck auseinander halten kann), sind seit gestern so weit, dass bei 6 Taster-Ereignissen verschiedene Eventfunktionen angesprungen werden können. Alles "unsichtbar" per Timer-OInterrupt organisiert. Macht Spaß und das Erstellen eines Programms wird zum Kinderspiel. Wenn du noch was wissen willst, frag einfach. Ich bin zwar C-einsteiger, stecke in dieser Materie Entprellen, Meßwertglättung und Dämpfung gerade mittendrin.
Warum eine Entprellroutine? Polling im 20ms-Raster behebt das Problem viel einfacher. Und die Timer-ISR braucht der Code ja auch. 20ms reichen für jeden Taster locker aus, und sind mehr als schnell genug, um manuelle Eingaben flüssig zu verarbeiten. Die Entprellroutine sollte man höchstens bei einem Drehencoder benötigen, wenn überhaupt.
Schwarzfunker schrieb: > Entprellt. Blöde Autovervollständigung. Warum benutzt ihr dieses Feature überhaupt? Diese Funktion gibt es seit mindestens 25 Jahren und sie ist immer noch Kacke! Hofft Ihr irgendwie auf einen heimlichen Durchbruch der KI?
jemand schrieb: > Polling im 20ms-Raster behebt das Problem viel einfacher. Meinst du das so?:
1 | __________ |
2 | Tastendruck ______| |_______________ |
3 | ________ |
4 | Signal ______||| |||_____________ |
5 | |
6 | Polling ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ |
7 | ______________ |
8 | Resultat _______| |__________ |
9 | ________ |
10 | oder: __________| |_____________ |
11 | ___________ |
12 | oder: _______| |_____________ |
13 | ___________ |
14 | oder: __________| |__________ |
Könnte klappen, wenn man mit den damit verbundenen bis zu 40ms langen Verzögerungen leben kann. Ich bin nicht sicher, ob das bei up/down Tasten (zum Beispiel zum Stellen einer Uhr) zufriedenstellend funktioniert. Müsste man mal ausprobieren.
Jan schrieb: > Kann ich die Routine auch hierzu nutzen? Ja. Kostet ja keinen zusätzlichen Code. Ich benutze das z.B. für einen Interlockkreis. Es soll ja nicht bei jedem Störimpuls abgeschaltet werden, sondern nur bei einem echten Schalten. Jan schrieb: > Wenn ich es richtig verstanden habe, geht die Repeatfunktion immer nur > für eine Taste gleichzeitig oder? Ja. Etwas anderes erschien mir unnötig. Jan schrieb: > Den Schalter habe ich aus dem Repeat > rausgenommen (sonst geht nichts mehr). Nur die Tasten dürfen in der Repeatmaske sein, die auch repeatet werden sollen.
Stefanus F. schrieb: > Könnte klappen, wenn man mit den damit verbundenen bis zu 40ms langen > Verzögerungen leben kann. Ich bin nicht sicher, ob das bei up/down > Tasten (zum Beispiel zum Stellen einer Uhr) zufriedenstellend > funktioniert. Müsste man mal ausprobieren. Doch funktioniert für normales Drücken! Es sind jedoch Randbedingungen zu beachten: Aus dem Alter der Digitaluhren mit Stoppfunktion ist bekannt, dass zwei Tastendrücke mindestens 100ms auseinander liegen. Oder anders: Du kannst eine Taste maximal 10/s drücken. Für 20ms Abtastrate musst Du sicherstellen (garantieren), dass * der Kontakt maximal 19.9ms prellt (je beim Drücken und beim Loslassen) * der Kontakt dazwischen mindestens 20.1ms durchgehend gedrückt bleibt Die Verzögerung von 1..20ms ist dabei in jedem Fall zu vernachlässigen, sie würde durch übliche Entprellungen im gleichen Rahmen liegen. Wenn man dass mit schnell kombinieren will, dann kann man bei stabilem Signal (>100ms gleicher Pegel) den ersten Peak in die anderen Richtung (im 1ms-Raster oder als Interrupt) als Tasten-Event verarbeiten und dann, ganz wichtig, das nächste 20ms-Signal ignorieren.
Stefanus F. schrieb: > Könnte klappen, wenn man mit den damit verbundenen bis zu 40ms langen > Verzögerungen leben kann. Ich bin nicht sicher, ob das bei up/down > Tasten (zum Beispiel zum Stellen einer Uhr) zufriedenstellend > funktioniert. Müsste man mal ausprobieren. Tut es im Normalfall. Man merkt es kaum. Außerdem prellen die wenigsten Taster 20ms, d.h. fallweise kann man also schneller pollen. Dazu kann man sich das mit dem Oszi ansehen. Ich stelle das Scope dazu einfach auf "persist", und malträtiere den Taster ein paar Minuten auf verschiedene Art und Weise. Dann schlage ich eine gute "Alterungsreserve" oben drauf. Natürlich gibt es Fälle, wo das zu langsam ist. Ein Encoder wäre da zum Beipsiel zu nennen. In solchen Fällen nehme ich Hardware. Ein RC-Glied+Schmitt-Trigger machen einen schönen Rechteck, wenn man die Zeitkonstante hoch genug wählt.
Der Ansatz mit dem 20ms Polling gefällt mir. ist viel simpler, als wie ich es bisher gemacht habe: Ich hatte die Abfrage des Tasters so lange wiederholt, bis ich mindestens 20ms lang ein stabiles Signal hatte (also ohne Wechsel). Das harmonierte aber schlecht mit parallel laufenden Threads. Das Polling in regelmäßigen Intervallen lässt sich hingegen sehr einfach in einer Timer ISR unterbringen und kostet fast nichts. Meine alte Methode wäre bei Tastern sinnvoll, die sehr lange prellen. Aber solche Taster meide ich ohnehin an den Stellen, wo die Anzahl der Tastendrücke innerhalb kurzer Zeit) eine Rolle spielt.
Jetzt wertet hier jemand jemandes Alternative konsequent ab! Hat wohl nach langer Zeit endlich Peters Routinen verstanden und ist pissed, dass er sich das auch hätte sparen können. Leute gibt's... Naja, einen kann ich neutralisieren!
Wiesjemand schrieb: > Stefanus F. schrieb: >> Könnte klappen, wenn man mit den damit verbundenen bis zu 40ms langen >> Verzögerungen leben kann. Ich bin nicht sicher, ob das bei up/down >> Tasten (zum Beispiel zum Stellen einer Uhr) zufriedenstellend >> funktioniert. Müsste man mal ausprobieren. > > Tut es im Normalfall. Man merkt es kaum. > > Außerdem prellen die wenigsten Taster 20ms, d.h. fallweise kann man also > schneller pollen. Wieso Verzögerung? Wenn man von Störungen absehen kann, kann man doch sofort reagieren, bzw. die Tasten als gedrückt annehmen. Nur was dann in den nächsten 10-20ms passiert, sollte man ignorieren. Nur "Sofort", will man sicher eher selten haben. Ein-Zwei Bestätigungen, sind da selbst bei ~50ms drin. Einen Drehenkoder pollt man so schnell, das wiederum einige Bestätigungen reinkommen (~1kHz). Durch die Codierung, kann ja nur zwischen zwei Zuständen gesprungen werden, fällt also nicht auf.
Teo D. schrieb: > Wieso Verzögerung? Schau Dir meine obigen ASCII Diagramme an und vergleiche die Resultate mit dem "Tastendruck". Die Verschiebungen auf der Zeitachse meinte ich.
Peter D. schrieb: > Ja. Kostet ja keinen zusätzlichen Code. > Ich benutze das z.B. für einen Interlockkreis. Es soll ja nicht bei > jedem Störimpuls abgeschaltet werden, sondern nur bei einem echten > Schalten. Hallo Peter, frage ist mit welcher Funktion frage ich das ab. Wenn ich KeyPressed nehme dann bekomme ich das Einschalten des Schalters. Aber woher weiß ich ob er noch an ist, bzw. wann er wieder ausgeschaltet wurde? Viele Grüße Jan
Stefanus F. schrieb: > Schau Dir meine obigen ASCII Diagramme an und vergleiche die Resultate > mit dem "Tastendruck". Die Verschiebungen auf der Zeitachse meinte ich. Bau da mal reale Zeiten ein und zeichne auch mal den kürzesten zu erwartenden Tastendruck ein. Das Abfragen der Tasten kann ja ruhig so schnell wie möglich erfolgen, nur wenn ein Ereignis eintritt, muss gewartet werden bis das Nächste als gültig angesehen werden kann. Oder anders, Polling heißt nicht unbedingt mit exakten Zeitabständen und ständig die Ports abzufragen. Das Ganze lässt sich auch gut mit einem Interrupt starten. Wenns den sein muss....
Wird sind uns aber einig, dass die Routine von Peter D. schon alleine deswegen besser ist, weil sie kurze Störimpulse heraus filtern kann?
Stefanus F. schrieb: > Wird sind uns aber einig, dass die Routine von Peter D. schon alleine > deswegen besser ist, weil sie kurze Störimpulse heraus filtern kann? Besser als was? :) Das ist eine EierlegendeWollMilchSau! Das ist nicht mit individuellen Lösungen zu vergleichen. Ich war auch noch nie genötigt, eine Tasten-Matrix abfragen zu müssen. Bei 1-2 Tasten lohnt der Einsatz nich wirklich, ist ja nur ne Handvoll Code. Ich plag mich auch lieber mit ner Zeitgesteuerten Mehrfachbelegung einer Taste rum, als das ich da in Erwägung ziehe, eine Zweite einzubauen. :D
Jan schrieb: > frage ist mit welcher Funktion frage ich das ab. Die entprellten Zustände stehen in key_state. Ein Eingang wird übernommen, wenn er 4-mal hintereinander den gleichen Zustand hatte.
1 | uint8_t get_key_state(uint8_t key_mask) |
2 | {
|
3 | return key_state & key_mask; |
4 | }
|
Teo D. schrieb: > Stefanus F. schrieb: >> Wird sind uns aber einig, dass die Routine von Peter D. schon alleine >> deswegen besser ist, weil sie kurze Störimpulse heraus filtern kann? > Besser als was? :) Besser als das oben skizzierte einfache Polling im 20ms Intervall.
Stefanus F. schrieb: > Wird sind uns aber einig, dass die Routine von Peter D. schon alleine > deswegen besser ist, weil sie kurze Störimpulse heraus filtern kann? Sehr allgemein gehaltene Aussage. Ein Engländer ist nicht deshalb der bessere 13er Schlüssel, weil er auch 14er kann.
Stefanus F. schrieb: > Wird sind uns aber einig, dass die Routine von Peter D. schon alleine > deswegen besser ist, weil sie kurze Störimpulse heraus filtern kann? Peter D. schrieb: > Ein Eingang wird > übernommen, wenn er 4-mal hintereinander den gleichen Zustand hatte. Und schon ist das große Geheimnis der Entstörung gelüftet. :) Mir reicht schon eine Bestätigung, ob die Taste immer noch gedrückt ist. Da ja meist der Mensch der Störfaktor ist.... Oft will man ja garnicht sofort reagieren. Passt sich so natürlich auch nicht auf Alte-Taste an, die länger prellen könnten. Stört mich aber nicht, da die in kürze eh total ausfallen. PS: Das soll hier kein "Ich kanns besser" werden! Nur ein weiterer Versuch, das Thema zu entmystifizieren. :)
Zwei Sachen sind dann doch zu bemerken: 1. Stefanus F. schrieb: > Schau Dir meine obigen ASCII Diagramme an und vergleiche die Resultate > mit dem "Tastendruck". Die Verschiebungen auf der Zeitachse meinte ich. Was hat denn das Diagramm mit realen Prellvorgängen zu tun? 2. Teo D. schrieb: > Mir reicht schon eine Bestätigung, ob die Taste immer noch gedrückt ist. Dann hast Du noch keine Erfahrung mit schlechten Tastern gemacht. Wenn es richtig dumm läuft, bekommt man nämlich mehrere Tastendrücke obwohl man permanent gedrückt hält.
m.n. schrieb: >> Schau Dir meine obigen ASCII Diagramme an und vergleiche die Resultate >> mit dem "Tastendruck". Die Verschiebungen auf der Zeitachse meinte >> ich. > Was hat denn das Diagramm mit realen Prellvorgängen zu tun? Lies nochmal zusammenhängend, worauf du dich beziehst. Das Diagramm stellt die Verschiebungen auf der Zeitachse dar, die durch das Polling in regelmäßigen Intervallen entsteht, wenn man es so einfach macht, wie der Benutzer "jemand" zuvor empfohlen hat. Das Polling wiederum hatte er als Lösungsansatz zum Entprellen genannt. Da ist der Zusammenhang zu Prellvorgängen.
Peter D. schrieb: > Die entprellten Zustände stehen in key_state. Ein Eingang wird > übernommen, wenn er 4-mal hintereinander den gleichen Zustand > hatte.uint8_t get_key_state(uint8_t key_mask) > { > return key_state & key_mask; > } Danke Peter, jetzt habe ich es verstanden. Danke für das Teilen von dem Code. @all: bitte weiter streiten :-) haha
m.n. schrieb: > Dann hast Du noch keine Erfahrung mit schlechten Tastern gemacht. Wenn > es richtig dumm läuft, bekommt man nämlich mehrere Tastendrücke obwohl > man permanent gedrückt hält. Wenn er wackelt is er hin! Wackeln (weniger, statt zu viel) die oft bei dir? Dann gug mal ob du auch den min. Schaltstrom einhältst!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.