Pfad:
Home =>
AVR-DE =>
Anwendungen =>
Tasten und Schalter am ADC =>
Tastenfeld => Kommandozeilentool Widerstandsmatrix
This page in English:
 |
Anwendungen von
AVR-Einchip-Mikrokontrollern AT90S, ATtiny, ATmega und ATxmega
Kommandozeilen-Berechnung von Tastenfeldern an einem ADC-Eingang
|
Kommandozeilen-Berechnung einer 12-er und 16-er Tastatur an einem AVR
Diese Seite zeigt,
- wie eine 12-er oder 16-er Tastatur an einen AD-Wandler-Eingang angeschlossen wird,
- wie die Widerstände mit Hilfe der Software berechnet werden,
- wie die Assembler-Software zum Ermitteln der gedrückten Taste funktioniert.
1.1 Schaltung mit 12 Tasten
Das Schaltbild zeigt ein 12-er Tastenfeld und die angeschlossene Widerstandsmatrix.
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, fließt kein Strom und die Ausgangsspannung 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
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 = Uplus / (R1 + R4 + R5 + R6)
Er verursacht einen kleinen Spannungsabfall an R1:
Y1 = I1 * R1
Die berechnete Größe Y1 ist derjenige Anteil der Betriebsspannung die
am AD-Wandler erscheint, wenn die Taste 1 gedrückt wird und muss noch mit der
Betriebsspannung multipliziert werden, um die Spannung zu erhalten. Diese Spannung
erscheint am Eingang des AD-Wandlers, da dessen Eingangswiderstand
sehr hoch ist und R2 und R3 keinen Spannungsabfall
verursachen.
Die Formel unten kombiniert die Stromberechnung und den Spannungsabfall an R1.
An den Seitenanfang
1.1.2 Die Widerstände beim Drücken der Taste 9
Wenn die Taste 9 gedrückt wird, funktioniert der Spannungsteiler anders. Nun bilden
R1, R2 und R3 zusammen den unteren Zweig des Spannungsteilers. Die Widerstände
R6 und R7 bilden zusammen den oberen Zweig. Der Strom ist jetzt
I9 = U+ / (R1 + R2 + R3 + R5 + R6 + R7)
Der Spannungsanteil ist dann
Y9 = I9 * (R1 + R2 + R3)
Jede einzelne Taste des Tastenfelds kombiniert so 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
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% fällig (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:
Das ändert die Berechnung ein wenig, ist aber gleichwertig zu der eingangs
beschriebenen seriellen Version.
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:
- Widerstände gibt es nur mit Genauigkeiten von plus und (!) minus 0,1, 1, 2
oder 5%. Widerstandswerte mit 5% Genauigkeit sind daher in einer Bandbreite von
10% um ihren nominellen Wert. Für einen 1k Widerstand liegt der tatsächliche
Wert irgendwo zwischen 950 und 1.050 Ohm. Die resultierenden Spannungen sind in einer
entsprechenden Bandbreite ungenau. Die niedrigste Spannung resultiert, wenn der
untere Zweig des Spannungsteilers den geringsten Wert aufweist und der obere Zweig
den größten Wert. Die höchste Spannung ergibt sich, wenn der untere
Zweig den größten Wert hat und der obere Zweig den niedrigsten. Diese Bandbreiten
müssen berücksichtigt werden und Unter- und Obergrenzen der Bandbreite
beim Ermitteln der Taste sind zu testen. Dafür können wir das manuelle
Aussuchen von genauen Widerstandswerten sein lassen und brauchen auch keinen Ofen
zum Konstanthalten der Temperatur der Widerstände. Glücklicherweise brauchen
wir auch keine 0,1%-Widerstände, daher können wir auch entsprechende
Unannehmlichkeiten vermeiden.
- Widerstände gibt es nur in bestimmten Werten, bekannt als E-Reihen. Die bekannteste
dieser Reihen ist die E12-Reihe: 1.0 - 1.2 - 1.5 - 1.8 - 2.2 - 2.7 - 3.3 - 3.9 -
4.7 - 5.6 - 6.8 - 8.2, und ihre dekadischen Vielfachen wie 10 - 12 - etc. oder
100 - 120 - etc.. Die E24-Reihe hat die doppelte Anzahl an Widerständen, die E48-Reihe
die vierfache und die E96-Reihe die achtfache Anzahl an diskreten Werten. Wenn wir unser
Problem mit diskreten Formeln lösen würden (Gleichungen mit 7 bzw. 8 Unbekannten,
mit entsprechend umfangreichen Matrizen), würden wir unter Garantie bei
Widerstandswerten landen, die es so gar nicht zu kaufen gibt, schon gar nicht in der
E96-Reihe. Daher sollten wir diese Methode ebenfalls schnell vergessen.
- Trotzdem es die E48- und E96-Reihen gibt, gibt es bei vielen Läden und
Versandhändlern diese gar nicht zum Kaufen. Man kann also gerne damit Herumspielen,
aber wenn es ans Einkaufen geht, kommt die Stunde der Wahrheit - und die der E12-Reihe.
Zum Schluss aber die gute Nachricht: es geht auch ganz alleine mit der E12-Reihe und wir
können uns Sonderbestellungen beim Händler sparen.
- Das Vertrackte an der Berechnung ist, dass jede Änderung an einem Widerstand
der E-Reihe die kompletten Ergebnisse ändert (und die jeweilige Bandbreite).
Deshalb muss das Ergebnis in einzelnen Näherungsschritten erzeugt werden. Dabei
ist das Ziel, die Spannungsbereiche aller Tasten möglichst gleichmäßig
über den gesamten verfügbaren Bereich von 0 bis zur Betriebsspannung zu
verteilen und keine Überlappungen zu haben, so dass jeder Taste ihr spezifischer
Spannungsbereich zukommt.
- Eine weitere Bedingung ist, dass der Druck auf eine Taste nicht zu einem hohen Strom
führt. Dazu muss die Summe aus den beiden Widerständen R1 und R7 (bzw. R8)
größer als 1000 Ohm sein, was einem Maximalstrom von 5 mA entspricht.
- Umgekehrt dürfen die Widerstände nicht zu groß werden. Wenn die Ströme
unter 10µA sinken, ist der Einfluss von Rauschen und Einstreuung einfach zu hoch.
In diesem Fall werden alle Widerstandswerte einfach durch 10 geteilt.
- Arbeitet der AD-Wandler mit der Betriebsspannung der Tastatur als Referenzspannung,
dann ist das Design besonders einfach. Wenn 8 Bit Auflösung des AD-Wandlers ausreicht
(das Left-Adjust-Bit ADLAR ist gesetzt und nur das MSB des AD-Wandlers wird gelesen), sind
die Ergebnisse im Bereich 0 und 255. Im Fall mit 10 Bit Auflösung sind die Ergebnisse
im Bereich von 0 und 1023. In beiden Fällen erübrigt sich die Umrechnung in
Spannungswerte und wir müssen die riesige Fließkommabibliothek erst gar nicht
bemühen.
An den Seitenanfang
2.2 Berechnungssoftware
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
- die Auswahl zwischen 12-er und 16-er Tasten (Umschalten mit Groß-T),
- die schrittweise Ausführung von einzelnen Näherungsschritten (Ausführung
mit Klein-s, Zufallswahl des anzunähernden Widerstands),
- die Ausführung von 1000 Näherungsschritten auf einmal (Drücken von Klein-n),
- zwischen 8 und 10 Bit Auflösung auszuwählen (Klein-r, 8 oder 10 eingeben),
- die Widerstandswerte von R1 bis R7 bzw. R8 manuell auszuwählen (1 bis 8 drücken,
Widerstandswert in Ohm eingeben),
- die Widerstandsgenauigkeit und die E-Reihe auszuwählen (Klein-t, 1/2/5 eingeben,
dann E12/E24/E48/E96 eingeben),
- das aktuelle Ergebnis in eine Datei zu schreiben (Klein-w drücken),
- das Programm zu beenden (Klein-x).
Das Fenster zeigt an:
- die aktuellen Widerstandswerte R1 bis R7 bzw. R8,
- die AD-Wandlerwerte der 12 bzw. 16 Tasten, jeweils für die gewählte
Auflösung, als Nominal-, Minimal- und Maximalwerte sowie den idealen Referenzwert,
- die aktuelle Reihenfolge der Tasten mit steigenden Spannungen (Reihenfolge kann sich
ändern),
- die gegenwärtig verwendete E-Reihe (E12/E24/E48/E96),
- die Anzahl an Überlappungen, sollte Null sein,
- die Summe der Differenzen zwischen dem Nominalwert und dem Referenzwert (sollte so gering
wie möglich sein),
- die Toleranz der Widerstandswerte und die AD-Wandler-Auflösung.
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 berechnet.
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.
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.
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 Einbahnstraße 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
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.
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.
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
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
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
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:
- Der 8-Bit-ADC-Wert befindet sich in Register R3.
- Die Registers R0 und R1 sind verfügbar und werden verwendet.
- Das Registerpaar Z wird als Tabellenzeiger verwendet.
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ößer 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:
- R0 enthält bei der Rückkehr den ASCII-Wert der Taste, FF keine Taste gedrückt
oder undefinierter ADC-Wert,
- R2:R1 wird für das Einlesen von Tabellenwerten verwendet,
- R4:R3 speichert den ADC-Wert,
- R5 zählt Durchläufe,
- Z wird als Zeiger 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 R,Z+ lassen
sich einige Quellcode-Zeilen einsparen.
An den Seitenanfang
©2014 by http://www.avr-asm-tutorial.net