Hallo Hier, wie ich denke, eine weitere sehr schlanke Routine zur Entprellung eines Tasters. Toni *************************************************************** uint16_t status; uint8_t taste0; void entprell(void) { status = ((status<<1) | (!bit_is_clear(PIND,PIND0)) | 0xe000); if (status==0xf000) taste0=0; else taste0=1; } *************************************************************** Funktion kann im Hauptloop stehen, oder per Interrupt regelmässig aufgerufern werden. Taste gedrückt entspricht Pegel "0". In 'status' wird eine '1' von rechts nach links geschoben, die die letze Flanke '1->0' darstellt. Falls Taste nicht prellt, folgen nur noch'0'. Im gesamten werden hier 12 Umgänge geprüft, kann mit Maske/Typ für/von 'status' geändert werden ! Also zu Beginn:status :1110 0000 0000 0000 (Maske 0xe00) Wärend prellen, z.B :1110 0010 0100 1001 Entpellt (12 cycles) :1111 0000 0000 0000 (status==0xf000)
Du hast Dir bestimmt noch nicht den erzeugten Assembler (56 Byte Code siehe Anhang) angesehen, sonst würdest Du nicht so leichtfertig von "schlank" sprechen. Mit auch 3 Bytes SRAM aber nur 46 Byte Code entprelle ich Dir sogar 8 Tasten gleichzeitig. Peter P.S.: Man sollte schon dem Namen Codesammlung gerecht werden und einen funktionierenden Code posten. Dein Fragment erzeugt aber nur tonnenweise Fehlermeldungen. Also das nächste mal wenigstens etwas compilierbares posten, d.h. mit den nötigen includes: #include <sfr_defs.h> #include <io.h>
@Toni: wenn mein AVR mit 16 MHz getaktet ist, und ich deine Entprellroutine in meiner Mainloop ständig aufrufe dann komme ich auf 16.000.000 / 16 = 1Mhz Entprellung. Jedes Prellen von Tastern muß mit einer Frequenz größer 1 Mhz reinkommen, alles was drunter liegt wird als Tastendruck erkannt. wenn mein AVR nun aber mit 32Khz getaktet ist so muß also 32.000 / 16 = 2Khz sein, alles was schneller als 2Khz ist wird als Prellen erkannt, alles was langsammer als 2Khz ist wird als Tastendruck erkannt. Das funktioniert also noch fast, wenn nicht viele Taster mit bis zu 10ms = 100Hz prellen würden. Ergo: damit deine Entprellroutine sauber funktioniert darf ich sie nut alle 20 mal in der Mainloop aufrufen, bei 32KHz Takt. Bei 16Mhz Takt darf ich sie nur alle 8000 male aufrufen. Es ist aber nun das Problem das in der Mainloop noch viele andere Aufgaben abgearbeitet werden, zb. alle 5 Sekunden für 2 Sekunden eine Datenüertragung die im 250ms Takt in die Mainloop zurückkehrt. In diesen Momenten würde der 8000'ernder Zähler aber nur alle 250ms inkremetiert und somit muß ich diesen Zähler ständig so anpassen das er auf alle diese zusätzlichen aufgaben umgestellt wird, um ein gleichmäßiges Pollen zu erreichen. Naja, mein jetziger Sourcecode, rein virtuell gesehen, verbraucht jetzt fast 1 Kb an zusäzlichen Code damit ich diesen Zähler so kontinuierlich an die Prozessorlast anpassen kann das deine Entprellroutine wieder periodisch alle 10 ms aufgerufen wird. Gruß Hagen
wenn du einen timer frei hast, dann packst du das in die isr von dem timer (siehe peters code) von einem in hochsprache geschriebenen programm kann man nicht erwarten, dass da wenige asm befehle rauskommen. Wenn man das will, dann muss man dann schon eine menege kohle für einen ordentlich optimierenden compiler hinlegen. oder schreibt es gleich in assembler
@Marcel, jo ich weis das, nur zu einem ordentlichen und funktionstüchtigen Code hier in der CodeLib sollten die kompletten Sourcen und nach Möglichkeit ein DEMO rein. Dann würde man sehen das sich die Aussage "schlank" nochmals relativiert. Gruß Hagen
"von einem in hochsprache geschriebenen programm kann man nicht erwarten, dass da wenige asm befehle rauskommen." Das hat auch nirgends nicht niemand behauptet. Aber wenn man int aufm 8-Bitter nimmt und viele Anweisungen in eine Zeile packt, mag das zwar optisch klein aussehen, nicht jedoch in realem Code. So schlecht finde ich den GCC garnicht. Zumindest bei meinen Code ist selbst in Assembler kaum noch was rauszuholen. Bei Tonis Code sieht man schön den doppel-RET-Bug, aber das sind ja nur 2 Byte toter Code je Funktion. Man muß das immer auf das gesamte Programm bezogen sehen, da sind dann 10% mehr Code nicht der Rede wert. Peter
http://www.mikrocontroller.net/articles/Entprellung hier kannst du deine routine eintragen. Dann gibt es eine übersicht mit allen entprellroutinen. Mit ihren Vorteilen und nachteilen.
Die Entprellung funktioniert wirklich sehr gut. Dank an den Autor!
Ich möchte mal eine andere Methode zur Entprellung vorschlagen: 1) Die erste Flanke triggert einen Speicher (z.B. flankengetriggerter Interrupt) 2) Danach interessiert mich die Taste erstmal nicht, d.h. ich ignoriere sie für mindestens die Prell-Zeit. 3) Dann werte ich die Taste wieder aus (Interrupt scharf schalten) Mit dieser Entprellung bekomme ich auch den kürzesten Druck mit, sowie auch die exaktere Zeit wann die Taste gedrückt wurde. Natürlich muss man die Prell-Zeit der Taste abschätzen, meistens ist sie spezifizert. Wenn nicht kann bei Bedienung durch Menschen 20ms-30ms sicher als kürzestes Intervall zwischen zwei mal drücken angenommen werden. Die Methode für eine gewisse Zeit auf einen stabilen Zustand zu warten macht für mich weniger Sinn, vorausgesetzt natürlich, die Taste prellt nicht von alleine, d.h. es gibt nur dann eine Flanke wenn auch wirklich einer versucht darauf rumzudrücken. Grüße Christian
>Mit dieser Entprellung bekomme ich auch den kürzesten Druck mit, sowie >auch die exaktere Zeit wann die Taste gedrückt wurde. Zur "exakten Zeit": Die Bedienung einer Taste durch einen Menschen (nicht nur solche mit Wurstfingern...) ist mit einer gewissen zeitlichen Ungenauigkeit behaftet, welche so groß ist, daß es schlicht keine Rolle spielt, ob der µC das Niederdrücken innerhalb von 4 Maschinenzyklen (Externe-Interrupt-Reaktionszeit) mitbekommt, oder erst 10 ms später. Und selbst wenn er es "sofort" mitbekommt: Speicherst Du den Tastenstatus zunächst in einer Variablen ab, läßt den µC dann erstmal noch 10 ms was anderes rechnen, und wertest danach die Tastenvariable aus, dann hast Du letztlich doch wieder eine um 10 ms verzögerte Reaktion. Zum "kürzesten Druck": Ein Mensch ist anatomisch nicht in der Lage, eine Taste kürzer als eine gewisse Mindestzeitspanne niederzudrücken. Wie groß die ist, hängt natürlich von dem Mensch und von dem Schalter ab, aber sie ist in jedem Fall so groß, daß Dir bei 50 Abtastungen/s mit Sicherheit auch nicht der kürzeste "man-made" Tastendruck entgeht. Zu dem, was ich in Deiner Beschreibung vermisse, nämlich die Nennung des Nachteils Deiner Methode: Du belegst einen wertvollen externen Interrupt mit einer läppischen Eingabetaste. Was ist, wenn Du den Interrupt dringend für eine andere Aufgabe benötigst, bei der es wirklich auf Speed ankommt? Und vielleicht hast Du auch nicht nur eine Taste, sondern eine 4x4-Tastenmatrix. Wie willst Du die an einen oder zwei Interrupteingänge anschließen?
"daß es schlicht keine Rolle spielt, ob der µC das Niederdrücken innerhalb von 4 Maschinenzyklen (Externe-Interrupt-Reaktionszeit) mitbekommt, oder erst 10 ms später." Und nicht nur das, es ist in der Regel auch völlig unerwünscht !!! Z.B. mit Gummisohlen über Teppich laufen und sich dem Gerät nähern: Ein Funke springt über, der externe Interrupt löst aus, obwohl man gar nichts drücken wollte ! Der Fahrstuhl in unserem Haus hat z.B. eine solche saublöde Entprellroutine. Man muß die Taste nur berühren (nicht mal drücken) und schon leuchten beide Fahrtrichtungen d.h. die Tür geht immer zweimal auf und zu. Abhilfe: Man muß sich vor dem Drücken immer erst an der Fahrstuhltür erden. Mit einer richtigen Entprellroutine würde sowas aber nicht passieren. Peter
Ich benutze eigentlich immer gerne einen interrupt-fähigen Eingang, da bei den meisten µC's dieser den µC aus den Sleep Mode holen kann. (ich habe fast nur mit mobilen Geräten zu tun) Auch Keypad's werden interrupt enabled (meistens ist die Veroderung schon im Chip implementiert) betrieben. ESD sichere Tasten natürlich vorrausgesetzt. Grüße Christian
"Ich benutze eigentlich immer gerne einen interrupt-fähigen Eingang, da bei den meisten µC's dieser den µC aus den Sleep Mode holen kann." Genau dazu ist ja der Pin-Change-Interrupt da. Man läßt damit die CPU aufwachen, wenn an einem Eingang irgendwas passiert. Die eigentliche Auswertung, was genau passiert ist, machen dann aber die entsprechenden Routinen. Und wenn sich herausstellt, daß nichts passiert ist, sondern es nur ein Störimpuls war, geht die CPU eben wieder in den Sleep-Mode. Ein paar richtige Zeilen Software sind bestimmt wesentlich kostenärmer als teuere ESD-feste Tasten. Die Tasten am Fahrstuhl sehen auch nicht gerade billig aus, aber sie tuns eben nicht wegen der fehlerhaften Software. Nicht alle Softwarefehler lassen sich durch Hardware korrigieren (und umgekehrt), beides muß richtig sein. Peter
Da die Tasterentprellung doch ein grundlegendes Problem darstellt, möchte ein Anfänger Tonis Programm als Lernhilfe anwenden (ähnelt dem von http://www.ganssle.com). Nachdem der Code unvollständig ist, macht es erhebliche Probleme dies nachzuvollziehen! Wäre nun schön, wenn jemand den kompletten funktionsfähigen Code reinstellen bzw. posten könnte.
Zum Entprellen folgender Ansatz: "buttons" enthält den Wert des Portregisters (PINx). Bei jedem Durchlauf wird die Warteschlange "debouncer" eins weitergeschubst und gleichzeitig mit den aktuellen Tastenzuständen verunded. Schließlich werden die aktuellen Tastenzustände an den Anfang der Schlange gestellt. Ausgewertet wird dann der letzte Eintrag der Schlange. Resultat: Erst, wenn ein Impuls störungsfrei durch die ganze Schlange gewandert ist, wird er ausgewertet.
1 | volatile uint8_t debouncer[5]; |
2 | |
3 | /* Im Timer-Interrupt wird dann alle paar ms folgendes gemacht: */
|
4 | for (i = 0; i < 4; i++) { |
5 | debouncer[i + 1] = debouncer[i] & buttons; |
6 | }
|
7 | debouncer[0] = buttons; |
Auszug aus dem Listfile (der GCC hat die Schleife aufgewickelt!):
1 | /* Debounce buttons */ |
2 | for (i = 0; i < 4; i++) { |
3 | debouncer[i + 1] = debouncer[i] & buttons; |
4 | 18e: 90 91 76 00 lds r25, 0x0076 |
5 | 192: 80 91 79 00 lds r24, 0x0079 |
6 | 196: 89 23 and r24, r25 |
7 | 198: 80 93 7a 00 sts 0x007A, r24 |
8 | 19c: 80 91 7a 00 lds r24, 0x007A |
9 | 1a0: 89 23 and r24, r25 |
10 | 1a2: 80 93 7b 00 sts 0x007B, r24 |
11 | 1a6: 80 91 7b 00 lds r24, 0x007B |
12 | 1aa: 89 23 and r24, r25 |
13 | 1ac: 80 93 7c 00 sts 0x007C, r24 |
14 | 1b0: 80 91 7c 00 lds r24, 0x007C |
15 | 1b4: 89 23 and r24, r25 |
16 | 1b6: 80 93 7d 00 sts 0x007D, r24 |
17 | } |
18 | debouncer[0] = buttons; |
19 | 1ba: 90 93 79 00 sts 0x0079, r25 |
Hallo zuerst eine Vorbemerkung: schlank muss nicht mit gut gleichgesetzt werden. Ich schreibe die Entprellung immer in einem Timerinterrupt. Dann kann ich ohne Probleme im Hauptprogramm den Schalter (als Globale, die im Interupt gesetzt worden ist) abfragen. Im Timerinterrupt zähle ich ein Variable hoch, falls die Taste gedrückt ist und ich zähle die Variable herunter, falls die Taste nicht gedrückt ist. Dann setze ich noch eine obere Grenze für die Variable, sodass nicht über 1000 gezählt wird und eine Grenze nach unten, sodass die Variable den Wert 0 nicht unterschreitet. Beim Drücken der Taste läuft die Variable, langsam nach oben. Mit einer oberen und unteren Schwelle, setzt ich (wie bei einem Schmitt-Trigger) den Schalterwert. Das Schöne ist, dass alles im Hintergrund läuft. (Der anagebene C-Code ist "frei" geschrieben und noch nicht über einen Compiler gelaufen. Kleinere Fehler können noch vorhanden sein) Beispiel:
1 | //globale
|
2 | int z, Schalter; |
3 | |
4 | Timer_intterupt() |
5 | {
|
6 | |
7 | if(PORTD.0 == 1) |
8 | {
|
9 | z++; |
10 | if(z>= 1000) |
11 | z= 1000; |
12 | }
|
13 | else
|
14 | {
|
15 | z--; |
16 | if (z<=0) |
17 | z=0; |
18 | }
|
19 | |
20 | if (z> 950) |
21 | Schalter = 1; |
22 | if (z< 50) |
23 | Schalter =0; |
24 | }
|
Gruß Franz
:
Bearbeitet durch User
Werner Dornstädter wrote: > Da die Tasterentprellung doch ein grundlegendes Problem darstellt, Nur für die absolut Lernresistenten, die starrsinnig die im Tutorial genannte effektive Methode für 1..8 Tasten ignorieren müssen, stellt es ein Problem dar. > Wäre nun schön, wenn jemand den kompletten funktionsfähigen Code > reinstellen bzw. posten könnte. Warum sollte man etwas komplettieren, was schon im Ansatz deutlich aufwendiger ist? Reicht Dir eine effektive und funktionierende Methode denn nicht? Peter
Danke für Eure Antworten und Ratschläge, doch die Aufgabenstellung ist etwas anders. Ich will erstmalig in C Programmieren und einen Mikrocontroller einsetzen. Und nun habe ich die Aufgabenstellung Schalter entprellen gewählt, um an dieser Aufgabe die Codes verstehen lernen. Wie ja jedem bekannt ist, hat man als Anfänger schon Probleme beim Kompilieren und nun müssen auch noch die entsprechenden Fehlermeldungen verstanden und behoben werden. Lange Rede kurzer Sinn: anbei meine ersten Gehversuche. So und nun hängt es! Aufgrund meiner Recherchen fand ich diesen Beitrag, der mir weiterhelfen könnte.
1 | #include <stdint.h> // Definition der Datentypen |
2 | #include <avr/io.h> // Wir brauchen Zugriff auf die I/O's des Controllers |
3 | #include <avr/interrupt.h> |
4 | #include <stdbool.h> // |
5 | |
6 | #ifndef F_CPU
|
7 | #define F_CPU 1000000 // processor clock frequency
|
8 | #endif
|
9 | |
10 | #define bool_t int
|
11 | |
12 | #define ON true
|
13 | #define OFF false
|
14 | |
15 | |
16 | //----------------------------------------------------------------------------
|
17 | // Diese Funktion liest den Schalterzustand der Hardware aus.
|
18 | // Service routine called by a timer interrupt
|
19 | // extern bool_t RawKeyPressed();
|
20 | bool_t RawKeyPressed() |
21 | //----------------------------------------------------------------------------
|
22 | |
23 | {
|
24 | |
25 | }
|
26 | |
27 | |
28 | //----------------------------------------------------------------------------
|
29 | // Service routine called by a timer interrupt
|
30 | // Routine liefert TRUE, wenn einmal ein entprellter Übergang
|
31 | // zum Schalter geschlossen aufgetreten ist.
|
32 | bool_t DebounceSwitch2() |
33 | //----------------------------------------------------------------------------
|
34 | |
35 | {
|
36 | static uint16_t State = 0; // Current debounce status |
37 | State=(State<<1) | !RawKeyPressed() | 0xe000; |
38 | if(State==0xf000) return true; |
39 | return false; |
40 | }
|
41 | |
42 | |
43 | //----------------------------------------------------------------------------
|
44 | // Service routine called by a timer interrupt
|
45 | int main (void) |
46 | //----------------------------------------------------------------------------
|
47 | {
|
48 | |
49 | |
50 | }
|
51 | |
52 | //----------------------------------------------------------------------------
|
Danke für Euer Verständnis. Sollte das Thread wohl verlegen, da hier ja nichts lauffähiges zu finden ist?
Ich verstehe auch nicht, warum solch ein 0815-Thema immer und immer wieder durchgekaut wird. Wo ist das Problem? 10ms Timer-Interrupt { Wenn Taste gedrückt { Zähler um 1 erhöhen } else { Zähler auf 0 setzen } Wenn Zähler = 5 { Aktion ausführen } Wenn Zähler > 100 { Aktion_bei_lange_gedrückter_Taste ausführen (falls gewünscht) } } Delays nach Belieben anpassen...
> Ich verstehe auch nicht, warum solch ein 0815-Thema immer und immer > wieder durchgekaut wird. Wo ist das Problem? Das Problem ist, dass viele meinen, dass ein C-Turorial durchzuarbeiten verschwendetet Zeit ist. Man googelt lieber stundenlang bis man irgendwo einen Code-Schnipsel findet, der sich kompilieren lässt und hält sich danach für den genialen Programmierer. Beim nächsten Mal gehr es dann wieder von vorne los.
Werner Dornstädter wrote: > Wie ja jedem bekannt ist, hat man als Anfänger schon Probleme beim > Kompilieren und nun müssen auch noch die entsprechenden Fehlermeldungen > verstanden und behoben werden. Man kann versuchen, vor den Fehlermeldungen davonzurennen. Man kann versuchen, vor seinem eigenen Schatten davonzurennen. Die Erfolgsaussichten sind beidesmal sehr gering. Wenn Du die erste Fehlermeldung im exakten Wortlaut postest und das C-File als Anhang, damit man die Zeilennummer zuordnen kann, sollte sich schnell jemand finden, der Dir weiterhilft. Bei C-Fragen vorzugsweise im GCC-Forum posten. Peter
Strahlemann wrote: > Ich verstehe auch nicht, warum solch ein 0815-Thema immer und immer > wieder durchgekaut wird. Wo ist das Problem? > > 10ms Timer-Interrupt { > > Wenn Taste gedrückt { Besser: Wenn Tastenzustand anders ist als der intern gemerkte entprellte Zustand > Zähler um 1 erhöhen > } else { > Zähler auf 0 setzen > } > > Wenn Zähler = 5 { Wenn Zähler = 3, denn ein Zweibit-Zähler kann nunmal nur von 0 bis 3, und bei kleinen Controllern mit knappen Ressourcen kann man schon Wert darauf legen, effizient zu programmieren. > Aktion ausführen Intern gemerkten entprellten Zustand toggeln, prüfen, ob es Tastendruck oder Tastenloslassen war, bei Tastendruck Key_press-Flag setzen, das in der Mainloop ausgewertet und gelöscht wird... > } > > Wenn Zähler > 100 { > Aktion_bei_lange_gedrückter_Taste ausführen (falls gewünscht) Dabei aber auch noch zwischen erster Verzögerung und Repeat-Verzögerung unterscheiden... > } > > } > > Delays nach Belieben anpassen... ...
Ich habe die besagte Routine aus der Artikelsammlung getestet. Funktioniert bei mir. Nun versuche ich sie ganz zu verstehen dabei tue ich mich aber schwer. Ist es egal ob die Taste 0-1 oder 1-0 wechselt? Die internen pullups sind ja an, also geht nur ein 1-0 wechsel? Erläuterung zu der routine wäre nett.
Will mein Problem noch etwas genauer sagen. in ct0 und ct1 ist für entprellte Tasten immer das entsprechende bit gesetzt? Wenn sie prellt und einmal eine 0 erscheint wird wieder resettet das Bit?
Also hab noch mal genau versucht alles nachzuvollziehen, aber ich denke ich bin zu dumm für euer forum. Jede Taste hat ein bin in ct1 und 0, sowie i. die werden einzeln addiert, aber wie wird dabei das carry berücksichtigt?
> Will mein Problem noch etwas genauer sagen. in ct0 und ct1 ist für > entprellte Tasten immer das entsprechende bit gesetzt? Ich kenne (und verstehe) zwar nur die ASM-Routine, der Algorithmus wird aber identisch sein. Die beiden Variablen ct0 und ct1 sind keine zwei 8-Bit-Variablen, sondern werden als acht 2-Bit-Variablen (8 Zähler) interpretiert. Dabei ist Bit 0 jedes Zählers in ct0 und Bit 1 jedes Zähler in ct1. Die Bitposition ist dann sozusagen die Zählernummer und entspricht der Bitposition des Port-Eingangs, an dem der entsprechende Taster angeschlossen ist. Somit hat jeder Eingang seinen eigenen 2-Bit-Zähler, der Zählerstände von 0 bis 3 ermöglicht. Wenn eine eingelesene Taste denselben Zustand hat, der intern als gültig entprellt gespeichert ist (key_state in der ASM-Version), dann wird der Prellzähler dieser Taste gelöscht. Besteht aber ein Unterschied zwischen neu und gemerkt, dann wird der Prellzähler erhöht. Beides passiert parallel für alle 8 Bits eines Ports gleichzeitig. Schafft es ein Prellzähler nun bis zum Zählerstand 3 (binär 11, Bit in ct0 und ct1 gesetzt), dann hat der Taster 4 mal (Entprell-Runden) hintereinander entgegengesetzten Pegel gegenüber vorher gehabt, worauf der intern gespeicherte Tastenzustand (key_state in ASM) dieser Taste (also nur dieses Bit) invertiert wird und der Tastendruck als gültig übernommen wird. Nun wird anhand key_state geprüft, ob es sich um das Drücken oder Loslassen der Taste handelt. War es Drücken, dann wird auch noch das entsprechende Bit in key_press (in ASM, die Namen in C kenne ich nicht, dürften aber ähnlich lauten) gesetzt, also das Tastenflag, das dem Hauptprogramm einen neuen Tastendruck meldet. Jede Taste hat also folgende Bitvariablen: - key_state intern gemerkter (entprellter) gültiger Zustand der Taste - key_press Merker, dass die Taste neu betätigt wurde - ct0 Entprell-Rundenzähler Bit 0 - ct1 Entprell-Rundenzähler Bit 1 wobei jede Variable die Bits aller 8 Tasten entsprechend ihrer Bitposition am Port enthält. > Wenn sie prellt > und einmal eine 0 erscheint wird wieder resettet das Bit? Nööö, siehe oben... Ich hoffe, ich konnte helfen... KH
> Jede Taste hat ein bin in ct1 und 0, sowie i. die werden einzeln > addiert, aber wie wird dabei das carry berücksichtigt? Es gibt kein Carry. Der Zähler zählt nur von 0 bis 3. Bei 3 wird die Taste (besser ausgedrückt der Pegelwechsel am Eingang) akzeptiert, bei Störungen durch Prellen wird auf 0 zurück gesetzt. KH
Hallo Kachel Heinz, ich lese schon eine ganze Weile im Forum und versuche Peters Entprellroutine zu verstehen. Deine Erklärung brachte die Erleuchtung! Danke dafür Michl
also die variante von peter ist wohl kaum zu schlagen (von der anzahl der code-bytes pro taster) und der effizienz. aber ich denke es ist auch (gerade für anfänger) die am schwierigsten zu verstehende variante. die variante mit dem schieberegister die eingangs gepostet wurde ist sicherlich auch ne lösung, selbst wenn es in meinen augen unnötig kompliziert ist (verweundung von integer, wo char reicht; maskieren mit 0xe000 [wofür überhaupt]). hier mal eine (ungetestete) ersatzvariante zum obigen code : #define TASTEN_PORT PINA #define TASTEN_BIT 6 static char shiftreg = 0; static char state = 0; char Entprellen (void) { shiftreg = (shiftreg << 1) | ((TASTEN_PORT >> TASTEN_BIT) & 1); if (shiftreg == 0x7f) { state = 1; } // taste nicht gedrückt if (shiftreg == 0x80) { state = 0; } // taste gedrückt return state; } selbst wenn diese variante nicht getestet ist, sollte (ja ich weiß :-)) sie dennoch funktionieren. verwende z.b. in fpga's gerne schieberegister mit einer solchen abfrage (auf 0b0111 bzw 0xb1000) gerne zum einsynchronisieren von signalen die in einer anderen takt-domäne laufen. beim entprellen sollte dies denselbigen zweck erfüllen. kurz zum verständnis : das schieberegister "taktet" den taster ein. es wird eine 0->1 flanke erkannt, sobald das letzte bit (in dem falle bit 7) 0 und alle anderen bits 1 sind. eine 1->0 flanke sobald das letzte bit 1 und alle anderen 0 sind. irgendwelche zwischenzustände ändern nichts am taster-zustand (was in dem falle ja auch gewollt ist). selbst wenn der taster schon grottig schlecht ist und noch 100ms lang prellen würde, sobald 7 einsen und eine null, bzw 7 nullen und eine 1 im schieberegister sind, wird ein tastendruck bzw loslassen erkannt. die polarität des tasters ist der einfachheit halber positiv (also gedrückte taste = ein high pegel am eingang). wenn es umgekehrt sein sollte wird einfach state = 1 und state = 0 vertauscht. die entprell-routine einfach in einen 1ms timer reinpacken und dann sollte nach spätestens 8ms ein tastendruck sauber erkannt werden. für die hautpschleife ist diese routine denke ich nichts (es sei denn es wird in der hauptschleife ein flag abgefragt welches von einem timer aus jede ms gesetzt wird). aber nochmals : an effizienz ist peters code nie und nimmer zu schlagen. hab meinen code nur mal als ergänzung zum obigen code gepostet
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.