Hier jetzt eine Entprellroutine, wie ich sie schon in vielen Geräten eingesetzt habe. Diesmal ist das Programm in C geschrieben. Sie funktioniert im Prinzip genau so, wie die 8-Tasten-Routine. D.h. das Entprellen erfolgt durch Vergleich zweier aufeinanderfolgender Tastenzustände. Auch das gleichzeitige Drücken mehrerer Tasten wird unterstützt, um z.B. Shift-Tasten zu realisieren. Bei mehr als 2 gedrückten Tasten, müssen jedoch die Tasten durch Dioden entkoppelt werden, da sonst in der Matrix keine eindeutige Erkenung mehr möglich ist. Um auch das gleichzeitige Betätigen mehrerer Tasten zu erkennen, kann diese Routine mehrmals aufgerufen werden, wenn ein Tastencode ungleich 0 zurückgeliefert wurde. Es werden unterschiedliche Kodes beim Drücken bzw. Loslassen erzeugt. Somit ist eine Auswertung von Shift-Tasten oder Repeatfunktion möglich. Peter
Gast
#568818
Guten Tag Herr Dannegger das ist mir jetzt zwar peinlich aber ich muss es fragen. die Zeile
1 | |
verstehe ich nicht. Mein Dozent meinte immer nur bei solchen konstrukten soll man klammern setzten damit man weiß was höhere priorität hat wenn man keine ahnung davon hat. ich habe jetzt keine ahnung und klammern setzten nützt mir nichts um es zu verstehen.
Im Array valid_keys[] hat jede Taste ein Bit. Ändert sich nun eine Taste, ist valid_keys[] ungleich dem eingelesenen Byte und es muß behandelt werden. Wurde noch keine Änderung bearbeitet, ist key_nr = 0 und diese Änderung kann bearbeitet werden. Anders gesagt, falls 2 Tasten sich exakt gleichzeitig ändern (sehr selten, aber nicht unmöglich), wird nur die erste bearbeitet (die andere dann im nächsten Durchlauf). Peter
Gast
#570593
achso dann werden erst die beiden vergleichsoperatoren ==,|= ausgeführt und dann der logische && operator.
Gast
#572776
Hi ich habe die routine mal AVR umgeschrieben. bis auf kleine änderungen in der syntax für avr-gcc musste ich noch etwas an der ansteuerung ändern, ein 4MHz AVR ist wohl etwas schneller wie ein 8051. das setzen der reihen habe ich zum ende der schleife geschoben.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
so hat bleibt ist mehr zeit, dass PINC die zustände annehmen kann. Es ändert sich natürlich auch der Tasten-Code, weil ja jetzt die letzte zeile zuerst eingelesen wird.
Andreas W. wrote: > ich habe die routine mal AVR umgeschrieben. bis auf kleine änderungen in > der syntax für avr-gcc musste ich noch etwas an der ansteuerung ändern, > ein 4MHz AVR ist wohl etwas schneller wie ein 8051. Ne, das ist geschwindigkeitsunabhängig. Der AVR latcht den Eingang schon im vorherigen Befehl, setzt die Ausgänge aber erst im nächsten. Man muß mindestens ein NOP einfügen, damits klappt. Peter
Gast
#572918
ich hatte es mit einen asm volatile ("nop") probiert, was auch nicht
funktioniert hat. deshalb dann der "umweg" mit den erneuten setzen
unten.
ich glaube so wird das programm auch nicht größer.
Gast
#590202
Hallo Peter, Wie genau ist den die Matrix an den µC angeschlossen?
Martin wrote: > Hallo Peter, > > Wie genau ist den die Matrix an den µC angeschlossen? die frage stelle ich mir auch gerade
Martin wrote: > Hallo Peter, > > Wie genau ist den die Matrix an den µC angeschlossen? Als 3*8 Matrix: die 8 Spalten an P2 und die 3 Zeilen an P0.0, P0.1, P0.2. Peter
Gast
#593652
Und Pulups, oder Dioden werden nicht verwendet?
Gast
#1500005
Hallo, erstmal vielen Dank für die Routine. Ich habe sie auf einem Mega8 laufen - 1A! Man kann die Routine entweder nach Andreas W. (s.o.) anpassen oder mind. 2 NOPs zwischen setzen und lesen der IO Register einfügen. Ich habe mich für die erste Möglichkeit entschieden. Wenn man die dadurch entstandene Verschiebung nicht mag einfach ROW[] anpassen. Allerdings ist mir im org. Coding ein Fehler aufgefallen. Beim setzen des Ausgangs heisst es:
1 | |
2 | |
Müsste es nicht aber
1 | |
2 | |
sein, also ohne ~ in der ersten Zeile? Ich möchte ja die 3 Outputs auf High setzen, um danach genau einen Low zu setzen. Die obige Variante würde die anderen Pins auf dem Port high setzen und die 3 relevanten in Ruhe lassen... Schneekönig
Schneekönig schrieb: > Müsste es nicht aber >
1 | |
2 | |
3 | |
> sein Ja. Beim AVR darf man auch nicht den Port setzen, sondern das DDR-Register (Portbit immer low), sonst kommt es zum Kurzschluß, wenn man 2 Tasten drückt. Man muß also einen Open-Drain-Ausgang nachbilden. Peter
Peter Dannegger schrieb: > Martin wrote: >> Hallo Peter, >> >> Wie genau ist den die Matrix an den µC angeschlossen? > > Als 3*8 Matrix: die 8 Spalten an P2 und die 3 Zeilen an P0.0, P0.1, > P0.2. > > > Peter Hallo Peter, wie sieht es aus wenn ich meine 4*4 Matrix an verschiedenen Ports habe (Kolonnen E4:7 und Reihen G0,G3,D4,D7) hab ich das mit deiner Routine schnell angepasst?
Hallo, ich habe die 4x3 Matrix so verschaltet.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
Anbei noch ein lauffähiges Codestück, dass in einem DTMF Generator mit Keypad verwendet wird.
Hallo µC Form, zur Vollständigkeit folgt noch der Link zu Beitrag "DTMF Encoder - seriell 19.200 Baud", wo die obige Klasse eingesetzt wird. http://forum.myluna.de/viewtopic.php?f=8&t=161 _
Gast
#3264657
Rico H. schrieb: > Hallo Peter, > > wie sieht es aus wenn ich meine 4*4 Matrix an verschiedenen Ports habe > (Kolonnen E4:7 und Reihen G0,G3,D4,D7) > > hab ich das mit deiner Routine schnell angepasst? Ohne Peter da zu nahe treten zu wollen. Ich würde das selbst nochmal ganz neu schreiben. Diesen veröffentlichten Code halte ich nicht unbedingt für nachahmenswert
LinWin schrieb: > Diesen veröffentlichten Code halte ich nicht > unbedingt für nachahmenswert Hast Du Dir überhaupt mal die Beschreibung durchgelesen? Vermutlich nicht. Diese Routine kann nämlich erheblich mehr als die üblichen Routinen. Wenn Du erkennen kannst, daß sie Mist ist, dann mußt Du ja auch wissen, wie man es "richtig" macht. Zeig dochmal, wie Du diese Funktionalität (press-, release-code, multiple keypress) realisieren würdest.
Hallo Peter, Deine "Magic" funktioniert bei meinen Projekten 100%. Vielen Dank für solchen wunderbaren Code! Sogar bei Portierungen macht er praktisch keinerlei Schwierigkeiten. Er lässt zumindest bei mir keine Wünsche offen und man kann sehr viel damit machen. Meine Letzte Adaptierung funktioniert jetzt übrigens einwandfrei auf der WSB über eine SPI MCP23S18 Schnittstelle. Bis jetzt portierte ich es auf STM32, einige PICs, AVR(Codevision), und ZILOG encore. Deine Quadratur Encoder Lösung ist auch eine sehr feine Sache. mfg, Gerhard
Gast
#3289933
Peter Dannegger schrieb: > Beim AVR darf man auch nicht den Port setzen, sondern das DDR-Register > (Portbit immer low), sonst kommt es zum Kurzschluß, wenn man 2 Tasten > drückt. > Man muß also einen Open-Drain-Ausgang nachbilden. Es wird also immer nur eine Reihe als Input geschaltet (über DDRx) und dann alle Spalten angeguckt... aber mit Portbit (PORTx) immer low fehlt mir doch der interne Pullup bei active low Tasten? ODer brauche ich die Pullups nur an den Spalten? So ganz bin ich auch noch nicht dahinter gekommen, wie mehrere gleichzeitig gedrückte Tasten unterschieden werden. Ab wann braucht man da Dioden und wo kommen die hin? Kann vielleicht jemand eine funktionierende Portierung für AVR hier einstellen? Danke.
Hallo Werner, Werner schrieb: > Peter Dannegger schrieb: >> Beim AVR darf man auch nicht den Port setzen, sondern das DDR-Register >> (Portbit immer low), sonst kommt es zum Kurzschluß, wenn man 2 Tasten >> drückt. >> Man muß also einen Open-Drain-Ausgang nachbilden. Man kann bei die meisten MCUs OPEN-DRAIN Ausgänge simulieren indem man alle Keypad Ausgangs PORT BITS einmalig auf Null setzt und die Ausgänge sequenziell nur mit dem DDRn Register als jeweilig eingeschalteten Ausgang ansteuert. Die jeweilig unbenutzten Ausgänge verhalten sich dann immer als Eingänge. In anderen Worten, nur der jeweilig angesteuerte PORT-PIN liegt auf Masse um die Spalten runter zu ziehen und ein Kurzschluss zwischen irgendwelchen Spaltenausgängen haben keine Wirkung. > > Es wird also immer nur eine Reihe als Input geschaltet (über DDRx) und > dann alle Spalten angeguckt... aber mit Portbit (PORTx) immer low fehlt > mir doch der interne Pullup bei active-low Tasten? ODer brauche ich die > Pullups nur an den Spalten? Die Pullups braucht man nur bei den Eingängen. Viele MCUs haben interne Pullup Widerstände die man einschalten kann. Beim AVR geht das ganz einfach indem man die PORTn Register auf H setzt und die PINs mit dem DDRn Register in den Eingang Modus versetzt. Das schaltet automatisch die Pullups ein. Bei anderen MCUs wie PIC geht das bei vielen älteren Modellen nur am PORTB. Ansonsten musst Du eben extra 2-10KOHM Widerstände einbauen. Diskrete Widerstände im Bereich von 2-10K haben aber auch den Vorteil dass mehr Strom durch die Tastenschalter fließt und sie dann zuverlässiger arbeiten. Viele Kontaktmaterialien brauchen einen gewissen Mindeststrom um zuverlässig funktionieren zu können. > > So ganz bin ich auch noch nicht dahinter gekommen, wie mehrere > gleichzeitig gedrückte Tasten unterschieden werden. Ab wann braucht man > da Dioden und wo kommen die hin? Da jedes Spalte einzeln zeitlich sequenziell angesteuert wird lässt sich das im Code wieder elegant entflechten. Ein Kurzschluss zwischen gleichen Spalten macht sowieso nichts aus und ein Kurzschluss über ein oder mehrere Spalten macht auch nichts aus weil sich das in den eingelesenen Werten ersichtlich ist. Da der ganze Scan Vorgang zeitlich sequenziell abläuft lässt sich alles richtig ableiten. > > Kann vielleicht jemand eine funktionierende Portierung für AVR hier > einstellen? Habe im Augenblick keine Portierung für AVR (Nur PIC). Das Beispiel von Peter ist aber für den AVR gezeigt und sollte anstandslos funktionieren. Es ist übrigens interessant zu sehen wie sein Code funktioniert. Wenn Du auf eine oder mehrere Tasten drückst wird jede Taste richtig nacheinander angezeigt. So, wenn man mehr als eine Taste drückt wird nacheinander im Zug der Portsequenz der Keycode ausgegeben: z.B. Taste 1 (2+3+4) gleichzeitig: [0x81] [0x82] [0x83] [0x84]... beim loslassen einer jeweiligen Taste wird das MSB bit geloescht: Drücken: [0x81] loslassen: [0x01] Bei mir verwende ich eine lookup table (LUT) um den Keycode um z.B mit einem 4x4 Tastenfeld die nummern 0-9A-F zu generieren. Mit dieser LUT lässt sich dann für jede Taste der gewünschte Keycode zuordnen. Ich hoffe das hilft Dir etwas weiter, mfg, Gerhard > > Danke.
Gast
#3290379
Ich glaube ich habe es verstanden... Die zu überprüfende Reihe wird per Ausgang auf low gezogen (PORTx.y = 0 und DDRx.y = 1). Die anderen Reihen sind floatende Eingänge (PORTx.y = 0 und DDRx.y = 0). Alle Spalten gehen zu Eingängen mit aktiviertem Pullup. Nun kann ich anhand der Spalten die Taster in der aktiven Reihe auswerten. Ein gedrückter Taster in der zu überprüfenden Reihe zieht den Spalteneingang auf low. Ein gedrückter Taster in einer anderen Reihe kann über den floatenden Eingang der Reihe die Spalte nicht auf low ziehen und stört nicht. Die Reihen werden nun nacheinander ausgewertet -> multiplexing. Ist das so richtig?
Gast
#3290384
Wofür bräuchte man denn dann noch Dioden, wenn man mehrere Tastendrücke gleichzeitig auswerten möchte?
Werner schrieb: > Ich glaube ich habe es verstanden... > > Die zu überprüfende Reihe wird per Ausgang auf low gezogen (PORTx.y = 0 > und DDRx.y = 1). > Die anderen Reihen sind floatende Eingänge (PORTx.y = 0 und DDRx.y = 0). Wenn Du aber (PORTx.y = 1 und DDRx.y = 0) einstellst dann aktivieren sich die eingebauten Port Pullup Widerstände. Wie schon gesagt favorisiere ich extra diskrete Pullup Widerstände weil man dann mehr Strom durch die Tasten fließen lassen kann was die Zuverlässigkeit der Tastenaktion erhöhen kann. > > Alle Spalten gehen zu Eingängen mit aktiviertem Pullup. > Nun kann ich anhand der Spalten die Taster in der aktiven Reihe > auswerten. > Ein gedrückter Taster in der zu überprüfenden Reihe zieht den > Spalteneingang auf low. Der jeweilig vom Code aktivierte Port PIN macht das;-) > Ein gedrückter Taster in einer anderen Reihe kann über den floatenden > Eingang der Reihe die Spalte nicht auf low ziehen und stört nicht. Ja. Da die übrigen ROW Output Pins als Eingange wirken macht das nichts aus. > > Die Reihen werden nun nacheinander ausgewertet -> multiplexing. > > Ist das so richtig? Ja. Der Rest passiert durch Peter's Magic Code;-) Gerhard
Werner schrieb: > Wofür bräuchte man denn dann noch Dioden, wenn man mehrere Tastendrücke > gleichzeitig auswerten möchte? Wenn man es wie beschrieben macht sind die Dioden überflüssig. Die Dioden sind nur notwendig wenn man keinen OPEN DRAIN Ausgänge zur Verfügung hat. Ich setzte mal ein Shift-Register (74HC164) als ROW Treiber ein. In diesem Fall waren die Dioden notwendig.
Gast
#3290446
Ok, danke, dann hab ich es jetzt verstanden :-) (PORTx.y = 1 und DDRx.y = 0) hab ich ja bei der Reihe auch nicht geschrieben. Das braucht man dann nur bei der Spalte oder eben externe Pullups. Und ja, um genau zu sein, der Taster verbindet nur die Reihe mit der Spalte. Der Spalteneingang wird dann durch den auf low gestellten (aktiven) Reihenausgang auf low gezogen.
Gast
#3291001
Habe das mal für AVR angepasst. Es kompiliert zumindest, kann es aber gerade mangels HW nicht testen. Es fehlt aber auch noch die Anpassung mit dem NOP. Kann mir jemand helfen, wo das genau zwischen muss? Danke!
Hallo, das hat Peter doch geschrieben: Beitrag "Re: Tasten-Matrix entprellen" Wie immer gibt es diese Info zum Lesen im Datenblatt deines µC im Abschnitt Ports.
Werner schrieb: > Wofür bräuchte man denn dann noch Dioden, wenn man mehrere Tastendrücke > gleichzeitig auswerten möchte? Sobald mehr als 2 Tasten gleichzeitig. Ohne Dioden kann es bei 3 Tasten gedrückt zu einer 4. Phantomtaste kommen.
Gast
#3293521
Kannst du das mit der Phantomtaste genauer erklären, wie das zustande kommt? Das verstehe ich noch nicht. Wegen des NOPs verstehe ich das so, dass vor dem Einlesen des Pins nach dem Setzen der Ausgänge ein bis zwei Takte gewartet werden muss, also so:
1 | |
2 | |
3 | |
4 | |
5 | |
Richtig?
Werner schrieb: > Kannst du das mit der Phantomtaste genauer erklären, wie das zustande > kommt? > Das verstehe ich noch nicht. Schau mal hier : http://www-user.tu-chemnitz.de/~heha/Mikrocontroller/Tastenmatrix.htm Ist in Tastenmatrix.c nicht noch ein Fehler drin? Ohne Dioden nur das DDRx Bit setzen dessen Reihe ausgewertet werden soll.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
Mit Dioden alle PORTx Bit's setzen bis auf das Bit welches augewertet werden soll.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
Gast
#3294152
Kai Großpietsch schrieb: > Schau mal hier : > http://www-user.tu-chemnitz.de/~heha/Mikrocontroller/Tastenmatrix.htm > > Ist in Tastenmatrix.c nicht noch ein Fehler drin? > > Ohne Dioden nur das DDRx Bit setzen dessen Reihe ausgewertet werden > soll. >
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
>
Danke, das mit dem Kurzschluss bei mehr als 2 Tasten gleichzeitig habe
ich jetzt verstanden.
Ich bin der Meinung, dass man die simulierten Open Drain Ausgänge auch
mit Dioden nutzen kann. Nur andersrum, gibt es Probleme, nämlich mit
normalen Ausgängen (über PORT) und keinen Dioden...
Ich meine, dass der Code im Simulator funktioniert hätte, bin aber
gerade verunsichert und würde es gerade so machen:1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
Werner schrieb: > Kannst du das mit der Phantomtaste genauer erklären, wie das zustande > kommt? Mal die Schaltung einer 2 * 2 Matrix auf und drücke 3 Tasten. Dann wird auch die 4. Taste als gedrückt erkannt, da die 3 Tasten den Stromkreis dafür schließen. Hat jede Taste eine Diode in Reihe, werden nur die 3 Tasten gemeldet, die wirklich gedrückt sind.
Ich habe die Funktion gerade mal auf meinen Cortex-M3 umgesetzt mit einer 2x9 Matrix. Funktioniert auch soweit wunderbar, nur fehlt mir sowas wie eine "get_key_pressed" und "get_key_released" Funktion, die ich in der main nutzen kann. Also etwas, dass den Tastendruck nur einmal zurückgibt. GetKey rufe ich im Timer alle 10ms auf und speichere die Rückgabe in einer Variablen. Daurch evaluiert aber die Abfrage in der Main je nach Durchlaufzeit vielfach. Soll ich die Variable zum Zwischenspeichern einfach nach der Evaluierung '0' setzen? Wie macht ihr das? Gruß Fabian
Fabian B. schrieb: > Daurch evaluiert aber die Abfrage in der Main je nach Durchlaufzeit > vielfach. Was könnte das bedeuten? > nach der Evaluierung '0' setzen? Was "evaluierst" (= "bewertest") du denn wie? > Daurch evaluiert aber die Abfrage in der Main je nach Durchlaufzeit > vielfach. Du könntest mal deine "Main" hier anhängen, dann könnte man die mal evaluieren...
Hallo Lothar, da gibts nicht anzuhängen ... die Main liest derzeit nur die Taste und gibt sie über die serielle aus. Hier setze ich jetzt schon keyp = 0 um eine Taste nur einmal zu behandeln.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
keyp selbst ist eine globale Variable (volatile uint8_t), die im 10ms-Timer mit
1 | |
"gefüllt" wird. So funktioniert das auch, aber mein Frage war ja ob das so gedacht ist oder ob's da was eleganteres gibt, was ich übersehe. Vergleichbar der get_key Funktionen aus PeDas "normaler" Tastenentprellung. Gruß Fabian
Keiner mehr? Vielleicht kann ja ein Anwender der Funktion die Tastenauswertung aus seinem Programm posten... Gruß Fabian
Hallo Peter, auch nach so vielen Jahren Danke für das Programm. Ich bin Quereinsteiger und es hat ein wenig gedauert, aber auch ich bin irgendwann durchgestiegen. Allerdngs habe ich mich auch über die
1 | |
gestolpert. Nun habe ich wg. der Pin Kurzschlüsse eine Frage. Ich möchte die Matrix (momentan Testmatrix 3x4, später 10x8) mittels Schieberegister realisieren. Dazu nehme ich je einen 595er und einen 165er. Gibt es dort auch das Problem mit Kurzschlüssen unter den Pins? Sollte ich dann direkt mit Dioden arbeiten? Wenn ja, welche Dioden sind dann zu empfehlen? Gruß Jens
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.