Pfad:
Home =>
AVR-DE =>
Anwendungen =>
Schalter und Tasten am ADC => Tastenfelder
This page in English:
 |
Anwendungen von
AVR-Einchip-Mikrokontrollern AT90S, ATtiny, ATmega und ATxmega
Tastenfelder an einem ADC-Eingang
|
Anschluss einer 12-er-Tastatur an einen AVR
Diese Seite zeigt, wie eine handelsübliche 12-er-Tastatur an
einen AVR angeschlossen und per Assembler-Software ausgelesen
werden kann. Die Abschnitte:
- Funktionsweise der Tastatur
- AVR: I/O-Anschlussmatrix einzeln
- AVR: Anschluss an einen ADC mit Widerstands-Matrix
12-er-Tastaturen sind Schalter, die über eine Matrix von
Zeilen (Rows) und Spalten (Columns) miteinander verbunden sind.
Wird die Taste "1" gedrückt, dann ist die Spalte 1 mit der
Zeile 1 verbunden, ist "2" gedrückt, dann Spalte 2 mit Reihe
1, usw..
Um herauszufinden, ob irgendeine der 12 Tasten gedrückt ist,
würde es reichen, die drei Spalten mit Null Volt zu verbinden
und die vier Zeilen zu verbinden und über einen Pull-Up-Widerstand
von z.B. 10 kΩ mit Plus zu verbinden. Der Output hat
ohne gedrückte Taste Plus-Potential. Jede gedrückte
Taste bewirkt dann, dass der Output auf Null Volt gezogen wird.
Um auch noch fest zu stellen, welche der 12 Tasten gedrückt
ist, wären z.B. nacheinander die drei Spaltenanschlüsse auf
Null Volt zu bringen (die beiden anderen jeweils auf Plus) und
das Ergebnis an den vier Zeilenanschlüssen abzulesen. Ist
einer der vier Zeilenanschlüsse auf Null, muss die Maschinerie
anhalten und den aktuellen Spaltenanschluss sowie das Ergebnis
der Zeilenanschlüsse in den Code einer gedrückten Taste
umwandeln. Etwa so:
Spalte | Zeile | Taste |
Spalte 1 | Spalte 2 | Spalte 3 | Zeile 1 | Zeile 2 |
Zeile 3 | Zeile 4 | Zeichen | Binärcode |
0 | 0 | 0 | 1 | 1 | 1 | 1 |
(Keins) | 1111 |
0 | 1 | 1 | 0 | 1 | 1 | 1 |
1 | 0001 |
1 | 0 | 1 | 0 | 1 | 1 | 1 |
2 | 0010 |
1 | 1 | 0 | 0 | 1 | 1 | 1 |
3 | 0011 |
0 | 1 | 1 | 1 | 0 | 1 | 1 |
4 | 0100 |
1 | 0 | 1 | 1 | 0 | 1 | 1 |
5 | 0101 |
1 | 1 | 0 | 1 | 0 | 1 | 1 |
6 | 0110 |
0 | 1 | 1 | 1 | 1 | 0 | 1 |
7 | 0111 |
1 | 0 | 1 | 1 | 1 | 0 | 1 |
8 | 1000 |
1 | 1 | 0 | 1 | 1 | 0 | 1 |
9 | 1001 |
0 | 1 | 1 | 1 | 1 | 1 | 0 |
* | 1010 |
1 | 0 | 1 | 1 | 1 | 1 | 0 |
0 | 0000 |
1 | 1 | 0 | 1 | 1 | 1 | 0 |
# | 1011 |
Um eine solche Tastatur mit diskreten Bauteilen auslesbar zu machen, braucht
es mindestens:
- einen Oszillator mit Schieberegister und Start/Stop zur Erzeugung der
Spaltensignale,
- Feststellung, ob einer der vier Zeilenanschlüsse Null ist,
- Umkodierer für die Auswertung der sieben Signale.
Oder ein fertiges IC, das das alles macht (aber das man gar nicht im
Versandhandel kriegt). Oder eben einen Mikrokontroller.
An den Seitenanfang
Eine Tastaturmatrix kann so direkt und ohne weitere Bauteile an einen
Mikrokontroller angeschaltet werden.
Im Beispiel sind dies die unteren sieben I/O-Pins des Ports B. Andere
Ports lassen sich ebenso verwenden.
Die Portpins PB4..PB6 werden als Ausgänge definiert und liefern die
Spalten-Nullen. Die Portpins PB0..PB3 dienen zum Einlesen der
Zeilenergebnisse. Die Pull-Up-Widerstände der Ports PB0..PB3 werden
per Software zuschaltet (DDRn = 0, PORTn = 1), externe Widerstände
sind unnötig.
Das folgende Software-Beispiel zeigt zunächst das Initiieren der
Ports. Sie wird nur ein Mal zu Beginn des AVR-Programms ausgeführt.
2.1 Init-Routine
;
; Init Keypad-I/O
;
.DEF rmp = R16 ; ein Hilfsregister definieren
; Ports definieren
.EQU pKeyOut = PORTB ; Ausgabe und Pull-Ups
.EQU pKeyInp = PINB ; Tastatur lesen
.EQU pKeyDdr = DDRB ; Datenrichtungsregister
; Init-Routine
InitKey:
ldi rmp,0b01110000 ; Datenrichtungsregister
out pKeyDdr,rmp ; des Keyports setzen
ldi rmp,0b00001111 ; Pull-Up-Widerstände
out pKeyOut,rmp ; an den Eingängen
2.2 Tastendruck feststellen
Die folgende Routine stellt zunächst fest, ob irgendeine
der Tasten gedrückt ist. Sie wird im Programmverlauf regelmäßig
wiederholt, z.B. in einer Verzögerungsschleife oder Timer-gesteuert.
;
; Check any key pressed
;
AnyKey:
ldi rmp,0b00001111 ; PB4..PB6=Null, pull-Up-Widerstände
out pKeyOut,rmp ; an den Eingängen PB0..PB3
in rmp,pKeyInp ; Tastaturport lesen
ori rmp,0b11110000 ; alle oberen Bits auf Eins
cpi rmp,0b11111111 ; alle Bits = Eins?
breq NoKey ; ja, keine Taste gedrückt
2.3 Gedrückte Taste feststellen
Ist irgendeine der Tasten gedrückt, ist jetzt der Auslesevorgang
am dransten. Nacheinander werden PB6, PB5 und PB4 Null gesetzt und
PB0..PB3 auf Nullen geprüft. Das Registerpaar
Z (ZH:ZL) zeigt dabei auf eine Tabelle mit den Tastencodes. Es zeigt
am Ende auf den identifizierten Tastencode, der mit der Instruktion
LPM aus dem Flash-Memory in das Register R0 gelesen wird.
;
; Identifiziere gedrueckte Taste
;
ReadKey:
ldi ZH,HIGH(2*KeyTable) ; Z ist Zeiger auf Tastencode
ldi ZL,LOW(2*KeyTable)
; read column 1
ldi rmp,0b00111111 ; PB6 = 0
out pKeyOut,rmp
in rmp,pKeyInp ; lese Zeile
ori rmp,0b11110000 ; obere Bits maskieren
cpi rmp,0b11111111 ; ein Key in dieser Spalte?
brne KeyRowFound ; Spalte gefunden
adiw ZL,4 ; Spalte nicht gefunden, Z vier Keys weiter
ldi rmp,0b01011111 ; PB5 = 0
out pKeyOut,rmp
in rmp,pKeyInp ; wieder Zeile lesen
ori rmp,0b11110000 ; obere Bits maskieren
cpi rmp,0b11111111 ; ein Key in dieser Spalte?
brne KeyRowFound ; Spalte gefunden
adiw ZL,4 ; Spalte nicht gefunden, Z vier Keys weiter
ldi rmp,0b01101111 ; PB4 = 0
out pKeyOut,rmp
in rmp,pKeyInp ; letzte Zeile lesen
ori rmp,0b11110000 ; obere Bits maskieren
cpi rmp,0b11111111 ; ein Key in dieser Spalte?
breq NoKey ; wider Erwarten auch hier nicht gefunden
KeyRowFound: ; Spalte ist gefunden, identifiziere Zeile
lsr rmp ; schiebe Bit 0 in das Carry-Flag
brcc KeyFound
adiw ZL,1 ; zeige auf naechsten Tastencode
rjmp KeyRowFound ; weiter schieben
KeyFound:
lpm ; lese keycode nach R0
rjmp KeyProc ; hier weiter mit Key-Verarbeitung
NoKey:
rjmp NoKeyPressed ; keine Taste gedrueckt
;
; Tabelle fuer Code Umwandlung
;
KeyTable:
.DB 0x0A,0x07,0x04,0x01 ; Erste Spalte, Tasten *, 7, 4 und 1
.DB 0x00,0x08,0x05,0x02 ; Zweite Spalte, Tasten 0, 8, 5 und 2
.DB 0x0B,0x09,0x06,0x03 ; Dritte Spalte, Tasten #, 9, 6 und 3
2.4 Entprellen
In den Routinen KeyProc und NoKeyPressed muss natürlich
noch ein Entprellen der Tasten erfolgen. Also z.B. muss in der
KeyProc-Routine eine Tastenoperation erst dann ausgeführt
werden, wenn die gleiche Taste 50 Millisekunden lang gedrückt
ist. In der NoKeyPressed-Routine kann der dazu verwendete Zähler
zurück gesetzt werden. Da das Timing der Entprellung auch noch
von anderen Bedürfnissen abhängig sein kann, ist es hier
nicht eingearbeitet.
2.5 Hinweise, Nachteile
In den Software-Beispielen ist zwischen der Ausgabe der Spalten-Adresse
und dem Einlesen der Zeilen-Information nur ein Takt Zeit gelassen.
Bei hohen Taktfrequenzen und/oder langen Leitungen zwischen Tastatur
und Prozessor ist es notwendig, zwischen den Out- und In-Instruktionen
mehr Zeit zu lassen (z.B. durch Einfügen von NOP-Instruktionen).
Die internen Pull-Ups liegen bei Werten um 50 kΩ. Bei langen
Leitungen und in hoch feldverseuchter Umgebung (bei Funkamateurs zu
Hause) kann es unter Umständen zum Fehlansprechen der Tastatur
kommen. Wer es weniger sensibel haben will, kann noch externe Pull-Ups
dazu schalten.
Der Nachteil der Schaltung ist, dass sie sieben Port-Leitungen
exklusiv benötigt. Die Lösung über einen AD-Wandler-Kanal
und ein Widerstands-Netzwerk (Abschnitt 3) ist da viel sparsamer.
An den Seitenanfang
Die meisten Tiny- und Mega-AVR-Typen haben heutzutage AD-Wandler an Bord.
Sie sind daher ohne größere Klimmzüge dazu in der Lage,
Analogspannungen zu messen und mit bis zu 10 Bits Genauigkeit aufzulösen
(Genauigkeit ca. 1 Promille). Wer also I/O-Ports sparen will (oder muss),
muss die Tastatur nur dazu bringen, ein Analogsignal zu liefern. Das macht
z.B. eine Widerstandsmatrix.
3.1 Widerstandsmatrix
Hier ist eine solche Widerstandsmatrix abgebildet. Die Spalten sind über
drei Widerstände auf Masse geführt, die Zeilen über vier
Widerstände auf die Betriebsspannung (z.B. 5V). Der AD-Wandler-Eingang
ist noch mit einem Folienkondensator von 1 nF abgeblockt, da der
ADC absolut keine Hochfrequenz mag, die da über die Tasten, die
Widerstände und die Zuleitungen eingestreut werden könnte.
Wird jetzt z.B. die Taste "5" gedrückt, dann entsteht ein
Spannungsteiler:
- a) 1 k + 820 Ω = 1,82k nach Masse,
- b) 3,3 k + 680 Ω + 180 Ω = 4,16k
nach Plus.
Bei 5 Volt Betriebsspannung gelangen dann
UADC = 5 * 1,82 / (1,82 + 4,16) = 1,522 Volt
an den AD-Wandler-Eingang. Rechnen wir noch 5% Toleranz der Widerstände
mit ein (jeweils nach unten und oben), dann liegt die Spannung irgendwo
zwischen 1,468 und 1,627 Volt. Der AD-Wandler macht daraus bei 5 V
Betriebs- und Referenzspannung einen Wert zwischen 300 bis 333. Verwenden wir
nur die oberen 8 Bit des AD-Wandler-Ergebnisses (Teilen durch vier oder
Linksjustieren des Wandlers), gibt das 74 bis 78.
3.2 Spannungswerte der Widerstandsmatrix
Die Matrix verwendet Widerstände der E12-Reihe, die überall
erhältlich sind. Daher rühren einerseits die krummen Werte.
Die unterschiedlichen Widerstandswerte, aus denen die Matrix aufgebaut ist,
resultieren aus der Anforderung, dass die Spannungen, die sich aus der Teilung
ergeben, den verfügbaren Spannungsbereich mögklichst gleichmäßig
auf die zwölf Tasten verteilen sollen, so dass sich für jede Taste
eine spezifische Spannung ergibt, die möglichst viel Abstand zur nächsten
und vorherigen Taste aufweist. Die hier verwendeten Widerstandswerte machen dies.
Noch ein Hinweis für diejenigen, die immer glauben, die Welt lasse sich mit
ein paar wenigen Formeln beschreiben und Herumprobieren sei unnötig: an diesem
Problem werdet Ihr Euch die Zähne gehörig ausbeißen. 12 Unbekannte,
und die auch noch ausschließlich aus der E12-Reihe, und dann noch 5% Toleranz,
das dürfte auch den gewieftesten Formelcracker in die Verzweiflung treiben.
Hier ist die Tabelle für die Matrix mit den dargestellten Widerstandswerten.
In der ersten Spalte die gedrückte Taste, in der zweiten Spalte der Widerstandswert,
der sich nach Masse hin ergibt. In der dritten Spalte der Widerstandswert, der sich
nach Plus ergibt.
Die Spannung, die aus den jeweiligen Teilern resultiert, ergibt sich aus der Formel
U = Uref * RMasse / (RMasse + RPlus)
Da die käuflichen Widerstände eine Toleranz von +/-5% haben, muss noch die
minimale und die maximale Spannung berechnet werden. Das Minimum ergibt sich, wenn die
Widerstände nach Masse alle 5% unter ihrem Nominalwert liegen und gleichzeitig
alle Widerstände nach Plus 5% über ihrem Nominalwert haben. Das ist
zwar nicht realistisch, aber wir wollen ja nicht alle Widerstände einzeln aussuchen
und bei Sommer- und Wintertemperaturen ausmessen.
| Widerstandsteiler | Spannungen | ADC-Wandlerwerte |
Taste | Widerstand nach Masse Ohm | Widerstand nach Plus Ohm | U Nominell @5V | U Min @5V | U Max @5V | N Nom @8Bit | N Min @8Bit | N Max @8Bit |
1 | 1000 | 19160 | 0,248 | 0,225 | 0,273 | 13 | 11 | 14 |
2 | 1820 | 19160 | 0,434 | 0,396 | 0,475 | 22 | 20 | 25 |
3 | 2820 | 19160 | 0,641 | 0,588 | 0,700 | 33 | 30 | 36 |
4 | 1000 | 4160 | 0,969 | 0,893 | 1,050 | 50 | 45 | 54 |
5 | 1820 | 4160 | 1,522 | 1,418 | 1,630 | 78 | 72 | 84 |
6 | 2820 | 4160 | 2,020 | 1,901 | 2,142 | 103 | 97 | 110 |
7 | 1000 | 860 | 2,688 | 2,563 | 2,812 | 138 | 131 | 144 |
8 | 1820 | 860 | 3,396 | 3,285 | 3,503 | 174 | 168 | 180 |
9 | 2820 | 860 | 3,832 | 3,740 | 3,919 | 196 | 191 | 201 |
* | 1000 | 180 | 4,237 | 4,170 | 4,300 | 217 | 213 | 221 |
0 | 1820 | 180 | 4,550 | 4,507 | 4,589 | 233 | 230 | 235 |
# | 2820 | 180 | 4,700 | 4,671 | 4,727 | 241 | 239 | 243 |
Die den Tasten zugeordneten Spannungswerte mit den jeweiligen Toleranzbereichen sind
in der Grafik dargestellt.
Wie zu sehen ist, macht sich die Toleranz der Widerstände nur bei den mittleren
Tasten bemerkbar.
Ergänzt ist die Tabelle noch um diejenigen Werte, die sich beim Messen mit dem AD-Wandler
ergeben. Da alle Wertebereiche ausreichend weit auseinander liegen, reicht dazu ein 8-Bit-Wandler.
Diese beiden Schaltungen sind etwas anders gestrickt: die unteren vier
Widerstände (im Bild links) an den vier Reihen der Tastatur sind
gestapelt geschaltet, während die oberen drei bzw. vier Spalten
über einzelne Widerstände nach Plus führen. Dasselbe
Prinzip, nur addieren sich die oberen Widerstände nicht.
Bei der 12-er-Tastatur ergeben sich mit 5%-E12-er Widerständen
die gezeigten Näherungsergebnisse: es gibt keine Überlappungen
und die Tastenreihung "147*2580369#" ist auch korrekt.
Und so sehen die Spannungen aller Tasten aus. Alles einigermaßen
gleich verteilt, und die in der Mitte recht großen Toleranzbereiche
liegen auch nirgends übereinander.
Und so sehen die Spannungen bei einer 16-er-Tastatur aus, bei der es
nötig war, 1%-Widerstände zu verwenden, damit keine
Überlappungen auftreten. Hier sind die Toleranzbereiche nur in
der Mitte etwas größer, aber auch wesentlich weniger
ausgeprägt als mit 5%.
Alle Grafiken hier wurden mit der Version 2.7 des AVR-Simulators
avr_sim angefertigt, der
auch einen fortgeschrittenen Widerstandsmatrix-Berechner enthält.
3.3 Spannungswerte und Auswertung
Wie zu erkennen ist, gibt es bei der Verwendung von 5%-Widerständen
und der dargestellten Widerstandskombination keine Überlappungen der
Spannungsbereiche der einzelnen Tasten.
Wer andere Widerstandskombinationen ausprobieren möchte, kann mit der
zugehöigen Tabelle herumspielen
(im Open-Office-Format,
im Excel-XP-Format).
Hier
gibt es ein komfortables Kommandozeilen-Programm, das das viel schöner
erledigt, und
hier gibt es sogar
eine grafische Anwendung, die das noch viel schöner erledigt. Beide
Programme können auch 4 * 4-Tastenfelder.
3.4 Hinweise zur AD-Wandler-Hardware
ATtiny-Typen bieten meist nur die Möglichkeit, eine intern erzeugte
Konstantspannung oder die Betriebsspannung als Referenzspannung des
AD-Wandlers zu wählen. Für die Tastaturschaltung kommt nur die
Betriebsspannung als Referenzspannung infrage. Diese Option ist beim
Initiieren des AD-Wandlers einzustellen.
Bei vielen ATmega-Typen kann auch eine extern erzeugte Referenzspannung
verwendet werden, die am Pin AREF zugeführt wird. Verwendet man
diese Möglichkeit, wäre auch die Tastaturschaltung aus dieser
Referenz zu speisen. Verwendet man keine externe Referenzspannung, dann
kommt für den Betrieb der Tastatur nur die Möglichkeit der
Verwendung der Betriebsspannung als Referenzspannung infrage. In diesem
Fall wird die Betriebsspannung per Software-Option intern an den AREF-Pin
geführt, der externe AREF-Pin wird mit einem Folienkondensator von
ca.10 nF abgeblockt.
ATmega-Typen bieten zur Erhöhung der Stabilität des AD-Wandlers
ferner die Möglichkeit, diesen über den AVCC-Pin separat zu
bespeisen. Für die Tastaturschaltung alleine kann dieser Pin direkt
an die Betriebsspannung angeschlossen werden. Sollen auch noch andere
Messungen veranstaltet werden, bei denen genauer gemessen werden soll,
wird der AVCC-Pin über eine Drossel von 22 µH an die
Betriebsspannung geführt und mit einem Keramikkondensator von
100 nF gegen Masse abgeblockt.
3.5 Initiieren und Lesen des AD-Wandlers
Zum Auslesen der Tastatur wird ein AD-Wandler-Kanal gebraucht. Der
AD-Wandler wird zu Beginn eingestellt. Die beiden Beispiele zeigen
den manuellen Einzelstart eines ATmega8 und den interrupt-gesteuerten
Dauerstart bei einem ATtiny13.
3.5.1 ATmega8: manuell starten
Als erstes Beispiel ein ATmega8, ohne Interrupts, mit manuellem Start
und Stop des AD-Wandlers. Das Tastatursignal liegt am AD-Kanal ADC0.
.DEF rKey = R15 ; Register fuer AD-Wert
.DEF rmp = R16 ; Vielzweck-Register
; setze MUX auf Kanal 0, Linksjustieren, AREF auf AVCC
ldi rmp,(1<<REFS0)|(1<<ADLAR) ; ADMUX Kanal 0, AREF auf AVCC
out ADMUX,rmp
; AD-Wandler einschalten, Wandlung starten, Teilerrate = 128
ldi rmp,(1<<ADEN)|(1<<ADSC)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)
out ADCSRA,rmp
; warten bis AD-Wandler fertig mit Wandlung ist
WaitAdc1:
; ADSC-Bit abfragen, wenn Null ist Wandlung fertig
sbic ADCSRA,ADSC ; Wandlung beendet?
rjmp WaitAdc1 ; noch nicht
; AD-Wandler-Wert MSB lesen
in rKey,ADCH
; AD-Wandler wieder abschalten
ldi rmp,(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0) ; ADC aus
out ADCSRA,rmp
Man beachte, dass diese eine Wandlung 25 * 128 Takte dauert, also bei
1 MHz Prozessortakt 3,2 Millisekunden. Das macht man nur, wenn sonst
nichts Wichtiges anderes zu tun ist als im Kreis herum zu laufen.
3.5.2 ATtiny13: Autostart AD-Wandlung, Interrupt-gesteuert
Ja, auch ein ATtiny13 kann unsere Tastaturmatrix einlesen (das wäre
mangels Pins bei der Einzelbedrahtung gar nicht möglich).
Eine typische Routine hierfür wäre für den ATtiny13
beispielsweise die folgende Sequenz, bei der ADC3 an Pin 2 des tiny13
im Dauerlauf (der AD-Wandler beginnt nach der Umwandlung von selbst
wieder) gestartet wird.
;
; AD-Wandler starten
;
; PB3=ADC3 wird nur fuer den AD-Wandler verwendet
ldi rmp,0b00001000 ; PB3 Digitaltreiber ausschalten, spart Strom
out DIDR0,rmp
; Referenz = Betriebsspannung, Links-Justieren Ergebnis,
; ADMUX auf ADC3 stellen
ldi rmp,0b00100011 ; Referenzspannung UB, ADC3 waehlen
out ADMUX,rmp
; Autostart-Option waehlen
ldi rmp,0b00000000 ; Freilauf waehlen (startet selbst)
out ADCSRB,rmp
; ADC starten, Interrupt ermoeglichen, Teilerrate einstellen
ldi rmp,0b11101111 ; ADC starten, Autostart,
out ADCSRA,rmp ; Int Enable, Teiler auf 128
; fertig initiiert
Der Betrieb per Interrupt setzt voraus, dass der entsprechende Sprungvektor
vorhanden ist, also z.B.
;
; Sprungvektoren fuer Reset und Interrupts, ATtiny13
;
.CSEG ; Assembliere in das Code Segment
.ORG $0000 ; an den Anfang des Code Segments
rjmp main ; Reset vector
reti ; Int0 interrupt vector
reti ; PCINT0 vector
reti ; TC0 overflow vector
reti ; Eeprom ready vector
reti ; Analog comparator int vector
reti ; TC0 CompA vector
reti ; TC0 CompB vector
reti ; WDT vector
rjmp intadc ; ADC conversion complete vector
;
Natürlich muss auch der Stapel initiiert sein und das Interrupt-
Statusflag gesetzt sein (SEI).
Die Service-Routine intadc liest den AD-Wandler aus. Da Links-Justieren
gesetzt ist, reicht es, das MSB des Ergebnisses zu lesen:
;
; Interrupt Service Routine AD-Wandler
;
.DEF rKey = R15 ; Ergebnisspeicher AD-Wandler-Wert
intadc:
in rKey,ADCH ; Lese AD-Wandler MSB
reti ; Rückkehr vom Interrupt
;
Im Register rKey steht jetzt laufend aktuell der Wandlerwert des Keyboards.
3.6 Umwandeln des AD-Wandler-Werts in einen Tastencode
Die Spannung alleine ist noch nicht sehr verwendungsfähig. Da die
Spannungen aufgrund der eigenwilligen Gestaltung von
Standard-Widerstandswerten (wer hat sich die Reihe 4,7 - 5,6 - 6,8 - 8,2)
bloß ausgedacht? Muss entweder ziemlich sturzbetrunken oder ein
Mathematiker gewesen sein!) und der arg krummen Formel
U = R1 / (R1 + R2) kommt hierfür nur
eine Tabelle in Betracht. Die Tabelle kann nicht primitiv sein, da wir
ja 256 mögliche ADC-Zustände haben und keine unnötige
Platzverschwendung betreiben wollen.
Wir hangeln uns mit dem ADC-Wert in rKey durch folgende Tabelle:
KeyTable:
.DB 7, 255, 18, 1, 28, 2, 42, 3, 64, 4, 91, 5
.DB 121, 6, 156, 7, 185, 8, 207, 9, 225, 10, 237, 0, 255, 11
Das niedrige erste Byte jedes Worts sind jeweils die AD-Werte: von 0 bis
<7: keine Taste gedrückt (Tastencode=255), von 7 bis <18:
Tastencode 1, etc..
Oder wer lieber gleich ASCII mag:
KeyTable:
.DB 7, 0 , 18, '1', 28, '2', 42, '3', 64, '4', 91, '5'
.DB 121, '6', 156, '7', 185, '8', 207, '9', 225, '*', 237, '0', 255, '#'
Der Code zur Auswertung sieht dann so aus:
;
; Umwandlung des AD-Werts in einen Keycode
;
GetKeyCode:
; falls der AD-Wert zwischendurch wechselt, vorher kopieren!
mov R1,rKey ; kopiere AD-Wandler-Wert nach R1
ldi ZH,HIGH(2*KeyTable) ; Z zeigt auf Tabelle
ldi ZL,LOW(2*KeyTable)
GetKeyCode1:
lpm ; Lese Wert aus Tabelle
cp R1,R0 ; vergleiche AD-Wert mit Tabellenwert
brcs GetKeyCode2 ; kleiner als Tabellenwert, Taste gefunden
inc R0 ; teste, ob am Tabellenende
breq GetKeyCode2 ; Tabellenende erreicht
adiw ZL,2 ; huepfe ein Wort weiter in der Tabelle
rjmp GetKeyCode1
GetKeyCode2:
adiw ZL,1 ; zeige auf MSB = Tastencode
lpm ; lese Tastencode aus Tabelle in R0
;
Natürlich ist jetzt noch zu prüfen, ob keine Taste gedrückt
ist (R0 = 0xFF bzw. bei ASCII: R0 = 0) und es sind Anti-Prell-Aktionen zu
basteln (wenn 20 mal hintereinander die gleiche Taste herauskommt, nehme
ich sie ernst, etc.).
3.7 Erfahrungen
Die Schaltung und die Software sind sehr stabil. In der ersten Version
waren die Widerstände 10 mal so groß. Das hatte höhere
Störanfälligkeit zur Folge, z.B. wenn in der Nähe mit
einer 2 W-Handfunke gerade gesendet wurde.
An den Seitenanfang
©2006-2017 by http://www.avr-asm-tutorial.net