Hallo,
da ich mich demnächst mit einer 4x4-Matrixtastatur beschäftigen werde,
habe ich Peter Danneggers Entprellroutine für eine 4x4 Matrixtastatur
samt ein paar Änderungen, die hier im Forum zu finden sind, für das
AVR-Studio 4 mit AVRgcc und dem ATmega8 zusammengefügt.
Hoffentlich bekomme ich von ihm keine Haue... ;)
Vielen Dank, Peter, für die Entprellroutine!
Die ist so tricky, dass ich noch nicht ganz dahinter gekommen bin, aber
dazu gibt es ja unmengen an Erklärungen hier im Forum!
Nach dem Compilieren erhalte ich:
1
AVR Memory Usage
2
----------------
3
Device: atmega8
4
5
Program: 828 bytes (10.1% Full)
6
(.text + .data + .bootloader)
7
8
Data: 15 bytes (1.5% Full)
9
(.data + .bss + .noinit)
10
11
12
Build succeeded with 0 Warnings...
Keine Warnungen, keine Fehler, das ist schon mal sehr gut! :)
Aber: Würde der Code auch so funktionieren?
Bin mir nicht 100%-ig sicher, ob vor allem die Funktion key_scan(void)
richtig funktioniert.
Im Anhang ist der Quellcode von Version 0.1 samt Kommentar.
Besten Dank,
Marc
Im Prinzip ist das Peter Daneggers Code.
Soll er sich um seinen Verhau kümmern.
Der Code basiert darauf, daß Tasten, die abgefragt wurden,
abgeholt worden sind, d.h. es ist nicht mehr vermerkt daß
es ein Ereignis mit ihnen gab.
Wenn man also Taste KEY1 auf key_press abfragte, muss man sich nicht
mehr wundern, wenn sie auf key_short keine Antwort mehr liefert.
Der Code an sich funktioniert also, bloss ob du ihn richtig
verwendest...
Das Windows API mit Ereignissen wie WM_KEYDOWN etc. zeigt, wie man es
besser gemacht hätte.
MaWin schrieb:> Im Prinzip ist das Peter Daneggers Code.> Soll er sich um seinen Verhau kümmern.
Ja, genau! Den Code wollte ich so wenig wie möglich verändern.
Dieser Code ist nicht aus meinem Hirnschmalz entstanden, sondern er
gehört zum größten Teil PeDa.
Aber auf die Haue von ihm freue ich mich schon! ;)
Ich wollte mit dem Code etwas universelles schreiben, denn hier im Forum
habe ich zu seiner Entprell-Routine viele Fragen und Antworten gelesen.
Um es einfacher zu machen, habe ich versucht die relevanten Funktionen
in eine C-Datei zu packen.
Leider habe ich keinen Code für eine 4x4-Matrixtastatur gefunden, darum
musste ich mir diesen zusammenbasteln (copy & paste).
MaWin schrieb:> Der Code basiert darauf, daß Tasten, die abgefragt wurden,> abgeholt worden sind, d.h. es ist nicht mehr vermerkt daß> es ein Ereignis mit ihnen gab.
Das macht Sinn, habe es auch so verstanden.
MaWin schrieb:> Wenn man also Taste KEY1 auf key_press abfragte, muss man sich nicht> mehr wundern, wenn sie auf key_short keine Antwort mehr liefert.
Okay, dann ist die for(;;)-Schleife in der main wohl etwas unglücklich
gestaltet:
1
for(;;)
2
{
3
if( get_key_press( 1<<KEY0 ))
4
;; // do something @ single press
5
6
if( get_key_short( 1<<KEY1 ))
7
;; // release after short press: task 1, long press: task 2
Allerdings, wenn man eine Eingabe-Funktion schreibt, benötigt man doch
sowieso nicht alle if-Bedingungen, die oben erwähnt werden.
Eine davon reicht doch z.B. für eine do-while-Schleife aus?!
> Der Code an sich funktioniert also, bloss ob du ihn richtig> verwendest...
Ja, genau das ist die Frage...
Man könnte doch versuchen gemeinsam den Code 100%-ig lauffähig zu machen
und ihn dann in die Codesammlung stellen, damit die geschätzen 1 Mio.
(Such-)Einträge zu dieser Funktion nicht auf 2 Mio. anwachsen! ;)
Gruß,
Marc
MaWin schrieb:> Das Windows API mit Ereignissen wie WM_KEYDOWN etc. zeigt, wie man es> besser gemacht hätte.
Besser nicht unbedingt, aber erheblich verschwenderischer.
Man muß schon unterscheiden, ob etwas auf einem zich GByte-System laufen
soll oder auch auf einem ATtiny13 mit nur 0,000.000.064 GByte RAM.
Und mit 64Byte SRAM wird es eben knapp mit OS, Multitasking und
Sanduhren.
Deshalb der Verzicht auf ne Queue die sich uralte Ereignisse merkt,
sondern die Beschränkung auf ein Ereignis pro Taste.
In der Regel können MC-Mainloops auch hinreichen kurz gehalten werden,
daß man keine Sanduhren einblenden muß und die Ereignisse sich stapeln.
Peter
MaWin schrieb:> Wenn man also Taste KEY1 auf key_press abfragte, muss man sich nicht> mehr wundern, wenn sie auf key_short keine Antwort mehr liefert.
Tut er ja auch nicht.
Er nimmt verschiedene Tasten und das funktioniert einwandfrei.
Peter
Peter Dannegger schrieb:> Er nimmt verschiedene Tasten und das funktioniert einwandfrei.
Später soll mit einer do-while-Schleife immer nur ein Tastendruck
erkannt werden, eine Repeat-Funktion brauche ich eigentlich gar nicht.
Habe diese aber mit übernommen, damit das Ganze universeller wird.
@PeDa:
Bekomme ich noch Haue von dir?
Tut mir leid, dass ich deinen Code etwas erweitert habe hier
"verteile"...
Gruß,
Marc
Peter Dannegger schrieb:> KEY_DDR = 1<<KEY_ROW1;> mal überdenken.
Hhm, ich wollte mich bzw. dich nicht verwirren und fange (aus
menschlicher Sicht) bei Reihe 1 an zu zählen, also nicht von KEY_ROW0
bis KEY_ROW3, sondern von KEY_ROW1 bis KEY_ROW4:
1
#define KEY_ROW1 PORTC0
2
#define KEY_ROW2 PORTC1
3
#define KEY_ROW3 PORTC2
4
#define KEY_ROW4 PORTC3
5
#define KEY_COL1 PORTC4
6
#define KEY_COL2 PORTC5
7
#define KEY_COL3 PORTC6
8
#define KEY_COL4 PORTC7
Somit dürfte doch KEY_DDR = 1<<KEY_ROW1; richtig sein, oder nicht?
Weiß nicht, worauf du hinaus möchtest.
Peter Dannegger schrieb:> Der Rest sieht vollkommen o.k. aus.
Danke! Hoffentlich kann ich es bald testen.
Bin ja gerade noch bei meinem Kumpel und er hat eine 4x4-Tastaturmatrix
rumliegen.
Werde es morgen mal an der Hardware testen, sofern ich dazu komme.
Kann man bereits jetzt schon bestimmen, welches Bit zu welcher Taste
gehört?
Peter Dannegger schrieb:> #define KEY_ROW1 PORTC0> ...> KEY_DDR = 1<<KEY_ROW1;> ...> keys = (keys << 4) | (KEY_PIN & 0x0F);>> Was denkst Du, liest Du damit ein?
Die Spalten, hoffe ich doch, von PC4 bis PC7.
Hhm, die Variable keys ist ja 16 Bit breit und wird auf 0 initialisiert.
Also steht am Anfang:
keys = 0b0000000000000000:
Mit (keys << 4) schiebe ich die niederwertigsten Bits um 4 nach links
und verodere mit 0x0F von PINC.
Okay, irgendwas sagt mir jetzt, dass da etwas mit der Anweisung
1
keys=(keys<<4)|(KEY_PIN&0x0F);
nicht stimmt.
Ich möchte sowas in der der Art haben:
1
keys = 0b 0000 0000 0000 0000
2
COL4 COL3 COL2 COL1
Muss ich erstmal um 0 nach links verschieben, danach erst jeweils um 4?
Also quasi:
Marc L. schrieb:>> keys = (keys << 4) | (KEY_PIN & 0x0F);>>>> Was denkst Du, liest Du damit ein?> Die Spalten, hoffe ich doch, von PC4 bis PC7.
Die sind aber nach (KEY_PIN & 0x0F) weg.
Peter
Marc L. schrieb:> Muss ich erstmal um 0 nach links verschieben, danach erst jeweils um 4?
Ich muss mich selbst korrigieren. Es ist doch Quatsch, wenn ich am
Anfang auf das Verschieben verzichte, denn ob ich nun alle Nullen
verschiebe oder nicht, ist doch egal. Nullen bleiben Nullen.
Peter Dannegger schrieb:> #define KEY_ROW1 PORTC0> ...> KEY_DDR = 1<<KEY_ROW1;> ...> keys = (keys << 4) | (KEY_PIN & 0x0F);
Ich hoffe, ich hatte in der Nacht den richtigen Einfall und müsste den
Code folgendermaßen ändern:
1
staticinlineuint16_tkey_scan(void)
2
{
3
uint16_tkeys=0;
4
uint8_ti;
5
6
KEY_DDR=1<<KEY_ROW1;
7
for(i=4;i;i--){
8
keys=(keys<<4)|(KEY_PIN&0xF0);// <----------
9
KEY_DDR<<=1;
10
}
11
return~keys;
12
}
Das meintest du, nicht wahr, PeDa?
Außerdem ist mir ein ganz großer Fehler im ersten Posting passiert.
Der ATmega8 hat gar kein PC7, geht nur bis PC6, und das ist auch noch
der RESET-Pin.
Im Anhang ist eine geänderte Version des Quelltextes aus dem Urposting:
PortD statt PortC wird nun verwendet.
Gruß,
Marc
Hallo,
anbei die Version 0.3 - diesmal für einen ATmega16.
Diesen Code habe ich mit Proteus (Softwaresimulator) getestet,
funktioniert 1A und sollte also auch auf der Hardware laufen.
Vielleicht kann es ja einer gebrauchen...
Danke PeDa für die Hilfestellung und deinen tricky Code! :)
Gruß,
Marc
PS: Für Hinweise und weitere Tipps habe ich immer ein Ohr offen!