Path: Home => AVR-Überblick => Tastatur => Widerstandsmatrix

12-er und 16-er Tastatur an einem AVR

Diese Seite zeigt,
  1. wie eine 12-er oder 16-er Tastatur an einen AD-Wandler-Eingang angeschlossen wird,
  2. wie die Widerstände mit Hilfe der Software berechnet werden,
  3. wie die Assembler-Software zum Ermitteln der gedrückten Taste funktioniert.

1 Anschliessen der Tastatur an einen AD-Wandler-Eingang

1.1 Schaltung mit 12 Tasten

12-er Tastatur Das Schaltbild zeigt ein 12-er Tastenfeld und die angeschlossene Widerstansmatrix. Die vier Zeilenleitungen sind an vier gestapelten Widerständen angeschlossen, die mit dem Pluspol der Spannungsquelle verbunden sind. Die drei Spaltenleitungen sind an eine weitere Widerstandsreihe angeschlossen.

Ist keine der Tasten gedrückt, fliesst kein Strom und die Aussgangsspannung am Punkt Y ist Null, weil die drei Widerstände Y mit dem Minuspol der Spannungsquelle verbinden.

Wird eine Taste geschlossen, z. B. Taste 5, dann verbindet die geschlossene Taste die Zeilenlinie, hier die der Tasten 4-5-6, mit der Spaltenlinie, hier die der Tasten 2-5-8-0.

1.1.1 Die Widerstände beim Drücken der Taste 1

Taste 1 gedrückt Das passiert, wenn die Taste 1 gedrückt wird: die Taste verbindet Zeile 1 mit Spalte 1. Nun fungieren R1, R4, R5, R6 und R7 als Spannungsteiler. Der Strom durch diesen Spannungsteiler ist I1 = U+ / (R1 + R4 + R5 + R6), er verursacht einen kleinen Spannungsabfall an R1, Y1 = I1 * R1. Diese Spannung erscheint am Eingang des AD-Wandlers, da dessen Eingangswiderstand sehr hoch ist.

Die Formel unten kombiniert die Stromberechnung und den Spannungsabfall an R1. Die berechnete Grösse Y1 ist derjenige Anteil der Betriebsspannung die am AD-Wandler erscheint, wenn die Taste 1 gedrückt wird.

An den Seitenanfang

1.1.2 Die Widerstände beim Drücken der Taste 9

Taste 9 gedrückt Wenn die Taste 9 gedrückt wird, funktioniert der Spannungsteiler anders. Nun bilden R1, R2 und R3 zusammen den unteren Zweig des Spannunsteilers. Die Widerstände R6 und R7 bilden zusammen den oberen Zweig. Der Strom ist jetzt I9 = U+ / (R1 + R2 + R3 + R5 + R6 + R7), die Spannung ist dann Y9 = I9 * (R1 + R2 + R3).

Jede einzelne Taste des Tastenfelds kombiniert spezifische Widerstände der Matrix und produziert eine spezifische Ausgangsspannung am Ausgang Y. Mit dieser Spannung lässt sich die gedrückte Taste leicht identifizieren. Die Aufgabe besteht nur darin, die Widerstände in optimaler Weise auszuwählen (mit der Software weiter unten).

An den Seitenanfang

1.2 16-er Tastenfeld

16-er Tastatur Vier weitere Tasten benötigen einen weiteren Widerstand. Die Schaltung sieht fast gleich aus wie die 12-er Version, aber die Berechnung der Spannungsteiler und die Spannungsbereiche unterscheiden sich. In diesem Fall werden aber Widerstände mit geringerer Toleranz von 2 oder 1% erforderlich (siehe unten).

An den Seitenanfang

1.3 Alternative mit Parallelwiderständen

Die vier Widerstände zum Pluspol müssen nicht seriell hintereinander geschaltet werden, es kann auch jede Tastaturzeile mit einem einzelnen Widerstand auf Plus gelegt werden. Daraus ergeben sich die folgenden Schaltungen:

12 Tasten, parallel 16 Tasten, parallel

Das ändert die Berechnung ein wenig, ist aber gleichwertig zu der eingangs beschriebenen seriellen Version.

2 Berechnung der Widerstandswerte

2.1 Berechnungsgrundlagen und Regeln

Dieses Kapitel zeigt die Randbedingungen und die Rechenregeln für die Widerstandswerte.

Die Berechnung der Widerstände für diese Spannungsteiler ist nicht trivial: An den Seitenanfang

2.2 Berechnungssoftware

12 Tasten Start Da das Berechnen solcher Widerstandsnetzwerke ein mühsamer Prozess ist, habe ich diese Software geschrieben. Es erlaubt, mit den Widerstandswerten und Parametern herumzuspielen.

Die Software hier (gezippte Win64-ausführbare Datei) oder hier für Linux i386-x64 ist eine einfache Kommandozeilenanwendung. Downloaden, entzippen und starten. Man kann auch den Quellcode in Pascal herunterladen, mit dem Free Pascal Compiler fpc kompilieren und die erzeugte ausführbare Datei starten. Wenn Du gegenüber ausfürbaren Dateien aus dem Internet misstrauisch bist, die ausführbare Datei für ein anderes Betriebssystem benötigst oder am Quellcode herumbasteln möchtest, ist das die Methode der Wahl.

Die Version hier (Win64) beherrscht zusätzlich auch die Parallelschaltung von Widerständen. Die Umschaltung zwischen Seriell- und Parallelschaltung erfolgt mit der Taste Klein-v. Den Pascal-Quellcode gibt es zum Selberkompilieren hier.

Die Software ermöglicht Das Fenster zeigt an:
An den Seitenanfang

2.3 Beispielberechnung mit 12 Tasten

Das folgende Beispiel ist mit 5% Toleranz, 8 Bit AD-Wandler-Auflösung und Widerstandsreihe E12 herechnet.

Schritt 1 Das ist das Ergebnis nach einem Näherungsschritt. Der Zufallsgenerator hat E4 ausgewählt und von 56k auf 68k erhöht. Dadurch haben sich statt 4 Überlappungen nur noch 3 ergeben und die Differenzen haben sich auf 548 abgesenkt.

Schritt 2 Der nächste Einzelschritt erhöht R2 auf 1k2, wodurch sich die Anzahl an Überlappungen wieder auf 4 erhöht, die Differenzen sind aber etwas geringer geworden.

Schritt 1000 Das ist das Ergebnis nach 1000 weiteren Näherungsschritten. Die Anzahl Überlappungen ist Null, wie es sein sollte, und die Differenzen zum Idealzustand haben sich auf 39 abgesenkt. Alle Spannungen haben ihre spezifische Bandbreite und genügend Abstand zur nächsten Taste. Mit dem Ergebnis lässt es sich leben.

Der Näherungsalgoritmus führt aber nicht immer zu einem idealen Ergebnis. Bedingt durch die Zufallsauswahl kann auch eine Einbahnstrasse entstehen, die nicht mehr zum idealen Endpunkt konvergiert. In dem Fall hilft nur die manuelle Korrektur an Widerstandswerten.

An den Seitenanfang

2.4 Beispielberechnung mit 16 Tasten

16 Tasten, Start Durch Eingabe von T gelangen wir in den 16-Tasten-Modus. Die Widerstandstoleranz ist auf 1% umgestellt, die AD-Wandler-Auflösung auf 10 Bit. 2% würde ebenfalls ausreichen, 2%-Widerstände sind aber schwerer im Handel zu kriegen. Die Widerstandsreihe bleibt bei E12, weil die Werte leichter zu kriegen sind.

Mit den Standardvoreinstellungen ist die Anzahl Überlappungen schon bei Null, aber die Differenzen lassen sich noch optimieren.

16 Tasten, Schritt 1 Das ist das Ergebnis nach einem Schritt. Die Zahl der Überlappungen ist jetzt auf 4 angestiegen, die Differenzen haben sich dabei allerdings verringert. Der Algorithmus geht halt eigene, nicht immer logische Wege.

16 Tasten, Schritt 1000 Das Resultat nach weiteren 1000 Näherungsschritten kann sich dann allerdings sehen lassen. Die Anzahl Überlappungen ist Null und die Differenzen sind drastisch abgesunken, wir sind dem Idealzustand sehr nahe gekommen. Das Problem ist gelöst.

An den Seitenanfang

2.5 Datei mit Ergebnissen, 12 Tasten

12 Tasten Ergebnisdatei Mit w kriegt man von der Software die Ergebnisse in eine Datei geschrieben.

Hier ist ein Blick auf die Ergebnisdatei mit einem einfachen Texteditor. Der Dateiname kennzeichnet die verwendeten Parameter, die Beispieldatei für 12 Tasten gibt es hier.

Der obere Teil der Datei zeigt die Ausgabe am Bildschirm. Der untere Teil liefert eine Tabelle zur Übernahme in die Assembler-Quelldatei. Die Tabelle kann verwendet werden, um die gedrückte Taste zu identifizieren (siehe unten). Der erste Wert in jeder Zeile gibt die Untergrenze an, ab der die entsprechende Taste in Frage kommt. Der zweite Wert gibt die Obergrenze plus Eins an, die bei dieser Taste zutrifft. Eine Taste ist dann gedrückt, wenn der ADC-Wert grösser oder gleich der Untergrenze (CP-Instruktion, Carry-Flag nicht gesetzt) und kleiner als die Obergrenze plus Eins ist (CP-Instruktion, Carry-Flag gesetzt).

Die Tabelle endet mit zwei Null-Bytes, damit das Ende der Tabelle erkannt werden kann.

Die beiden letzten Zeilen in der Datei enthalten die ASCII-Werte der Tasten.

An den Seitenanfang

2.6 Datei mit Ergebnissen, 16 Tasten

16 Tasten Ergebnisdatei Der Dateiname der Datei spiegelt wieder die Parameter wieder, die entsprechende Datei ist hier. Der obere Teil der Datei zeigt wieder die Bildschirmausgabe.

Der untere Teil der Datei enthält wieder eine Tabelle zur Übernahme in die Assembler-Quelldatei. Die Tabelle besteht nun aus 16-Bit-Werten mit der Tastenuntergrenze und der Tastenobergrenze plus Eins.

Die Tabelle endet mit einem Nullwert um ihr Ende zu signalisieren.

Die letzten beiden Zeilen in der Datei stellen eine ASCII-Tabelle mit den Tastenwerten zur Verfügung.

An den Seitenanfang

3 Assembler Software

Die Assembler Software zur Tastenerkennung unterscheidet sich bei den 8- und 10-Bit-Versionen.

3.1 Assembler-Software für 8 Bit ADC-Werte

Die folgende Software basiert auf Folgendem: Die Tabelle in der Ergebnisdatei wird in den Assembler-Quellcode eingefügt:

; Dezimaltabelle fuer Assembler
Keytable: ; Untergrenze, Obergrenze+1, 'Taste'
.DB 28, 35 ; '1'
.DB 36, 44 ; '2'
.DB 49, 58 ; '3'
.DB 68, 80 ; '4'
.DB 83, 96 ; '5'
.DB 105, 118 ; '6'
.DB 121, 134 ; '7'
.DB 139, 152 ; '8'
.DB 161, 174 ; '9'
.DB 189, 199 ; '*'
.DB 202, 211 ; '0'
.DB 215, 223 ; '#'
.DW 0 ; Tabellenende
Keyvalues:
.DB "123456789*0#" ; Tastenwert ASCII 
Das folgende Unterprogramm liest zuerst die erste Untergrenze aus der Tabelle. Ist der eingelesene Wert Null, dann ist das Ende der Tabelle erreicht und keine Taste gefunden. In diesem Fall gibt die Routine 0xFF im Register R0 zurück. Dasselbe passiert, wenn der ADC-Wert in R3 kleiner ist als diese Untergrenze, dann ist entweder keine Taste gedrückt (erster Durchlauf der Schleife) oder der ADC-Wert liegt zwischen zwei gültigen Bandbreiten.

Dann wird die Obergrenze plus Eins aus der Tabelle gelesen und der ADC-Wert in R3 damit verglichen. Ist danach das Carry-Flag gesetzt, dann ist die Taste erkannt. In diesem Fall wird der Zeiger Z auf den Anfang der ASCII-Tabelle gesetzt, der Zähler R1 dazu addiert, das ASCII-Zeichen aus der Tabelle in R0 eingelesen und mit diesem Wert zurückgekehrt.

Ist der ADC-Wert grösser als die Obergrenze plus Eins, dann wird die Schleife wiederholt.

GetKey12: ; Ermittle den ASCII-Wert der gedrueckten Taste, kehrt mit dem Ergebnis in R0 zurueck
    clr R1 ; Loesche Zaehler                      +-------------------+
    dec R1 ; Setze Zaehler auf FF                 | Zaehler R1 auf FF |
    ldi ZH,HIGH(2*Keytable) ; Z auf Tabellenanfang| Z auf Tabelle     |
    ldi ZL,LOW(2*Keytable) ;                      +-------------------+
GetKey1:                                                    |
    lpm ; Lese Untergrenze                           ->Lese Untergrenze
    tst R0 ; Tabellenende erreicht?                 /      / \__________> ja
    breq GetKey3 ; table end reached               |       \0/nein       |
    inc R1 ; Zaehler erhoehen                      | Zaehler erhoehen    v
    cp R3,R0 ; ADC-Ergebnis vergleichen            |       / \__________>|ja
    brcs GetKey3 ; Kleiner als Untergrenze         |       \C/nein       |
    adiw ZL,1 ; Lese Obergrenze plus Eins          |  Lese Obergrenze    |
    lpm ; read to R0                               |  und vergleiche     |
    adiw ZL,1 ; Zeiger erhoehen                    |        |            |
    cp R3,R0 ; Vergleich mit Obergrenze             \______/ \           |
    brcc GetKey1 ; Groesser als Obergrenze             nein\C/           |          
    ldi ZH,HIGH(2*KeyValues) ; Zeiger auf ASCII-      Tabellenzeiger     |
    ldi ZL,LOW(2*KeyValues) ;  Tabelle                      |            |
    add ZL,R1 ; Addiere Zaehler                       Addieren Zaehler   |
    brcc GetKey2 ; Kein Ueberlauf                           |            |
    inc ZH ; Ueberlauf, addiere Eins zu MSB             Erhoehe MSB      |
GetKey2: ;                                                  |            |
    lpm ; Lese ASCII-Zeichen nach R0                  Zeichen nach R0    |
    ret ; Rueckkehr mit Ergebnis                           RET           |
GetKey3: ; Tabellenende oder Zwischenwert                 Fehler         v
    clr R0 ; Loesche Ergebnis                            R0 auf 0 <------
    dec R0 ; FF in Ergebnis                              R0 auf FF
    ret ;                                                  RET
Das ist es.

An den Seitenanfang

3.2 Assembler-Software für 10-Bit ADC-Werte

10-Bit ADC-Werte erfordern eine wortweisen Vergleich. Die folgenden Register werden verwendet:

; Dezimaltabelle fuer Assembler
Keytable: ; Untergrenze, Obergrenze+1, 'Taste'
.DW 110, 115 ; '1'
.DW 136, 142 ; '2'
.DW 166, 173 ; '3'
.DW 199, 206 ; 'A'
.DW 288, 297 ; '4'
.DW 339, 350 ; '5'
.DW 394, 405 ; '6'
.DW 448, 459 ; 'B'
.DW 504, 516 ; '7'
.DW 565, 576 ; '8'
.DW 623, 634 ; '9'
.DW 675, 685 ; 'C'
.DW 766, 775 ; '*'
.DW 809, 817 ; '0'
.DW 846, 853 ; '#'
.DW 876, 882 ; 'D'
.DW 0 ; Tabellenende
Keyvalues:
.DB "123A456B789C*0#D" ; Tastenwert ASCII 
;
; Wandle ADC-Wert in R4:R3 in ASCII-Code um
GetKey16:
	clr R5 ; Loesche Zaehler
        dec R5 ; Setze Zaehler auf FF
        ldi ZH,HIGH(2*Keytable) ; Z auf Tabellenanfang
        ldi ZL,LOW(2*Keytable)
GetKey16a:
        inc R5 ; Erhoehe Zaehler
	lpm ; Lese LSB aus Tabelle
	adiw ZL,1 ; Naechstes Byte
	mov R1,R0 ; kopiere LSB nach R1
	lpm ; Lese MSB aus Tabelle
	adiw ZL,1 ; Naechstes Byte
        mov R2,R0 ; Kopiere nach R2
	tst R1 ; Ist LSB Null?
	brne GetKey16b ; Nein, weitermachen
	tst R2 ; Ist MSB Null?
	breq GetKey16d ; Tabellenende erreicht
GetKey16b:
	cp R3,R1 ; Vergleiche LSB ADC mit Untergrenze
        cpc R4,R2 ; Vergleiche MSB plus Ueberlauf aus LSB
	brcs GetKey16d ; Carry signalisiert Wert kleiner Untergrenze
	lpm ; Lese LSB Obergrenze
	adiw ZL,1 ; Naechstes Byte
	mov R1,R0 ; Kopiere nach R1
        lpm ; Lese MSB Obergrenze
	sbiw ZL,1 ; Naechstes Byte
	mov R2,R0 ; Kopiere nach R2
	cp R3,R1 ; Vergleiche LSB
	cpc R4,R2 ; Vergleiche MSB plus Ueberlauf
	brcc GetKey16a ; ADC-Wert groesser oder gleich Obergrenze
	ldi ZH,HIGH(2*KeyValues16) ; Z auf ASCII-Tabelle
	ldi ZL,LOW(2*KeyValues16)
	add ZL,R5 ; Addiere Zaehler
	brcc GetKey16c ; Kein Ueberlauf
	inc ZH ; Ueberlauf, Addiere 1 zu MSB
GetKey16c:
	lpm ; Lese ASCII-Wert aus Tabelle in R0
	ret ; Rueckkehr
GetKey16d:
	clr R0 ; Setze R0 auf FF
	dec R0
	ret ; Rueckkehr mit R0=FF
Hinweis: Alle LPM-Instruktionen sind AVR-Oldstyle. Mit LPM Z+,R lassen sich einige Quellcode-Zeilen einsparen.



An den Seitenanfang

©2014 by http://www.avr-asm-tutorial.net