Guten Abend, Ich hätte eine Frage bezüglich, der von mir verwendeten Tastermatrix (siehe Anhang). Wie ma erkennen kann handelt es sich um eine 8*3 Active-high Matrix mit externen Pull-downs. Keine Standardmatrix, aber für mich einfacher zu verstehen, da ich noch Neuling im Gebiet der µC bin. Meine Frage bezieht sich auf die Entprellung der Matrix, da sich einige Tasten immer wieder einfach von alleine drücken. Hier ein Ausschnitt aus dem Quellcode zur Abfrage und Entrprellung der Tasten: PORTB |= ( ( 1 << PB2 ) ); for (ui8Count = 0; ui8Count < 5; ui8Count++) { if ( PINC & (1<<PC3) ) ui8Prellen[21]++; if ( PINC & (1<<PC4) ) ui8Prellen[22]++; if ( PINC & (1<<PC5) ) ui8Prellen[23]++; _delay_ms(5); } PORTB &=~ ( ( 1 << PB2 ) ); Mein Gedankengang: - Ausgang des Controllers auf high Schalten - Die Eingänge kontrollieren und damit die Taste eindeutig indentifizieren - Wenn der Eingang vier mal hintereinander ein high-Signal erkennt gilt die Taste als gedrückt und entprellt Nicht wirklich sehr effektiv, aber die Funktion steht im Vordergrund. Wichtig wäre vielleicht noch, dass es nicht möglich sein muss zwei Tasten gleichzeitig zu drücken (deshalb habe ich auch auf eine Endkopplung mit Dioden verzichtet). Im voraus danke für eine Antwort mgf Stefan
Zum Entprellen eiget sich besser, in einer ISR alle 10ms (z.B.) auf die Matrix zu schauen. In der ISR sete zu die Ports, wartest evtl kurz (also ein paar Ticks() und liest dann die aktuelle Zeile/Spalte ein. Durch die Abtastung in den Schritten hast du ne Entprellung, und eine nicht-blockierende Hauptschleife. Das kurze Warten dient dem Anpassen der Pegel. Je nach Schaltung/Leitungen haben die ne Kapazität von ein paar pF, und wenn der AVR schbekk läüft, brauchts u.U ein paar 100ns bis sich die Pegel nach Umschaltung angepasst haben. Pro ISR wird nur eine Zeile abgearbeitet, in der nächsten dann eine weitere. Johann
Sory mein Fehler, ich habe vergessen zu erwähnen, dass die Entprellung bereits in einer ISR (also in einem Timer, der alle 10ms Aufgerufen wird) erfolgt. Innerhalb eines durchlaufs wird aber die gesamte Matrix abgefragt... Ich kann mir nur nicht ganz erklähren warum sich die Tasten teilweise von selbst Drücken?? inzwischen danke für die schnelle Antwort
Im moment fällt mir kein Softwarefehler auf. Kann es sein dass es an der Hardware liegt? Kurzschluss? Fehlkontakte? Wackelkontakt? Ich würde auf alle Fälle die Hardware nachkontrollieren.
>S25 ist aber ein übler Kandidat...:-)
Tut mir leid da kann ich leider nicht ganz folgen??
War ja auch ne Fehlleistung von mir... Hatte mit deinem eigentlichen Problem auch nichts zu tun, sah auf den ersten Blick so aus, als ob der direkt zwischen Vcc und Masse liegt.
S25 wird durch das Gehäuse und ein bischen mechanischer Bastelei zu einem Schalter, ist aber nicht das eigentliche Problem, das liegt wie ich hoffe (Platine ist bereist fertig) und vermute an der Software. Also keiner eine Idee warum der Controller immer wider Tasten als gedrückt erkennt, ohne dass diese wirklich gedrückt worden sind??
stefan schrieb: > Hier ein Ausschnitt aus dem Quellcode zur Abfrage und Entrprellung der > Tasten: > > PORTB |= ( ( 1 << PB2 ) ); > > for (ui8Count = 0; ui8Count < 5; ui8Count++) > { > if ( PINC & (1<<PC3) ) > ui8Prellen[21]++; > if ( PINC & (1<<PC4) ) > ui8Prellen[22]++; > if ( PINC & (1<<PC5) ) > ui8Prellen[23]++; > > _delay_ms(5); > } > > PORTB &=~ ( ( 1 << PB2 ) ); > > Mein Gedankengang: > - Ausgang des Controllers auf high Schalten > - Die Eingänge kontrollieren und damit die Taste eindeutig > indentifizieren > - Wenn der Eingang vier mal hintereinander ein high-Signal erkennt gilt > die Taste als gedrückt und entprellt Das steht aber nicht in Deinem Codeschnipselchen. 99% der Fragesteller sind betriebsblind, d.h. posten immer nur Schnipselchen, die den Fehler garantiert nicht enthalten oder schlimmer noch, dem getesteten Code garnicht entsprechen. Daher besser einen compilierfähigen, getesteten Code als Anhang posten. > Nicht wirklich sehr effektiv, aber die Funktion steht im Vordergrund. Zur Zeit ist er ja beides nicht. Hier mal ein funktionierendes Beispiel: Beitrag "Tasten-Matrix entprellen" Peter
Ich habe Ihren Code bereist genau angeschaut aber nicht wirklich sehr viel verstanden. Ich weiß, dass die Matrix Bitweise ausgelesen und dabei auch entprellt wird. Außderm hab ich verstanden, dass der Code für eine "Active-Low" - Matrix geschrieben wurde. Es werden Registerrichtungen (Ausgang-Eingang) gesetzt und auf Low abgefragt und nicht wie ich das mache Ports geschalten (high-low) und dann ein high-Signal abfragen. Das ist leider alles was ich verstanden habe, deshalb habe ich auch nicht die geringste Ahnung wie ich Ihren Code an mein Problem anpassen könnte. >99% der Fragesteller sind betriebsblind, d.h. posten immer nur >Schnipselchen, die den Fehler garantiert nicht enthalten oder schlimmer >noch, dem getesteten Code garnicht entsprechen. >Daher besser einen compilierfähigen, getesteten Code als Anhang posten. Ok könnte stimmen, dann nocheinmal ein neuer Versuch. (compilierfähiger Code im Anhnag). > Nicht wirklich sehr effektiv, aber die Funktion steht im Vordergrund. >Zur Zeit ist er ja beides nicht. Nein eigentlich nicht wirklich, der Tastendruck wird zwar immer erkannt, aber wie schon gesagt drücken sich die Tasten immer wider von selbst, was vermutlich daran liegt, dass die Tasten nicht ausreichend entprellt werden. Thoretisch müsste, die Entprellung und das Einlesen der Matrix aber so funktionieren? Glaube ich zu mindest? Wie schon gesag es muss nicht effektiv sein aber funktionieren, außerdem ist meine Variante so einfach, dass sie sogar ich verstehe, was mir auch sehr wichtig ist.
Tut mir leid meiner Meinung nach müsste der Quellcode stimmen, theoretisch als auch in der Ausführung. Sicher keine Fehler in der Hardeware?
Welche Art Tasten verwendest du? sind das Folientaser oder "richtige" Mechanische? Wie ist der Spass verkabelt? An AVCC/AGND auch noch einen Abblockkondensator angeschlossen? Lässt du zwischen den High-Schalten einer Zeile und dem Auslesen eine Pause? Ich vermute, dass durch die kurzen Impulse beim Einschalten die Zuleitungen bzw. die Taster wie Kondensatoren verhalten und daher "falsche" Werte liefern. _.-=: MFG :=-._
Das kann Übersprechen sein. In der ISR immer nur 1 spalte abfragen und am ende der ISR auf die nächste umschalten. Dadurch bekommen die Signale zeit sich einzuschwingen. Als ausgleich kann man die ISR ja öfter starten. mfg.
>Welche Art Tasten verwendest du? sind das Folientaser oder "richtige" >Mechanische? Wie ist der Spass verkabelt? An AVCC/AGND auch noch einen >Abblockkondensator angeschlossen? Lässt du zwischen den High-Schalten >einer Zeile und dem Auslesen eine Pause? -Es sind mechanische Taster -Die Schaltung ist bereits auf einer Platine -an AVCC/AGND ist ein 100nF Kondensator zwischengeschaltet (müsste reichen?) -eine Pause wird auch gemacht >Das kann Übersprechen sein. >In der ISR immer nur 1 spalte abfragen und am ende der ISR auf die >nächste umschalten. >Dadurch bekommen die Signale zeit sich einzuschwingen. >Als ausgleich kann man die ISR ja öfter starten. Wie schon gesagt bin ich noch Anfänger und habe mit Mühe und Not einen ISR zum Starten gebracht. Wenn ich es richtig Verstanden habe müsste ich dann 8 verschiedene ISRs haben um jeweils 3 Tasten auszulesen. Am Ende von der Einen müsste die Nächste gestartet werden Zum Ausgleich müsste die gesamte Prozdur mehrmals gestartet werden?? Giibt es überhaupt 8 verschieden ISRs? Kann ich irgendwie testen ob es sichh um das benannte Problem handelt? Kann mein Problem wirklich nicht an der Entprellung liegen? Danke inzwischen Stefan
Wenn du deine Entprellung sicher testen willst, dann les mal nur eine Zeile deiner Matrix ein und lass die anderen mal aussen vor. Wenn's dann einwandfrei geht weißt du, dass deine Entprellung läuft und der Fehler wahrscheinlich durch überpsrechen kommt. Wenn's nicht läuft hat auf jeden Fall deine Entprellung auch noch nen Fehler. Nein, du brauchst weiterhin nur eine ISR. Du brauchst eine globale Variable, die du bei jedem ISR-Aufruf um eins verringerst. Je nach Wert der Variable wird dann eine Zeile ausgelesen. In Pseudocode könnte das so ungefähr aussehn: verringer global_cnt wenn global_cnt == 0, dann global cnt = Anzahl Zeilen lese Tastenwerte ein deaktiviere Zeile mit der Nummer von global_cnt aktiviere Zeile mit der Nummer von global_cnt+1 Hier dann die Entprellroutine Return Auf die weise hat die Matrix eine Interrupt-periode (z.B.10ms) Zeit bevor die neue Zeile eingelesen wird. Auf die weise sollten dann alle Kapazitäten umgeladen sein. In der initialisierung aktivierst du dann schonmal die erste Zeile und lädst die anzahl zeilen in dein globales register bevor du den Timer startest. Hatte übrigens vor einigen Tagen das gleiche Problem und hab es genau so gelöst. Aber in Assambler, mein Code wird dir also nicht viel helfen. Sebastian
Der Fehler wird sich wohl doch bei der Entprellung eingeschlichen haben. Im Anhang nocheinmal der Testcode, der nur nor eine Zeile ausliest. Trotz das nur eine Zeile ausgelesen wird drücken sich die Tasten b,h,j immer wider von selbst, obwohl nur die Tasten a,b,c abgefragt werden. Die Tasten werden zwar nicht mehr so oft als gedrückt erkannt aber leider immer noch? Also muss der Fehler beim Entprellen liegen oder kann Trotzdem ein überspringen darfür verantwortlich sein? Noch eine kurze Frage zum getrennten behandeln der ISRs. Müsste es vom Prinzip nicht das selbe sein wie: Pseudocode: verringer global_cnt wenn global_cnt == 0, dann global_cnt = Anzahl_Zeilen wenn zeile_nr == global_cnt, dann lies entsprechende Zeile aus So wird in jedem ISR Durchgangn nur jeweils eine Zeile (also drei Tasten) abgefragt
Es macht definitiv keinen Spaß, sich diesen Code anzusehen. Es werden Unmengen an Flash und SRAM verschwendet ohne den geringsten Effekt. Auch wenn es für den Anfänger scheint, Copy&Paste sei einfach, das Gegenteil ist der Fall. Der Code wird nur unübersichtlich und fehlerträchtig. Gleiche Sachen immer zusammenfassen, entweder als Loop oder Funktion oder notfalls erstmal als Macro. Schmeiß alles weg und versuche mal einen komplett neuen Ansatz: Trenn Erkennung, Entprellen, Anzeigen und Warten voneinander und schreibe eins nach dem anderen. Du willst ja nur eine Taste erkennen, also sind 24 Variablen genau 23 zuviel. Die Erkennungsroutine gibt Dir einfach ne Zahl 0..24 zurück, die der ersten erkannten Taste entspricht. Die Entprellroutine ruft diese im Timerinterrupt alle 10ms auf. Dann zählst Du nur noch, ob 4-mal hintereinander der gleiche Wert gelesen wird und voila, die Taste ist entprellt. Dann zeigst Du sie an, aber nicht im Timerinterrupt. Bezüglich Timerinterrupt: irgendwelche Delays haben darin absolut nichts verloren. Das ist ja gerade der Witz am Timerinterrupt, daß er selbst das Delay darstellt und die Rechenzeit ans Main zurück gibt statt sie zu vergeuden. Wenn man also schon Delays benutzt, dann ausschließlich im Main! Als Anfänger sollte man auch nicht alle Portpins lustig durcheinanderwürfeln, damit machst Du Dir nur selber das Leben schwer. Der AVR ist ein 8-Bitter und Du hast 8 Zeilen, da sollte man schon möglichst alle Zeilen auf den gleichen Port legen. Das vereinfacht die Auswertung erheblich. Das Verwürfeln von Portpins ist dann schon höhere Programmierschule (ist aber mit Bitvariablen auch gut lesbar). Peter
stefan schrieb: > Es werden Registerrichtungen > (Ausgang-Eingang) gesetzt und auf Low abgefragt und nicht wie ich das > mache Ports geschalten (high-low) und dann ein high-Signal abfragen. Nun, dann überlege mal, wenn jemand 2 Tasten drückt und dadurch ein 0-Ausgang mit einem 1-Ausgang kurzgeschlossen wird. Der MC überlebt es in der Regel, aber die Stromaufnahme steigt erheblich. Daher ist Ausgänge umschalten falsch! Alle Ausgänge müssen den gleichen Wert haben und nur die Richtung wird umgeschaltet. Man spart Rechenzeit und Code, wenn man die kleinere Anzahl umschaltet und dann die größere einliest. Also die 3 Spalten als Ausgang und die 8 Zeilen als Eingang. Peter
Ich weiß nicht ob ich wirklich verstanden habe was Sie meinen aber hier nocheinmal ein Versuch Vielen Vielen dank für die Gedult Stefan
Es wäre wohl sinvoll, wenn du deinen Schaltplan nochmal änderst. Wenn du die 8 Zeilen zusammen auf einen Port gibst und dann zwischen den 3 Spalten auswählst wird die Software deutlich einfacher. Schneller und kürzer sowieso. Seh ich das richtig, dass du versuchst, bei jedem ISR-Aufruf eine ganze Entprellung durchzuführen, also 5 Samples zu nehmen? Dann kommst du um ein Delay tatsächlich nicht rum. Aber das Konzept ist Mist. Du musst bei jedem ISR-Aufruf nur ein Sample nehmen. Der letzte Zustand wird gespeichert und es wird jedesmal ein Zähler verringert, der zählt, wie lange sich der Zustand schon nicht geändert hat. Erreicht der Zähler 0, dann liegt ein sauberer Pegel an. Dieser Pegel wird für Main übernommen und es wird nichtmehr weitergezählt. Sind aktueller und letzter Zustand unterschiedlich wird der Zähler (z.B. auf 4) zurückgesetzt. Für den Anfang solltest du mal nur eine der 3 Spalten deiner Matrix verwenden. Die muss dann aber auch immer aktiv bleiben, also auch außerhalb der ISR (für den ersten test jetzt). Wenn dann deine Entprellung funktioniert, kannst du anfangen, dich mit der Matrix rumzuärgern. Schau doch auch mal in die Codesammlung, wie andere soetwas lösen. Sebastian
>Schau doch auch mal in die Codesammlung, wie andere soetwas lösen. Ich habe jetzt seit über 2 Wochen Beiträge studiert, aber die einzig Gute Entprellroutine (die von Peter) verstehe ich nicht, der Rest war nicht besonders hilfreich. >Es wäre wohl sinvoll, wenn du deinen Schaltplan nochmal änderst. Wenn du >die 8 Zeilen zusammen auf einen Port gibst und dann zwischen den 3 >Spalten auswählst wird die Software deutlich einfacher. Schneller und >kürzer sowieso. Den Schaltplan nocheinmal zu ändern ist leider nicht mehr möglich. Dass das was ich produziert habe reiner Mist ist habe ich jetzt auch verstanden. Ich muss: - in der ISR nur jeweils eine Zeile überprüfen - und damit in der ISR keine delays verwenden - die Zeilen und Spalten aufgrund der Effektivität vertauschen - die Auswertung (Ausgabe auf dem Display) in der Main realisieren Ok das habe ich verstanden hab aber leider keine Ahnung wie ich das machen soll?? Ein Pseudocode von Peters Routine oder eine Erklährung wäre sehr hilfreich? Ich bin mir nicht sicher ob ich das Konzept mit den oben genannten Punkten wirklich verstanden habe. Ich hoffe miar kenn jemad weiterhelfen Danke im voraus Stefan
Hi >Ich muss: >- in der ISR nur jeweils eine Zeile überprüfen Persönlich trenne ich bei Martixtastaturen die Erkennung einer gedrückten Taste und die Ermittlung der gedrückten Taste. Zur Tastenerkennung reicht es alle Ausgänge in den aktiven Zustand zu versetzen und die Eingänge abzufragen. Erst wenn dadurch (irgend-)eine Taste erkannt wurde erfolgt die Decodierung der Taste. Dadurch ist die Tastenerkennung relativ schnell und kompakt und die zeitliche Trennung von Erkennung und Dekodierung reicht u.U. schon für die Entprellung. MfG Spess
> Den Schaltplan nocheinmal zu ändern ist leider nicht mehr möglich.
Warum? Platine schon geätzt? Vor allem als Anfänger sollte man sowas
vielleicht erstmal auf Lochraster probieren, bevor man ne Platine ätzt.
Leiterbahnen auftrennen und mit Draht neu verlöten kann durchaus auch ne
Alternative sein. Ich kenne dein layout nicht.
Es gibt noch tausend andere und teils sicher bessere möglichkeiten, aber
hier mal ein Weg, der zum erfolg führen sollte und vielleicht für dich
nachvollziebar ist. Dabei werden (erstmal) nur 2 Samples genommen bis
der Zustand als gültig erkannt wird. Mehrere Samples darfst du selbst
einbauen, wenn's nötig ist.
Für den ersten Test beachtest du nur die Spalte an PC3.
In der Init:
-PC3 wird auf ausgang und High gestellt und dann nicht mehr verändert.
-Die ISR wird initialisiert
-globale Variable sw_old=0 anlegen (hier wird der letze Zustand deiner
Tasten gespeichert)
-globale Variable sw_state anlegen (hier wird der entprellte Zustand
deiner Tasten gespeichert)
-ab nach main
in der ISR:
-Zeilen einlesen und in ein Byte vereinen. Jede Taste bekommt ein Bit,
das den Zusatnd der Taste anzeigt.(Genau der Punkt wäre mit anderem
Layout einfacher, kürzer und schneller)
-neuer Zustand==sw_old? wenn ja: sw_state= neuer Zustand
-sw_old=neuer Zustand //neuen zustand als "neuen alten Zustand"
übernehmen
-ende
in der main kannst du dann mit sw_state lesend machen was du willst,
blos schreiben darfst du hier dann nicht.
Wenn du an dem Konzept was nicht verstehst frag nach. Ansonsten antworte
ich erst wieder, wenn das bei dir läuft und du verstanden hast, warum.
Sebastian
stefan schrieb: > Ich weiß nicht ob ich wirklich verstanden habe was Sie meinen aber hier > nocheinmal ein Versuch Nein. Ich meinte, die Aufgaben zu trennen (teile und herrsche). Und Spaghetticode vermeiden (Schleifen statt Copy&Paste).
1 | #include <io.h> |
2 | |
3 | |
4 | #define COL0 PC3
|
5 | #define COL1 PC4
|
6 | #define COL2 PC5
|
7 | |
8 | #define ROW0 PC0
|
9 | #define ROW1 PC1
|
10 | #define ROW2 PC2
|
11 | #define ROW3 PB0
|
12 | #define ROW4 PB1
|
13 | #define ROW5 PB2
|
14 | #define ROW6 PD6
|
15 | #define ROW7 PD7
|
16 | |
17 | |
18 | uint8_t get_key_row( void ) |
19 | {
|
20 | uint8_t key = 0; |
21 | uint8_t row; |
22 | |
23 | row = (PINB & (1<<ROW3 | 1<<ROW4 | 1<<ROW5)) << 3; |
24 | row |= PINC & (1<<ROW0 | 1<<ROW1 | 1<<ROW2); |
25 | row |= PIND & (1<<ROW6 | 1<<ROW7); |
26 | |
27 | if( row ) |
28 | for(;;){ |
29 | key++; // count bit number |
30 | if( row & 1) // until bit found |
31 | break; |
32 | row >>= 1; |
33 | }
|
34 | return key; // 0 = no key, 1..8 = key |
35 | }
|
36 | |
37 | |
38 | uint8_t key_scan( void ) |
39 | {
|
40 | uint8_t key = 0; |
41 | uint8_t col = 1<<COL0; // 1th column |
42 | |
43 | do{ |
44 | if( !key ) |
45 | key = get_key_row(); |
46 | else
|
47 | key += 8; |
48 | |
49 | PORTC = col; |
50 | DDRC = col; // open drain to avoid short circuit !!! |
51 | col <<= 1; // next column |
52 | }while( col & (1<<COL2 | 1<<COL1)); |
53 | |
54 | return key; // 0 = no key, 1..24 = key pressed |
55 | }
|
56 | |
57 | |
58 | uint8_t key_debounce( void ) // call every 10ms |
59 | {
|
60 | static uint8_t old_key = 0xFF; |
61 | static uint8_t debounce_cnt = 0; |
62 | uint8_t key; |
63 | |
64 | key = key_scan(); |
65 | |
66 | if( old_key == key ){ |
67 | if( debounce_cnt == 4 ) // four times equal (40ms) |
68 | return key; |
69 | debounce_cnt++; |
70 | }else{ |
71 | old_key = key; |
72 | debounce_cnt = 0; |
73 | }
|
74 | return 0; |
75 | }
|
Peter P.S.: In Foren ist "Sie" ungebräuchlich.
Ja habe die Platine leider schon geätzt und gelötet da miar einwenig die Zeit davon rennt... Ok danke für die schnelle Antwort, einige Kleinigkeiten hätte ich aber noch die ich dabei noch nicht ganz verstanden habe: >in der main kannst du dann mit sw_state lesend machen was du willst, >blos schreiben darfst du hier dann nicht. -Wenn ich die Ausgabe nicht in der ISR und in der Main auch nicht machen soll, wo soll ich das ganze dann ausgeben -für die Ausgabe muss ich dann aber immer noch abfragen welches Bit gesetzt wurde um die Taste zu erkennen z.B. if (sw_state == 0b10000000) Taste1->gedrückt else if (sw_state == 0b01000000) Taste2->gedrückt das ganze dann 3 mal für jede Zeile liege ich damit richtig? -Für eine Zeile glaube ich das Prinzip verstanden zu haben, aber wie soll ich das ganze anschließend für drei Zeilen realisiern Nochmal herzlichen Dank ohne Euch wäre ich verloren mgf Stefan
Mit "Ausgabe" meinst du das Anzeigen auf dem Display welche Taste gedrückt ist? Bzw. halt die jeweilige Aktion, die ausgeführt werden soll? Das muss in der main passieren. Deine ISR liest die Tasten ein und entprellt sie. Der entprellte Zustand kommt in den Ram (hier ist das sw_state). In deinem eigentlichen Programm (main) interessiert dich die Matrix dann garnicht mehr, weil du einfach aus sw_state den Zustand der Tasten einliest. In main könnte dann durchaus ein Konstrukt stehen, wie du es angedeutet hast: if (sw_state == 0b00000001) Aktion von Taste1 else if (sw_state == 0b00000010) Aktion von Taste2 Zeig mal deinen Sourcecode für eine Spalte. Dann weiß man, wie du das umgesetzt hast und kann konkret dort weiterhelfen. Als grober Anriss: Man liest bei jedem Aufruf der ISR nur eine Spalte ein, deaktiviert sie danach und aktiviert die nächste Spalte. Auf die Weise können sich die Kapazitäten der Matrix umladen, ohne dass man delays braucht. Nicht unbedingt das beste, aber wohl einfachste ist es jetzt, die ersten 2 Spalten erstmal zwischenzuspeichern. Einfach der Wert, der gerade eingelesen wurde. Wenn die dritte Zeile eingelesen wird führt man alle Zustände zusammen in ein longint (? irgendwas mit mindestens 24 bit halt) und führt darauf wieder die debug-routine aus. Schau dir auch mal den Code an, den Peter vorhin gepostet hat. Er hat alles schön aufgeteilt, sodass der Code leicht lesbar wird. Er hat dann ein "modul" zum einlesen der Zustände und vereinen in ein Byte, eines um die Spalten umzuschalten und eines um das ganze dann zu entprellen. Er hat sogar eine 4-fache Statusabfrage drin. @Peter Wenn ich das richtig sehe liest du alle 3 Spalten direkt hintereinander ein. Das kann funktionieren, muss aber nicht. Bei mir ist die Tastenmatrix vielleicht einen halben Meter abgesetzt und es hat nicht funktioniert. Atmel macht in seinen Appnotes deswegen Warteschleifen rein. Dass das Mist ist wissen wir beide. Deshalb würde ich bei jedem ISR-Aufruf nur eine Zeile einlesen. Macht die Software aufwändiger, aber sonst kommts eben zu genau den "Geistertasten" des Threadopeners. Gruß, Sebastian
Sebastian schrieb: > @Peter > Wenn ich das richtig sehe liest du alle 3 Spalten direkt hintereinander > ein. Das kann funktionieren, muss aber nicht. Ich wollts erstmal nicht zu unübersichtlich machen. Ich setze sie auch erst am Ende der Schleife, d.h. da sind noch einige Instruktionen dazwischen bis zur Abfrage. > Bei mir ist die > Tastenmatrix vielleicht einen halben Meter abgesetzt und es hat nicht > funktioniert. Das dürfte dann aber eher Probleme mit dem CE-Zeichen geben. Falls die CPU von der Tastatur abgesetzt werden muß, gönne ich der Tastatur nen eigenen MC, spart dann auch Leitungen. Peter
> Ich wollts erstmal nicht zu unübersichtlich machen. Ja, hatte ich mir schon gedacht. Hab dann aber die andere Version beschrieben, da der OP ja genau mit komischen Tastenereignissen Probleme hatte. Ob die jetzt daher kamen kann ich nicht sagen. Der alte Sourcecode war mir zu unübersichtlich. > Das dürfte dann aber eher Probleme mit dem CE-Zeichen geben. Da ich für meine Privatbasteleien kein CE-Zeichen brauch hab ich da nochmal glück gehabt :-) Hat sich auch nur im Testaufbau so ergeben. Soll später noch näher zusammenrücken. Und so ist die Software wohl störsicherer. Gruß, Sebastian
Sebastian schrieb: > Hab dann aber die andere Version > beschrieben, da der OP ja genau mit komischen Tastenereignissen Probleme > hatte. Ich vermute ja, daß er mal 2 Tasten drückt und es dann zum Kurzschluß kommt, weil er ja nicht auf mich hören will und alle Ausgänge gleichzeitig an läßt. Ob sein Code funktionieren kann, weiß ich nicht. Peter
>P.S.: In Foren ist "Sie" ungebräuchlich.
Bei miar in der Gegend ist das 56k - Modem Zeitalter erst seit 10 Tagen
Vergangenheit also ist meine Forumerfahrung nicht besonders groß;-)
Ich höhre gerne auf jeden der mir weiterhilft. Studiere gerade den Code
von Peter (danke erstmals) und werde mich dann selbst versuchen, endlich
was sinnvolles auf die Reihe zu bringen...
gruß
Stefan
Stefan, du sagst, daß deine Funktion in einer ISR alle 10ms aufgerufen wird, aber selbst ein _delay_ms(5) enthält welches 5 mal ausgeführt wird, also in der Summe 25ms dauert. Wie soll das funktionieren, wenn die ISR noch nicht fertig ist, wenn sie schon wieder aufgerufen wird ? Warum ist das bisher noch niemandem aufgefallen ? Zweitens sagst du, dass du nur alle 10ms die Tastatur abfragen willst. Damit ist eine Taste endweder gedrückt, oder nicht gedrückt. Wenn sie (weniger als 10ms) prellt, mekrt das die Tastaturabfrageroutine nicht, sie sieht die Taste bereits ohne Prellen. Daher ist es überflüssig und eher schädlich, nun noch: "Wenn der Eingang vier mal hintereinander ein high-Signal erkennt gilt die Taste als gedrückt und entprellt." zu versuchen. Sollte die Taste länger als 10ms, sondern 40ms prellen, dann mach deine ISR so, dass sie die Tastatur nur noch alle 50ms abfragt. Du musst nicht entprellen. Warum ist das bisher noch niemandem aufgefallen ? Du musst nur die Tastatur in längeren Intervallen abfragen, als die Tasten maximal prellen, und ebkommst automatisch einen entprellten Tastenzustand. Wenn nun noch die Ausgänge richtig auf Ausgang geschaltet sind und nur der von einer Reihe auf HI liegen, und die Eingaenge mit den 10k PullDown nicht gegen einen eingeschalteten internen PullUp des AVR anarbeiten müssen, dann ist es sogar egal, ob die Ausgänge noch den überflüssigen 10k Widerstand R12..R14 gegen Masse enthalten. Ja, die sind überflüssig. Klüger wäre es natpürlich, PC und PD aus Ausgang zu definieren, dann braucht amn nur die 3 Widerstaende an den dann als Eingang geschalteten PA, und noch klüger wäre es, die eingebauten PullUps des AVR zu verwenden,dann spart man sich alle externen Widerstaende.
>du sagst, daß deine Funktion in einer ISR alle 10ms aufgerufen wird, >aber selbst ein _delay_ms(5) enthält welches 5 mal ausgeführt wird, also >in der Summe 25ms dauert. >Wie soll das funktionieren, wenn die ISR noch nicht fertig ist, wenn sie >schon wieder aufgerufen wird Die ISR kann nicht nocheinmal aufgerufen werden, da zu beginn von dieser die Interrupts global ausgeschlaten und erst nachdem diese abgearbeitet worden ist wider eingeschalten werden. Ok mit den Widerständen känntest Du recht haben ist jetzt aber auch nicht mehr weiter schlimm da sie schon verbuat sind. Ich verstehe nur nicht warum alle von entprellen sprechen, wenn die Sache wirklich so einfach wäre (Timer zur abfrage nur alle 50ms aufrufen)???? @peter Ich hätte noch ein paar Fragen zu Deinem Code, da ich in wirklich geren verstehen möchte: -key_debounce() ist klar damit werden die Tasten entprellt -get_key_row() findet heraus ob überhaupt eine Taste gedrückt wurde, ich verstehe nur nicht wenn das if (row & 1) erfüllt wird und die Schleife abgebrochen? -bei key_scan() habe ich dann ein totales Balckout col = 1<<COL0; verstehe ich überhaupt nicht. Und bedeutet dass key += 8, alle acht bits auf null setzt, was logisch wäre oder bekommt key den Binäerwert von der Dezimalzahl 8?
> wenn die Sache wirklich so einfach wäre
Sie ist es. Wenn Tasten weniger als 50ms prellen, sieht man in Abfragen
die 50ms auseinanderliegen keine prellenden Tasten. Es geht auch mit
10ms, denn kaum eine Taste prellt 10ms.
Wenn du nun noch die richtigen Ports ansprichst, denn dein Schaltplan
passt nicht zum Code.
Der code von Peter funktioniert einwandfrei, auch wenn dabei innerhalb einer ISR alle Zeilen abgefragt werden. Recht herzlichen dank nocheinmal an Peter Wäre Nett wen Du oder jemad mir die weiter oben gestellten Fragen zu deinem Code noch kurz erläutern könnte? Danke nocheinmal Ihr wart echt meine Rettung
stefan schrieb: > -get_key_row() findet heraus ob überhaupt eine Taste gedrückt wurde, ich > verstehe nur nicht wenn das if (row & 1) erfüllt wird und die Schleife > abgebrochen? Ich will die Nummer der ersten gedrückten Taste, d.h. nachdem das Bit 1 war, darf ich nicht mehr weiter zählen. Alle Bits werden nach rechts geschoben, d.h. irgendwann habe ich die 1. Und der Zähler (key) sagt mir dann die Bitnummer. > -bei key_scan() habe ich dann ein totales Balckout col = 1<<COL0; Ich setzte COL0 auf 1. Dann wird nach links geschoben (col <<= 1;) und im nächsten Durchlauf wird damit COL1 = 1 usw. > Und bedeutet dass key += 8 Die Reihenerkennung liefert immer nur 1..8, dazu muß ich je nach Spalte dann 0, 8 oder 16 addieren. Welche Taste nun welchen Wert hat, ist nebensächlich, daß macht man dann später mit ner Lookuptable wie man es wünscht. Peter
Erleuchtung;-) Super danke jetzt hab sogar ich verstanden Nochmals vielen dank an alle
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.