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.
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.
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
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).
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