199 5 21MB
German Pages 304 [308] Year 1995
Pascal-Kurs technisch orientiert Band 2: Anwendungen von Prof. Dipl.-Ing. Günter Schmitt 2., verbesserte Auflage
R.Oldenbourg Verlag München Wien 1995
Die Deutsche Bibliothek - CIP-Einheitsaufnahme Schmitt, Günter: Pascal-Kurs technisch orientiert / von Günter Schmitt. München ; Wien : Oldenbourg. Bd. 2. Anwendungen. - 2., verb. Aufl. - 1995 ISBN 3-486-23279-7
© 1995 R. Oldenbourg Verlag GmbH, München Das Werk einschließlich aller Abbildungen ist urheberrechtlich geschützt. Jede Verwertung außerhalb der Grenzen des Urheberrechtsgesetzes ist ohne Zustimmung des Verlages unzulässig und strafbar. Das gilt insbesondere für Vervielfältigungen, Übersetzungen, Mikroverfilmungen und die Einspeicherung und Bearbeitung in elektronischen Systemen. Gesamtherstellung: R. Oldenbourg Graphische Betriebe GmbH, München ISBN 3 - 4 8 6 - 2 3 2 7 9 - 7
Inhaltsverzeichnis Vorwort
7
1.
Einführung in die Hardware
9
1.1 1.2 1.3 1.4 1.5 1.6 1.7
Systemübersicht Interne Darstellung der ordinalen Datentypen Die Prozessoren der 80 x86-Familie Die Adressierung des Arbeitsspeichers Die Adressierung der Peripherie Die Interrupt- und DMA-Steuerung Der externe Systembus
9 11 16 19 23 27 39
2.
Einführung in die Maschinensprache
40
2.1 2.2 2.3 2.4 2.5
Pascal-und Assemblerprogramme Der Register-und Befehlssatz Die Arbeit mit Unterprogrammen Die Arbeit mit dem Arithmetikprozessor Der integrierte Assembler
41 47 53 64 70
3.
Einführung in das Betriebssystem
74
3.1 3.2 3.3 3.4
Die Der Die Die
76 79 82 86
4.
Die parallele Druckerschnittstelle
4.1 4.2 4.3 4.4 4.5 4.6
Aufbau und Programmierung der Druckerschnittstelle Die Übertragung digitaler Daten Die Ein/Ausgabe analoger Daten Die Rechner-Rechner-Kopplung Die Interruptsteuerung der Druckerschnittstelle Erweiterung des Druckerports
91 94 99 103 107 108
5.
Die serielle Schnittstelle
110
5.1 5.2
Der Zugriff über das Betriebssystem Aufbau und Programmierung des Schnittstellenbausteins
113 115
Verbindung über die Unit Dos Aufruf von BIOS-und DOS-Interrupts Zeit- und Uhrenfunktionen in Pascal Arbeit mit Geräten und Dateien
90
4
Inhaltsverzeichnis
5.3 5.3.1 5.3.2 5.3.3 5.4 5.5
Serielle Übertragungsverfahren Die Drei-Draht-Verbindung Das Hardware-Handshake-Verfahren Das Software-Handshake-Verfahren Die Interruptsteuerung der Serienschnittstelle Die serielle Mausschnittstelle
121 122 124 125 129 133
6.
Der Spieleadapter (Gameport)
136
6.1 6.2 6.3 6.4
Die Die Die Die
136 138 139 140
7.
Der Anschluß von Peripheriekarten
142
7.1 7.2 7.3 7.3.1 7.3.2 7.3.3 7.4
Die Adressierung der Peripherie Die Entwicklung einer Peripheriekarte Peripheriekarten für technische Anwendungen Die Parallelschnittstelle 8255 der Karte Der Timerbaustein 8253 der Karte Der Analogteil der Karte Systemfremde Peripheriebausteine
142 145 150 151 153 156 158
8.
Der lEC-Meßgerätebus
160
9.
Anwendungsbeispiele
172
9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4
Beispiele aus der Digitaltechnik Die Messung von Zeiten Die Messung von Frequenzen Die Ausgabe von Rechtecksignalen Beispiele aus der Mikrocomputertechnik Ausgabe und Speicherung von Bitmustern Der Aufbau eines externen Peripheriebus Der Aufbau eines Hardware-Emulators (8085) Das Auslesen eines Speicheroszilloskops Die Ansteuerung von Schrittmotoren Beispiele aus der analogen Meßtechnik Die Messung von Widerständen Die Messung von Spannungen und Strömen Die Aufzeichnung analoger Größen Die Ausgabe analoger Größen Beispiel eines digitalen Filters Beispiele für die Auswertung von Meßergebnissen
172 172 181 188 193 193 199 204 216 222 226 227 232 237 242 246 249
Schaltung des analogen Joysticks Programmierung über das Betriebssystem Programmierung über den Peripherieport Impulslängenmessung mit dem Timer
Inhaltsverzeichnis
5
10.
Einführung in die Objektorientierte Programmierung
259
10.1 10.2 10.3 10.4
Variablen in Unterprogrammen Der Datentyp OBJECT Die Beschreibung von Schaltwerken durch Objekte Graphische Darstellungen durch Objekte
259 261 266 269
11.
Ergänzende und weiterführende Literatur
274
11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.1.5 11.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4
Bücher und Sammelwerke Schwerpunkt Pascal Schwerpunkt Hardware und Maschinensprache Schwerpunkt Betriebssystem MS-DOS Schwerpunkt Schnittstellen Schwerpunkt Anwendungen Zeitschriften Aufsätze Schwerpunkt PC-Hardware Schwerpunkt MS-DOS Betriebssystem Schwerpunkt PC-Schnittstellen Schwerpunkt Anwendungsbeispiele
274 274 274 275 275 275 276 277 277 278 280 282
12.
Anhang
285
12.1 12.2 12.3 12.4 12.5 12.6 12.7 12.8 12.9
Stiftbelegung des PC/XT-Erweiterungssteckers Stiftbelegung der Paralleldruckerschnittstelle Stiftbelegung der seriellen Schnittstelle Stiftbelegung des IEC-Bus-Steckers Schaltplan der Paralleldruckerschnittstelle Programm zur Ausgabe der Interruptvektoren Programm der Unit Aushexbi Programm der Unit Komplex Programm der Unit Iecbus
285 286 287 288 289 290 291 293 298
13.
Register
301
Vorwort Der vorliegende zweite Band des Werkes Pascal Kurs - technisch orientiert behandelt schwerpunktmäßig Anwendungen aus dem technischen Bereich. Er setzt die Grundlagen der Pascalprogrammierung als bekannt voraus. Besondere Vorkenntnisse der Digital- und Mikrocomputertechnik sind nicht unbedingt erforderlich. Turbo Pascal gestattet mit seinen vielfältigen Möglichkeiten einen Zugriff auf fast alle Bereiche des Betriebssystems und der Rechnerhardware, die früher ausschließlich der Maschinensprache (Assembler) vorbehalten waren. Und wenn es aus zeitlichen Gründen einmal gar nicht anders geht, so lassen sich ab Version 6.0 des Turbo Pascal auch Assemblerbefehle direkt in das Pascalprogramm einbauen. Daher beschäftigen sich die drei ersten Kapitel mit der Hardware, der Maschinensprache und dem Betriebssystem des PC in Verbindung mit Pascalprogrammen. Die in jedem PC vorhandenen Standardschnittstellen (Paralleldrucker, Serienschnittstelle und Spieleadapter) lassen sich auf vielfältige Weise für technische Anwendungen nutzen. Daher behandeln die drei folgenden Kapitel den Aufbau und die Programmierung dieser Schnittstellen mit Turbo Pascal Programmen. Reichen diese Standardschnittstellen nicht aus, so wird man besonders in industriellen Anwendungen spezielle Peripheriekarten einsetzen oder hochgenaue Meßsysteme über den IEC-Meßgerätebus betreiben. Daher sind diesen Gebieten und ihrer Verbindung mit Pascal zwei besondere Kapitel gewidmet. Das 9. Kapitel zeigt eine Vielzahl von Anwendungsbeispielen aus der Digitaltechnik, der Mikrocomputertechnik und der analogen Meßtechnik, die sich mit einfachen Mitteln an den Standardschnittstellen realisieren lassen. Einem technisch interessierten Leser sei daher empfohlen, diese Beispiele nicht nur theoretisch durchzuarbeiten, sondern auch praktisch zu erproben. Das Literaturverzeichnis liefert weitere Anregungen zu selbständiger Weiterarbeit. Ab Version 5.5 definiert Turbo Pascal den Datentyp OBJECT, der im abschließenden 10. Kapitel für die Beschreibung und graphische Darstellung von logischen Speicherschaltungen verwendet wird. Mit dieser Einführung in die Objektorientierte Programmierung basiert das Gesamtwerk nunmehr auf der Turbo Pascal Version 7.0
Günter Schmitt
1. Einführung in die Hardware Die Bezeichnung PC für Personal Computer kennzeichnet heute eine Klasse von Rechnern mit folgenden gemeinsamen Merkmalen: - Bedienung über eine Tastatur und einen Bildschirm, - externer magnetischer Speicher (Floppydisk, Harddisk), - Druckeranschluß, - leistungsfähiger Mikroprozessor (z.B. der 80x86-Familie), - komfortables Betriebssystem (z.B. DOS), - Programmierung in Hochsprachen (z.B. Turbo Pascal) und - eine Fülle von Anwendungssoftware (z.B. Textverarbeitung).
1.1
Systemübersicht
Der ursprünglich von einem Hersteller (IBM) entwickelte und auch auf dem Markt eingeführte PC (Personal Computer) wurde fortlaufend weiter verbessert, auch von anderen Herstellern, so daß heute eine Vielzahl von Bauformen auf dem Markt zu finden ist. Bild 1-1 zeigt den allgemeinen Aufbau eines Personal Computers.
Disk
Tastatur
m
BIOS
EPROM
DOS
Bildschirm
Drucker
Benutzer
Arbeitsspeicher (RAM)
Harddisk Floppy Tastatur Bildschirm
Drucker Serienschnittst. Joystick
Steuerung
Steuerung
Peripheriebausteine
ZusatzPeripherieKarten
Steckplätze
S y s t e m b u s Takt Reset DMA Timer Interrupt Steuerung
Register Mikroprozessor 80x86
Bild l-l: Blockschaltplan eines Personal Computers
Arithmetikprozessor 80x87
10
1. Einführung in die
Hardware
Der Mikroprozessor z.B. aus d e r Familie d e r 80x86-Prozessoren b e s t e h t a u s dem Steuerwerk, dem Rechenwerk, u n d Speichern, die Register g e n a n n t werden. Er k a n n wahlweise durch einen Arithmetikprozessor (z.B. 80x87) e r g ä n z t werden, d e r d a n n die arithmetischen Operationen u n d mathematischen Funktionen wesentlich schneller als d u r c h Software a u s f ü h r t . Eine Systemsteuerung leitet P r o g r a m m u n t e r b r e c h u n g e n ( I n t e r r u p t s ) an den Prozessor weiter u n d s t e u e r t zusammen mit einem Zeitgeber (Timer) den d i r e k t e n Speicherzugriff (DMA). Nach dem Einschalten d e r V e r s o r g u n g s s p a n n u n g bzw. nach einem Zurücksetzen des Systems (Reset) wird ein Basisbetriebssystem (BIOS) g e s t a r t e t . Es b e f i n d e t sich in einem F e s t w e r t speicher (EPROM). Es b r i n g t das System in eine G r u n d s t e l l u n g u n d lädt ein d i s k e t t e n o r i e n t i e r t e s Betriebssystem (DOS) von einer F e s t p l a t t e (Harddisk) oder Wechselplatte (Floppydisk) in den Arbeitsspeicher (RAM). Eine wesentliche Aufgabe des Betriebssystems b e s t e h t in einer Kontrolle d e r D a t e n ü b e r t r a g u n g zwischen dem Arbeitsspeicher u n d den a n g e s c h l o s s e nen P e r i p h e r i e g e r ä t e n . Dies geschieht ü b e r b e s o n d e r e P e r i p h e r i e b a u s t e i ne, die auch dem Benutzer in seinen Programmen z u r V e r f ü g u n g s t e h e n , ü b e r b e s o n d e r e Steckplätze (Slots) lassen sich zusätzliche Karten z.B. f ü r S p e i c h e r e r w e i t e r u n g e n oder hochauflösende Grafik oder P e r i p h e r i e s c h a l t u n g e n anschließen. In diesem Buch, das sich im wesentlichen mit Turbo Pascal u n t e r dem Betriebssystem DOS u n d mit t e c h n i s c h e n Anwendungen b e s c h ä f t i g t , w e r d e n Systeme mit den Bezeichnungen PC bzw. XT u n d AT behandelt. Ein Personal Computer mit der Bezeichnung PC bzw. XT zeichnet sich d u r c h folgende Merkmale aus: - Mikroprozessor 8088 oder 8086 (16 bit), - maximal 1 MByte Speicher (Max. 640 KByte u n t e r DOS), - ein I n t e r r u p t s t e u e r b a u s t e i n (8 Leitungen), - ein DMA-Steuerbaustein (4 Kanäle), - ein Timer u n d eine Parallelschnittstelle u n d - E r w e i t e r u n g s s t e c k p l ä t z e mit 2x31 Busleitungen. Personal Computer d e r Bauform AT (Advanced Technology) haben allgemein folgende Merkmale: - Mikroprozessor 80286 (16 bit) oder 80386 (32 bit), - ü b e r 16 MByte Speicher (Max. 640 KByte u n t e r DOS), - zwei I n t e r r u p t s t e u e r b a u s t e i n e (15 Leitungen), - zwei DMA-Steuerbausteine (7 Kanäle), - ein Timer u n d eine Ein/Ausgabeschnittstelle, - b a t t e r i e g e p u f f e r t e r Uhrenbaustein u n d - Steckplätze wie PC/XT mit zusätzlicher B u s e r w e i t e r u n g . Die Programmiersprache Turbo Pascal sowie das Betriebssystem DOS sind u n a b h ä n g i g von d e r Bauform des Personal Computers f ü r alle Mikroproz e s s o r t y p e n vom 8088 bis zum 80386 und 80486 v e r w e n d b a r . Die U n t e r schiede liegen im wesentlichen in d e r Arbeitsgeschwindigkeit.
1.2 Interne Darstellung der ordinalen Datentypen
1.2
11
Interne Darstellung der ordinalen Datentypen
Für den Pascalprogrammierer, der sich vorwiegend mit numerischen P r o blemen oder mit der Verarbeitung von Texten beschäftigt, ist die interne Darstellung seiner Daten von untergeordneter Bedeutung. Der Einsatz von Pascal f ü r die Lösung von technischen Aufgabenstellungen wie z.B. die Ausgabe von digitalen Steuersignalen oder das Abtasten von Signalleitungen erfordert auch vom Pascalprogrammierer ein "Bitdenken", wie es in der Maschinenorientierten Programmierung üblich ist. Daher ist es notwendig, näher auf die interne Darstellung der ordinalen Datentypen einzugehen, die vorzugsweise im Zusammenhang mit technischen Aufgabenstellungen verwendet werden.
Datentyp
Länge
Speicheraufbau
BYTE
8 bit
WORD
16 bit I
SHORTINT
8 bit
INTEGER
16 bit
Vz
LONGINT
32 bit
Vz|
CHAR
8 bit
Fcode
BOOLEAN
8 bit
I
dual
Bereich dezimal 0 .. 255
dual
I
-128 .. +127
|Vz| dual| dual
0 .. 65535
| dual
]
|0/1|
-32768 .. +32767 | -2147483648 .. +2147483647 ASCII-Code mit Blockgraphik 0 = FALSE
1 = TRUE
Bild 1-2: Die ordinalen Datentypen
Zu den ordinalen Datentypen (Bild 1-2) gehören die vorzeichenlosen g a n zen Zahlentypen BYTE und WORD, die vorzeichenbehafteten ganzen Zahlentypen SHORTINT, INTEGER und LONGINT, der Zeichentyp CHAR und der logische Datentyp BOOLEAN. Der oberste Grundsatz lautet: Alle Daten (Zahlen, Zeichen und sonstige Zustände) werden intern binär gespeichert und verarbeitet. In der Datenverarbeitung drückt man dies durch die Zeichen 0 und 1 aus, in der Digitaltechnik durch die elektrischen Potentiale Low und H i g h . Besonders im Hinblick auf technische Anwendungen soll nun die interne Darstellung der ganzen Zahlen näher erläutert werden. Aus digitaltechnischen und rechentechnischen Gründen werden ganze und auch reelle Zahlen maschinenintern als Dualzahlen dargestellt. Der Addier e r als Bestandteil des Rechenwerks ist zunächst nur in der Lage, vorzeichenlose Dualzahlen der Datentypen BYTE und WORD zu addieren. Bei der Einführung vorzeichenbehafteter Dualzahlen (Datentypen SHORTINT, INTEGER und LONGINT) wird aus praktischen Gründen eine Zahlendarstellung gewählt, die es erlaubt, den gleichen Addierer wie f ü r vorzeichenlose Dualzahlen zu verwenden. Bei positiven Zahlen ist das Vorzeichenbit in der linkesten Bitposition eine 0, in den restlichen Bitpositionen steht der duale
12
1. Einführung in die Hardware
Zahlenwert. Das f o l g e n d e Beispiel zeigt die Dezimalzahl +13 in d e r v o r z e i c h e n b e h a f t e t e n INTEGER-Darstellung mit einem positiven Vorzeichen u n d 15 Dualstellen. Jeweils v i e r Bitpositionen w u r d e n zu einer Gruppe zusammengefaßt. +13 d e z i m a l
= 0 0 0 0 0000 0000 1101 d u a l
Negative Zahlen werden im Zweierkomplement d a r g e s t e l l t . Dabei wird d u r c h die Addition eines Verschiebewertes d a s negative Vorzeichen beseitigt. Wählt man als Verschiebewert die größtmögliche vorzeichenlose Dualzahl, so e n t s t e h t d a s Einerkomplement, das sich r e c h e n t e c h n i s c h d u r c h einen einfachen Negierer (in Pascal d u r c h eine NOT-Operationen) f ü r j e d e Dualstelle verwirklichen läßt. Wegen d e r b e s s e r e n Korrekturmöglichkeit (Vernachlässigung d e s Ü b e r t r a g s ) nimmt man einen um 1 größeren Verschiebewert und e r h ä l t aus dem Einerkomplement d u r c h Addition einer 1 das Zweierkomplement Dabei e r g i b t sich automatisch eine 1 in der linkesten Bitposition als negatives Vorzeichen. Das folgende Beispiel zeigt die Darstellung d e r Dezimalzahl - 1 3 = - 0 1 1 0 1 dual in einem 16-bit-Wort vom Datentyp INTEGER. Verschiebewert: -13
dezimal:
+1111 1111 U l i
Uli
- 0 0 0 0 0000 0000 1 1 0 1
Einerkomplement: A d d i t i o n von 1 :
Uli
Uli
Uli
0010 +1
Zweierkomplement:
Uli
Uli
Uli
0011
Negative Zahlen sind also durch eine 1 im Vorzeichenbit gekennzeichnet. Die Rückkomplementierung einer d e r a r t i g e n Zweierkomplementzahl in eine r e i n e Dualzahl mit Vorzeichen geschieht nach dem gleichen Verfahren: e r s t bitweise n e g i e r e n u n d d a n n eine 1 addieren. Beispiel: Zweierkomplement:
Uli
Uli
Uli
0011
Einerkomplement: A d d i t i o n von 1 :
0 0 0 0 0000 0000
1100 +1
Dualzahl: Dezimal z a h l :
- 0 0 0 0 0000 0 0 0 0 -13
1101
Die Rechenoperation Subtrahiere wird vom Rechenwerk nach d e r Formel "a - ( + b ) = a + ( - b ) " auf eine Addition des negativen Zahlenwertes z u r ü c k g e f ü h r t . Dabei wird der abzuziehende Operand bitweise n e g i e r t (Einerkomplement), u n d es wird zusätzlich eine 1 in d e r letzten Stelle a d d i e r t (Zweierkomplement). Das Rechenwerk stellt Additions- u n d S u b t r a k t i o n s b e f e h l e f ü r 8-bit-Operanden (Datentypen BYTE, SH0RTINT u n d CHAR) u n d f ü r 16-bit-Operanden (Datentypen WORD u n d INTEGER) zur V e r f ü g u n g . Operationen f ü r 32-bit-Operanden (Datentyp LONG INT) w e r den auf 16-bit-Operationen u n t e r B e r ü c k s i c h t i g u n g eines Zwischenübert r a g s z u r ü c k g e f ü h r t . Bei d e r Multiplikation u n d Division gibt es g e t r e n n t e Befehle f ü r die vorzeichenlose u n d die v o r z e i c h e n b e h a f t e t e Zahlendarstel-
1.2 Interne Darstellung der ordinalen Datentypen
13
lung. Der Abschnitt 2.4 Bild 2-20 zeigt die Darstellung der REAL-Datentypen. Benutzerdefinierte Aufzählungstypen werden in Pascal wie vorzeichenlose Zahlen (BYTE bzw. WORD) behandelt. Binäre Speicherinhalte werden üblicherweise in der Maschinenorientierten Programmierung - jedoch nicht in Pascal - durch ein vorangestelltes Zeichen % oder durch einen abschließenden Buchstaben B bzw. b gekennzeichnet. Beispiel: 13 d e z i m a l
= 100001101 = 00001101B = 00001101b
Zwecks Verkürzung der Darstellung werden Speicheradressen und Speicherinhalte fast immer hexadezimal angegeben, auch wenn es sich nicht um Zahlen, sondern ganz allgemein um Bitmuster handelt. Das hexadezimale oder sedezimale Zahlensystem arbeitet mit 16 Ziffern und Stellenwertigkeiten zur Basis 16. Es entsteht aus dem dualen Zahlensystem durch eine Zusammenfassung von vier Dualstellen. Bild 1-3 zeigt die hexadezimalen Ziffern von 0 bis 9 und A bis F als Zusammenfassung von vier Binärstellen.
Bitmuster 0 0 00 0 0 01 0 0 10 0 0 11 0 10 0 0 10 1 0 110 O l l i 10 0 0 10 0 1 10 1 0 10 11 110 0 110 1 1110 1111
hexdezimal $0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $A $B $C $D iE $F
dezimal
= 0H = 1H = 2H = 3H = 4H = 5H = 6H = 7H = 8H = 9H = 0AH = 0BH = OCH = 0DH = 0EH = 0FH
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Bild 1 -3: Hexadezimale (sedezimale) Darstellung Pascal kennzeichnet hexadezimale Darstellungen 3owohl als Zahlenkonstanten im Programm als auch bei der Eingabe von ganzen Zahlen durch ein vorangestelltes Zeichen $. Beispiel: VAR i , x : INTEGER; BEGIN i := $1234; ( * 1 *4096 + 2*256 + 3*16 + 4 = 4660 ReadLn(x); WriteLn('i=',i,' x=',x); END. Eingabezeile: $1234 er
•)
14
1. Einführung
in die Hardware
In der Maschinenorientierten Programmierung der 80x86-Prozessoren und in den Handbüchern des Betriebssystems DOS werden Hexadezimalzahlen durch den Kennbuchstaben H bzw. h hinter der Ziffernfolge gekennzeichnet. Erscheint in der vordersten Stelle der Hexadezimalzahl ein Buchstabe (A-F bzw. a - f ) , so wird eine führende Null vorangestellt. Beispiele für 16-bit-DarStellungen (INTEGER): + 13 = %0000 0000 0000 1101 = $000D = 000DH = OOOdh - 1 3 = H i l l 1111 1111 0011 = $FFF3 = 0FFF3H = 0 f f f 3 h Da es in Pascal standardmäßig keine Möglichkeit gibt, Speicherinhalte binär oder hexadezimal auszugeben, werden in diesem Buch die in Bild 1-4 zusammengefaßten benutzerdefinierten Ausgabeprozeduren der BenutzerUnit Aushexbi verwendet. Der Anhang enthält die Pascalprogramme dieser Unit. Prozedurdefinition Ausnib(x : BYTE) Ausbyte(x : BYTE) Ausbhex(x : BYTE) Auswhex(x : WORD) Ausdhex(x : LONGINT) Ausbin(x : BYTE) Ausbbin(x : BYTE) Auswbin(x : WORD) Ausdbin(x : LONGINT) Ausreg(x : Register) Ausmem(p:POINTER s:W0RD)
Ausgabe rechtes Halbbyte hexadezimal Byte zweistellig hexadezimal $ 2 Hexadezimal stellen Leerzeichen $ 4 Hexadezimalstellen Leerzeichen $ 8 Hexadezimal stellen Leerzeichen Byte achtstellig binär % 8 Binärstellen Leerzeichen % 16 Binärstellen Leerzeichen % 32 Binärstellen Leerzeichen alle Prozessorreg ister hexadezimal Speicheradresse und Speicherinhalt
Bild 1-4: Prozeduren der benutzerdefinierten Unit Aushexbi In den Ausgabeprozeduren werden binäre Werte durch ein vorangestelltes %-Zeichen und hexadezimale Werte wie in Pascal durch ein $-Zeichen gekennzeichnet. Das in Bild 1-5 dargestellte Programmbeispiel zeigt die Ausgabe von INTEGER-Zahlen, die als Variablen dezimal oder hexadezimal eingelesen werden. Die Ausgabe erfolgt in der "natürlichen" Darstellung, in der die Werte z.B. in den Registern des Prozessors erscheinen. Die Prozedur Ausmem wird mit einem Zeiger (Addr) und einer Längenangabe ( S i z e O f ) der INTEGER-Variablen aufgerufen und liefert die Adresse und den Inhalt der Variablen im Arbeitsspeicher. Dabei zeigt es sich, daß im Speicher zuerst das niederwertige Byte und dann das höherwertige Byte angeordnet ist. Besonders im Bereich der technischen Anwendungen sollte man sich auch als Pascalprogrammierer darüber im klaren sein, daß alle Daten letztlich nur aus Bitmustern bestehen und daß man ein und dasselbe Bitmuster v e r schiedenartig interpretieren kann. Als Beispiel diene hier das Muster $81 = 81H = X10000001 = 1000000IB. Als vorzeichenlose Dualzahl vom Datentyp BYTE ist es die Dezimalzahl 129, als vorzeichenbehaftete Dualzahl vom Datentyp SHORT INT ist es die Dezimalzahl -127 und als Datentyp CHAR ist es das Zeichen ü.
1.2 Interne Darstellung der ordinalen Datentypen
15
PROGRAB proglp2; (« Bild 1-5: INTEGER-Zahlendarstellung *) USES Aushexbi; (* enthält Auswhex, Auswbin, Ausraem *) VAR i : INTEGER; BEGIN REPEAT WriteLn; WriteC Eingabe -> ' ) ; ReadLn(i) ; WriteC Dezimal: \ i ) ; WriteLn; WriteC Binaer: ' ) ; Auswbin(i); WriteLn; Write(' Hexadezimal : •); Ausvhex(i); WriteLn; WriteC Speicher: ' ) ; Ausnem(Addr(i),SizeOf(i)); WriteLn; UNTIL i = 0; END. Eingabe -> Dezimal: Binaer: Hexadezimal: Speicher: Bild
1 -5:
+13 13 %000000000000U01 $000D $61C1 : $003E = $OD $00
Binäre und hexadezimale Ausgabe von INTEGER-Zahlen
Auf die ganzzahligen Datentypen BYTE, WORD, SHORTINT, INTEGER und LONGINT lassen sich die logischen Operatoren NOT, AND, XOR und OR zur Ausführung von Bitoperationen anwenden. Dabei werden alle Bitpositionen logisch miteinander verknüpft. SHR und SHL verschieben die Bits. Der NOT-Operator dient zur bitweisen Negation (aus 1 mach 0 und aus 0 mach 1) des Operanden. Beispiel: NOT $0F ergibt $F0 Operand: XOOOO 1111 E r g e b n i s : X l l l l 0000 Der AN D-Operator bildet bitweise das logische UND der beiden Operanden und dient zum Löschen von Bitpositionen durch eine Maske. Das Ergebnis wird in den Bitpositionen auf 0 gesetzt, in denen die Maske 0 Ist, und in den Bitpositionen unverändert übernommen, in denen die Maske 1 ist. Das folgende Beispiel löscht alle Bitpositionen bis auf die letzte durch die Maske $01. $0F AND $01 ergibt $01 Operand: XOOOO 1111 Maske: X0000 0001 E r g e b n i s : XOOOO 0001 Der OR-Operator bildet bitweise das logische ODER der beiden Operanden und dient zum Setzen von Bitpositionen. Das Ergebnis wird in den Bitpositionen auf 1 gesetzt, in denen die Maske 1 ist, und in den Bitpositionen unverändert übernommen, in denen die Maske 0 ist. Das folgende Beispiel setzt die links stehende Bitposition auf 1. $0F OR $80 ergibt $8F Operand: XOOOO 1111 Maske: X1000 0000 E r g e b n i s : X1000 1111
16
1. Einführung
in die Hardware
Der XOR-Operator bildet bitweise das logische EODER bzw. das exklusive ODER der beiden Operanden und wird dazu verwendet, bestimmte Bitpositionen zu komplementieren. Im Gegensatz zum NOT-Operator werden nur die Positionen komplementiert, in denen die Maske 1 ist. Das folgende Beispiel komplementiert (negiert) nur die letzte Bitposition und läßt die anderen unverändert. $0F XOR $01 ergibt $0E Operand: 10000 U l i Maske: £0000 0001 E r g e b n i s : X0000 1110 Der SHL-Operator schiebt ein Bitmuster um n bit nach links. Frei werdende Bitpositionen werden durch 0 aufgefüllt, herausgeschobene gehen v e r l o ren. Beispiel: $0F SHL 2 ergibt $3C Operand: 10000 U l i E r g e b n i s : X0011 1100 Der SHR-Operator schiebt ein Bitmuster um n bit nach rechts. Frei werdende Bitpositionen werden durch 0 aufgefüllt, herausgeschobene gehen verloren. Beispiel: $OF SHR 2 ergibt $03 Operand: X0000 U l i E r g e b n i s : 10000 0011
1.3
Die Prozessoren der 80x86-Familie
Als 80x86-Familie bezeichnet man die Mikroprozessoren des Herstellers Intel mit den Typenbezeichnungen 8086, 8088, 80186, 80188, 80286, 80386 und neuerdings auch 80486. In Turbo Pascal unter dem Betriebssystem DOS gilt f ü r alle Prozessoren das in Bild 1-6 dargestellte Registermodell der Prozessoren 8088/8086. Alle Erweiterungen des Registersatzes sowie zusätzliche Betriebsarten der Prozessoren ab 80286 sind in Pascal nur über eingebaute Maschinenbefehle oder Assemblerunterprogramme v e r fügbar.
1 1 SS
1 |DS
i
I IP
1 1 SP
MSI
j i DI
t
Befehlszähler
1 Segmentregister
1 ES
Ics
1 Adreßregister
.
| BP 8/16 b i t
AX|AH
I AL 1
ALU
BXlBH
|BL 1
Flagreg ister O D I T S Z -
cx
A - P - C
Ich
|cl
I
DX i D T T o r i
Bild 1-6: Das Registermodell der 80x86-Prozessoren
Arbeitsregister
1.3 Die Prozessoren der 80x86-Familìe
17
Alle R e g i s t e r s i n d 16 b i t l a n g . Die v i e r S e g m e n t r e g i s t e r CS ( C o d e S e g m e n t ) , S S ( S t a p e l S e g m e n t ) , DS ( D a t e n S e g m e n t ) u n d E S ( E x t r a S e g m e n t ) d i e n e n z u r A d r e s s i e r u n g v o n v i e r B e r e i c h e n d e s A r b e i t s s p e i c h e r s . Die v i e r A d r e ß r e g i s t e r S P ( S t a c k P o i n t e r o d e r S t a p e l z e i g e r ) , BP (Base P o i n t e r o d e r B a s i s z e i g e r ) , S I ( S o u r c e I n d e x o d e r Q u e l l i n d e x ) u n d DI ( D e s t i n a t i o n I n d e x o d e r Zielindex) w e r d e n z u r i n d i r e k t e n A d r e s s i e r u n g v e r w e n d e t . Der B e f e h l s z ä h l e r ( I P o d e r I n s t r u c t i o n P o i n t e r ) i s t i n P a s c a l n i c h t v e r f ü g b a r . Die v i e r 1 6 - b i t - A r b e i t s r e g i s t e r AX ( A k k u m u l a t o r ) , BX ( B a s i s a d r e ß r e g i s t e r ) , CX ( Z ä h l r e g i s t e r ) u n d DX ( H i l f s r e g i s t e r ) k ö n n e n a u c h a l s 8 - b i t - R e g i s t e r b y t e w e i s e v e r w e n d e t w e r d e n . Das F l a g r e g i s t e r (Flag = F l a g g e ) e n t h ä l t A n z e i g e b i t s f ü r b e d i n g t e S p r u n g b e f e h l e (z.B. Null o d e r Z a h l e n ü b e r l a u f ) u n d f ü r b e s o n d e r e P r o z e s s o r z u s t ä n d e (z.B. I n t e r r u p t ) .
Name Registers FCarry FParity FAuxiliary FZero FSign FOverflow Intr(n.r) MsDos(r) CS eg DSeg SSeg SPtr Hi (wort) Lo(wort) Swap(wort) Bild
Typ RECORD CONST CONST CONST CONST CONST CONST Prozedur Prozedur Funktion Funktion Funktion Funktion Funktion Funktion Funktion
Unit Dos Dos Dos Dos Dos Dos Dos Dos Dos
Anwendung Datenstruktur der Register DS,ES,BP,SI,DI,FL. Maske $0001 für Carryflag (Übertrag) Maske $0004 für Parityflag (Parität) Maske $0010 für Auxiliarycarry (Hilfsübertrag) Maske $0040 für Zeroflag (Nullanzeige) Maske $0080 für Signflag (Vorzeichen) Maske $0800 für Overflowflag (Überlauf) Interrupt Nr. "n" mit Registersatz "r" Interrupt $21 mit Registersatz "r" WORD liefert Inhalt des CS-Registers WORD liefert Inhalt des DS-Registers WORD liefert Inhalt des SS-Registers WORD liefert Inhalt des SP-Registers BYTE liefert das High-Byte eines Wortes BYTE liefert das Low-Byte eines Wortes WORD liefert High-Byte vertauscht mit Low-By.
1-7: V o r d e f i n i e r t e V e r e i n b a r u n g e n u n d
Unterprogramme
Die v o r d e f i n i e r t e U n i t D o s e n t h ä l t e i n e R e i h e v o n D e f i n i t i o n e n u n d U n t e r p r o g r a m m e n (Bild 1-7), d i e e s g e s t a t t e n , v o n P a s c a l a u s d i r e k t mit d e m B e t r i e b s s y s t e m DOS z u v e r k e h r e n . Da d a b e i d i e R e g i s t e r d e s P r o z e s s o r s z u r Ü b e r g a b e v o n P a r a m e t e r n v e r w e n d e t w e r d e n , d e f i n i e r t die Unit Dos u n t e r dem B e z e i c h n e r R e g i s t e r s e i n e R e c o r d - D a t e n s t r u k t u r mit d e n P r o z e s s o r r e g i s t e r n e n t s p r e c h e n d d e m R e g i s t e r m o d e l l Bild 1 - 6 . Die W o r t r e g i s t e r m i t d e n B e z e i c h n u n g e n DS, E S , B P , S I , DI, F l a g s , AX, BX, CX u n d DX s i n d v o m D a t e n t y p WORD. Die B y t e r e g i s t e r m i t d e n B e z e i c h n u n g e n AH, AL, BH, BL, CH, CL, DH u n d DL s i n d v o m D a t e n t y p BYTE u n d i d e n t i s c h m i t d e n e n t s p r e c h e n d e n T e i l e n d e r W o r t r e g i s t e r ; AL i s t d a s n i e d e r w e r t i g e B y t e v o n AX. Mit d e n v o r d e f i n i e r t e n M a s k e n k ö n n e n d i e e i n z e l n e n B i t p o s i t i o n e n d e s F l a g r e g i s t e r s u n t e r s u c h t w e r d e n . Das f o l g e n d e Beispiel t e s t e t d a s Carrybit: USES D o s ; VAR reg : Registers; ( * D a t e n t y p RECORD i n D o s ! « ) ( * A u f r u f d e s B e t r i e b s s y s t e m s m i t I n t r o d e r MsDos * ) I F ( r e g . F l a g s AND F C a r r y ) = 0 THEN W r i t e ( ' C = 0 * ) ;
18
1. Einführung
in die Hardware
Die Datenstruktur R e g i s t e r s kann nur Im Zusammenhang mit den v o r d e finierten Prozeduren I n t r bzw. Ms Dos verwendet werden. Dabei dienen P r o z e s s o r r e g i s t e r zur Übergabe von Eingabeparametern an die Prozedur und zur Rückgabe von Ergebnisparametern. Die Prozeduren werten nur bestimmte Register aus und ändern auch nur bestimmte Register; alle anderen Werte d e r Datenstruktur sind bedeutungslos und o f t zufällig. Ein Beispiel ist die vordefinierte Prozedur Ms Dos. übergibt man im AH-Register die Funktionsnummer $30, so l i e f e r t sie in den Byteregistern AL und AH die Nummer der DOS-Version zurück. USES D o s ; VAR reg : Registers; ( « RECORD d e f . i n Dos ! «) BEGIN r e g . a h := $30; ( * W e r t z u w e i s u n g an AH *) MsDos(reg); (* Betriebssystem aufrufen * ) WriteLn(reg.al,'.1,reg.ah) ( * AL und AH a u s w e r t e n *) END. Die Inhalte der Register CS, DS, SS und SP lassen sich durch Aufruf der entsprechenden vordefinierten Funktionen lesen, aber nicht ändern. Die Funktionen H i , Lo und Swap vereinfachen die Arbeit mit den Registern. In der benutzerdefinierten Unit A u s h e x b i (Bild 1-4) befindet sich eine Prozedur A u s r e g , mit der die Prozessorregister wie in dem Testhilfesystem DEBUG ausgegeben werden können. Bild 1-8 zeigt dazu ein P r o grammbeispiel. Die mit kleinen Buchstaben gekennzeichneten Registerinhalte (z.B. ax) stammen aus dem vordefinierten Record R e g i s t e r s , das möglicherweise unbestimmte Werte übergeben kann. Die mit großen Buchstaben gekennzeichneten Register SP, DS, SS und CS werden durch den Aufruf von vordefinierten Funktionen gewonnen und enthalten immer aktuelle Werte.
PROGRAM proglp3; (* Bild 1-8: Register des Prozessors USES Dos, Aushexbi; ( * enthalten Registers, Ausreg VAR reg : Registers; ( * RECORD d e f i n i e r t in Dos BEGIN Intr($12,reg); ( * l i e f e r t Speichergröße in ax Write(reg.ax,' KByte '); reg.ah := $30; (* ah = Funktionsnununer HsDos(reg); ( » l i e f e r t DOS-Version in al und ah WriteLn('DOS-Version 1 , r e g . a l , 1 . ' , r e g . a h ) ; Ausreg(reg); (* Ausgabe der Prozessorregister END.
») *) «) «) *) *) *)
640 KByte DOS-Version 3.30 ax=$lE03 bx=$0000 cx=$0000 dx=$0000 SP=$3FE0 bp=$01B5 si=$0009 di=$0010 DS=$61A7 es=$01BE SS=$61D3 CS=$60CC IP=$xxxx Flags= fcOlllOOlO «OOIOOIO ODIT SZ-A-P-C Bild 1-8: DOS-Funktionen und Registerausgabe
1.4 Die Adressierung des Arbeitsspeichers
1.4
19
D i e A d r e s s i e r u n g des A r b e i t s s p e i c h e r s
Die Adreßregister des Prozessors und der Adreßteil der Maschinenbefehle sind 16 bit lang, damit läßt sich jedoch nur ein Speicherbereich von 64 KByte adressieren. Zur Erweiterung des adressierbaren Speicherbereiches auf 1 MByte (1024 KByte) durch 20 Adreßleitungen dienen die vier Segmentregister des Prozessors. Bild 1-9 zeigt, wie sich eine 20 bit lange Physikalische Speicheradresse aus den beiden Anteilen Segment ( S e g mentregister) und Offset (Adreßregister bzw. Adreßteil des Befehls) zusammensetzt. Offset bedeutet soviel wie Verschiebewert oder Abstand.
Bild 1-9: Bildung der Physikalischen Speicheradresse
Die Segmentadresse wird durch Anhängen von vier Nullen mit 16 multipliziert und zur Offsetadresse addiert, die durch vier führende Nullen erweitert wurde. Die Summe ist die 20 bit lange Physikalische Speicheradresse. Diese Adreßrechnung führt der Prozessor automatisch bei jedem Speicherzugriff durch. Für den Befehlsbereich wird immer das Codesegmentregister, f ü r den Datenbereich wird das Datensegmentregister und f ü r den Stapelbereich wird das Stapelsegmentregister verwendet. Beim Start eines Pascalprogramms lädt das Betriebssystem diese drei Segmentregister mit den Adressen freier Speichersegmente und legt damit fest, auf welchen physikalischen Adressen sich das Programm, die Daten und der Stapel befinden. Für jede Variable legt der Pascalcompiler den Offset innerhalb des maximal 64 KByte großen Datenbereiches fest. Zeigervariablen werden
20
1. Einführung
in die Hardware
ebenfalls im Datensegment angelegt. Bezugsvariablen erhalten durch die Prozeduren N e w und G e t M e m vom Betriebssystem besondere Datensegmente zugewiesen. Bei einem Vergleich von Zeigern ist zu beachten, daß ein und dieselbe Physikalische Speicheradresse durch eine Vielzahl von Kombinationen von Segment und Offset gebildet werden kann. Beispiele: Segment Offset
$0000 $ 1234
Segment Offset
$0123 $0004
Segment Offset
$0111 $0124
Adresse
$01234
Adresse
$01234
Adresse
$01234
Auch in Pascal können anstelle von symbolischen Bezeichnern Zahlenwerte als Adressen von Daten verwendet werden. Die Angabe
segment
:
offset
dient in Pascal zur Adressierung von Speicherbereichen, die sich außerhalb des Datenbereiches auf bestimmten Adressen befinden, segment und o f f s e t sind dezimale oder hexadezimale Konstanten bzw. Variablen oder Ausdrücke vom Datentyp WORD. Die Festlegung der Speicheradressen kann bereits bei der Definition von Variablen vorgenommen werden.
VAR b e z e i c h n e r
datentyp
ABSOLUTE
VAR b e z e i c h n e r
datentyp
ABSOLUTE b e z e i c h n e r
segment
: offset
Erscheint bei einer Variablendefinition hinter dem Kennwort ABSOLUTE eine Angabe in der Form s e g m e n t : o f f s et, so liegt die Variable nicht im Datensegment des Programms, sondern auf einer festen Speicheradresse. Das folgende Beispiel legt eine Variable mit dem Bezeichner ram vom Datentyp WORD auf die absolute Adresse $ 0 0 4 0 : $ 0 0 1 3 , auf der das Betriebssystem normalerweise die Größe des Arbeitsspeichers in der Einheit KByte ablegt. Auf dieses Wort greift die Prozedur I n t r ( $ 12 , r e g i s t e r ) des Beispiels Bild 1-8 zu. VAR ram : WORD ABSOLUTE $0040:$0013 Erscheint hinter dem Kennwort ABSOLUTE der Bezeichner einer bereits definierten Variablen, so weist der Pascalcompiler beiden Variablen die gleiche Speicheradresse (Offset) zu. Der direkte Speicherzugriff durch Angabe einer Adresse und nicht über einen Bezeichner geschieht in Pascal über Ausdrücke, die wie ein Feld ( A r r a y ) aufgebaut sind und daher Pseudofelder genannt werden. Für diesen Zweck sind die drei Pseudofelder Mem vom Datentyp B Y T E , M e m W vom Datentyp WORD und MemL vom Datentyp LONG I N T vordefiniert. Sie werden durch den Pseudoindex s e g m e n t : o f f s e t zur Adressierung von Bytes, Wörtern (2 Bytes) und Doppelwörtern (4 Bytes) verwendet.
1.4 Die Adressierung des Arbeitsspeichers
Mem[segment MemW[segment MemL[segment
21
offset] offset] offset]
Die P s e u d o f e l d e r werden wie Datenfelder (ARRAYs) v e r w e n d e t . Erscheint das Pseudofeld auf d e r linken Seite einer Wertzuweisung, so wird d e r alte Speicherinhalt überschrieben. Erscheint es in einem Ausdruck, so w i r d mit dem augenblicklichen Speicherinhalt g e a r b e i t e t . Das f o l g e n d e Beispiel g i b t v o n d e r Adresse $ 0 0 4 0 : $ 0 0 1 3 ein Wort mit d e r Größe des A r b e i t s s p e i chers aus. Eine Variablendefinition ist d u r c h Verwendung des v o r d e f i n i e r ten Pseudofeldes nicht e r f o r d e r l i c h . WriteLn(MemW [ $ 0 0 4 0 : $ 0 0 1 3 ] , ' K B y t e ' ) ;
Name Seg(x) Ofs(x) Addr(x) Ptr(s.o) SizeOf(x)
Typ Funktion Funktion Funktion Funktion Funktion
Unit
Anwendung : : : : :
WORD liefert die Segmentadresse WORD liefert den Offset (Abstand) Zeiger liefert Adresse als Zeiger (a) Zeiger Segment "s" + Offset "o" WORD liefert Speicherlänge in Bytes
Bild 1-10: V o r d e f i n i e r t e Funktionen zur S p e i c h e r a d r e s s i e r u n g Mit den in Bild 1-10 zusammengestellten v o r d e f i n i e r t e n Funktionen ist es möglich, in Pascal Adressen anstelle v o n Bezelchnern zu v e r w e n d e n . Die Funktion P t r setzt eine Zeigervariable auf eine durch ( s e g m e n t , o f f s e t ) g e g e b e n e Adresse und kann dazu dienen, v o r g e g e b e n e f e s t e S p e i c h e r b e reiche über Zeiger zu adressieren. Das f o l g e n d e Beispiel g i b t den I n h a l t des Wortes auf der Adresse $ 0 0 4 0 : $ 0 0 1 3 mit d e r Größe des A r b e i t s s p e i chers aus. VAR p o i n t : "WORD; BEGIN p o i n t := P t r ( $ 0 0 4 0 , $ 0 0 1 3 ) ; WriteLn(point*,' KBytes'); Das in Bild 1-11 dargestellte Testprogramm z e i g t die v e r s c h i e d e n e n M ö g lichkeiten d e r Speicheradressierung. Durch Bezeichner g e k e n n z e i c h n e t e Variablen und Zeigervariablen liegen in einem maximal 64 KByte großen Datensegment, dessen Lage das Betriebssystem durch Laden des Datens e g m e n t r e g i s t e r s f e s t l e g t . Bezugsvariablen, die mit den P r o z e d u r e n New und GetMem a n g e f o r d e r t werden, können jeweils maximal 64 KByte u m f a s sen. Sie liegen in besonderen Datensegmenten, die ebenfalls vom B e t r i e b s system zugeteilt werden. Mit dem Zusatz ABSOLUTE sowie mit den P s e u d o f e l d e r n Mein, MemW und MemL und mit der Zeigerfunktion P t r kann man v o n Pascal aus auf j e d e Speicherstelle des A r b e i t s s p e i c h e r s z u g r e i f e n . In den Beispielen wurden diese Speicherstellen aus " S i c h e r h e i t s g r ü n d e n " nur gelesen, es ist aber auch ein Beschreiben z.B. des Bildumlaufspeichers möglich.
22
1. Einführung in die
Hardware
PROGRAM proglp4; (* Bild 1-11: Speicheradressierung *) OSES Aushexbi; (* enthält Ausuhex, Ausdhex, Ausmem *) VAR ram : WORD ABSOLUTE $0040:$0013; x : LONGINT; point : 'WORD; zeiger : *LONGINT; BEGIN Write(ram, 1 KByte = ' ) ; Write(HemW[$0030:$0113],' KByte = ' ) ; point := Ptr($0020,$0213); WriteLn(point*, ' KByte 1 ); x := $12345678; Write(' Wert von x hexadezimal = ' ) ; Ausdhex(x); WriteLn; Write(' Speicheradresse von x = ' ) ; Ausuhex(Seg(x)); Write(': ' ) ; Auswhex(Ofs(x)); WriteLn; Write(' Speicherinhalt von x = ' ) ; Au3mem(Addr(x),Size0f(x)); WriteLn; Write('Datensegmentregister DS = ' ) ; Auswhex(DSeg); WriteLn; GetHem(zeiger,4); zeiger* := $FEDCBA98; Write('Zeigervariable Adresse und Inhalt = ' ) ; Ausmem(Addr(zeiger),SizeOf(zeiger) ) ; WriteLn; Write('Bezugsvariable Adresse und Inhalt = ' ) ; Ausmem(Addr(zeiger*),SizeOf(zeiger*)); WriteLn; END. 640 KByte = 640 KByte = 640 KByte Wert von x hexadezimal = $12345678 Speicheradresse von x = $61F2 : $003E Speicherinhalt von x = $61F2 : $003E = $78 $56 $34 $12 Datensegmentregister DS = $61F2 Zeigervariable Adresse und Inhalt = $61F2 : $0046 = $00 $00 $1D $66 Bezugsvariable Adresse und Inhalt = $661D : $0000 = $98 $BA $DC $FE Bild
1-11:
Die
A d r e s s i e r u n g des A r b e i t s s p e i c h e r s
Besonders i n t e r e s s a n t ist die Anordnung d e r Daten im Arbeitsspeicher. Die b e n u t z e r d e f i n i e r t e P r o z e d u r Ausmem d e r Unit A u s h e x b i gibt Speicherinhalte byteweise aus. Dabei zeigt es sich, daß Wörter und Doppelwörter mit dem Low-Byte z u e r s t auf der n i e d r i g e r e n Speicheradresse a n g e o r d n e t sind. Zeigervariablen enthalten ein Doppelwort; z u e r s t wird die Offseta d r e s s e u n d d a n n die Segmentadresse abgelegt, wobei jedes Wort wieder mit dem Low-Byte z u e r s t im Speicher liegt. Beispiele: Wort: Doppelwort: Zeiger:
$12 34 $12345678 $1234:5678
im S p e i c h e r : im S p e i c h e r : im S p e i c h e r :
$34 $12 $78 $56 $34 $78 $56 $34
$12 $12
1.5 Die A dressierung der Peripherie
1.5
2 3
Die Adressierung der Peripherie
Als Peripherie bezeichnet man alle Geräte (z.B. den Drucker), die an den PC angeschlossen sind und die zur Eingabe und Ausgabe von Daten dienen. Die elektrische Verbindung geschieht über Peripheriebausteine, auch Schnittstellen genannt, die auf der einen Seite am Systembus des Rechners liegen und auf der anderen Seite an das Gerät angeschlossen sind (Bild 1-1). Sie enthalten Schaltungen, die Register, Kanäle oder Ports genannt werden. Der Zugriff erfolgt in den meisten Fällen byteweise (8 bit). Bei den Rechnern mit 80x86-Prozessoren liegen die Adressen der Peripheriebausteine vorzugsweise in einem besonderen Peripheriebereich, der von den Adressen des Arbeitsspeichers getrennt ist. Der Zugriff auf die Peripherie erfolgt über die Maschinenbefehle IN und OUT. Gerät (z.B. Drucker)
.tmtnr Datenport
Interface-Baustein A9
A15 Register DX:
AO •Adreßbus • Peripherieauswahlsignal
.AO
16 - bit - Adresse
Befehle IN und OUT
Bild 1-12: Peripherieadressierung
Die Adressierung des Peripheriebereiches (Bild 1-12) geschieht durch ein besonderes Auswahlsignal und eine 16-bit-Portadresse, die direkt auf den Adreßbus gegeben wird. Eine Adreßumsetzung mit einem Segmentregister findet nicht statt. Sind die Peripheriebausteine nur an den unteren Datenbus angeschlossen, so geschieht der Zugriff byteweise. Dies gilt f ü r die Systembausteine des PC wie z.B. den Timer, den Interrupt- und den DMASteuerbaustein sowie für die seriellen und die parallelen Schnittstellen. Die aktuellen Peripherieadressen eines Rechners können den Unterlagen des Geräteherstellers entnommen werden. Beim Start des Betriebssystems werden die Anfangsadressen (Basisadressen) der angeschlossenen Serienschnittstellen (COM) und parallelen Druckerschnittstellen (LPT) in acht Wörter ab Adresse $0040: $0000 eingetragen. Sie können durch das in Bild 1-13 dargestellte Programm ausgegeben werden. Eine Adresse $0000 bedeutet, daß die Schnittstelle in der Schaltung des Rechners nicht v o r handen ist.
24
1. Einführung in die Hardware
PROGRAM proglp5; (* Bild 1-13: Peripherieadressen *) USES Aushexbi; (* enthält Auswhex *) VAR abst : WORD; BEGIN FOR ab3t := 0 TO 3 DO BEGIN Write(' COM',abst+l,•: ' ) ; Auswhex(HeraW[$0040:abst«2]) END; WriteLn; FOR abst := 4 TO 7 DO BEGIN WriteC LPT1 ,abst-3, 1 : •); Auswhex(HemW($0040:abst*2]) END; WriteLn END. COH1: $03F8 LPT1: $0378
COM2: $02F8 LPT2: $0278
COM3: $0000 LPT3: $0000
COM4: $0000 LPT4: $0000
Bild 1-13: Ausgabe der Schnittstellenadressen
Die Ports oder Register der Peripherieschnittstellen sind in Pascal über zwei Pseudofelder zugänglich:
Port[portadresse] PortW[portadres se]
Das Pseudofeld P o r t überträgt Bytes von und zu einem Peripherieport. Das Pseudofeld PortW überträgt Wörter. Als Portadresse (Pseudoindex) dient eine Konstante, Variable oder ein Ausdruck vom Datentyp WORD. Ü b licherweise werden bei einem PC für die Peripherieadressierung von den 16 Adreßbits nur die unteren 10 zur Auswahl der Ports verwendet. Damit stehen anstelle der möglichen 64 Kbit nur 1 Kbit (1024 dezimal) Portadressen zur Verfügung. Werden die oberen sechs Adreßbits wie in Bild 1-14 dargestellt nicht zur Bausteinauswahl verwendet, so lassen sich für einen Port 2 hoch 6 = 64 mögliche Adressen angeben.
Adresse hexadez. $03FF $07 FF $0BFF $0FFF $13FF
$FFFF
n i c h t verwendet A15 A14 A13 A12 A11 AIO 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 1 0
1
1
1
1
1
1
10-bit-Portadresse A9 A8 A7 . . . AO 1 1 $ F F 1 1 $ F F 1 1 $ F F 1 1 $ F F 1 1 $ F F 1
Bild 1-14: Mehrfachadressierung des Ports $03FF
1
$ F F
1.5 Die Adressierung der Peripherie
25
Das folgende Beispiel schreibt den Zahlen wert 85 ($55) in den Port $03FF (Scratch Päd von COM1) und liest ihn von allen möglichen 64 Portadressen wieder zurück. Mit diesem Testprogramm läßt sich das Verhalten eines Rechners bezüglich der Mehrfachadressierung von Peripherieports ü b e r prüfen. VAR i : WORD; BEGIN
P o r t [ $ 03FF] := $55; FOR i : = 0 TO 63 DO W r i t e ( P o r t [ $ 0 3 F F + $ 0 4 0 0 * i ] , ' W r i t e ( ' W e i t e r - > ' ) ; ReadLn
');
Das folgende Beispiel zeigt den Zugriff auf die Serienschnittstelle 8250 des PC, die üblicherweise für den Anschluß der Maus oder eines Modems verwendet wird. Diese Geräte müssen vor der Ausführung des In Bild 1-16 dargestellten Testprogramms entfernt werden! Stattdessen werden e n t sprechend Bild 1-15 ein Voltmeter und ein Taster angeschlossen. Das Bild zeigt die Stiftbelegungen des 9poligen bzw. des 25poligen Steckers an der Rückwand des Rechners. Das Voltmeter dient zur Ausgabe eines Signals; mit dem Taster wird ein Steuersignal eingegeben. Das Programm Bild 1-13 prüft, welche Schnittstellen vorhanden sind.
DTR DCD 0 1
U (V) - 9.8 +10.4
,(5)(4)(3)(2X1
RTS DTR Modemsteuerregister Basis+4 = $03FC
UCU
KI USR
eis
Modemstatusregister Basis+6 = $03FE
Hilfsregister (Scratch Päd) Basis+7 = $03FF Basisadresse C0M1 = $03F8
Serienschnittstelle 8250
Bild 1-15: Steuerleitungen einer seriellen Schnittstelle Die Ports oder Register der Peripheriebausteine liegen auf Adressen, die einen bestimmten Abstand von der Basis- oder Anfangsadresse des Bausteins haben. Das Bild zeigt als Beispiel drei Register der Serienschnittstelle 8250 des PC. Das Hilfsregister ( S c r a t c h Päd) hat den Abstand $7 von der Basisadresse. Es kann wie eine Speicherstelle beschrieben und gelesen werden und hat keine weiteren Aufgaben. Die beiden Bitpositionen 0 und 1
26
1. Einführung
in die Hardware
des Modemsteuerregisters (Basisadresse + $4) sind ü b e r L e i t u n g s t r e i b e r an den Anschlußstecker C0M1 bzw. AUX an d e r Rückseite des PC g e f ü h r t . Eine logische 0 im Bit 0 (DTR) e r s c h e i n t i n v e r t i e r t als High-Potential am Ausgang des Bausteins. Der ebenfalls i n v e r t i e r e n d e L e i t u n g s t r e i b e r s e t z t eine High-Eingangsspannung in eine Ausgangsspannung von ca. -10 Volt um, die am S t i f t 4 des 9poligen Steckers gemessen werden kann. Eine l o g i sche 1 e r s c h e i n t an diesem Stift als ca. +10 Volt. I n dem Modemstatusregis t e r (Basisadresse +$6) wird der Zustand v o n v i e r Eingangssignalen a n g e z e i g t . Eine Spannung g r ö ß e r +3 Volt am S t i f t 1 z.B. wird von dem i n v e r t i e r e n d e n L e i t u n g s e m p f ä n g e r in ein Low-Potential umgesetzt, das ebenfalls i n v e r t i e r t als logische 1 im Bit 7 (DCD) des R e g i s t e r s erscheint. Eine E i n g a n g s s p a n n u n g < - 3 Volt am Stift 1 e r s c h e i n t als logische 0. Bild 1-16 z e i g t ein Testprogramm, mit dem die Modemsteuersignale d e r seriellen Schnittstelle untersucht w e r d e n können. Vor dem Start des P r o gramms i s t darauf zu achten, daß ein möglicherweise an den Stecker a n g e schlossenes Gerät (Maus, serieller D r u c k e r ) e n t f e r n t wird. Ausgang S t i f t 4 ( 9 p o l i g e r S t e c k e r ) wird mit dem Eingang S t i f t 1 oder den anderen d r e i Eingängen v e r b u n d e n . Die Spannung w i r d g e g e n Stift 5 (Masse, Ground) gemessen. Bei Verwendung von v o r g e f e r t i g t e n Anschlußkabeln können möglicherweise Leitungen vertauscht sein. Die vollständigen S t i f t b e l e g u n gen des 25poligen Steckers und des 9poligen Steckers b e f i n d e n sich im Anhang. Das Programmbeispiel b e n u t z t die zweite serielle Schnittstelle (COM2) auf d e r A d r e s s e $02F8. Für die e r s t e serielle Schnittstelle ist die d r i t t e Programmzeile zu ändern: CONST
com = $ 0 3 F 8 ;
(*
1.
serielle
Schnittstelle
C0M1
PROGRAM proglp6; (* Bild 1-16: Modemsteuersignale *) USES Crt, Aushexbi; (* enthält Ausbbin binäre Ausgabe *) CONST com = $02F8; (« 2. serielle Schnittstelle COM2 «) VAR z : CHAR; (« für C0M1: CONST com = $03F8 ! *) BEGIN Port[com+7] := $55; (« Bitmuster = %0101 0101 *) Vrite('Hilfsregister Scratch = '); Ausbbin(Port[com+7]); WriteLn; Write(' Modemsteuerregister = '); Ausbbin(Port[com+4]); WriteLn; Write(' Modemstatusregister = '); Ausbbin(Port[com+6]); WriteLn; REPEAT WriteLn('*-> > >*• :31); Write('Ausgabe: '); Ausbbin(Port[com+4]); Write(' Eingabe: '); Ausbbin(Port[com+6]); WriteLn; Write('Umschalten Bit ! mit Taste (Ende mit *) :'); z := ReadKey; WriteLn; IF z '*' THEN Port[com+4] := Port[com+4] XOR $01; UNTIL z = '*'; WriteLn; END. Hilfsregister Scratch = %01010101 Modemsteuerregister = SsOOOOOOOO Modemstatusregister = %00000000 «_> > >. Ausgabe: W O O O O O O Eingabe: W O O O O O O Umschalten Bit ! mit Taste (Ende mit «) : *->
>
>*
Bild 1-16: T e s t d e r Modemsteuersignale
*)
1.6
1.6
Die Interrupt-und
DMA-Steuerung
27
Die Interrupt- und DMA-Steuerung Abfrageschleife
Interruptsignal
Bild 1 -17: I n t e r r u p t g e s t e u e r t e D a t e n ü b e r t r a g u n g
b e d e u t e t , daß ein Programm d u r c h ein b e s o n d e r e s E r e i g n i s Ein Interrupt u n t e r b r o c h e n wird. Ein d e r a r t i g e s E r e i g n i s wäre ein S t e u e r s i g n a l , d a s meldet, daß an einer Schnittstelle Daten z u r Übernahme d u r c h den Comput e r b e r e i t liegen. Bild 1-17 zeigt die beiden V e r f a h r e n d e r A b f r a g e s c h l e i f e (Polling) u n d d e s I n t e r r u p t s . Müßte d a s Programm in einer A b f r a g e s c h l e i f e die S t e u e r l e i t u n g l a u f e n d kontrollieren, so könnte d e r Rechner keine weit e r e n Arbeiten zu d i e s e r Zeit a u s f ü h r e n . Aus diesem Grunde b e s i t z e n die M i k r o p r o z e s s o r e n b e s o n d e r e I n t e r r u p t e i n g ä n g e , die eine U n t e r b r e c h u n g d e s l a u f e n d e n Programms g e s t a t t e n , um z w i s c h e n d u r c h ein a n d e r e s P r o gramm z.B. z u r D a t e n ü b e r t r a g u n g a u s z u f ü h r e n . Ein Interruptsignal veranlaßt den P r o z e s s o r , nach B e e n d i g u n g d e s l a u f e n den B e f e h l s den S t a n d d e r V e r a r b e i t u n g ( A d r e s s e d e s n ä c h s t e n Befehls) zu r e t t e n und ein I n t e r r u p t p r o g r a m m zu s t a r t e n , d a s die a n g e f o r d e r t e T ä t i g k e i t a u s f ü h r t . Durch Zurückholen d e r g e r e t t e t e n B e f e h l s a d r e s s e wird d a s u n t e r b r o c h e n e Programm normalerweise f o r t g e s e t z t . Bild 1-18 zeigt die I n t e r r u p t s t e u e r u n g d e r P r o z e s s o r e n d e r 80x86-Familie in einem PC. Beim E i n s c h a l t e n d e r V e r s o r g u n g s s p a n n u n g b r i n g t ein R e s e t - S i g n a l den P r o z e s s o r zusammen mit den P e r i p h e r i e b a u s t e i n e n in einen G r u n d z u s t a n d . Dabei wird d a s B e t r i e b s s y s t e m p r o g r a m m (BIOS) a b A d r e s s e $ F F F F : $ 0 0 0 0 a u s einem F e s t w e r t s p e i c h e r (EPROM) g e s t a r t e t . Ein R e s e t - S i g n a l , d a s währ e n d d e s B e t r i e b e s z.B. d u r c h eine R e s e t - T a s t e a u s g e l ö s t wird, b r i c h t d a s l a u f e n d e Programm a b u n d s t a r t e t d a s B e t r i e b s s y s t e m , ohne daß d a s a b g e b r o c h e n e Programm f o r t g e s e t z t w e r d e n k a n n .
28
I. Einführung in die Hardware
G e r ä t z.B. Timer
Nr. $00 W
Schnittstelle
7 6 5 4 3 2 1 0 Interruptsteuerbaustein 8259 A Adresse $20 und $21 Kennzahl
Vektortabelle Adresse Vektor $0 0000 CS : IP $0 0004 CS : IP
Prozes sori nterrupts
2. 8259A ( AT )
Geräteinterrupts
Kennzahl
Software i nterrupts (Betriebssystem)
Datenbus weitere Interrupts INTA
$FF
$0 03FC
CS : IP
INTR Steuerung
externe Sperre XT/PC:$A0 AT:$70 [b7T 0: gesp. 1: f r e i
interne Sperre
Befehl INT n I
I i i t 0: gesp. 1 :frei "•"Vektor $02 —
NMI. RESET-
iKennzahll * 4
_f
[CS" IP
Prozessor
Flag retten nach Stapel
- S t a r t bei $FFFF:0000 M i k r o p r o z e s s o r
80x86
Bild 1-18: Die I n t e r r u p t s t e u e r u n g d e r 80x86-Prozessoren
Ein Signal am NMI-Eingang des P r o z e s s o r s u n t e r b r i c h t das laufende P r o gramm und s t a r t e t ein Interruptprogramm. Die Startadresse ( A d r e s s e des e r s t e n B e f e h l s ) des Interruptprogramms l i e g t als Doppelwort (Segment: O f f s e t ) ab Adresse $ 0 0 0 0 : $ 0 0 0 8 in einer Vektortabelle. NMI bedeutet "Nicht Maskier b a r e r I n t e r r u p t " , weil e r p r o z e s s o r i n t e r n nicht s p e r r b a r ist. In PC-Schaltungen kann er e x t e r n g e s p e r r t bzw. f r e i g e g e b e n w e r d e n und dient zur Behandlung von Hardwarefehlern. Der Eingang INTR ( I n t e r r u p t Request = I n t e r r u p t a n f o r d e r u n g ) kann p r o zessorintern durch das I - B i t des F l a g r e g i s t e r s ü b e r Maschinenbefehle g e s p e r r t und f r e i g e g e b e n werden. I s t beim A u f t r e t e n eines INTR-Signals d e r I n t e r r u p t g e s p e r r t , so setzt das laufende Programm u n g e s t ö r t seine A r b e i t f o r t . I s t der I n t e r r u p t jedoch f r e i g e g e b e n , so w i r d das Programm nach Beendigung des laufenden Befehls unterbrochen. Das Codesegmentr e g i s t e r CS, d e r Befehlszähler I P mit der Adresse des nächsten Befehls und das F l a g r e g i s t e r w e r d e n auf den Stapel g e r e t t e t . Der I N T R - I n t e r r u p t w i r d dabei automatisch ü b e r das I - B i t des F l a g r e g i s t e r s f ü r w e i t e r e U n -
1.6 Die Interrupt-und DMA-Steuerung
29
t e r b r e c h u n g e n g e s p e r r t . Der Prozessor f o r d e r t mit einem INTA-Signal ( I n t e r r u p t Acknowledge = I n t e r r u p t b e s t ä t i g u n g ) ü b e r den Datenbus ein Byte mit einer Kennzahl an. Sie wird von d e r Schaltung geliefert, die den I n t e r r u p t ausgelöst hat, normalerweise von einem I n t e r r u p t s t e u e r b a u s t e i n PIC 8259. Die Kennzahl wird d u r c h Anhängen von zwei Nullen mit 4 multipliziert und l i e f e r t den Offset eines Doppelwortes (32 bit = 4 Bytes) im Datensegment $0000. In diesem Doppelwort b e f i n d e t sich eine Adresse in d e r Anordnung S e g m e n t : Off s e t . Die S e g m e n t a d r e s s e gelangt in das Codesegmentregister, die O f f s e t a d r e s s e gelangt in den Befehlszähler IP. Dadurch wird das I n t e r r u p t p r o g r a m m g e s t a r t e t u n d a u s g e f ü h r t . Durch einen Befehl IRET ( R ü c k s p r u n g aus einem I n t e r r u p t ) am Ende des I n t e r r u p t p r o g r a m m s werden die d r e i g e r e t t e t e n Register CS, IP u n d Flag wied e r vom Stapel z u r ü c k g e l a d e n . Dadurch wird das u n t e r b r o c h e n e Programm f o r t g e s e t z t . Da dabei auch das u r s p r ü n g l i c h e I-Bit wiederhergestellt wird, ist d e r Prozessor wieder f ü r neue IN T R - I n t e r r u p t s bereit. Die NMI- u n d I N T R - I n t e r r u p t s werden im PC von Schaltungen bzw. P e r i p h e r i e b a u s t e i n e n ausgelöst, die Hardwarefehler bzw. die B e r e i t s c h a f t zur D a t e n ü b e r t r a g u n g melden. Andere I n t e r r u p t s löst d e r Prozessor s e l b s t aus, wenn z.B. d a s Rechenwerk eine Division d u r c h Null e r k e n n t . Da in diesem Fall das Ergebnis nicht d e f i n i e r t ist, ist es auch nicht sinnvoll, das Programm f o r t z u s e t z e n . Daher e r z e u g t der P r o z e s s o r eine eigene Kennzahl u n d s t a r t e t damit ein I n t e r r u p t p r o g r a m m , das diesen Divisionsüberlauf z.B. mit einer Fehlermeldung weiterbehandeln k a n n . Als Softwareinterrupt bezeichnet man den Maschinenbefehl INT ( I n t e r r u p t ) , d e r die Kennzahl des zu s t a r t e n d e n I n t e r r u p t p r o g r a m m s im Operandenteil enthält. Diese Art d e r P r o g r a m m u n t e r b r e c h u n g d u r c h einen Befehl w i d e r s p r i c h t d e r Vorstellung, ein Programm d u r c h ein Hardwaresignal zu u n t e r b r e c h e n . Sie wird jedoch vorzugsweise vom Betriebssystem zum Aufruf von Unterprogrammen angewendet u n d wird auch in Turbo Pascal d u r c h v o r d e f i n i e r t e Funktionen und P r o z e d u r e n u n t e r s t ü t z t . Softwarei n t e r r u p t s dienen zum t a b e l l e n g e s t e u e r t e n Aufruf von Unterprogrammen speziell des Betriebssystems. In einem PC u n t e r dem Betriebssystem DOS b e f i n d e t sich die Vektortabelle im Arbeitsspeicher (RAM) a b Adresse $0000 : $0000. Alle Einträge mit den S t a r t a d r e s s e n d e r I n t e r r u p t p r o g r a m m e werden vom Betriebssystem in d e r Anlaufphase v o r b e s e t z t . Da sich die Vektortabelle in einem S c h r e i b / L e s e speicher (RAM) b e f i n d e t , k a n n sie jederzeit, also auch von einem B e n u t z e r programm, g e ä n d e r t werden. Bild 1-19 zeigt die aktuellen Einträge, die normalerweise f ü r den Programmierer ohne I n t e r e s s e sind. Sie wurden mit einem im Anhang befindlichen Programm a u s g e g e b e n . Die I n t e r r u p t s i g n a l e d e r Systembausteine wie z.B. Timer, Harddisk, Flopp y d i s k u n d Schnittstellen werden ü b e r einen (beim AT zwei) I n t e r r u p t s t e u e r b a u s t e i n PIC 8259A (Programmable I n t e r r u p t Controller) auf den I N T R - I n t e r r u p t e i n g a n g des P r o z e s s o r s geschaltet. Der S t e u e r b a u s t e i n übernimmt e n t s p r e c h e n d Bild 1-20 das S p e r r e n u n d F r e i g e b e n d e r I n t e r r u p t s i g n a l e d e r einzelnen Geräte. Er wird beim S t a r t des Betriebssystems so programmiert, daß e r je nach Gerät die Kennzahlen von $08 bis $0F bzw. beim AT zusätzlich von $70 bis $77 liefert. Der größte Teil d e r Kennzahlen
30
1. Einführung
Aktuelle Nummer Adresse 0 $00 $0000 1 $01 $0004 2 $02 $0008 3 $03 $000C 4 $04 $0010 5 $05 $0014 6 $06 $0018 7 $07 $001C 8 $08 $0020 9 $09 $0024 10 $0A $0028 11 $0B $002C 12 $0C $0030 13 $0D $0034 14 $0t $0038 15 $0F $003C 16 $10 $0040 17 $11 $0044 18 $12 $0048 19 $13 $004C 20 $14 $0050 21 $15 $0054 22 $16 $0058 23 $17 $005C 24 $18 $0060 2b $19 $0064 26 $1A $0068 27 $1B $006C 28 $1C $0070 29 $1D $0074 30 $1E $0078 31 $1F $007C 32 $20 $0080 33 $21 $0084
in die Hardware
Interrupt - Vektortabelle Segment O f f s e t Anwendung $407B $00CE Prozessor: Division durch Null $1352 $145C Prozessor: Einzelschrittsteuerung $0DDF $0016 NHI-Interrupt: Systemfehler $1352 $1465 Haltepunkt durch Code $CC $0070 $075C Befehl INTO (Interrupt bei Overflow) $F000 $FF54 BIOS: Hardcopy durch Druck-Taste $F000 $F856 Prozessor (80286: unbekannter Code) $F000 $F856 Prozessor (80286: Speicherschutz) $0DDF $00AB Gerät IRQ0: Timer $1352 $14BA Gerät IRQ1: Tastatur $F000 $F853 Gerät IRQ2: AT: 2.PIC-Baustein XT:Bildschirm $F000 $F853 Gerät IRQ3: COM2 ( S e r i e n s c h n i t t s t e l l e ) $10FD $11BE Gerät IRQ4: COM1 ( S e r i e n s c h n i t t s t e l l e ) $F000 $F853 Gerät IRQ5: AT: LPT2 (Drucker) XT: Festplatte $0DDF $043A Gerät IRQ6: Diskettenlaufwerke $0070 $0750 Gerät IRQ7: LPT1 (Drucker) $1352 $1711 BIOS: Bildschirmfunktionen $F000 $F84D BIOS: Ausgabe der Konfigurationsdaten $F000 $F841 BIOS: Ausgabe der Speichergröße $1352 $1704 BIOS: Disketten- und Festplattenfunktionen $FOOO $E739 BIOS: S e r i e l l e Schnittstellenfunktionen $F000 $F859 BIOS: AT: Echtzeituhr XT: Kassettenlaufwerk $F000 $E82E BIOS: Tastatur- und Druckerfunktionen $F000 $EFD2 BIOS: P a r a l l e l s c h n i t t s t e l l e (Drucker) $FOOO $E000 BIOS: Start des ROM-BASIC (wenn vorhanden) $0070 $191C BIOS: Systemneustart (Strg + A l t + Entf) $F000 $FE6E BIOS: Systemuhrenfunktionen $0AA£ $00F2 BIOS: Unterbrechung (Strg + Pause) $F000 $FF53 BIOS: Timer-Interrupt (18.2 mal pro sek) $F000 $F0A4 BIOS: Zeiger auf Videotabelle $0000 $0522 BIOS: Zeiger auf Laufwerktabelle $C000 $483E BIOS: Zeiger auf Grafikzeichentabelle $0275 $145C DOS: Rücksprung nach DOS $1352 $171F DOS: Betriebssystemfunktionen BsDos(register)
Bild 1-19: Die I n t e r r u p t v e k t o r t a b e l l e im Arbeitsspeicher
bis $7F wird vom Betriebssystem zur Datenübertragung innerhalb des Systems v e r w e n d e t . Dies geschieht im wesentlichen über die S o f t w a r e i n t e r r u p t s mit dem Befehl INT und einer Kennzahl. Ein Beispiel ist die Tastatur. Sie l i e g t am Eingang IRQ1 des I n t e r r u p t s t e u e r b a u s t e i n s und löst beim Betätigen einer Taste einen Geräteinterrupt mit d e r Kennzahl $09 aus. Das über den d o r t e i n g e t r a g e n e n Vektor g e s t a r t e t e Interruptprogramm ermittelt den Tastencode und löst bei der Taste Druck ( P r t S c r ) mit dem Befehl INT $05 einen S o f t w a r e i n t e r r u p t aus. Damit wird ein I n t e r r u p t p r o gramm g e s t a r t e t , dessen Startadresse unter dem d o r t a b g e l e g t e n Vektor e i n g e t r a g e n ist. Die Tastenkombination S t r g und U n t b r ( B r e a k ) f ü h r t z.B. auf den Vektor Nr. $1B. Andere Tastenfunktionen sind über die Vektoren Nr. $16 und $21 v e r f ü g b a r , auf die auch z.T. über weitere Zwischenstationen die Pascalprozeduren Read und EeadLn z u g r e i f e n . Da sich die V e k t o r tabelle in einem RAM-Speicher b e f i n d e t , kann man sich auch von Pascal aus d e r I n t e r r u p t t e c h n i k bedienen. Bild 1-21 z e i g t einige d a f ü r v o r g e s e h e n e v o r d e f i n i e r t e P r o z e d u r e n d e r Unit Dos.
1.6 Die Interrupt-und DMA-Steuerung Disk
LPT2
COM!
COM2
PIC2
Tast. Timer
IRQ7
IRQ6
IRQ5
IRQ4
IRQ3
IRQ2
IRQ1
17 16 15 14 $21
12 11 10
0
Interruptfreigabe 0:frei 1:gesp.
Gerät Timer Tastatur 2. PIC COM2 C0M1 LPT2 Disk LPT1 Bild
CO
LPT1
Interrupt IRQO IRQ1 IRQ2 IRQ3 IRQ4 IRQ5 ÌRQ6 ÏRQ7
$20
Freigabe
w
$FD $FB $F7
$eT $DF $BF $7F
1
1
0
IRQO
0
X
31
RTC
8259 X
X
Interruptbestätigung xxx = IRQ-nr. Sperre
15T $02 $04 $08 $10 $20 $40 $80
Bestätig. $60 $61 $62 $63 $64 $65 $66 $67
Vektor $08 $09 $0A $0B $0C $0D $0E $0F
1 -20: Die P r o g r a m m i e r u n g d e s I n t e r r u p t s t e u e r b a u s t e i n s 8259
Name GetlntVec(n.p) SetlntVec(n.p) SwapVectors Intr(n.r) MsDos(r)
Typ Unit Prozedur Dos Prozedur Dos Prozedur Dos Prozedur Dos Prozedur Dos
Anwendunq kopiert Vektor Nr. "n" nach Zeiger "p" setzt Vektor Nr. "n" auf Zeiger "p" vertauscht Benutzer- mit Dos-Vektoren Interrupt Nr. "n" mit Registersatz "r" Interrupt Nr. $21 mit Registersatz "r"
Bild 1 -21: V o r d e f i n e r t e P r o z e d u r e n z u r I n t e r r u p t b e h a n d l u n g Die P r o z e d u r I n t r e n t s p r i c h t dem M a s c h i n e n b e f e h l INT u n d l ö s t e i n e n S o f t w a r e i n t e r r u p t a u s . Die V e k t o r n u m m e r u n d ein R e c o r d mit dem R e g i s t e r s a t z w e r d e n a l s a k t u e l l e P a r a m e t e r ü b e r g e b e n . Die P r o z e d u r Ms Dos v e r w e n d e t s p e z i e l l die V e k t o r n u m m e r $21 zum A u f r u f d e s B e t r i e b s s y s t e m s DOS. Bild 1 - 8 z e i g t ein A n w e n d u n g s b e i s p i e l . Mit d e r P r o z e d u r S e t l n t V e c k ö n n e n die vom B e t r i e b s s y s t e m v o r b e s e t z t e n I n t e r r u p t v e k t o r e n ü b e r s c h r i e b e n u n d a u f P r o z e d u r e n d e s B e n u t z e r s u m g e l e n k t w e r d e n . Die V e k t o r n u m m e r u n d e i n Z e i g e r mit d e r A d r e s s e e i n e r b e s o n d e r s zu k e n n z e i c h n e n d e n P a s c a l p r o z e d u r w e r d e n als a k t u e l l e P a r a m e t e r ü b e r g e b e n . Bei e i n e r n o r m a l e n B e e n d i g u n g d e s P a s c a l p r o g r a m m s w e r d e n die ü b e r s c h r i e b e n e n I n t e r r u p t v e k t o r e n vom P a s c a l s y s t e m a u t o m a t i s c h w i e d e r h e r g e s t e l l t . Dies k a n n a u c h ü b e r die P r o z e d u r e n G e t l n t V e c ( R e t t e n ) u n d S e t l n t V e c ( Z u r ü c k s c h r e i b e n ) vom P a s c a l p r o g r a m m a u s e r f o l g e n . P a s c a l p r o z e d u r e n , die d u r c h e i n e n I n t e r r u p t a u f g e r u f e n w e r d e n m ü s s e n h i n t e r d e r Definition b e s o n d e r s g e k e n n z e i c h n e t w e r d e n :
sollen,
32
1. Einführung
in die Hardware
PROCEDURE name;
INTERRUPT;
PROCEDURE n a m e ( r e g i s t e r l i s t e " W O R D ) ;
INTERRUPT;
Durch das Kennwort INTERRUPT beendet der Pascalcompiler die Prozedur mit dem Maschinenbefehl IRET, der im Gegensatz zu einem normalen Unterprogrammrücksprung den Befehlszähler IP, das Codesegmentregister CS und das Flagregi3ter vom Stapel zurückholt. Daher kann eine mit INTERRUPT gekennzeichnete Prozedur nicht durch das Pascalprogramm, sondern nur durch einen Interrupt aufgerufen werden. Wird die Interruptprozedur ohne formale Parameter (Registerliste) definiert, so können Werte zwischen dem Hauptprogramm und der Interruptprozedur nur über globale Variablen übergeben werden. Das folgende Beispiel definiert eine Interruptprozedur aus, die durch einen Interrupt Nr. $05 (Druck-Taste) aufgerufen werden soll und den Inhalt der Variablen i ausgibt. USES Dos; ( * wegen S e t l n t V e c *) VAR i : LONGINT; (* Globale PROCEDURE aus; INTERRUPT; BEGIN WriteLn(i) END; ( * Hauptprogramm * ) BEGIN SetlntVec($05,Addr(aus)) ; i := 0; REPEAT Inc(i) UNTIL i > 10000000 END.
Variable
*)
Eine Parameterübergabe kann nur über die Register des Prozessors mit dem vordefinierten Record R e g i s t e r s der Unit Dos erfolgen. Wird die Interruptprozedur mit formalen Parametern definiert, so müssen die Register der Registerliste in der Reihenfolge F lags,CS,IP,AX,BX,CX,DX,SI,DI,DS,ES,BP erscheinen; lediglich Register am Anfang der Liste können entfallen. Die Interruptsteuerung des PC wird in erster Linie vom Betriebssystem für den Betrieb des Gerätes verwendet. Durch Eingriffe des Benutzers, die sich bei technischen Anwendungen und beim Testen nicht vermeiden lassen, kann es zu einem Systemzusammenbruch kommen, der unter Umständen den Griff zum Reset-Schalter oder gar zum Netzschalter erforderlich machen kann. So kann es z.B. zu Schwierigkeiten kommen, wenn eine W r i t e - bzw. WriteLn-Prozedur durch einen Interrupt unterbrochen und in dem Interruptprogramm erneut aufgerufen wird. Da sie nicht wiedereintrittsfest (reentrant) ist, erfolgt kein ordnungsgemäßer Rücksprung. Bei einem Aufruf unter Verwendung der Unit Crt (USES C r t ) arbeiten die
1.6 Die Interrupt-und
DMA-Steuerung
33
Ausgabeprozeduren jedoch einwandfrei direkt in den Bildspeicher. Derartige "Fallen" sind leider in den Pascal- bzw. DOS-Handbüchern nicht immer - auch an der richtigen Stelle - dokumentiert! Die folgenden Beispiele wurden zwar auf dem Gerät des Verfassers erfolgreich getestet, können aber unter Umständen auf anderen Rechnern oder mit anderen Betriebssystemversionen oder Pascalversionen zu Problemen führen.
PROGRAM proglp7; (* Bild 1-22 Interrupt Druck-Taste OSES Dos, Crt; (* Ort wegen Wrlte-Prozedur CONST ende : BOOLEAN = FALSE; zahl : BYTE = 0; (« Durch Interrupt mit Druck-Taste aufgerufen PROCEDURE taste ; INTERRUPT; BEGIN WriteLn('Durch Druck-Taste abgebrochen ! ! ! ' ) ; ende := TRUE ( » oder Halt - Anweisung END; (* Hauptprogramm * ) BEGIN SetIntVec($05,Addr(taste)); (* Vektor umlenken WriteLn('Ausgabe durch "Druck"-Taste abbrechen'); REPEAT WriteLn( 'Testschleife Zahl = \ z a h l ) ; Inc(zahl) UNTIL ende END.
*) *) *)
*)
*)
Ausgabe durch "Druck"-Taste abbrechen Testschleife Zahl = 0 Testschleife Zahl = 1 Testschleife Zahl = 2 Testschleife Zahl = 3 Testschleife Zahl = 4 Testschleife Zahl = 5 Testschleife Zahl = 6 Testschleife Zahl = 7 Testschleife Zahl = 8 Durch Druck-Taste abgebrochen ! ! ! Bild 1 -22: Interrupt durch die Druck-Taste
Die einfachste Testmöglichkeit zur Auslösung eines Interrupts bietet die Tastatur. Das Programmbeispiel Bild 1-22 verwendet dazu die Taste D r u c k (PrtScr), mit der normalerweise der Bildschirminhalt ausgedruckt wird. Der Softwareinterrupt Nr. $05 wird durch den Aufruf der vordefinierten Prozedur S e t l n t V e c auf das Interruptprogramm t a s t e umgelenkt. Dort wird die globale Schaltervariable e n d e auf TRUE gesetzt, durch die die Testschleife des Hauptprogramms ein Ende findet. Die Pascalprozedur H a l t könnte dazu verwendet werden, das Programm bereits in der I n t e r ruptprozedur abzubrechen. Durch Zuordnung der Unit C r t kann die A u s gabeprozedur W r i t e L n sowohl im Hauptprogramm als auch in der I n t e r ruptprozedur verwendet werden. Ohne diese direkte Ausgabe könnte es unter Umständen zu einem Systemzusammenbruch kommen.
34
1. Einführung in die Hardware
PROGRAB proglpS; (* Bild 1-23: Interrupt Strg - Untbr * ) USES Dos, Crt; ( « Nur als PR0G1P8.EXE starten Ii* *> VAR rettvek : POINTER; reg : Registers; zahl : BYTE; ( * Aufgerufen durch Interrupt mit Tasten Strg - Untbr * ) PROCEDURE taste(Flags,CS,IP,AX,BX,CX,DX,SI,DI, DS,ES,BP:WORD); INTERRUPT; BEGIN WriteLn(11nterruptprograrom aufgerufen ! ! ! ' ) ; reg.ax := 1; (* ax = Endemarke für Hauptprogramm * ) END; (* Hauptprogranun *) BEGIN GetIntVec($IB,rettvek); (* Vektor retten *) SetIntVec($lB,addr(taste)); (* Vektor umlenken * ) reg.ax := 0; zahl := 1; WHILE reg.ax = 0 DO (* Endemarke für Interrupt * ) BEGIN WriteLnC Testschleife Durchlauf ' , z a h l ) ; Inc(zahl) END; SetIntVec($lB,rettvek); (* Vektor zurück *) WriteLn('Programmabbruch Register AX = ' , reg.ax) END. C:\TURB0P\PR0G1>proglp8 Testschleife Durchlauf 1 Testschleife Durchlauf 2 Testschleife Durchlauf 3 Testschleife Durchlauf 4 Testschleife Durchlauf 4 Testschleife Durchlauf 6 Interruptprogramm aufgerufen ! ! ! Programmabbruch Register AX = 1 Bild 1 -23: Interrupt durch die Abbruchtaste Das in Bild 1-23 dargestellte Programmbeispiel benutzt die Abbruchtaste ( S t r g - U n t b r bzw. B r e a k ) zur Auslösung eines Interrupts mit der Nr. $1B. Die Parameterübergabe e r f o l g t in diesem Beispiel über das AX-Register. Der ursprüngliche Vektor wird mit G e t l n t V e c gerettet und v o r der Beendigung des Programms mit S e t i n t V e c wiederhergestellt. Als das P r o gramm aus der integrierten Entwicklungsumgebung des Pascalmenüs g e startet wurde, führte die Abbruchtaste wie üblich zurück in die Pascaltesthilfe Debug. Erst die Compilierung eines EXE-Programms und der Start aus dem Betriebssystem brachte den gewünschten Aufruf des I n t e r r u p t programms t a s t e . Auch hier zeigt es sich wieder, daß man bei der d i r e k ten Arbeit mit dem Betriebssystem mit Überraschungen rechnen muß und auf eigene Testprogramme angewiesen ist. Das in Bild 1-24 dargestellte vereinfachte Schaltbild zeigt die Wege, die ein Interruptsignal vom Eingang DCD (Stift 1) der seriellen Schnittstelle COM1 bis zum Prozessor nimmt. Jede Änderung des Stiftpotentials (High nach Low bzw. Low nach High) setzt die Bitposition B3 des Modemstatus-
1.6 Die Interrupt-und
U
pGQ dhàw
11
4,5
4
A
tra A
I I » H
h
À
0 Ì RTS ! DTR
O i 0
35
55 ms —•
Kl I HlOOub
3(3)
DMA-Steuerung
Modemsteuerreg i ster Basis+4 = $03FC
DCD
DCO
Modemstatusregister Basis+6 = $03FE
|0 o I o i 0 j 1 1 0 j Interruptfreigaberegister Basis+1 = $03F9
0|
Basisadresse COM1 = $03F8
| x | x | x| 0 1 X 1 X 1 Interruptfreigaberegister Adresse $21 Maske $EF: IRQ4 f r e i
IQ l 0 Leitungssteuerregister Basis+3 = $03FB Serienschnittstelle 8250
x x l
-HO ¡ 0 ! OS 0 1 1 1 1 1 0 1 Ol Interruptvektorreg i ster Vektor $0C: IRQ4
lo 1 1 1 1 1 0 1 0 1 1 1 0 1 ol Interruptbestätigungsregister Adresse $20 Byte $64: IRQ4 bestätigt
Interruptsteuerbaustein PIC 8259A
Inte rruptvektdebug prog2pl.exe -r AX=0000 BX=0000 CX=03A0 DX=0000 SP=4000 DS=5585 ES=5585 SS=5610 CS=5595 IP=0023 5595:0023 9A00009E55 CALL 559E:0000
BP=0000 SI=0000 DI=0000 NV UP EI PL NZ NA PO NC
42
2. Einführung in die Maschinensprache
- u 3b 49 5595:003B 5595:003D 5595:0040 5595:0041 5595:0043 5595:0045 5595:0048 5595:0049 -q
BOOO BAFC03 EE EBOO B001 BAFC03 EE EBFO
MOV MOV OUT JHP MOV MOV OUT JHP
AL,00 DX,03FC DX, AL 0043 AL, Ol DX,03FC DX,AL 003B
lade AL mit Bitmuster 0000 0000 = $00 lade DX mit P o r t a d r e s s e $03FC (C0M1) gib AL auf Port aus (DX e n t h ä l t A d r e s s e ) s p r i n g e immer zum Befehl Adresse $00*13 lade AL mit Bitmuster 0000 0001 = $01 lade DX mit P o r t a d r e s s e $03FC (C0M1) gib AL auf Port aus (DX e n t h ä l t A d r e s s e ) s p r i n g e immer zum Befehl Adresse $003B
Bild 2-1: P a s c a l p r o g r a m m mit R ü c k ü b e r s e t z u n g Das i n Bild 2-1 d a r g e s t e l l t e P a s c a l p r o g r a m m l i e f e r t e v o n a l l e n u n t e r s u c h t e n r e i n e n P a s c a l p r o g r a m m e n mit 208 kHz d i e h ö c h s t e F r e q u e n z . D u r c h d e n u n b e d i n g t e n S p r u n g GOTO e n t f ä l l t g e g e n ü b e r d e r i n Bild 1 - 2 5 g e z e i g t e n L ö s u n g m i t d e r S c h l e i f e REPEAT UNTIL d i e z e i t a u f w e n d i g e S c h l e i f e n k o n t r o l l e . Der e i g e n t l i c h ü b e r f l ü s s i g e S p r u n g GOTO l o o p 2 d i e n t d a z u , b e i d e H a l b w e l l e n g l e i c h l a n g zu m a c h e n ( T a s t v e r h ä l t n i s 1:1). Das P r o g r a m m w u r d e mit d e m T u r b o P a s c a l S y s t e m in e i n l a d b a r e s b i n ä r e s M a s c h i n e n p r o g r a m m ü b e r s e t z t u n d mit dem Z u s a t z .EXE in d a s z u g e o r d n e t e V e r z e i c h n i s a u f g e n o m m e n . D e r v o m Compiler e r z e u g t e M a s c h i n e n c o d e , d e r i n d e r E X E D a t e i a b g e s p e i c h e r t i s t , k a n n mit d e m T e s t h i l f e s y s t e m DEBUG ( E n t w a n z e r o d e r K a m m e r j ä g e r ) u n t e r s u c h t w e r d e n . Der A u f r u f v o n DEBUG e r f o l g t a u s dem B e t r i e b s s y s t e m mit d e m Kommando
> DEBUG
name.EXE
S t e h t h i n t e r DEBUG d e r Name e i n e r D a t e i (z.B. p r o g 2 p l . e x e ) , s o w i r d d i e s e in d e n A r b e i t s s p e i c h e r geladen u n d s t e h t z u r U n t e r s u c h u n g d u r c h die D E B U G - K o m m a n d o s z u r V e r f ü g u n g . Die H a n d b ü c h e r zum B e t r i e b s s y s t e m DOS e n t h a l t e n e i n e B e s c h r e i b u n g v o n DEBUG. Das K o m m a n d o r g i b t d e n I n h a l t d e r P r o z e s s o r r e g i s t e r a u s . Die S e g m e n t r e g i s t e r CS u n d DS e n t h a l t e n d i e S e g m e n t a d r e s s e f ü r d e n C o d e u n d d e n D a t e n b e r e i c h . Der Befehlszähler IP e n t h ä l t die S t a r t a d r e s s e . Das R e g i s t e r CX e n t h ä l t d i e A n z a h l d e r g e l a d e n e n B y t e s . Alle Z a h l e n a n g a b e n im T e s t h i l f e s y s t e m DEBUG s i n d H e x a d e z i m a l z a h l e n o h n e $ b z w . H. Das K o m m a n d o u b e r e i c h k a n n z u r R ü c k ü b e r s e t z u n g v o n b i n ä r e m C o d e i n d i e A s s e m b l e r s c h r e i b w e i s e v e r w e n d e t w e r d e n ( D i s a s s e m b l e r ) . D a s Bild 2-1 zeigt die R ü c k ü b e r s e t z u n g d e r Ausgabeschleife; die Kommentare w u r d e n n a c h t r ä g l i c h e i n g e f ü g t . D e r M a s c h i n e n b e f e h l JMP e n t s p r i c h t d e r P a s c a l a n w e i s u n g GOTO. E r f ü h r t e i n e n u n b e d i n g t e n S p r u n g zum a d r e s sierten Befehl aus. Mit d e m K o m m a n d o q k e h r t man z u r ü c k i n d a s B e t r i e b s s y s t e m . E i n e A n a l y s e d e s e r z e u g t e n C o d e s z e i g t , daß d e r B e f e h l MOV DX, 0 3 F C , d e r s o g a r z w e i mal v o r k o m m t , a u s d e r S c h l e i f e h e r a u s g e n o m m e n w e r d e n k ö n n t e , d a d a s R e g i s t e r DX i n d e r S c h l e i f e n i c h t v e r ä n d e r t w i r d . Dies k a n n n u r in e i n e m A s s e m b l e r p r o g r a m m g e s c h e h e n , i n d e m d e r P r o g r a m m i e r e r d i r e k t mit d e m Register- und Befehlssatz des Prozessors arbeitet.
2.1 Pascal-und Assemblerprogramme
C:\>debug -r AX=0000
BX=0000
DS=556D
ES=556D
CX=0000
DX=0000
SP=FFEE
BP=0000 S1=0000 DI=0000 NV UP EI PL NZ NA PO NC
IP=0100 S S = 5 5 6 D CS==556D HOV DX.03FC
556D:0100 BAFC03 -a 556D:0100 mov dx,03fc 556D:0103 mov al,00 556D-.0105 out dx,al 556D:0106 jmp 0108 5S6D:0108 mov al,Ol 556D:010A out dx,al 556D:010B jmp 0103 556D:010D -u 0100 010b , 556D:0100 BAFC03 556D:0103 B000 556D:0105 EE 556D:0106 EBOO 556D:0108 B001 556D:010A EE 556D:010B EBF6
T=
DTR + 10V-
-10V
HOV MOV OUT JHP HOV OUT JHP
DX.03FC AL.00 DX,AL 0108 AL, O l D X , AL 0103
43
us
f = 227
kHz^
/
LT l_
lade OX nit Portadresse $03FC (C0M1) lade AL mit Bitmuster 0000 0000 = $00 gib AL auf Port aus (OX enthalt Adresse) springe inner zun Befehl Adresse $0108 lade AL nit Bitmuster 0000 0001 = $01 gib AL auf Port aus (DX enthält Adresse) springe inner zun Befehl Adresse $0103
-q
C:\>
Bild 2-2: Eingabe eines Assemblerprogramms mit DEBUG
Mit dem Kommando a kann das Testhilfesystem DEBUG dazu verwendet werden, Assemblerbefehle symbolisch einzugeben und in den Maschinencode übersetzen zu lassen. Der Aufruf von DEBUG erfolgt dabei ohne einen Dateinamen. Der DEBUG-Assembler enthält Einschränkungen gegenüber den Mehrpass-Assemblern wie z.B. Turbo Assembler oder MASM. In dem in Bild 2-2 dargestellten Programmbeispiel wurde der Befehl MOV DX.03FC aus der Schleife herausgenommen. Dadurch erhöhte sich die Ausgabefrequenz auf 227 kHz. Weitere Untersuchungen zeigten, daß die Schleife LOOP:
OUT
DX,AL
XOR
AL.01H
JMP
LOOP
eine noch höhere Frequenz von 250 kHz liefert. Dabei wird das letzte Bit von AL durch die exklusive ODER von 0 auf 1 bzw. von 1 auf 0 laufend umgeschaltet. Das in Bild 2-3 dargestellte reine Assemblerprogramm bereitet einen Interrupt mit der Druck-Taste vor und benutzt die schnelle Ausgabeschleife. Es wurde mit dem Turbo Assembler des Herstellers Borland übersetzt, der auch Turbo Pascal und Turbo C liefert. Bei der Arbeit mit einem Mehrpass-Assembler (nicht DEBUG!) wird wie in Pascal zunächst das symbolische Programm vollständig eingegeben. Da die Assembler in der Regel keinen integrierten Editor zur Verfügung stellen, kann die Eingabe z.B. mit dem Editor des Turbo Pascal erfolgen. Das symbolische Assemblerprogramm erhält einen Namen mit dem Zusatz . ASM. Ruft man den Assembler (Ubersetzer) aus dem Betriebssystem z.B. mit >TASM name,, , ;
44
2. Einführung
Turbo Assembler PROG2P2.ASH
Version 1.01 Ergebnis : T = 4.0 ms f = 250 kHz
0000 0000 0000 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
in die Maschinensprache
0000 0002 0004 0006 0008 000A OOOD OOOF 0011
B4 BO CD 8C 8E BA B4 BO CD
35 05 21 C8 D8 001 Dr 25 05 21
0013 0016 0018 0019 001B
BA BO EE 34 EB
03FC 00
001D 001F 0021 0023 0025 0027 0029 002A 002B 002C 002E 0030
8C 8E 8B B4 BO CD 58 58 9D B4 BO CD
Ol FB CO D8 D3 25 05 21
4C 00 21
1
1
27/04/90 15:01:42
Page 1
Bild 2-3: Assemblerprogramm Rechteck .HÖDEL SHALL ; Code- und Datenseg .STACK 100h ; 256 Bytes Stapel .CODE ; Befehlsbereich Vektor "Druck"-Taste retten und umlenken start: mov ah,35h Vektor lesen mov al, 05h "Druck"-Taste DOS-Aufruf: ES:BX int 21h mov Codesegmentreg. ax, es mov ds, ax DS = Segmentadr. mov dx,OFFSET druck ; dx = Offset mov Vektor schreiben ah,25h mov al,05h "Druck"-Taste DOS-Aufruf: DS:DX int 21h ; Rechteck ausgeben Abbruch mit "Druck" mov dx,03fch DX = Portadresse mov al,00h AL : DTR = Low auf Port ausgeben aus: out dx,al xor DTR umschalten al,01h Schleife jmp aus ; Interrupt durch "Druck"-Taste druck: mov ax, es Vektor zurueck mov ds.ax DS = Segmentadr. mov dx.bx DX = Offsetadr. mov ah,25h Vektor schreiben mov al,05h "Druck"-Taste int 21h DOS-Aufruf: DS:DX pop ax IP vom Stapel pop ax CS vom Stapel popf Flags vom Stapel mov ah,4ch DOS-Ruecksprung Endecode: normal mov al,00h int 21h DOS-Ruecksprung end start Ende der Zeilen
Bild 2-3: U b e r s e t z u n g s l i s t e des T u r b o Assemblers
auf, so e r z e u g t d i e s e r neben dem Maschinencode eine Ü b e r s e t z u n g s l i s t e , die mit dem DOS-Kommando TYPE name. LST auf dem Bildschirm a u s g e g e ben w e r d e n k a n n . Ein Bindeprogramm, das z.B. mit >TLINK name a u f g e r u f e n w i r d , e r z e u g t ein Maschinenprogramm name .EXE, das mit Hilfe d e s Betriebssystems g e l a d e n und a u s g e f ü h r t w e r d e n kann. In d e r i n t e g r i e r t e n E n t w i c k l u n g s u m g e b u n g d e s T u r b o Pascal sind Editor, Ü b e r s e t z e r (Compiler), Binder, L a d e r u n d Testhilfe in einem Programmpaket zusammengefaßt. Ein Vergleich des Pascalprogramms Bild 2-1 mit dem Assemblerprogramm Bild 2-3 zeigt, daß d e r Assembler die Eingabe von optimierten Programmen ermöglicht, die schnell a u s g e f ü h r t w e r d e n ; jedoch ist die Programmierung in d e r A s s e m b l e r s p r a c h e umständlicher u n d z e i t a u f w e n d i g e r als in Pascal. Durch die I N L I N E - A n W e i s u n g des T u r b o Pascal ist es möglich, in einem Pascalprogramm Maschinenbefehle zu v e r w e n d e n , die j e d o c h bereits h e x a dezimal ü b e r s e t z t v o r l i e g e n müssen.
2.1 Pascal-und Assemblerprogramme
INLINE
(element/element/
45
);
Auf das Kennwort I N L I N E f o l g t in Klammern eine Liste d e r in das Pascalprogramm e i n z u f ü g e n d e n Maschinencodes, die durch einen S c h r ä g s t r i c h / zu trennen sind. Ein Element kleiner als 256 wird als Byte a b g e l e g t . Sonst werden Wörter in der Reihenfolge L o w - B y t e und High-Byte a b g e l e g t . Der Operator > e r z e u g t immer ein Wort, g e g e b e n e n f a l l s mit f ü h r e n d e n Nullen. Der Operator < e r z e u g t immer ein Byte, g e g e b e n e n f a l l s durch A b schneiden v o n f ü h r e n d e n Stellen. Es sind dezimale und hexadezimale Konstanten sowie Bezeichner v o n Konstanten und Variablen des Pascalprogramms zulässig. Bei globalen Variablen w i r d die Adresse ( 1 6 - b i t - O f f s e t ) im Datensegment e i n g e t r a g e n , nicht d e r Inhalt (Wert). Beispiele: $12/ Hexadezimales Byte >$12/ A u s g e d e h n t e s W o r t $0012 g i b t $12 $00 $1234/ H e x a d e z i m a l e s W o r t g i b t $34 $12 debug prog2p3.exe -r AX=0000 BX=0000 CX=0390 DX=0000 SP=4000 DS=5589 ES=5589 SS=5613 CS=5599 IP=0023 5599:0023 9A0000A155 CALL 55A1:0000 -u 3b 43 5599::003B BAFC03 MOV DX,03FC 5599::003E B000 MOV AL, 00 5599::0040 EE DX, AL OUT 5599::0041 3401 AL,Ol XOR 5599::0043 EBFB JMP 0040
Bild
BP=0000 SI=0000 DI=0000 NV UP EI PL NZ NA PO NC
2-4: Pascalprogramm mit I N L I N E - A s s e m b l e r c o d e
46
2. Einführung
in die
Maschinensprache
Das in Bild 2-4 d a r g e s t e l l t e Pascalprogramm enthält den Code d e r schnellen Ausgabeschleife aus dem Assemblerprogramm Bild 2-3. Die R ü c k ü b e r setzung der Schleife mit DEBUG z e i g t , daß d e r Pascalcompiler die hexadezimalen Befehle r i c h t i g eingesetzt hat. Bei der Übernahme d e r Maschinenbefehle aus den Übersetzungslisten d e r T e s t h i l f e DEBUG bzw. d e r Mehrpass-Assembler ist äußerste Vorsicht g e b o ten. So wird z.B. d e r Befehl MOV DX, 03FCH in d e r Ü b e r s e t z u n g s l i s t e Bild 2-3 als BA 03FC d a r g e s t e l l t ; die Wortkonstante wird aber im Speicher mit dem L o w - B y t e z u e r s t abgelegt. Erst eine Kontrolle des Speichers mit DEBUG z e i g t die r i c h t i g e Reihenfolge BA FC 03. Weitere Probleme e r g e b e n sich an den durch r , s o d e r e g e k e n n z e i c h n e t e n Stellen, an denen sich noch Adreß w e r t e ändern können, sowie bei Unterprogrammen mit lokalen Variablen, d i e im Stapel angelegt werden. Eine Folge v o n Maschinencodes, die mehrmals in einem Pascalprogramm b e n ö t i g t wird, kann mit einer INLINE-Deklaration d e f i n i e r t werden.
PROCEDURE name; I N L I N E (e1ement/e1ement/ . . . ) ;
Hinter dem Kennwort PROCEDURE steht der Name (Bezeichner) g e f o l g t v o n dem Kennwort I N L I N E und einer Liste d e r Maschinencodes. An den Stellen, an denen d e r Name im Programm erscheint, baut d e r Pascalcompiler die d e f i n i e r t e n Maschinenbefehle ein. Das in Bild 2-5 dargestellte Programmbeispiel z e i g t die Definition des Codes f ü r die schnelle Ausgabeschleife u n t e r dem Bezeichner r e c h t e c k . Die Rückübersetzung mit DEBUG zeigt, daß d e r Pascalcompiler die Codefolge an d e r Stelle des A u f r u f s mit r e c h t e c k e i n g e f ü g t hat.
PROGRAM prog2p4; ( * B i l d 2-5: INLINE-Prozedur Assemblercode USES Dos; CONST aus = $03fc; ( * h i e r : C0M1 für C0112.: aus = $02fc ( * Abbruch der S c h l e i f e durch Interrupt mit "Druck"-Taste PROCEDURE stopp; INTERRUPT; BEGIN halt END; ( * INLINE-Prozedur enthält hexadezimalen Assemblercode PROCEDURE rechteck; INLINE ($BA/aus/ ( * mov dx,03fch Ergebnis : $BO/$00/ ( « mov al,00h * T = 4.0 ys $EE/ ( * out dx,al f = 250 kHz $34/$01/ ( * xor al,01h * $EB/$FB ( * jmp r e l -5 *
);
«) *) ") *)
BEGIN ( * Hauptprogramm i n i t i a l i s i e r t Interrupt "Druck"-Taste * ) SetIntVec($05,Addr(stopp)); rechteck; ( * Prozedur zur Rechteckausgabe auf DCD von COH1 * ) END.
2.2 Der Register-und
C:\TURBOP\PROGl>debug prog2p4.exe -r AX=0000 BX=0000 CX=0390 DX=0000 SP=4000 DS=5592 ES=5592 SS=561C CS=55A2 IP=0023 55A2:0023 9A0000AA55 55AA:0000 CALL -u 3b 43 MOV 55A2:003B BAFC03 DX,03FC AL,00 55A2:003E B000 HOV 55A2:0040 EE OUT DX, AL 55A2:0041 3401 XOR AL, Ol 55A2:0043 EBFB JHP 0040 -q
Befehlssatz
47
BP=0000 SI=0000 DI=0000 NV UP EI PL HZ NA PO NC
Bild 2-5: Pascalprogramm mit INLINE-Deklaration Die INLINE-Deklaration e n t s p r i c h t d e r Makro-Deklaration d e r Assemblersprache, bei d e r ebenfalls v o r d e f i n i e r t e Befehlsfolgen in das Assemblerprogramm eingebaut werden können. Die INLINE-Deklaration ist t r o t z des Kennwortes PROCEDURE kein Unterprogramm, das nur einmal im A r b e i t s speicher steht und mehrmals a u f g e r u f e n wird. Dies e r k e n n t d e r Compiler an dem fehlenden BEGIN . . . END;. Das gleiche gilt auch f ü r I N L I N E Deklarationen mit den Kennwörtern PROCEDURE und FUNCTION, die wie in der Unterprogrammtechnik Parameter enthalten. Fehlen die Kennwörter BEGIN . . . END;, so werden keine Unterprogramme a u f g e r u f e n , sondern es w i r d der v e r e i n b a r t e Code in das Programm eingebaut!
2.2
Der Register-und Befehlssatz
Befehlsbereich
Stapelbereich
Datenbereich
Datenbereich
Codesegment
Stapelsegment
Datensegment
Ziel bei Stringbefehlen
64 KByte
64 KByte
64 KByte
64 KByte
HE
-
-
-
-
0 D I T
-
A
-
P
-
Flagregister
C
SS TsF
3
LBP
1
• s i r r s ^ i ¡pi 1 1
r . j
•displacement
Bild 2-6: Die Speicheradressierung
48
2. Einführung
in die
Maschinensprache
Das in Bild 2-6 dargestellte Modell zeigt den Registersatz, den Turbo Pascal standardmäßig ohne Rücksicht auf den tatsächlich zur V e r f ü g u n g stehenden P r o z e s s o r zur Adressierung des A r b e i t s s p e i c h e r s v e r w e n d e t und der auch in den folgenden Betrachtungen benutzt werden soll. Im Abschnitt 1.4 Bild 1 - 9 wurde g e z e i g t , wie die 20 bit lange Physikalische S p e i c h e r a d r e s s e aus einer 16-bit-Segmentadresse und einem 1 6 - b i t - O f f s e t ( A b s t a n d ) zusammengesetzt wird. Das Codesegmentregister CS a d r e s s i e r t zusammen mit dem Befehlszähler I P den Befehlsbereich. Das Datensegmentr e g i s t e r DS a d r e s s i e r t zusammen mit einer Datenadresse ( O f f s e t ) bzw. mit A d r e ß r e g i s t e r n den Datenbereich. Das Stapelsegmentregister SS a d r e s s i e r t zusammen mit dem Stapelzeiger SP bzw. mit dem Basiszeiger BP den Stapelbereich, d e r eine besondere Rolle in d e r I n t e r r u p t - und U n t e r p r o grammtechnik spielt. Das Extradatensegmentregister ES wird nur im Zusammenhang mit Stringbefehlen v e r w e n d e t . Diese v o r g e g e b e n e Zuordnung d e r Segmentregister kann durch einen Segmentvorsatz v o r einer Datenadresse a u f g e h o b e n werden. Neben den v i e r Segmentregistern u n t e r scheidet man unabhängig v o n i h r e r Verwendung die acht Wortregister SP, BP, DI, SI, AX, BX, CX und DX und die acht B y t e r e g i s t e r AH, AL, BH, BL, CH, CL, DH und DL. AH ist das höherwertige Byte v o n AX; AL ist das n i e d e r w e r t i g e Byte v o n AX. Diese symbolischen Registerbezeichnungen sind f e s t in d e r Assemblersprache v e r e i n b a r t und d ü r f e n nicht zur Bezeichnung v o n Datenspeicherstellen und Sprungzielen v e r w e n d e t werden.
name name ñame
name name
typ
name
DB DM DD ~
byte wort doppelw.
wert EQU EXTRN FAR NEAR OFFSET name name PTR ~ PUBLIC" name SEG name
PROC
typ
DatenVereinbarungen legt Bytekonstanten ab bzw. reserviert Bytes legt Wortkonstanten ab bzw. reserviert Wörter legt Doppelwortkonstanten ab bzw. reserviert Assembleranweisunqen legt unter einem Namen eine Konstante ab kennzeichnet eine extern definierte Adresse Adresse wird gebildet aus Segment : offset Segmentadresse bleibt, Adresse ist offset liefert den Abstand (offset) einer Adresse legt Typ des Operanden fest Name auch in anderen Moduln verfügbar liefert das Segment einer Adresse "Rahmen" eines Unterprogramms typ = FAR (weit) oder NEAR (nahe)
ENDP
Endemarke des Unterprogramms
sname
SEGMENT ASSUME
"Rahmen" eines Seqmentes Anfang des Segmentes segmentreg ister : segmentname
sname
ENDS
Ende des Seqmentes
END
start
Endemarke eines Assemblerprogramms
Bild 2-7: Einige wichtige Assembleranweisungen
2.2 Der Register- und Befehlssatz
49
In der Assemblersprache unterscheidet man Assembleranweisungen, die nur die Arbeitsweise des Assemblers (Übersetzers) steuern und daher keinen Code erzeugen, und Befehle, die in ausführbaren Maschinencode übersetzt werden. Kommentare beginnen mit einem Semikolon ";". Bild 2-7 zeigt die wichtigsten Assembleranweisungen. Durch Datenvereinbarungen können Datenspeicherstellen wie in Pascal mit frei wählbaren symbolischen Hamen (Bezeichnern) angesprochen werden. Dabei unterscheidet man die Reservierung von Speicherplatz ohne Vorbesetzung (Pascal: VAR name : typ) und mit Vorbesetzung durch Konstanten (Pascal: CONST name : typ = Wert). Beispiele: daten bzahl bkons wzahl wkons daten
SEGMENT DB ? DB DW 10 D U P (?) DW 1234H ENDS
Anfang Datensegment 1 Byte reserviert Zeichenkonstante vorbesetzt 10 W ö r t e r r e s e r v i e r t Wortkonstante vorbesetzt Ende D a t e n s e g m e n t
Die festgelegten Bezeichner f ü r die Maschinenbefehle sowie ihre Wirkung können den Befehlslisten der Prozessor- bzw. Assemblerhersteller entnommen werden. Der wichtigste Befehl f ü r das übertragen von Daten (kopieren!) ist der Befehl MOV in der allgemeinen Form
MOV
ziel,quelle
Er entspricht der einfachen Wertzuweisung des Pascal:
ziel
quelle
Die folgenden Beispiele geben einen überblick über die Adressierungsarten der 80x86-Prozessoren. Dabei ist das AX-Register das Zielregister f ü r Wörter (16 bit) und das AL-Register das Zielregister f ü r Bytes (8 bit). Für alle Speicheradressen wird das Datensegmentregister DS als Segmentregister vorausgesetzt. 1. Der Quelloperand befindet sich in einem anderen Register: MOV AX.BX ; AX : = BX kopiere Inhalt von BX nach AX MOV AL.AH ; A L : = A H kopiere Inhalt von AH nach AL 2. Der Quelloperand ist eine unmittelbar folgende Konstante: MOV AX.1234H ; AX := $ 1 2 3 4 lade AX mit dem Wert $1234 MOV AL.12H ; A L := $ 1 2 lade AL mit dem Wert $12 3. Der Quelloperand befindet sich in einer Speicherstelle, deren Bezeichner (wkons bzw. b k o n s ) als Adresse (Offset) verwendet wird: MOV A X , wkons ; AX : = wkons lade AX mit Inhalt von wkons MOV AX, [wkons] ; wie MOV AX,wkons MOV A L , bkons ; A L : = bkons lade AL mit Inhalt von bkons
50
2. Einführung
in die
Maschinensprache
4. Wie 3., j e d o c h soll d i e A d r e s s e d u r c h d e n A s s e m b l e r b e r e c h n e t (Adreßrechnung zur Übersetzungszeit): MOV AX, [ w k o n s + 2 ] ; AX : = Wort h i n t e r w k o n s MOV AL , [ b k o n s - 1 ] ; AL : = B y t e v o r b k o n s
werden
5. L a d e BX m i t d e r A d r e s s e ( O f f s e t ) d e s Q u e l l o p e r a n d e n . L a d e AX mit e i n e m D a t e n w o r t , d i e A d r e s s e b e f i n d e t s i c h in BX ( i n d i r e k t e A d r e s s i e r u n g ) : MOV BX, OFFSET w k o n s ; BX : = D a t e n a d r e s s e ( O f f s e t ) MOV AX, [BX] ; AX : = D a t e n [ i n d i r e k t mit BX a d r e s s i e r t ] 6. L a d e BX m i t d e r A d r e s s e d e s Q u e l l o p e r a n d e n . L a d e AX mit e i n e m D a t e n w o r t , d i e A d r e s s e i s t d i e S u m m e a u s d e m I n h a l t v o n BX u n d d e r B y t e k o n s t a n t e n 02H ( A d r e ß r e c h n u n g z u r L a u f z e i t ) : MOV BX,OFFSET w k o n s ; BX : = D a t e n a d r e s s e ( O f f s e t ) MOV AX, [ B X + 2 ] ; AX : = D a t e n [ A d r e s s e = BX + B y t e k o n s t . ] 7. L a d e BX mit d e r W o r t k o n s t a n t e n 0002. L a d e AX mit e i n e m D a t e n w o r t , d i e A d r e s s e i s t d i e S u m m e a u s dem Off s e t v o n w k o n s u n d d e m I n h a l t v o n BX (Adreßrechnung zur Laufzeit): MOV BX, 0 0 0 2 H ; BX : = W o r t k o n s t a n t e MOV AX, w k o n s [BX] ; AX : = D a t e n [ A d r e s s e = BX + W o r t k o n 3 t . ] 8. L a d e BX mit d e r A d r e s s e s t a n t e n 0002H. L a d e AX mit d e m I n h a l t v o n BX u n d d e m MOV BX, OFFSET w k o n s MOV S1,0002H MOV AX, [BX + S I ]
d e s Q u e l l o p e r a n d e n . L a d e SI mit d e r W o r t k o n einem D a t e n w o r t , d i e A d r e s s e i s t d i e Summe a u s I n h a l t v o n SI ( A d r e ß r e c h n u n g z u r L a u f z e i t ) : ; BX : = D a t e n a d r e s s e ( O f f s e t ) ; SI := W o r t k o n s t a n t e ; AX : = D a t e n [ A d r e s s e = BX + SI]
9. L a d e BX mit d e r A d r e s s e d e s Q u e l l o p e r a n d e n . L a d e SI mit d e r W o r t k o n s t a n t e n 0001H. L a d e AX mit einem D a t e n w o r t , d i e A d r e s s e i s t d i e S u m m e a u s d e m I n h a l t v o n BX u n d d e m I n h a l t v o n SI u n d d e r B y t e k o n s t a n t e n 01H (Adreßrechnung zur Laufzeit): MOV BX, OFFSET w k o n s ; BX : = D a t e n a d r e s s e ( O f f s e t ) MOV SI , 0001H ; S I := W o r t k o n s t a n t e MOV AX , [BX + S I +1 ] ; AX := D a t e n [ a d r e s s e = BX + SI + B y t e k o n . ] 10. L a d e BX mit d e r W o r t k o n s t a n t e n 0001H. L a d e SI mit d e r W o r t k o n s t a n t e n 0001H. L a d e AX mit e i n e m D a t e n w o r t , d i e A d r e s s e i s t d i e S u m m e a u s d e m O f f s e t v o n w k o n s u n d d e m I n h a l t v o n BX u n d dem I n h a l t v o n SI ( A d r e ß r e c h n u n g zur Laufzeit): MOV BX , 0 0 0 1 H ; BX : = W o r t k o n s t a n t e MOV SI , 0001H ; S I := W o r t k o n s t a n t e MOV AX, w k o n s [BX + S I ] ; AX := D a t e n [ a d r e s s e = BX + SI + W o r t k o n . ] Die g l e i c h e n A d r e s s i e r u n g s a r t e n g e l t e n f ü r e i n e D a t e n s p e i c h e r s t e l l e a l s Ziel. I n d e n F ä l l e n , in d e n e n d i e O p e r a n d e n l ä n g e n i c h t d u r c h e i n e R e g i s t e r a n g a b e f e s t g e l e g t i s t , m ü s s e n d i e O p e r a t o r e n BYTE PTR f ü r B y t e o p e r a t i o n e n u n d WORD PTR f ü r W o r t o p e r a t i o n e n v e r w e n d e t w e r d e n . Das f o l g e n d e Beispiel l ä d t eine W o r t k o n s t a n t e in eine S p e i c h e r s t e l l e , d e r e n A d r e s s e i n BX s t e h t : MOV BX,OFFSET w z a h l ; BX : = D a t e n a d r e s s e ( O f f s e t ) MOV WORD PTR [ B X ] , 1 2 3 4 H ; l a d e D a t e n w o r t mit W o r t k o n s t a n t e n
2.2 Der Register-und
Befehl MOV MOV MOV " MOV MOV MOV LES LOS liOP """ OUT" IN
Operanden breg z.breg q wreg z.wreg q breg z.konst wreg z.konst wreg z.sreg q sreg z.wreg q wreg z.dwort " wreg z ,dwort
""
DX.AL AL.DX
Befehlssatz
51
Wirkung lade Byteregister z mit Byteregister q lade Wortregister z mit Wortregister _q lade Byteregister z mit einer Bytekonstanten lade Wortregister z mit einer Wortkonstanten lade Wortregister z mit einem Segmentregister lade Segmentreg i s t e r z (außer CS) lade Segmentreg i s t e r ES mit Segment lade Wortregister z mit O f f s e t lade Segmentregister DS mit Segment lade Wortregister z mit O f f s e t No Operation (tu nix) DX enthält Portadresse, AL auf Port ausgeben ÄL mit Port laden, DX enthält Postadresse
Bild 2-8: Befehle zur Datenübertragung
Bild 2-8 zeigt einige häufig v e r w e n d e t e Befehle zur Datenübertragung. Bei einem P e r i p h e r i e z u g r i f f mit IN bzw. OUT steht die P o r t a d r e s s e im W o r t r e g i s t e r DX und wird nicht mehr mit einem Segmentregister v e r ä n d e r t . Bei allen S p e i c h e r z u g r i f f e n mit den A d r e ß r e g i s t e r n BX, SI und DI allein bzw. mit Kombinationen aus dem Basisregister BX und den I n d e x r e g i s t e r n SI und DI wird das Datensegmentregister DS v e r w e n d e t . Bei allen S p e i c h e r z u g r i f f e n mit dem Basiszeiger BP bzw. mit Kombinationen aus dem Basiszeig e r BP und den I n d e x r e g i s t e r n SI und DI w i r d das Stapelsegmentregister SS als Segmentregister v e r w e n d e t . Die Stapeladressierung w i r d im Zusammenhang mit d e r Unterprogrammtechnik erklärt. Mit Hilfe v o n Segmentv o r s ä t z e n (CS:, DS:, ES: bzw. SS:) kann die automatische Zuordnung d e r Segmentregister (Bild 2-6) g e ä n d e r t werden. Das f o l g e n d e Beispiel g r e i f t über BX als A d r e ß r e g i s t e r auf ein Datenwort im Stapel zu. MOV BX, SP ; BX := S t a p e l z e i g e r MOV
AX , SS : [BX]
; AX
:= Datenwort aus Stapel
Die A d r e s s i e r u n g d e r Befehle (Bild 2-9) e r f o l g t ausschließlich über das Codesegmentregister CS und den Befehlszähler IP. Bei S p r u n g b e f e h l e n JMP und Befehlen zum A u f r u f von Unterprogrammen C A L L u n t e r s c h e i d e t man den weiten Sprung (FAR), bei dem das Codesegmentregister und d e r Befehlszähler neu geladen werden, und den nahen Sprung (NEAR), bei dem das Codesegmentregister u n v e r ä n d e r t bleibt und nur d e r Befehlszähler g e ä n d e r t wird. Bei Sprüngen und Unterprogrammaufrufen innerhalb des Segmentes (NEAR) wird vom Assembler nicht die Adresse des Sprungziels, sondern d e r Abstand (Displacement) zum S p r u n g z i e l in den Befehl e i n g e t r a g e n . Ein p o s i t i v e r Abstand erhöht den Befehlszähler und e r g i b t einen V o r w ä r t s s p r u n g , ein n e g a t i v e r Abstand v e r m i n d e r t den Befehlszähler und e r g i b t einen Rückwärtssprung ( S c h l e i f e ) . Bei einem k u r z e n r e l a t i v e n S p r u n g (Code EBH) steht der Abstand als v o r z e i c h e n b e h a f t e t e Dualzahl im f o l g e n d e n Byte. Die Sprungweite b e t r ä g t +127 bzw. -128 Bytes. Bei einem langen r e l a t i v e n Sprung (Code E9H) b e t r ä g t die Sprungweite +32 767 bzw. -32 768 Bytes, da der Abstand in einem Wort u n t e r g e b r a c h t wird. Bild 2-10 z e i g t ein Programmbeispiel.
2. Einführung in die Maschinensprache
52
Codesc>gment Adresse Inhalt
Codesegir ent 1 Adresse Inhalt
JMP offset
JMP IP neu CS neu
Befehl
CALL IP neu CS neu
ziel
CALL offset upro
Codesegrr ent 2 Adresse Inhalt
ziel
Befehl
upro
I.Befehl
I.Befehl RET near
CS
R E T far
bleibt IP
neu
IP i_ alt _ IP Toffset"
Befehle: JMP near CALL near
Befehle: JMP far CALL far
Bild 2-9: S p r u n g b e f e h l e und Aufruf von Unterprogrammen
Turbo Assembler TEST7.ASK l 2 3 4 5 6 7 8 9 10 11 12 13 14
0000 0000 0000 0003 0005 0006 0009 OOOB OOOC OOOE 0011 Olli
Version 1.01
BA 03FC - — BO 00 EE EB 01(90) N O P BO 0 1 W EE EB F5 E9 0100 0100«(90) E9 FEFA -
04/05/90 18:04:49
Page 1
; Bild 2-10 Intrasegmentspruenge •HOBEL small • CODE Portadresse start: mov dx,03fch al,00h niedr: mov out dx,al voruaerts kurz jrap hoch al,01h hoch: mov out dx,al jmp niedr rueckwaerts kurz vorwärts lang rueck: jmp weit db 100h dup (90h) ; 256 NOPs ; rueckwaerts lang weit: jmp rueck end Start
Bild 2-10: Relative S p r u n g a d r e s s i e r u n g
2.3 Die Arbeit mit
Unterprogrammen
53
Bei der Übernahme von Übersetzungslisten (z.B. Turbo Assembler) f ü r INLINE-Maschinencode müssen einige Besonderheiten beachtet werden. Bei Rückwärtssprüngen kann der Assembler bereits im ersten Durchlauf entscheiden, ob ein kurzer Sprung (Code EBH Abstand Byte) oder ein langer Sprung (Code E9H Abstand Wort) erforderlich ist. Bei Vorwärtssprüngen wird im ersten Durchlauf zunächst ein Wort f ü r einen langen Sprung freigehalten. Wird jedoch im zweiten Durchlauf ein kurzer Sprung verwendet, so füllt der Assembler das überflüssige Byte mit einem NOPBefehl (Code 90H). Soll z.B. aus zeitlichen Gründen ein kurzer Vorwärtssprung erzwungen werden, so ist die Assembleranweisung SHORT zu v e r wenden. Beispiel: JMP SHORT hoch ; kurzer Vorwaertssprung hoch: In der Übersetzungsliste erscheint die lange Sprungweite als Wort in der Anordnung High-Byte - Low-Byte; z.B. für den Abstand $100: E9 0100 Bei der Übernahme in den INLINE-Code müssen jedoch die beiden Bytes der langen Sprungweite vertauscht werden; z.B. f ü r den Abstand $100: E9 00 01
2.3
Die A r b e i t mit U n t e r p r o g r a m m e n
Befehl CALL RET RET PUSH PUSH POP POP INT IRET ADD
Operand name
Wirkung rufe Unterprogramm (PROC NEAR bzw. PROC FAR) Rücksprung aus Unterprogramm (NEAR bzw. FAR) zahl Rücksprung mit Erhöhung von SP um zahl wreg SP := SP - 2 bringe Wortregister nach Stapel SP := SP - 2 bringe Segmentregister nach Stapel sreprog3pl Test 1234 Der Aufruf der ParamStr(0) ParamStr(1) ParamStr(2)
vordefinierten Funktionen ergibt: = 'C:\TURB0\PR0G3P1.EXE' = 'Test' = '1234'
Normalerweise verläßt man ein Pascalprogramm nach Ausführung der letzten Anweisung oder durch die vordefinierten Prozeduren E x i t oder H a l t und k e h r t zurück an die Stelle, von der aus das Programm gestartet wurde; also zurück in das Pascalsystem oder in das Betriebssystem. Die Prozedur Exec ermöglicht die Ausführung von Programmen, die normalerweise n u r aus der Kommandoebene gestartet werden können, ohne daß das Pascalprogramm verlassen werden muß. Da d a f ü r zusätzlicher Arbeitsspeicher erforderlich ist, muß der Speicherbereich des a u f r u f e n d e n Pascalprogramms durch die Compileranweisung $M begrenzt werden. (*$M S t a p e 1 l ä n g e , H e a p _ m i n , H e a p _ m a x
*)
Die Speichergrößen werden als dezimale oder hexadezimale Konstanten angegeben. Das folgende Beispiel begrenzt den Stapel und den Heap (ZusatzSpeicher f ü r Zeigervariablen) auf je 8 KByte. (*$M $ 2 0 0 0 , 0 , 8 1 9 2 ») Vor dem Aufruf der vordefinierten Prozedur Exec müssen die I n t e r r u p t vektoren mit der Prozedur SwapVectors gerettet und danach wieder zurückgeladen werden. In dem folgenden Beispiel wird in einem Pascalprogramm ein Maschinenprogramm "druckmen.EXE" gestartet, das sich in dem augenblicklich zugeordneten Verzeichnis befindet. Dabei werden keine Parameter übergeben. (*$M $ 2 0 0 0 , 0 , $ 2 0 0 0 *) USES Dos; BEGIN SwapVectors; Exec('druckmen.exe' '); SwapVectors; END.
78
3. Einführung
in das
Betriebssystem
Die Funktion GetEnv für den vordefinierten Bezeichner COMSPEC liefert den Suchweg zum Kommandointerpreter "COMMAND.COM". Das folgende Beispiel übergibt dem Kommandointerpreter den Parameter "dir *.exe" und gibt dadurch die Namen aller Dateien vom Typ ".EXE" aus. SwapVectors; Exec(GetEnv('COMSPEC'),'/C d i r « . e x e '); SwapVectors; Im Pascalsystem kann man im File-Menü mit OS s h e l 1 auf die Kommandoebene des Betriebssystem (Shell) gehen und diese mit dem Kommando e x i t wieder verlassen. Auf diese Art kann man z.B. den Drucker umschalten. Das gleiche ist auch aus einem Pascalprogramm möglich, wenn als auszuführendes Programm der Kommandointerpreter "COMMAND.COM" ohne Parameter aufgerufen wird. Die Kommandoebene des Betriebssystems muß mit dem Kommando >exit wieder verlassen werden. Das in Bild 3-4 dargestellte Programmbeispiel zeigt eine Anwendung der als Beispiele behandelten Definitionen der Unit Dos. Die Prozeduren I n t r und MsDos werden im folgenden Abschnitt mit Anwendungsbeispielen behandelt.
PROGRAM prog3pl; (* Bild 3-4: Beispiele Unit Dos *) (*$M $2000,0,$2000 *) (* 8 KByte Stapel 0..8K Byte Heap *) USES Dos; CONST vbez : ARRAY[0..6] OF STRING = ('Sonntag','Bontag','Dienstag','Mittwoch', 'Donnerstag','Freitag','Samstag'); VAR jähr,monat,tag,wtag : MORD; std,min,sec,hsec : WORD; i : INTEGER; BEGIN (* Ausgabe von Datum und Uhrzeit *) GetDate(jähr,monat,tag,wtag); Wri teLn; Write('Heute i s t : ',wbez[wtag], ' , der 1 , t a g , ' . ' , m o n a t , ' . ' , j ä h r , ' GetTime(std,min,sec,hsec); WriteLn(std,' Uhr ',min, ' Min ' , s e c , ' . ' , h s e c , ' Sek 1 ); (* Kommandozeilenparameter bei Start als .EXE.Datei *) Write(' Programm: ',ParamStr(0), ' Parameter: ' ) ; FOR i := 1 TO ParamCount DO Write(ParamStr(i), 1 ' ) ; WriteLn; (* DOS - Kommandoebene *) WriteLn; WriteLnC '); WriteLn( 1 *«* MS-DOS-Kommandoebene *** Zurueck mit . . . > e x i t ' ) ; SwapVectors; Exec(GetEnv('COMSPEC'), " ) ; SwapVectors ; IF DosError 0 THEN WriteLn('Fehler:' ,DosError); WriteLnC*** Wieder im Programm 1,ParamStr(O), ' » * * * ' ) ; END. C:\TURBOP\PROG1>prog3pl
1 2
3
Heute i s t : Freitag, der 25.1.1991 19 Uhr 23 Min 44.91 Sek Programm: C:\TURB0P\PR0G1\PR0G3P1.EXE Parameter: 1 2 3
');
3.2 Der Aufruf von BIOS-und
*** HS-DOS-Koiranandoebene ***
DOS-Interrupts
79
Zurueck mit . . . > e x i t
Microsoft(R) HS-DOS(R) Version 3.30 (C)Copyright Microsoft Corp 1981-1987 C : \TURBOP\PROG1 >exit **« Wieder im Programm C:\TURBOP\PROGl\PROG3Pl.EXE ***« C:\TURB0P\PR0G1> Bild 3-4: Der A u f r u f d e s B e t r i e b s s y s t e m s ü b e r Dos
3.2
Der Aufruf von BIOS- und DOS-Interrupts
Das BIOS e n t h ä l t Maschinenprogramme, die d i r e k t auf die P e r i p h e r i e b a u s t e i n e d e s R e c h n e r s z u g r e i f e n . Wie b e r e i t s im A b s c h n i t t 1.6 d a r g e s t e l l t , k ö n n e n diese B e t r i e b s s y s t e m p r o g r a m m e a u c h vom B e n u t z e r ü b e r d e n M a s c h i n e n b e f e h l INT u n d eine Kennzahl ( S o f t w a r e i n t e r r u p t ) a u f g e r u f e n w e r d e n . Beim S t a r t d e s Systems w e r d e n die P e r i p h e r i e b a u s t e i n e Initialis i e r t ( e i n g e s t e l l t ) , die I n t e r r u p t v e k t o r e n (Bild 1-19) u n d die Variablen d e s BIOS v o r b e s e t z t . Die v o r b e s e t z t e n I n t e r r u p t v e k t o r e n l a s s e n sich mit d e n P r o z e d u r e n G e t l n t V e c , S e t l n t V e c u n d S w a p V e c t o r s auf B e n u t z e r p r o z e d u r e n umlenken. Diese m ü s s e n d u r c h d e n Zusatz INTERRUPT b e s o n d e r s g e k e n n z e i c h n e t w e r d e n . Die S y s t e m v a r i a b l e n d e s BIOS liegen im Ber e i c h d e r A d r e s s e n $0040:$0000 bis $0050:$0000. Bild 3-5 zeigt einige Beispiele. Anfangsadresse $0040 : $0000 $0040 : $0002 $0040 : $0004 $0040 : $0006 $0040 : $0008 $0040 : $000A $0040 : $000C $0040 : $000E $0040 : $0015 $0040 : $0017 $0040 : $0018 $0040 : $006C
Bytes 2 2 2 2 2 2 2 2 2 1 1 4
Inhalt Portadresse C0M1 (1. serielle Schnittstelle) Portadresse COM2 (2. serielle Schnittstelle) Portadresse COM3 (3. serielle Schnittstelle) Portadresse COM4 (4. serielle Schnittstelle) Portadresse LPT1 (1. Paralleldrucker) Portadresse LPT2 (2. Paralleldrucker) reserviert reserviert Speichergröße in KByte Tastaturstatus erweiterter Tastaturstatus Langwort mit Timer-Tie (alle 55 ms erhöht)
Bild 3-5: Beispiele f ü r BIOS-Variablen Der Zugriff auf d i e s e Variablen e r f o l g t v o n Pascal a u s mit d e n P s e u d o f e l d e r n Mem, MemW u n d MemL. Von b e s o n d e r e m I n t e r e s s e i s t d e r 3 2 - b i t - Z e i t z ä h l e r (Timer Tic) a b A d r e s s e $0040:$006C, d e r d u r c h d e n T i m e r - I n t e r r u p t $08 alle 55 ms (18.2 mal p r o S e k u n d e ) um 1 e r h ö h t wird. Dabei liegt das n i e -
80
3. Einführung
in das Betriebssystem
d r i g s t e B y t e d e s Doppelwortes (Datentyp LONG I N T ) auf dem O f f s e t $006C; das höchste B y t e auf $006F. Die Timer Tic Variable dient als Basis f ü r die Berechnung d e r Zeit d u r c h das Betriebssystem. Das f o l g e n d e Beispiel liest den Timer Tic in eine Benutzervariable z e i t : VAR z e i t : LONGINT; BEGIN z e i t := MemL[$0040:$006C];
Interrupt $10 $11 $12 $13 $14 $15 $15 $15 $16 $17 $18 T19 $1A $1A $1A $ 1A $1B $1C $ 1D-$ 1F $20 $21 $22-$7F
AH-Reg.
$83 $86
$00 ~$02 $04 $06
_
Aufgabe Bildschirmfunktionen Konfiguration nach AX bringen Speichergröße nach AX bringen Disketten- und Harddiskfunktionen serielle Schnittstelle Sonderfunktionen (RTC-Uhr, Joystick) Bit B7 in Byte (ES:BX) nach (CX:DX) JJS setzen (AT) (CX:DX) ps warten (nur AT) Tastaturfunktionen Paralleldruckerfunktionen ROM - BASIC starten Betriebssystemneustart (booten) Timer-Tie (Zeitzähler) nach CX und DX lesen Zeit: CH=Stunde CL=Minute DH=Sekunde (nur AT) Datum: CX=Jahr DH=Monat DL=Tag (nur AT) Alarmzeit setzen (löst Interrupt $4A aus) (nur AT) Einsprung für BREAK-Interrupt Einsprung für Timer Interrupt (alle 55 ms) Tabellen Programm beenden (besser $21 Code $4C) DOS - Interrupts (Tabelle Bild 3-7) Sonderfunktionen (Maus Zusatzspeicher)
Bild 3-6: Einige BIOS-Interrupts
Der Z u g r i f f auf die in Bild 3-6 d a r g e s t e l l t e n BIOS-Interrupts e r f o l g t v o n Pascal aus mit d e r v o r d e f i n i e r t e n P r o z e d u r I n t r . Als Wertparameter wird die Kennzahl ü b e r g e b e n , als Referenzparameter e r w a r t e t die P r o z e d u r einen Record mit den P r o z e s s o r r e g i s t e r n . Die Unit Dos stellt d a f ü r den v o r d e f i n i e r t e n Datentyp R e g i s t e r s zur V e r f ü g u n g . Die meisten BIOSI n t e r r u p t s e r w a r t e n im Register AH einen Kennwert zur Auswahl v o n Unterfunktionen. Das f o l g e n d e Beispiel liest den Timer Tic in die Register CX und DX vom Datentyp WORD. Beide Wörter werden zu der Variablen z e i t vom Datentyp LONGINT zusammengesetzt. USES Dos; VAR reg : Registers; z e i t : LONGINT; BEGIN r e g . a h := $00; Intr($ 1A,reg); z e i t := r e g . c x * $ 1 0 0 0 0 + r e g . d x ;
3.2 Der Aufruf
von BIOS-und
DOS-Interrupts
81
Anstelle des Interrupts $21 (Prozeduraufruf I n t r ( $ 2 1 , r e g ) ) kann auch die v o r d e f i n i e r t e Prozedur M s D o s ( r e g ) verwendet werden. Als R e f e r e n z parameter wird wieder ein Record mit den Prozessorregistern übergeben. Das Register AH enthält einen Kennwert zur Auswahl von Unterfunktionen. Bild 3-7 zeigt einige Beispiele.
AH-Reg. $00 $01 $02 $03 $04 $05 $2A """~J |30 $25 $35 " $4C
Aufgabe Programm beenden (besser Code AH = $4C) Tastaturzeichen nach AL lesen (mit Echo) Zeichen aus DL auf Bildschirm ausqeben Zeichen von serieller Schnittstelle nach AL lesen Zeichen aus DL auf serieller Schnittstelle ausgeben Zeichen aus DL auf Drucker ausgeben Datum: AL=Wochentag CX=Jahr DH=Monat DL=Tag Uhrzeit: CH=Stunde CL=Minute DH=Sekunde DL=1/100 sek DOS-Version: AL=Hauptversion AH=Zusatzanqabe Interruptvektor setzen AL=nr DS=Segment DX=0ffset Interruptvektor lesen AL=nr ES=Segment BX=0ffset Programm beenden, Rückkehr nach DOS
Bild 3-7: Einige DOS-Interrupts
Die DOS-Interrupts greifen auf BIOS-Interrupts zu und werten sie aus. Ein Beispiel ist der Interrupt $21 mit der Unterfunktion AH = $2C, der aus dem Timer Tic die Uhrzeit berechnet. Die Stunde wird im Register CH, die Minute in CL, die Sekunde in DH und die Hundertstelsekunde in DL ü b e r geben. Das folgende Beispiel gibt die Uhrzeit aus. USES Dos; VAR reg : R e g i s t e r s ; BEGIN r e g . a h := $2C; M s D o s ( r e g ) ; WriteLn(reg.ch,' : ',reg.cl,' : '.reg.dh); END.
82
3. Einführung in das
3.3
Betriebssystem
Die Zeit- und Uhrenfunktionen in Pascal 1.193182 MHF]
(Timer 01 $40
I Timer 1| $41
Sound(frequenz) NoSound ¡Timer 21 $42
I Steuerung I $43
T IRQO
r 2.4 V). Das Leitungspotential kann durch einen auf der gleichen Adresse (x+0) liegenden Eingabeport wieder zurückgelesen werden. Ein Low-Potential (< 0.8 V) ergibt eine "0", ein High-Potential (>2.0 V) eine "1".
Auf der Adresse x+1 befindet sich ein Eingabeport, mit dem vom Drucker ausgehende Statussignale gelesen werden können. Die Punkte an den Bausteinen bedeuten, daß die Signale invertiert (negiert) werden. Beim BUSY-Eingang z.B. erscheint ein Low-Potential der Leitung als "1" und ein High-Potential als "0". Der ACK-Eingang z.B. wird zweimal invertiert; eine doppelte Verneinung bedeutet aber wieder "ja": Low ergibt "0" und High ergibt "1". Auf der Adresse x+2 befindet sich ein Ausgabeport für Steuersignale zum Drucker und ein Eingabeport, mit dem die Signale teilweise wieder zurückgelesen werden können. Auch hier bedeuten die Punkte wieder eine Invertierung des Signals. Die Interruptsteuerung wird in normalen Druckeranwendungen nicht verwendet, über Brücken läßt sich die Nummer des Interrupts (z.B. IRQ7 für LPT1) einstellen. Die Datenübertragung von der Schnittstelle zum Drucker erfolgt im Quit— tungs- oder Handshakebetrieb. Ist der Drucker bereit (BUSY = Low), so wird das auszugebende Zeichen in den Datenausgabeport geschrieben. Ein Low-Impuls auf dem Steuerausgang DS (Data Strobe = Datenimpuls) meldet dem Drucker, daß gültige Daten anliegen. Während der Übernahme und Verarbeitung des Zeichens meldet der Drucker mit BUSY = High, daß er z.Z. belegt ist. Die Übernahme des Zeichens wird vom Drucker mit einem LowImpuls auf der ACK-Leitung bestätigt (Acknowlege = Bestätigung). Nachdem der Drucker wieder bereit ist (BUSY = Low), erfolgt die Übertragung des nächsten Zeichens. Auf eine Auswertung des Bestätigungssignals ACK und eine Interruptauslösung wird in den meisten Steuerprogrammen v e r zichtet. Die restlichen Status- bzw. Steuersignale melden z.B. das Papier-
4.1 A ufbau und Programmierung der Druckerschnittstelle
93
ende oder bringen den Drucker in eine Grundstellung (Reset). Sie können den Unterlagen des verwendeten Druckers entnommen werden. Der Anhang enthält die Stiftbelegung mit den Signalbezeichnungen. PROGRAM prog4p0; (* Bild 4-2: Schnittstellentest *) USES Crt, Aushexbi; (* enthält Auswhex, Ausbbin *) VAR abst,padr : WORD; z : CHAR; wert : BYTE; BEGIN WriteLn('Installierte Parallelschnittstellen:'); FOR abst := 4 TO 7 DO BEGIN UriteC LPT',abst-3,•: '); Auswhex(HemW[$0040:abst*2]); END; WriteLn; VriteC Adresse eingeben (hexadezimal $xxxx): '); ReadLn(padr); REPEAT WriteLn; Write(' Daten: '); Ausbbin(Port[padr+0]); Write(' Status: '); Ausbbin(Port[padr+1]); Write(' Steuer: '); Ausbbin(Port[padr+2]); WriteLn; Write('Ausgabe: Daten = D Keine = X Ende = E Steuer = S > '); z := UpCase(ReadKey); WriteLn(z); IF z = 'D' THEN BEGIN Write('Datenbyte eingeben (hexadezimal $xx): '); ReadLn(wert); Port[padr+0] := wert; END; IF z = 'S' THEN BEGIN Write('Steuerbyte eingeben (hexadezimal $xx): '); ReadLn(wert); Port[padr+2] := wert; END; UNTIL z = 'E'; END. Installierte Parallel Schnittstellen: LPT1: $0378 LPT2: $0278 LPT3: $0000 LPT4: $0000 Adresse eingeben (hexadezimal $xxxx): $0278 Daten: SfcOOOOOOOO Status: %01111111 Steuer: 1100000 Ausgabe: Daten = D Keine = X Ende = E Steuer = S > D Datenbyte eingeben (hexadezimal $xx): $55 Daten: $01010101 Status: $01111111 Steuer: $11100000 Ausgabe: Daten = D Keine = X Ende = E Steuer = S > S Steuerbyte eingeben (hexadezimal $xx): $00 Daten: $01010101 Status: $01111111 Steuer: $11100000 Ausgabe: Daten = D Keine = X Ende = E Steuer = S > S Steuerbyte eingeben (hexadezimal $xx): $aa Daten: $01010101 Status: $01111111 Steuer: $11101010 Ausgabe: Daten = D Keine = X Ende = E Steuer = S > D Datenbyte eingeben (hexadezimal $xx): $00
Bild 4-2: Testprogramm der Druckerschnittstelle
94
4. Die parallele
Druckerschnittstelle
Das in Bild 4-2 d a r g e s t e l l t e Programmbeispiel dient zur U n t e r s u c h u n g von D r u c k e r s c h n i t t s t e l l e n . Nach Ausgabe d e r beim S y s t e m s t a r t e r k a n n t e n S c h n i t t s t e l l e n a d r e s s e n wird vom Benutzer die Eingabe d e r P o r t a n f a n g s a d r e s s e v e r l a n g t ; damit können auch Schnittstellen auf a n d e r e n Adressen u n t e r s u c h t werden. In einer Leseschleife werden die drei Eingabeports binär angezeigt. Der Benutzer kann nun wählen, ob er Daten oder S t e u e r signale a u s g e b e n will oder ob er n u r eine weitere Anzeige wünscht. Mit diesem Testprogramm ist es d u r c h a u s möglich, d u r c h Anlegen von Datenb y t e s u n d Ausgabe d e r DS-Impulse Zeichen auf dem Drucker a u s z u g e b e n . Normalerweise k a n n man jedoch davon a u s g e b e n , daß die D r u c k e r a u s g a b e problemlos d u r c h die Betriebssystemsoftware erfolgt, so daß man von Sonderfällen a b g e s e h e n auf eigene Druckerprogramme v e r z i c h t e n k a n n . Die folgenden Abschnitte beschäftigen sich d a h e r mit d e r Verwendung d e r D r u c k e r s c h n i t t s t e l l e z u r Ü b e r t r a g u n g von digitalen Signalen sowie z u r parallelen R e c h n e r k o p p l u n g .
4.2
Die Übertragung digitaler Daten
Die D r u c k e r s c h n i t t s t e l l e k a n n zur Eingabe u n d Ausgabe von digitalen Signalen f ü r Anwendungen in der Meß-, S t e u e r u n g s - u n d Regelungstechnik v e r w e n d e t werden. Bild 4-3 zeigt die drei üblicherweise in d e r TTLTechnik v e r w e n d e t e n Ausgangsschaltungen.
a. Totem-Pole-Ausgang
b. Tristate-Ausgang
c. Open-Collector-Ausgang
Bild 4-3: A u s g a n g s s c h a l t u n g e n d e r TTL-Technik Der Totem-Pole- oder G e g e n t a k t a u s g a n g (Bild 4-3a) wird d u r c h einen d e r beiden A u s g a n g s t r a n s i s t o r e n entweder auf High- oder auf Low-Potential gelegt; eine mit einem d e r a r t i g e n Ausgang a n g e s t e u e r t e Leitung k a n n normalerweise n u r als Ausgang v e r w e n d e t werden. Bei dem T r i s t a t e - A u s g a n g (Bild 4-3b) s o r g t ein zusätzlicher S t e u e r e i n g a n g d a f ü r , daß beide A u s g a n g s t r a n s i s t o r e n a b g e s c h a l t e t werden können. Der Ausgang b e f i n d e t sich dann in einem d r i t t e n "hochohmigen" Zustand. Dadurch, daß n u n ein a n d e r e r Ausgang ein Signal auf die Leitung legen k a n n , ist ein Betrieb in beiden Richtungen (bidirektional) auf einer Leitung möglich. Der OpenCollector-Ausgang nach Bild 4-3c eignet sich ebenfalls f ü r den b i d i r e k t i o nalen Betrieb einer Leitung. Das d u r c h den Arbeitswiderstand auf High
4,2
Die Übertragung digitaler
Daten
95
gelegte Leitungspotential k a n n von m e h r e r e n Schaltern bzw. A u s g a n g s t r a n s i s t o r e n auf Low gezogen werden. Welche B e t r i e b s a r t e n sind n u n f ü r die Leitungen d e r Druckerschnittstelle möglich? Die folgenden B e t r a c h t u n g e n beziehen sich auf die u r s p r ü n g l i c h e TTLA u s f ü h r u n g des D r u c k e r p o r t s . Der Datenausgang (Adresse x+0) b e s t e h t a u s einem 8 - b i t - D - R e g i s t e r 74LS374, das bei High max. 2.6 mA a b g e b e n u n d bei Low max. 24 mA aufnehmen kann. Dieser TTL-Baustein b e s i t z t einen T r i s t a t e s t e u e r e i n g a n g , d e r jedoch f e s t auf Low gelegt ist, so daß kein T r i s t a t e z u s t a n d möglich ist u n d d e r Ausgang immer ein f e s t e s Potential liefert. Daher ist kein Eingabebetrieb f ü r diesen Port v o r g e s e h e n . Der Zus t a n d d e r Datenleitungen k a n n jedoch d u r c h einen Bustreiber 74LS244 (Adresse x+0) z u r ü c k g e l e s e n werden. In einigen Veröffentlichungen wird empfohlen, einfach d u r c h Einschreiben von Einsen die Ausgänge auf High zu legen; sie k ö n n t e n d a n n wahlweise d u r c h Schalter oder TTL-Ausgänge auf Low gezogen u n d z u r ü c k g e l e s e n w e r d e n . Damit wäre auch eine Dateneingabe d u r c h Lesen des Datenports (Adresse x+0) möglich. An a n d e r e r Stelle wird g e r a t e n , den f e s t auf Low gelegten T r i s t a t e s t e u e r e i n g a n g OC des Bausteins 74LS374 a u f z u t r e n n e n u n d mit dem noch f r e i e n Ausgang B5 des S t e u e r p o r t s (Adresse x+2) zu v e r b i n d e n . Dieser bestimmt dann die Richtung d e r D a t e n ü b e r t r a g u n g : B5=0 b e d e u t e t dann schreiben; B5=l b e d e u t e t dann lesen. In allen folgenden Beispielen wird auf ein Zurücklesen des Datenports (x+0) u n d damit auf einen bidirektionalen Betrieb an diesem Port v e r z i c h t e t , da nicht sichergestellt ist, daß die g e n a n n t e n Vorschläge auch an allen Bauformen und u n t e r allen B e t r i e b s b e d i n g u n g e n einwandfrei arbeiten. Die fünf Leitungen des S t a t u s p o r t s (Adresse x+1) können n u r als Eingänge v e r w e n d e t werden. Der S t e u e r a u s g a n g (Adresse x+2) b e s t e h t in d e r TTLA u s f ü h r u n g a u s einem 6-bit-D-Register 74LS174. Die vier u n t e r e n Ausgänge BO bis B3 liegen an i n v e r t i e r e n d e n T r e i b e r n 7405 mit offenem Kollektor (max. 16 mA nach Low). Diese Ausgänge k ö n n e n auf d e r gleichen P o r t a d r e s s e (x+2) wieder zurückgelesen werden; d a h e r ist ein bidirektionaler Betrieb dieser v i e r Steuerleitungen möglich. Sieht man einmal von den Eingabemöglichkeiten des Datenports ab, so k ö n nen von den 17 Leitungen d e r Druckerschnittstelle a c h t n u r als Ausgang, fünf n u r als Eingang und vier in beiden Richtungen (bidirektional) v e r wendet werden. Die Abschnitte 4.6 u n d 9.2.2 zeigen Schaltungen und Verf a h r e n , mit denen die Druckerschnittstelle zu einem universellen I n t e r f a c e f ü r ( f a s t ) beliebig viele digitale Eingabe- u n d Ausgabesignale erweitert werden kann. F ü r orientierende U n t e r s u c h u n g e n ist es zweckmäßig, die Anschlußleitungen des D r u c k e r p o r t s mit Eingabe- u n d Ausgabeschaltungen zu v e r s e h e n . Bild 4-4 zeigt den Anschluß des D r u c k e r p o r t s an die Testplatine eines Mikrocomputer V e r s u c h s - und Übungssystems (MVUS) mit Kippschaltern f ü r die Eingabe u n d Leuchtdioden f ü r die Ausgabe von digitalen Signalen.
96
4. Die parallele
Druckerschnittstelle
binäre Ausgabe
Ù
binäre Eingabe —I
8 x
8 x MVUS-Testplatine
r +0 schreiben
I I |X|X|X|
+2 schreiben
+1 lesen
XX X XjX
j010 ]o 1 oI Ol 1 i0 1 o [
II
+2 lesen —
writelpt(adr.x)
readlpt(adr.x)
initlpt(adr)
Bild 4-4: V e r s u c h s s c h a l t u n g f ü r digitale S i g n a l ü b e r t r a g u n g
Der Zustand d e r a c h t Datenausgänge (Adresse +0) wird mit Leuchtdioden angezeigt. Eine logische "0" e r s c h e i n t auf d e r Leitung als Low-Potential u n d wird ü b e r den I n v e r t e r zu High gemacht: die Leuchtdiode g e h t aus. Eine logische "1" legt die Leitung auf High u n d den Ausgang des I n v e r t e r s auf Low: die Leuchtdiode g e h t an. Die fünf S t a t u s e i n g ä n g e u n d drei b i direktionalen Steuerleitungen werden mit Widerständen auf High gehalten u n d können mit Kippschaltern z u r Dateneingabe auf Low gelegt werden. Dazu ist es jedoch e r f o r d e r l i c h , die d r e i S t e u e r a u s g ä n g e d e r D r u c k e r s c h n i t t s t e l l e v o r h e r auf High zu b r i n g e n . Dies g e s c h i e h t d u r c h Ausgabe des Bitmusters $04 = 0000 0100 auf dem S t e u e r p o r t (Adresse +2). Die Eingab e l e i t u n g e n d e r beiden P o r t s können d u r c h Maskierung u n d I n v e r t i e r u n g zu einem E i n g a b e d a t e n b y t e zusammengesetzt werden.
4.2 Die Übertragung digitaler Daten
X X X X +2
r
X X X
lesen
I o |o I o ¡o 1 o I o[öT" readselin(adr)
97
0 0 0 0
1 0 0 L +2 s c h r e i b e n |
0: 1: writeselin(adr.x)
High Low
Bild 4-5: Bidirektionale Steuerleitung SLCT IN
Bild 4-5 zeigt die Schaltung der Leitung SLCT IN, die in den folgenden Beispielen als bidirektionale Steuerleitung verwendet wird. Durch den invertierenden Treiber mit offenem Kollektor am Steuerportausgang (Adresse +2) ist ein Betrieb in beiden Richtungen möglich. F ü r eine Signaleingabe muß jedoch der Ausgang auf High gelegt werden. Auf der Testplatine wird der Leitungszustand mit einem Inverter und einer Leuchtdiode angezeigt. Die Leitung wird mit einem Widerstand auf High gehalten und kann mit einem entprellten Taster (RS-Flipflop) auf Low g e bracht werden. Die Schaltung kann mit dem in Bild 4-6 dargestellten Testprogramm untersucht werden.
98
4. Die parallele Druckerschnittstelle
PROGRAM prog4pl; ( « Bild 4-6: Kippschalter ein => LED aus * ) USES Crt; VAS nr.padr : WORD; daten : BYTE; PROCEDURE i n i t l p t ( a d r : BYTE); ( * Port i n i t i a l i s i e r e n *) BEGIN Port[adr+2] := $04 ( * 0000 0100 Steuerausgaenge High * ) END; PROCEDURE readlpt(adr : WORD; VAR x : BYTE); ( * Port lesen *) VAR x l , x2 : BYTE; BEGIN INLINE($FA); ( * CLI ; Interrupts sperren * ) x l := Port[adr+1]; x2 := Port[adr+2]; INLINE($FB); (* STI ; Interrupts freigeben *) x := ( ( x l XOR $80) AND $F8) OR ( ( x 2 XOR $03) AND $07); END; PROCEDURE w r i t e l p t ( a d r : WORD; x : BYTE); (* Port ausgeben " ) BEGIN Port[adr+0] := x END; FUNCTION readselin(adr : WORD) : BOOLEAN; (* SLCT IN lesen « ) BEGIN readselin := NOT (BOOLEAN((Port[padr+2] AND $08) SHR 3 ) ) END; PROCEDURE w r i t e s e l i n ( a d r : WORD; x : BOOLEAN); ( « SLCT ausge. * ) BEGIN IF x THEN Port[adr+2] := $04 ELSE Port[adr+2] := $0C END; BEGIN (* Hauptprogramm « ) W r i t e C LPT1, 2, 3 oder 4 > ' ) ; ReadLn(nr); padr := MemW[$0040:nr*2+6]; WriteLnC Kippschalter nach Leuchtdioden bis SLCT IN = LOW ' ) ; initlpt(padr); writeselin(padr,FALSE); Delay(lOOO); writeselin(padr,TRUE); WHILE readselin(padr) DO BEGIN read1pt(padr,daten); writelpt(padr,daten) END END. Bild 4-6: Testprogramm f ü r digitale Ein/Ausgabe
Das Hauptprogramm besteht im wesentlichen aus einer bedingten Schleife, die d u r c h den Taster auf d e r Testplatine ( L e i t u n g SLCT IN) a b g e b r o c h e n w e r d e n kann. In d e r Schleife wird das an den Kippschaltern eingestellte Bitmuster auf den Leuchtdioden wieder angezeigt. Die Initialisierung ( E i n s t e l l u n g ) d e r ausgewählten Druckerschnittstelle sowie die Eingabe u n d A u s g a b e wird mit b e n u t z e r d e f i n i e r t e n P r o z e d u r e n und Funktionen d u r c h g e f ü h r t . Die P r o z e d u r i n i t l p t l e g t alle v i e r bidirektionalen S t e u e r l e i t u n g e n auf High u n d ermöglicht damit eine Dateneingabe. Die P r o z e d u r r e a d l p t setzt ein Eingabebyte a u s den S t a t u s - u n d Steuersignalen z u sammen. Das logische X O R i n v e r t i e r t alle Bitpositionen, in denen die Maske ein Einerbit enthält. Das logische A N D löscht alle Bitpositionen, in denen die Maske ein Nullbit enthält. Das logische OR setzt die beiden Teile d e r E i n g a b e zu einem Byte zusammen. Die P r o z e d u r w r i t e l p t g i b t ein Byte
4.3 Die Ein/Ausgabe
analoger Daten
99
auf dem Druckerport aus. Die Funktion readselin formt das Potential der Statusleitung SLCT IN in ein logisches Ergebnis um: ein High-Potential ergibt TRUE, ein Low-Potential liefert FALSE. Die Prozedur writeselin gibt ein TRUE als High-Potential und ein FALSE als Low-Potential aus. Mit der Testplatine lassen sich digitale Ein- und Ausgabesignale f ü r ü b u n g s und Testzwecke simulieren. Die Platine enthält gleichzeitig ein Steckbrett, auf dem weitere Testschaltungen wie z.B. die im nächsten Abschnitt d a r g e stellte Analogperipherie aufgebaut werden können.
4.3
Die Ein/Ausgabe analoger Daten
Ein Digital/Analogwandler verwandelt einen binären Eingangswert in eine analoge Ausgangsspannung. Der Eingangswert $00 liefert z.B. in der unipolaren Schaltung eine Ausgangsspannung von 0 Volt, der Eingangswert $FF ergibt am Ausgang + 5 Volt. Dazwischen liegen bei einem 8-bit-Wandler noch 253 weitere Spannungsstufen. In der bipolaren Schaltung liegt die Ausgangsspannung z.B. zwischen - 2.55 Volt ($00) und + 2.55 Volt ($FF). 0 Volt entspricht dem digitalen Wert $7F. Der Wandlerbaustein besteht im wesentlichen aus Flipflops zur Speicherung des digitalen Eingangswertes, einem R-2R-Netzwerk zur Bewertung der Bitpositionen und einem Verstärker, der die bewerteten Teilspannungen addiert. Mit Operationsverstärkern läßt sich die normalerweise zwischen 0 und 2.55 Volt liegende analoge Ausgangsspannung v e r s t ä r k e n (0 bis + 10 V) bzw. auf bipolares Potential v e r s c h i e b e n ( - 5 V bis + 5 V). Die Umsetzzeit zwischen dem Einschreiben des digitalen Wertes und der analogen Ausgabe hängt nur von der Schaltzeit der Bauteile ab und liegt unter 1 fis. Ein Analog/Digitalwandler verwandelt eine analoge Eingangsspannung in einen digitalen Ausgangswert. In der unipolaren Schaltung liefert z.B. eine Eingangsspannung von 0 Volt den digitalen Wert $00 und ein Eingang von + 5 Volt den Wert $FF. Wie bei Digital/Analogwandlern gibt e s auch den bipolaren Betrieb z.B. zwischen + 2.55 und - 2.55 Volt. Die meisten Umwandl u n g s v e r f a h r e n vergleichen die umzusetzende Spannung mit einer von einem Digital/Analogwandler e r z e u g t e n Vergleichsspannung: - Rampenumsetzer benutzen eine Sägezahnspannung zum Vergleich. Wegen ihrer langen Umsetzzeit im Millisekundenbereich werden sie v o r wiegend zur Erfassung langsamer Vorgänge verwendet. - Umsetzer nach dem Verfahren der schrittweisen Näherung ( S u k z e s s i v e Approximation oder Wägeverfahren) f ü h r e n den Vergleich bitweise b e ginnend mit der werthöchsten Bitposition durch. Ein 12-bit-Wandler b e nötigt 12 Schritte. Die Umsetzzeit liegt zwischen 1 und 20 fjs. - Parallelumsetzer erzeugen für jede Stufe eine eigene Vergleichsspannung; ein 8-bit-Wandler b e s t e h t also aus 256 Vergleichern und einer digitalen Bewertungsschaltung. Wegen der hohen Umsetzgeschwindigkeit (< 1 ßs) können diese Wandler im DMA betrieben werden. - Nachlaufumsetzer stellen lediglich fest, ob sich die umzusetzende Spannung g e g e n ü b e r der v o r h e r g e h e n d e n Wandlung erhöht oder vermindert hat und liefern daher die k ü r z e s t e Umsetzzeit.
100
4. Die parallele
Druckerschnittstelle
Bild 4-7: Analogperipherie an der Druckerschnittstelle
Die in Bild 4-7 dargestellte Schaltung besteht aus einem 8-bit-Digital/ Analogwandler und einem 12-bit-Analog/Digitalwandler nach dem Verfahren der schrittweisen Näherung (Umsetzzeit 4 y.s). Sie wird direkt an der Druckerschnittstelle betrieben. Für die analoge Ausgabe kann die gleiche Prozedur w r i t e l p t wie f ü r die digitale Ausgabe (Programm Bild 4-6) verwendet werden. Am Analogeingang liegt ein Abtast- und Halteverstärker (S&H = Sample And Hold), der während der Umsetzzeit den Eingang vom Wandler trennt. Der Leseimpuls wird von der Prozedur w r i t e s e l in erzeugt. Die Prozedur r e a d l p t liest nur die oberen acht Bitpositionen des 12-bit-Wandlers; die unteren v i e r werden nicht berücksichtigt. Bild 4-8 zeigt ein Testprogramm, das zum Einstellen und Abgleichen der Wandler und Verstärkerbausteine dienen kann. Dazu muß der Ausgang des Digital/Analog Wandlers mit dem Eingang des Analog/Digitalwandlers verbunden werden.
4.3 Die Ein/Ausgabe
analoger
PROGRAM prog4p2; (* Bild 4-8: Abgleich Analogschaltungen VAR nr,padr : WORD; daten : BYTE; PROCEDURE initlpt(adr : WORD); (* Port initialisieren BEGIN Port[adr+2] := $04 (* 0000 0100 Steuerausgaenge High END; PROCEDURE readlpt(adr : WORD; VAR x : BYTE); (* Port lesen VAR xl, x2 : BYTE; BEGIN xl := Port[adr+1]; x2 := Port[adr+2]; x := ((xl XOR $80) AND $F8) OR ((x2 XOR $03) AND $07); END; PROCEDURE writelpt(adr : WORD; x : BYTE); (* Port ausgeben BEGIN Port[adr+0] := x END; FUNCTION readselin(adr : WORD) : BOOLEAN; (* SLCT IN lesen BEGIN readselin := NOT (BOOLEAN((Port[padr+2] AND $08) SHR 3)) END; PROCEDURE writeselin(adr : WORD; x : BOOLEAN); (* SLCT IN aus BEGIN IF x THEN Port[adr+2] := $04 ELSE Port[adr+2] := $0C END; BEGIN (» Hauptprogramm *) WriteC LPT1, 2, 3 oder 4 >'); ReadLn(nr); padr := tlemW[$0040:nr*2+6]; WriteLnC Analog aus => analog ein bis SLCT IN = LOW '); initlpt(padr); WHILE readselin (padr) DO BEGIN Write('Eingabe 0..255: > '); ReadLn(daten); write1pt(padr,daten); (* analog aus *) writeselin(padr,FALSE); (* CS = LOW *) read1pt(padr,daten); (* analog ein *) writeselin(padr,TRUE); (« CS = HIGH *) WriteLn('Ausgabedaten = ',daten) END END.
Daten
101
*) *) *) *)
*)
*)
*)
LPT1, 2, 3 oder 4 >2 Analog aus => analog ein bis SLCT IN = LOW Eingabe 0..255: > 255 Ausgabedaten = 255 Eingabe 0..255: > Bild 4-8: T e s t p r o g r a m m f ü r d e n W a n d l e r a b g l e i c h Das H a u p t p r o g r a m m i n i t i a l i s i e r t die a u s g e w ä h l t e D r u c k e r s c h n i t t s t e i l e , d i e S c h l e i f e k a n n d u r c h e i n L o w - P o t e n t i a l am b i d i r e k t i o n a l e n E i n g a n g SLCT IN a b g e b r o c h e n w e r d e n . Die d i g i t a l e E i n g a b e d e s B e n u t z e r s im B e r e i c h v o n $00 b i s $FF w i r d a n a l o g a u s g e g e b e n u n d k a n n mit einem V o l t m e t e r g e m e s s e n w e r d e n . Die a n a l o g e E i n g a n g s s p a n n u n g w i r d g e w a n d e l t u n d d i g i t a l a u f dem B i l d s c h i r m a u s g e g e b e n . I s t d e r A n a l o g a u s g a n g mit dem A n a l o g e i n g a n g v e r b u n d e n , so k ö n n e n die A b g l e i c h w i d e r s t ä n d e d e r V e r s t ä r k e r so e i n g e stellt w e r d e n , daß d e r von T a s t a t u r e i n g e g e b e n e Zahlenwert wieder auf dem B i l d s c h i r m e r s c h e i n t . Bild 4-9 z e i g t e i n P r o g r a m m , mit dem die A b t a s t u n g u n d sofortige Ausgabe von Analogsignalen u n t e r s u c h t werden k a n n .
102
4. Die parallele
Druckerschnittstelle
PROGRAM prog4p3; (« Bild 4-9 analog e i n => analog aus *) VAR x l , x2, daten : BYTE; n r , padr : WORD; BEGIN Write('LPT1, 2, 3 oder 4 > ' ) ; ReadLn(nr); padr := HemW[$0040:nr*2+6]; Port[padr+2] := $04; (» 0000 0100 CS = High «) WriteLn('Analog e i n => analog aus b i s SLCT IN = LOW ' ) ; INLINE($FA); (* CLI I n t e r r u p t s gesp. *) WHILE (Port[padr+2] AND $08) = 0 DO BEGIN Port[padr+2] := $0C; (« 0000 1100 CS = Low *) x l := P o r t [ p a d r + l ] ; x2 := Port[padr+2]; (* analog ein *) Port[padr+2] := $04; (* 0000 0100 CS = High *) daten := ( ( x l XOR $80) AND $F8) OR ((x2 XOR $0B) AND $07); Port[padr+0] := daten; (* analog aus *) END; INLINE($FB) (* STI I n t e r r u p t s f r e i *) END.
Bild 4-9: A b t a s t u n g u n d A u s g a b e e i n e s A n a l o g s i g n a l s
F ü r die d i g i t a l e V e r a r b e i t u n g v o n a n a l o g e n S i g n a l e n im E c h t z e i t b e t r i e b z.B. d u r c h d i g i t a l e F i l t e r u n g ist e s e r f o r d e r l i c h , d a s E i n g a n g s s i g n a l m ö g l i c h s t s c h n e l l u n d k o n t i n u i e r l i c h a b z u t a s t e n . Das T e s t p r o g r a m m v e r z i c h t e t d a h e r auf b e q u e m e , a b e r l a n g s a m e U n t e r p r o g r a m m e u n d g r e i f t d i r e k t auf d i e P o r t b a u s t e i n e z u . Eine n o c h s c h n e l l e r e A b t a s t u n g ließe sich d u r c h E i n f ü g e n v o n A s s e m b l e r c o d e mit INLINE e r r e i c h e n . F ü r eine B e u r t e i l u n g d e r A b t a s t g ü t e w i r d d e r g e w a n d e l t e Wert w i e d e r a n a l o g a u s g e g e b e n u n d k a n n mit einem Oszilloskop b e o b a c h t e t w e r d e n . F ü r die Dauer e i n e s A b t a s t - u n d A u s g a b e z y k l u s w i r d die I n t e r r u p t s t e u e r u n g g e s p e r r t . Bei F r e q u e n z e n o b e r h a l b e t w a 5 kHz z e i g t e sich b e i dem v e r w e n d e t e n R e c h n e r d e r s t ö r e n d e E i n f l u ß d e r R e f r e s h - S t e u e r u n g . Eine s c h n e l l e , k o n t i n u i e r l i c h e u n d u n t e r b r e c h u n g s f r e i e A b t a s t u n g w a r n i c h t möglich. Der n ä c h s t e A b s c h m i t t z e i g t d a h e r die K o p p l u n g d e s PC ü b e r die D r u c k e r s c h n i t t s t e l l e mit einem M i k r o c o m p u t e r , d e r u n t e r b r e c h u n g s f r e i , also o h n e T i m e r i n t e r r u p t u n d R e f r e s h , die a n a l o g e E i n / A u s g a b e ü b e r n i m m t .
4.4 Die
4.4
Rechner-Rechner-Kopplung
103
Die Rechner-Rechner-Kopplung
Die in Bild 4-10 dargestellte Rechnerkopplung verbindet den PC über die Druckerschnittstelle mit einem Peripherierechner, der einen 16-bit-Mikroprozessor 68000 enthält. Das Bild zeigt nur die Parallelschnittstelle 68230, an die die Leitungen der Druckerschnittstelle zur Datenübergabe angeschlossen sind. Dabei kann der PC sowohl Daten ausgeben als auch Daten einlesen; der Betrieb e r f o l g t also bidirektional in beiden Richtungen; der PC ist einmal Sender und einmal Empfänger. Gleiches gilt f ü r den Peripherierechner. Bild 4-11 zeigt das verwendete Datenübertragungsprotokoll, das von dem in Bild 4-1 dargestellten Druckerprotokoll abweicht.
104
4. Die parallele
Druckerschnittstelle
BUSY f _ ®
®
(j>
bereit
©
^
belegt
i
bereit
Daten )(
DS
Daten"
© J
Daten
gültig
S e n d e r
E m p f ä n g e r
solange BUSY = High(belegt) warten
!/ BUSY := Low ( b e r e i t ) " !
Datenbyte ausgeben
solange DS = High
DS (SLCT IN) := Low Zeitverzögerung solange BUSY = High(belegt) warten DS (SLCT IN) := High J ~
warten 1
BUSY := High ( b e l e g t ) _ f ~ Daten lesen und verarbeiten BUSY
Low (bereit
solange DS = Low warten
Weitere Daten übertragen
Weitere Daten übernehmen
Bild 4-11: übertragungsprotokoll der Rechnerkopplung
Zum Zeitpunkt (1) legt der Empfänger seinen Ausgang BUSY auf Low und meldet sich bereit. Erkennt der Sender aus seinem BUSY-Eingang, daß der Empfänger bereit ist (BUSY = Low), so legt er das auszugebende Byte auf die Datenleitungen und macht dann zum Zeitpunkt (2) seinen Ausgang DS (Data Strobe) Low; die Daten sind gültig. Erkennt der Empfänger zum Zeitpunkt (3), daß gültige Daten anliegen, so meldet er sich zunächst belegt und legt dazu seinen BUSY-Ausgang auf High. Dann werden die Daten g e lesen und ausgegeben bzw. gespeichert. Nach der Verarbeitung meldet sich der Empfänger zum Zeitpunkt (4) wieder bereit (BUSY = Low). Daraufhin macht der Sender zum Zeitpunkt (5) das Strobe-Signal wieder High und kann nun neue Daten übertragen. Bild 4-12 zeigt die Pascalprogrammierung des Übertragungsprotokolls.
4.4 Die
Rechner-Rechner-Kopplung
105
PROGRAM prog4p4; (* Bild 4-12 parallele Rechnerkopplung USES Crt; (* HVUS-Programm prog4p4.68k lpt = $0278; Wartezeit = 10; CONST TYPE feldtyp = ARRAY[1..1024] OF BYTE; VAR x,z : BYTE; y : feldtyp; i : INTEGER; PROCEDURE ausbyte(x:BYTE); (* Byte ausgeben VAR warte : INTEGER; BEGIN $00 DO; Busy = High WHILE (Port[lpt+1] AND $80) *) Busy = Low Port[lpt+0] := x; *) SLCT IN := Low Port[lpt+2] := $0C; warten FOR warte := 1 TO Wartezeit DO *) WHILE (Port[lpt+1] AND $80) $00 DO; ' Busy = High *) Port[lpt+2] := $04; SLCT IN := High END; PROCEDURE ausfeld(x:feldtyp); (* Feld ausgeben VAR i : INTEGER; BEGIN FOR i := 1 TO 1024 DO ausbyte(x[i]); END; PROCEDURE einbyte(VAR x:BYTE); (* Byte lesen VAR xl,x2 : BYTE; BEGIN INLINE($FA); (* CLI ; Int. gesp Portflpt+O] := $7F; (* bereit Busy = 0 WHILE (Port[lpt+2] AND $08) = $00 DO; ( warten bis DS=0 Port [lpt+0] := $FF; ( belegt Busy = 1 xl := Port[lpt+1]; x2 := Port[lpt+2]; x := ((xl XOR $80) AND $F8) OR ((x2 XOR $03) AND $07); Port[lpt+0] := $7F; bereit Busy = 1 WHILE (Port[lpt+2] AND $08) = $08 DO; warten bis DS=1 * ) INLINE($FB); STI ; INT frei * ) END; PROCEDURE einfeld(VAR x:feldtyp); (* Feld lesen VAR i INTEGER; BEGIN FOR i = 1 TO 1024 DO einbyte(x[i]); END; BEGIN (' Hauptprogrcunm zum Test der Betriebsarten *) Port[lpt+2] := $04; SLCT IN := High *) WriteLn('Eingabeschleife bis Wert 123 REPEAT Write('Eingabe:'); ReadLn(x); ausbyte(1); ausbyte(x); Betriebsart ausbyte(3); einbyte(z); Betriebsart writeLn('Ausgabe:',z); UNTIL x = 123; FOR i := 1 TO 1024 DO y[i] := i; ausbyte(2); ausfeld(y); (« Betriebsart 2 REPEAT Delay(lOOO); WriteLn('Feld ein:'); ausbyte(4); einfeld(y); (* Betriebsart 4 *) WriteLn('Feld aus:'); ausbyte(2); ausfeld(y); (* Betriebsart 2 UNTIL KeyPressed END. Bild 4-12: P r o g r a m m zur parallelen R e c h n e r k o p p l u n g
106
4. Die parallele
Druckerschnittstelle
Die Prozedur a u s b y t e gibt ein Zeichen aus, wenn der PC als Sender arbeitet. Die Prozedur e i n b y t e liest ein Zeichen von der Druckerschnittstelle ein. Da nun die Analogperipherie nicht mehr aus einfachen Wandlerbausteinen besteht, sondern mit einem "intelligenten" Rechner ausgerüstet ist, lassen sich auf dem Peripherierechner verschiedene Wandlerschaltungen auswählen und auch Werte speichern. Zur Auswahl der Betriebsart wurde vereinbart, v o r der eigentlichen Datenübertragung zunächst ein Steuerbyte an den Peripherierechner zu senden. In der Betriebsart 1 f o l g t auf das Steuerbyte $01 ein Datenbyte, das auf einem 8-bit-Digital/Analogwandler (unipolar 0 bis +5V) ausgegeben wird. In der Betriebsart 2 sendet der PC das Steuerbyte $02 und erwartet dann ein Datenbyte von einem 8-bit-Analog/Digitalwandler (unipolar 0 bis +5V 12 fjs Wandlungszeit). Das Starten der Umwandlung und das Auslesen des Wandlerbausteins übernimmt der Peripherierechner. In der Betriebsart 3 folgen auf das Steuerbyte $03 genau 1024 Datenbytes, die in dem Peripherierechner zunächst gespeichert und dann zyklisch auf einem 12-bit-Digital/Analogwandler ausgegeben werden. Dieser ist bipolar geschaltet und mit einem einstellbaren Tiefpassfilter und einem Ausgangskondensator ausgerüstet. Da nur Bytes übertragen werden, liegen die v i e r unteren Datenbits des Wandlers fest auf Low. Jeder Wert wird 4 /JS lang gehalten. Am Beginn des Ausgabezyklus wird auf einem 8-bit-Digital/ Analogwandler ein kurzer Triggerimpuls f ü r ein Oszilloskop ausgegeben. Die zyklische Ausgabe der Analogwerte e r f o l g t durch den Peripherierechner ohne Beteiligung des PC. Sie wird durch ein neues Steuerbyte a b g e brochen. In der Betriebsart 4 sendet der PC das Steuerbyte $04 und erwartet dann genau 1024 Datenbytes von einem 12-bit-Analog/Digitalwandler. Dieser ist bipolar geschaltet und mit einem Eingangskondensator, einem einstellbaren Tiefpassfilter und einer Abtast- und Halteschaltung ausgerüstet. Nach dem Empfang des Steuerbytes $04 liest der Peripherierechner zunächst 1024 Werte mit einer Abtastrate von 4 fis (250 kHz) in einen Pufferspeicher und überträgt sie anschließend byteweise an den PC; die unteren vier Bits werden abgeschnitten.
4.5 Die Interruptsteuerung
4.5
der
Druckerschnittstelle
107
Die Interruptsteuerung der Druckerschnittstelle ACK
L :
XXX
x xjx
XXX
x+2 anzeigen
x+1 lesen
X X X
X X X X
x+2 schreiben
o
0: gesperrt 1: frei
Druckerschnittstelle
£
IRQ7 LPT1
IRQ5 LPT2
0
X
IRQ7 IRQ6 IRQ5 IRQ4 IRQ3 IRQ2 IRQ1 IRQO 17 | 16 15
14
13
12
11
$21 Interruptfreigabe IRQ7: Maske $7F frei Maske $80 gesperrt IRQ5: Maske $DF frei Maske $20 gesperrt IRQ7: Vektor $0F IRQ5: Vektor $0D
10
0
1
1
0
X X
$20 Interruptbestätigung IRQ7: $67 bestätigt IRQ5: $65 bestätigt
Interruptcontroller PIC 1
Bild 4-13: Die Auslösung eines D r u c k e r i n t e r r u p t s
Bild 4-13 zeigt ein Modell der I n t e r r u p t s t e u e r u n g , die jedoch in den meisten Druckerprogrammen nicht verwendet wird. Die Schaltung der beiden I n t e r r u p t s t e u e r b a u s t e i n e e n t s p r i c h t dem Modell "AT". Standardmäßig ist f ü r die D r u c k e r s c h n i t t s t e l l e "LPT1" der I n t e r r u p t "IRQ7" und f ü r "LPT2" der I n t e r r u p t "IRQ5" v o r g e s e h e n . Dies läßt sich bei den meisten S c h n i t t s t e l l e n k a r t e n durch B r ü c k e n (Jumper) einstellen. Der I n t e r r u p t muß sowohl auf der D r u c k e r s c h n i t t s t e l l e ( S t e u e r r e g i s t e r Bit B4) als auch im I n t e r r u p t s t e u e r b a u s t e i n PIC f r e i g e g e b e n werden. E r wird durch eine s t e i gende Flanke des B e s t ä t i g u n g s s i g n a l s ACK ausgelöst. Am Ende des I n t e r ruptprogramms ist es erforderlich, den I n t e r r u p t im I n t e r r u p t s t e u e r b a u stein PIC zu b e s t ä t i g e n . Bild 4-14 zeigt ein Programmbeispiel, das in einer Schleife abwechselnd zwei Bitmuster a u s g i b t , bis die Schleife durch einen ACK-Impuls a b g e b r o c h e n wird. Dabei sollte möglichst ein e n t p r e l l t e r T a s t e r als Signalquelle verwendet werden.
108
4. Die parallele
Druckerschnittsteile
PROGRAM prog4p5; ( ' B i l d 4-14 IRQ5 durch ACK-Signal USES Dos, C r t ; CONST marke : BOOLEAN = FALSE; PROCEDURE e n d e ; INTERRUPT; BEGIN marke := TRUE; (* Harke f u e r Programraende P o r t [ $ 2 0 ] := $65 (* PIC I n t e r r u p t 5 b e s t a e t i g t END; BEGIN (* Hauptprogramm «) SetIntVec($OD,addr(ende)); (* Vektor umlenken P o r t [ $ 2 1 ] := P o r t [ $ 2 1 ] AND $DF; (* 1101 1111 IRQ5 f r e i Port[$0278+2] := $14; (* 0001 0100 ACK f r e i W r i t e L n ( ' B l i n k e n b i s ACK-Impuls ' ) ; REPEAT P o r t [ $ 0 2 7 8 ] := $55; Delay(lOOO); (* 01010101 ausgeben P o r t [ $ 0 2 7 8 ] := $AA; Delay(lOOO); (* 10101010 ausgeben UNTIL marke; P o r t [ $ 2 1 ] := P o r t [ $ 2 1 ] OR $20; (* 0010 0000 IRQ5 gesp END.
»)
*) «) *) «) *) «) *) «)
Bild 4-14: I n t e r r u p t d u r c h e i n e n A C K - I m p u l s
4.6
Erweiterung des Druckerports
I n d e n A n w e n d u n g e n , b e i d e n e n d i e 17 L e i t u n g e n d e s D r u c k e r p o r t s n i c h t ausreichen, müssen ü b e r zusätzliche Ausgabespeicher u n d Eingabemultip l e x e r w e i t e r e E i n / A u s g a b e k a n ä l e g e s c h a f f e n w e r d e n . Die u n i v e r s e l l s t e L ö s u n g b e s t e h t d a r i n , g e m ä ß Bild 4-15 e i n e n b i d i r e k t i o n a l e n 8 - b i t - B u s mit f ü n f z u s ä t z l i c h e n S t e u e r l e i t u n g e n am D r u c k e r p o r t a u f z u b a u e n . Die u n t e r e n v i e r B i t s l i e f e r t d e r S t e u e r p o r t ( A d r e s s e +2), d e r j a i n t e r n s c h o n mit O f f e n e n - K o l l e k t o r - A u s g ä n g e n a u s g e r ü s t e t i s t . Die o b e r e n v i e r B i t s l i e f e r t d e r D a t e n p o r t ( A d r e s s e +0), d e r z u s ä t z l i c h mit ( i n v e r t i e r e n d e n ) T r e i b e r n mit O f f e n e n - K o l l e k t o r - A u s g ä n g e n a u s g e r ü s t e t w i r d , i n V e r b i n d u n g mit d e m S t a t u s p o r t ( A d r e s s e +1). Die D a t e n a u s g a b e g e s c h i e h t d u r c h S c h r e i b e n i n d i e A u s g a b e r e g i s t e r . Vor d e r D a t e n e i n g a b e m ü s s e n d i e A u s g ä n g e d u r c h S c h r e i b e n a u f High g e b r a c h t w e r d e n . D a n n l a s s e n s i c h d i e a u ß e n a n l i e g e n d e n P o t e n t i a l e von d e n E i n g a b e r e g i s t e r n lesen. Die u n t e r e n v i e r B i t s d e s D a t e n p o r t s k ö n n e n z u r S t e u e r u n g d e r D a t e n ü b e r t r a g u n g v e r w e n d e t w e r d e n . Mit e i n e m S c h r e i b s i g n a l l a s s e n s i c h A u s g a b e d a t e n s p e i c h e r , mit e i n e m L e s e s i g n a l E i n g a b e d a t e n s p e i c h e r f r e i g e b e n . L i e g e n m e h r e r e S p e i c h e r b a u s t e i n e am B u s , so m ü s s e n sie d u r c h e i n e A d r e s s e u n t e r s c h i e d e n w e r d e n . Dies k a n n d i r e k t d u r c h d i e S t e u e r l e i t u n gen oder d u r c h eine Auswahlschaltung (Decoder) oder d u r c h b e s o n d e r e A d r e ß s p e i c h e r g e s c h e h e n . Der A b s c h n i t t 9.2.2 z e i g t a l s B e i s p i e l d e n A u f b a u e i n e s P e r i p h e r i e b u s am D r u c k e r p o r t , d e r d i e S i g n a l e d e r P C - P e r i p h e r i e n a c h b i l d e t u n d d a m i t d e n B e t r i e b v o n P C - P e r i p h e r i e k a r t e n am D r u c k e r port ermöglicht.
4.6 Erweiterung des Druckerports
bidirektionaler 7 6 5 4
+0 schreiben
+1 lesen
8-bit-Bus 3 2 10
+2 lesen
109
5-bit-Steuerbus
+2 schreiben
Bild 4-15: Erweiterung des Druckerports zu einem Bussystem
Die Druckerschnittstelle a r b e i t e t mit T T L - P e g e l . Die Kabellänge ist ohne besondere Treiberbausteine auf 1 bis 2 m b e g r e n z t . Die Geschwindigkeit der Datenübertragung hängt sowohl v o n der Hardware des Rechners ( T a k t und Bitbreite des P r o z e s s o r s ) als auch v o n der Software (Programmiers p r a c h e ) ab. Die im nächsten Kapitel behandelte Serienschnittstelle a r b e i tet wesentlich langsamer, sie läßt jedoch größere Reichweiten zu.
5. Die serielle Schnittstelle Die serielle S c h n i t t s t e l l e dient zum Anschluß von Hilfsgeräten (serielle D r u c k e r , Plotter oder Maus) und zur Verbindung von Rechnern u n t e r e i n a n d e r z.B. ü b e r das Telefonnetz. Bild 5-1 zeigt den Aufbau einer seriellen Datenübertragungsstrecke.
Sender
Pegelumsetzer seriell
F
Leitung
Modem
Modem
aus
Sendetakt
Empfänger
Pegelumsetzer seriell
r
-1-
ein
Eapfangstakt
Bild 5-1: Das Prinzip d e r seriellen D a t e n ü b e r t r a g u n g
Die zu ü b e r t r a g e n d e n Daten wie z.B. Texte liegen normalerweise in b y t e c o d i e r t e r Form v o r . Sie werden vom S e n d e r von der byteparallelen Darstellung in eine b i t s e r i e l l e Darstellung umgewandelt. Dies g e s c h i e h t h a r d waremäßig d u r c h ein S c h i e b e r e g i s t e r mit parallelen Eingängen und einem seriellen Ausgang, d e r TTL-Pegel liefert: < 0.4 V f ü r Low und > 2.4 V f ü r High. Bei Ü b e r t r a g u n g s s t r e c k e n l ä n g e r als 1 m v e r w e n d e t man zur V e r b e s s e r u n g d e r Ü b e r t r a g u n g s s i c h e r h e i t Pegelumsetzer. Das u n t e r d e r B e zeichnung V.24 (RS 232C) bekannte Verfahren s e t z t den TTL-Low-Pegel in eine Spannung von > 5 Volt und den TTL-High-Pegel in eine Spannung von < - 5 Volt um. Zur D a t e n ü b e r t r a g u n g in Telefonnetzen müssen die digitalen Signale mit Modems (Modulator/Demodulator) in T o n f r e q u e n z (z.B. 1200 Hz/ 2400 Hz) umgesetzt werden. Auf d e r Empfängerseite werden die seriellen Daten nach e n t s p r e c h e n d e r Umsetzung (Modem und Pegelumsetzer) wieder einem S c h i e b e r e g i s t e r zugeführt, das die seriell ankommenden E i n g a n g s daten wieder zu einem Byte zusammensetzt und b y t e p a r a l l e l dem empfangenden Gerät oder R e c h n e r ü b e r g i b t . Gegenüber e i n e r parallelen Datenü b e r t r a g u n g (z.B. D r u c k e r s c h n i t t s t e l l e ) sind n u r eine Datenleitung sowie die Masseleitung (Ground) e r f o r d e r l i c h . Sender und Empfänger müssen mit dem gleichen S c h i e b e t a k t arbeiten und s y n c h r o n i s i e r t werden. Bild 5-2 zeigt das üblicherweise verwendete a s y n c h r o n e s e r i e l l e ü b e r t r a g u n g s v e r f a h r e n ( T T L - P e g e l am Ausgang des S e n d e r s ) .
5. Die serielle Schnittstelle
Ausgang (TTL)
Ruhe
!
S
Abtastungen
durch
|
I
|
BO B1
I
B2
B3
den
Empfänger
M
B4
111
I
B5
M
M
Ruhe
B6 B7
D a t e n b i t s
Stopbits Paritätsbit
Startbit Übertragungsrahmen mit Daten Baud (bit/s) 110 150 300 600 1200 2400 4800 9600 19200
Bitzeit 9.091 ms 6.667 ms 3.333 ms 1.667 ms 833 ms 416 lis 208 MS 104 us 52 ms
Zeichenzeit (10 bit) 100 ms 67 ms 33 ms 16 ms 8 ms 4 ms 2 ms 1 ms 500 MS
Zeichenzeit für 1 Startbit 8 Datenbits 0 Paritätsbits 1 Stopbit 10 bit/Zeichen
Bild 5-2: Die a s y n c h r o n e s e r i e l l e D a t e n ü b e r t r a g u n g Wird k e i n Zeichen ü b e r t r a g e n , so l i e g t d e r A u s g a n g d e s S e n d e r s auf TTLHigh. Der ü b l i c h e r w e i s e v e r w e n d e t e V . 2 4 - P e g e l u m s e t z e r l e g t d i e L e i t u n g auf ca. - 12 Volt. Die Ü b e r t r a g u n g e i n e s Zeichens b e g i n n t mit einem S t a r t b i t (TTL-Low bzw. bei V.24-Pegel ca. + 12 Volt). D u r c h d i e f a l l e n d e F l a n k e d e s S t a r t b i t s wird d e r E m p f ä n g e r s y n c h r o n i s i e r t . Dann f o l g e n j e n a c h v e r w e n d e t e m Code 5 b i s 8 D a t e n b i t s . Ein b e s o n d e r s z u v e r e i n b a r e n d e s P a r i t ä t s b i t d i e n t d e r C o d e s i c h e r u n g . Ein o d e r zwei S t o p - B i t s , die immer TTL-High (V.24 ca. - 12 Volt) s i n d , s c h l i e ß e n die Ü b e r t r a g u n g d e s Z e i c h e n s a b . Die D a t e n b i t s w e r d e n mit dem w e r t n i e d r i g s t e n Bit z u e r s t g e s e n d e t . Da keine Taktinformationen ü b e r t r a g e n werden, müssen Ü b e r t r a g u n g s p a r a m e t e r z w i s c h e n S e n d e r u n d E m p f ä n g e r v e r e i n b a r t w e r d e n . Dies s i n d d i e B a u d r a t e ( b l t / s e c ) , die Anzahl d e r D a t e n b i t s u n d d i e V e r w e n d u n g e i n e s P a r i t ä t s b i t s . Die f o l g e n d e n Beispiele a r b e i t e n mit 4800 B a u d , 8 D a t e n b i t s , o h n e P a r i t ä t u n d mit einem S t o p b i t . Die Ü b e r t r a g u n g e i n e s Z e i c h e n s mit Rahmen (10 b i t ) d a u e r t d a b e i ca. 2 ms. Beim p r a k t i s c h e n A u f b a u e i n e r asynchronen seriellen D a t e n ü b e r t r a g u n g s s t r e c k e werden zusätzlich M o d e m s t e u e r s i g n a l e z w i s c h e n S e n d e r u n d E m p f ä n g e r ü b e r t r a g e n . Bild 5-3 z e i g t d i e ü b l i c h e B e s c h a t t u n g d e r s e r i e l l e n P C - S c h n i t t s t e l l e sowie d e n z e i t l i c h e n Verlauf d e r S i g n a l e (TTL- u n d V.24-Pegel). Die B e d e u t u n g d e r M o d e m s t e u e r s i g n a l e w i r d im Bild 5-7 n ä h e r e r l ä u t e r t . Die S i g n a l b e z e i c h n u n g e n b e z i e h e n s i c h auf d e n A n s c h l u ß e i n e s Modems, s e l b s t w e n n k e i n s v o r h a n d e n i s t u n d d i e V e r b i n d u n g d i r e k t mit TTL- bzw. V.24-Pegel e r f o l g t . Die Modemsignale m ü s s e n bei d e r P C - S c h n i t t s t e l l e d u r c h S o f t w a r e k o n t r o l l i e r t u n d a u s g e g e b e n w e r d e n ; z.B. d u r c h die BIOSu n d DOS-Systemsoftware. In diesen Betriebssystemprogrammen sendet die
112
5. Die serielle
TxD +5V TU 0
•
Schnittstelle
Initialisierung i Zeichen $0F empfangen i Zeichen $55 senden ! ' JT|oJT]oJT|oJT|oJ77 ^
TxD +12V V.24 -12V
1 1 1 1—
RxD +5V TTL 0
j s 1 1 1 1 0 0 0 Öls s I
RxD +12V V.24 -12V
,11
RTS +5Vt TTL 0^
In—
•- •
Jjl
RTS +12Vf~ V.24 — 12 V1
Bild 5-3: Schnittstellensteuerung und Signalverlauf Schnittstelle n u r dann, wenn der Eingang CTS (Clear To Send) eingeschaltet i s t ( > + 3 Volt); sie empfängt n u r dann, wenn d e r Eingang DSR (Data Set Ready) eingeschaltet ist ( > + 3 Volt). Die Ausgänge DTR (Data Terminal Ready) u n d RTS (Request To Send) liegen nach d e r Initialisierung der Schnittstelle d u r c h das Betriebssystem auf festem Potential ( > + 5 Volt). Der Datenausgang TxD liegt im Ruhezustand auf TTL-High bzw. V.24 ( < - 5 Volt).
5.1 Der Zugriff über das
5.1
Betriebssystem
113
Der Zugriff über das Betriebssystem
Die in einem Rechner installierten asynchronen seriellen Schnittstellen werden mit "COM1" oder "AUX" sowie mit "COM2", "COM3" und "COM4" b e zeichnet. COM bedeutet Communication, AUX bedeutet Auxiliary. Nach dem S t a r t des Betriebssystems ist normalerweise die serielle Schnittstelle "COM1" ("AUX") zugeordnet. Die Portadressen der beim Systemstart e r kannten seriellen Schnittstellen werden in den BIOS-Variablen $0040:$0000 bis $0040: $0006 festgehalten. Standardmäßig sind folgende Portadressen f ü r die Serienschnittstellen vorgesehen: COMl: $ 0 3 F 8 COM2: $ 0 2 F 8 COM3: $ 0 3 E 8 COM4: $ 0 2 E 8 Mit dem Betriebssystembefehl "MODE" lassen sich die voreingestellten Ubertragungsparameter der Schnittstellen und die Zuordnungen ändern. Das folgende Beispiel initialisiert die Serienschnittstelle "COMl" für 4800 Baud, ohne Parität, 8 Datenbits und 2 Stopbits sowie für einen Druckerbetrieb. Die f ü r den Paralleldrucker "LPT1" bestimmte Ausgabe wird dann auf die serielle Schnittstelle "COMl" und damit auf einen seriellen Drucker umgelenkt. >M0DE c o m l : 4 8 0 0 t N , 8 , 2 , p >M0DE l p t 1 : = c o m l : Der BIOS-Interrupt $14 stellt vier Funktionen zur Voreinstellung (Initialisierung), zum Zeichen senden, zum Zeichen lesen und zur Statusabfrage zur Verfügung. Dabei enthält das Register DX die Nummer der seriellen Schnittstelle (0 f ü r COMl). Der DOS-Interrupt $21 liefert Funktionen zum Empfangen und Senden von Zeichen über die serielle Schnittstelle COMl. Bild 5-4 zeigt ein Testprogramm, das Zeichen von der Tastatur (Konsole) seriell ausgibt und seriell ankommende Zeichen auf dem Bildschirm anzeigt. Vor einem Testlauf des Programmbeispiels ist darauf zu achten, daß die Gegenstation (Terminal, Rechner oder Schnittstellentestgerät) die S t e u e r signale CTS und DSR liefert und selbst direkt oder mit den Steuerausgängen DTR und RTS eingeschaltet wird (Bild 5-3). In der zweiten Testschleife (DOS-Interrupt $21) ist zu beachten, daß die Eingabefunktion (AH = 3) wartet, bis ein Zeichen seriell empfangen wurde. Eine S t a t u s a b f r a g e ist nur ü b e r den B I O S - I n t e r r u p t $14 möglich. Der Empfangscode $03 ( S t r g und C) löst einen I n t e r r u p t $23 aus. Da nur wenige Gegenstationen auf das in Bild 5-3 dargestellte Übertragungsprotokoll mit RTS eingestellt sind, greift man in der praktischen Anwendung meist direkt auf den Schnittstellenbaustein zu.
114
5. Die serielle
PROGRAM USES CONST (* 4800
prog5p5; (* Bild 5-4 BIOS- und DOS-Funktionen *) Dos, Crt; konfig = $c7; (* Parameter 110 0 Olli") Bd (ungerade) ohne Parität 2 Stopbits 8 Datenbits *) comnr = 0; (* 0 = COH1 1 = C0I12 *) reg : Registers; (* Dos -Registerdefinitionen *) z : CHAR;
VAR
Schnittstelle
BEGIN (* Initialisierung und Übertragung mit BIOS-Interrupt $14 reg.ah := 0; reg.al := konfig; (* Initialisierung reg.dx := comnr; Intr($14,reg); (* dx bleibt !!!!! (* Schnittst. => Konsole; Konsole => Schnittst. bis esc WriteLn; WriteLn('Eingabe bis esc1); z := #$00; (* esc REPEAT (« Status lesen reg.ah := 3; Intr($14,reg); IF (reg.ah AND $01) 0 THEN (* 0000 0001 Empfänger ? BEGIN reg.ah := 2; Intr($14,reg); (* Zeichen vom Empfänger Write(CHAR(reg.al)); (* nach Bildschirm END; (* wenn Taste betätigt IF KeyPressed THEN BEGIN z := ReadKey; (* Tastencode abholen REPEAT reg.ah := 3; Intr($14,reg); (« Status lesen UNTIL (reg.ah AND $60) 0; (* 0110 0000 Sender ? reg.ah := 1; reg.al := BYTE(z); Intr($14,reg); (* Zeichensenden END UNTIL z = #$lb; (* Abbruch mit Taste esc (* Lese- und Ausgabeschleife mit DOS-Interrupt $21 WriteLn; WriteLn('Eingabe bis esc'); z := #$00; (« esc REPEAT reg.ah := 3; HsDos(reg); (* C0M1 warten auf Zeichen Write(CHAR(reg.al)); (* nach Bildschirm ausgeben IF KeyPressed THEN (* wenn Taste betätigt BEGIN z := ReadKey; reg.dl := BYTE(z); reg.ah := 4; MsDos(reg) (* Zeichen über C0K1 senden END UNTIL z = #$lb (* Abbruch mit Taste esc END. Eingabe bis esc ABCDEF Eingabe bis esc 0123456789 Bild 5-4: T e s t d e r BIOS- u n d DOS-Funktionen
«) *) «) ») *) *) *) *) *) *) *) *) *) *) *) *) *) *) ») *) *) *)
5.2 Aufbau und Programmierung des Schnittstellenbausteins
5.2
115
Aufbau und Programmierung des Schnittstellenbausteins
x = $03F8 (C0M1 AUX)
x = $02F8 (COM2)
Bild 5-5: Die R e g i s t e r u n d A n s c h l ü s s e d e r S e r i e n s c h n i t t s t e l l e
Der S c h n i t t s t e l i e n b a u s t e i n (Bild 5-5) t r ä g t in d e n meisten Fällen d i e Bez e i c h n u n g UART 8250 ( U n i v e r s a l A s y n c h r o n o u s R e c e i v e r T r a n s m i t t e r ) . E r wird ü b e r T T L / V . 2 4 - T r e i b e r b z w . - E m p f ä n g e r an e i n e n 9 p o l i g e n o d e r 25pol i g e n S t e c k e r a n g e s c h l o s s e n . Der A n h a n g e n t h ä l t d i e g e n o r m t e n A n s c h l u ß b e z e i c h n u n g e n u n d S t i f t b e l e g u n g e n . Der B a u s t e i n b e s t e h t a u s einem S e n d e - u n d einem E m p f a n g s t e i l , einem p r o g r a m m i e r b a r e n B a u d r a t e n g e n e r a t o r f ü r den ü b e r t r a g u n g s t a k t , einer S e n d e r - u n d E m p f ä n g e r s t e u e r u n g , einer M o d e m s t e u e r u n g u n d e i n e r I n t e r r u p t s t e u e r u n g sowie einem H i l f s r e g i s t e r o h n e b e s o n d e r e F u n k t i o n e n . Da f ü r die i n s g e s a m t 11 R e g i s t e r n u r 8 A d r e s s e n z u r V e r f ü g u n g s t e h e n , w i r d ein S t e u e r b i t DLAB z u r A d r e ß u m s c h a l t u n g v e r w e n d e t . Die A n f a n g s a d r e s s e "x" d e r S c h n i t t s t e l l e läßt sich bei den meisten S c h n i t t s t e l l e n k a r t e n mit B r ü c k e n ( J u m p e r n ) e i n s t e l l e n , so daß m e h r e r e S e r i e n s c h n i t t s t e l l e n in einem S y s t e m b e t r i e b e n w e r d e n k ö n n e n . I n d e n f o l g e n d e n P r o g r a m m b e i s p i e l e n wird die A n f a n g s a d r e s s e "x" e n t w e d e r als K o n s t a n t e v e r e i n b a r t (CONST x = $ 0 2 F 8 ; ) o d e r als Variable vom D a t e n t y p WORD g e l e s e n ( W r i t e ( ' x e i n g e b e n > ' ) ; R e a d L n ( x ) ; ) o d e r n a c h E i n g a b e e i n e r K e n n z a h l d e r BIOS-Variablen e n t n o m m e n : VAR n r , x : WORD; BEGIN W r i t e ( ' C 0 M 1 , 2, 3 o d e r A > ' ) ; R e a d L n ( n r ) ; x := M e m W [ $ 0 0 A 0 : 2 * ( n r - 1 ) ] ; P o r t [x + 7] := $ 5 5 ; (« H i l f s r e g i s t e r «)
116
5. Die serielle
Schnittstelle
TxD
RxD
RCLK
Schieberegister I l l. I l x x x x x x x x
Schieberegister < :16
Sendedaten x+0 schreiben DLAB=0
Empfangsdaten x+0 lesen DLAß=0
Abtastungen: Schiebetakt*l6
- T e i l e r für ßaudratengenerator
(Takt*16)
1.8432 MHz
T e i l e r High x+1 DLAß=1 Baudrate 110 Teiler 1047 Takt*16
T e i l e r Low x+0 DLAB=1 150 768
Le i tungssteuerreg i s t e r x+3
300 384
Teiler =
1.8432*10 Baudrate»16
600 1200 2400 4800 9600 19200 192 96 48 24 12 6
Leitungsstatusregister x+5
B7 B6 B5 B4 B3 B2 B1 B0
B7 B6 B5 B4 B3 B2 B1 B0 i lI0 0: 5 b i t 0: leer 0 1: 6 b i t 1: v o l l 1 0: 7 b i t Empfangsdatenr. 1 1: 8 b i t 0: kein Überlauf Datenbits 1: Empfängerüberl. 1 Stopbit 0: kein P a r i t ä t s f . 2 Stopbits 1: P a r i t ä t s f e h l e r 1 1/2 (5 b i t ) 0: kein Stopbitfehler 0: kein P a r i t ä t s b i t 1: Stopbitfehler 1 : mit P a r i t ä t s b i t 0: kein Empfängerbreak 0: ungerade Parität 1: Empfängereingang Low 1: gerade Parität 0 : Sendedatenregister v o l l 0: ohne Ausgleichsparität 1: Sendedatenregister leer 1 : mit Ausgleichsparität 0: Sendeschieberegister v o l l 0: Senderfreigabe 1: Sendeschieberegister leer 1: TxD = 0 (Break) 0 : B7 i s t immer 0 0: (DLÀB) Sendedatenregister Interruptfre i gabereg i ster 1: (DLAB) T e i l e r r e g i s t e r
Bild 5-6: S e n d e r - u n d E m p f ä n g e r s t e u e r u n g mit ß a u d r a t e n g e n e r a t o r
Bild 5-6 z e i g t d i e S e n d e r - u n d E m p f ä n g e r s t e u e r u n g s o w i e d e n p r o g r a m mierbaren ßaudratengenerator.
5.2 Aufbau und Programmierung des Schnittstellenbausteins
117
Vor d e r D a t e n ü b e r t r a g u n g werden üblicherweise die Ü b e r t r a g u n g s p a r a meter f e s t g e l e g t ; sie gelten gleichermaßen f ü r den S e n d e r und f ü r den Empfänger. Dazu wird z u n ä c h s t das Adreßumschaltbit DLAB im L e i t u n g s s t e u e r r e g i s t e r (x+3) auf 1 g e s e t z t . Dadurch werden beim Zugriff auf die R e g i s t e r a d r e s s e n (x+1) und (x+0) die beiden T e i l e r r e g i s t e r des B a u d r a t e n g e n e r a t o r s a d r e s s i e r t . Die Teilerformel b e r ü c k s i c h t i g t , daß standardmäßig die Empfangsleitung mit dem 16fachen ü b e r t r a g u n g s t a k t a b g e t a s t e t wird. F ü r 4800 Baud und einen Quarz von 1.8432 MHz e r g i b t sich ein T e i l e r f a k t o r von 24. Nach d e r Umschaltung von DLAB auf 0 sind u n t e r der A d r e s s e (x+0) die beiden D a t e n r e g i s t e r und u n t e r (x+1) das I n t e r r u p t f r e i g a b e r e g i s t e r v e r f ü g b a r . Das S t e u e r b y t e f ü r 8 Datenbits, 2 Stopbits, kein P a r i t ä t s b i t und e i n g e s c h a l t e t e n S e n d e r l a u t e t 0000 O l l i b i n ä r ($07). Es wird in d a s L e i t u n g s s t e u e r r e g i s t e r g e s c h r i e b e n . Damit sind die U b e r t r a g u n g s p a r a meter f e s t g e l e g t . Auf d e r Adresse (x+0) befinden sich zwei R e g i s t e r . Wird in diese Adresse g e s c h r i e b e n , so gelangen die Daten in das S e n d e d a t e n r e g i s t e r , wird von d i e s e r Adresse g e l e s e n , so wird das E m p f a n g s d a t e n r e g i s t e r g e l e e r t . Das L e i t u n g s s t a t u s r e g i s t e r (x+5) zeigt im Bit BO an, ob ein Datenbyte im E m p f a n g s d a t e n r e g i s t e r b e r e i t liegt. Das folgende Beispiel liest das L e i t u n g s s t a t u s r e g i s t e r und p r ü f t es mit d e r Maske 0000 0001: I F ( P o r t [ x + 5 ] AND $ 0 1 ) 0 THEN (* Daten b e r e i t «) Die Bitpositionen B5 und B6 zeigen a n , ob das S e n d e d a t e n r e g i s t e r bzw. das S e n d e s c h i e b e r e g i s t e r f r e i sind zur Übernahme eines neuen Zeichens. Das folgende Beispiel liest das L e i t u n g s s t a t u s r e g i s t e r und p r ü f t es mit d e r Maske 0110 0000: I F ( P o r t [ x + 5 ] AND $ 6 0 ) 0 THEN (* Sender f r e i *)
M o d e m = Modulator/Demodulator
m
V.24-T rei ber'
Loop 0UT2 0UT1 RTS DTR interne Schleife
Modemsteuerregister x+4 0UT2 0UT1 RTS DTR DCD RI DSR CTS
Bild
= = = = = = = =
V.24-Empfänger
DCD RI
V
DSR CTS DCD RI
O.- TTL-High V.24 < - 5 V
0: TTL-High V.24 < - 3 V
1: TTL-Low V.24 > +5V
1: TTL-Low V . 2 4 > +3V
DSR CTS
0: lesen Register I 1: Änderung (Flanke)| der Leitung j
Modemstatusregister x+6
Ausgang für Interruptsteuerung nicht verwendet Request To Send = Schnittstelle schaltet Sendeteil des Modems ein Data Terminal Ready = Sendeteil der Schnittstelle ist bereit Data Channel Detected = Modem meldet, daß Empfangspegel anliegt Ring Indicator = Modem meldet ankommenden Ruf Data Set Ready = Modem meldet sich betriebsbereit Clear To Send = Modem meldet sich sendebereit
5-7: Die Modemsteuerung d e r S e r i e n s c h n i t t s t e l l e
118
5. Die serielle
Schnittstelle
Im G e g e n s a t z z u S c h n i t t s t e l l e n b a u s t e i n e n a n d e r e r H e r s t e l l e r w e r d e n d i e in Bild 5-7 d a r g e s t e l l t e n M o d e m s t e u e r s i g n a l e n u r d u r c h Ü b e r t r a g u n g s p r o g r a m m e e r z e u g t u n d a u s g e w e r t e t ; sie h a b e n k e i n e n d i r e k t e n Einfluß auf d i e H a r d w a r e d e s B a u s t e i n s . Die g e n o r m t e n S i g n a l b e z e i c h n u n g e n o r i e n t i e r e n sich am Anschluß e i n e s Modems, sie w e r d e n j e d o c h a u c h in B e t r i e b s a r t e n o h n e Modem v e r w e n d e t . Die v i e r E i n g ä n g e (DCD, RI, DSR u n d CTS) w e r d e n in d e n o b e r e n v i e r B i t p o s i t i o n e n d e s M o d e m s t a t u s r e g i s t e r s a l s L e i t u n g s z u s t ä n d e a n g e z e i g t ; in d e n v i e r u n t e r e n Bitpositionen e r s c h e i n e n Ä n d e r u n g e n ( F l a n k e n ) d e s L e i t u n g s z u s t a n d e s a l s 1. Diese v i e r A n z e i g e b i t s w e r d e n d u r c h ein L e s e n d e s M o d e m s t a t u s r e g i s t e r s w i e d e r z u r ü c k g e s e t z t . A b s c h n i t t 5.4 b e h a n d e l t d i e I n t e r r u p t s t e u e r u n g d e r S c h n i t t s t e l l e . Bei e i n e r B e w e r t u n g d e r L e i t u n g s p o t e n t i a l e i s t b e s o n d e r s zu b e a c h t e n , d a ß die Signale sowohl in d e r S c h n i t t s t e l l e i n v e r t i e r t als a u c h mit V . 2 4 - P e g e l w a n d l e r n u m g e s e t z t w e r d e n . S c h r e i b t man z.B. d u r c h e i n e n B e f e h l in d a s Bit BO (DTR) d e s M o d e m s t e u e r r e g i s t e r s eine 0, so e r s c h e i n t am A u s g a n g d e s B a u s t e i n s ein TTL-High u n d am S t e c k e r d e r S c h n i t t s t e l l e e i n L e i t u n g s p o t e n t i a l v o n < - 5 Volt (z.B. - 1 2 V). Eine 1 e r g i b t TTL-Low u n d auf d e r L e i t u n g eine S p a n n u n g v o n > + 5 Volt (z.B. +12 V). L i e g t z.B. am E i n g a n g DCD d e s S t e c k e r s ein L e i t u n g s p o t e n t i a l v o n < - 3 Volt (z.B. - 10 V), so e r s c h e i n t am B a u s t e i n ein TTL-High u n d im Bit B7 d e s M o d e m s t a t u s r e g i s t e r s eine 0. Ein L e i t u n g s p o t e n t i a l > + 3 Volt (z.B. + 10 V) l i e f e r t am B a u s t e i n e i n TTL-Low u n d im Bit B7 e i n e l o g i s c h e 1. Bild 5 - 8 z e i g t d e n A u f b a u e i n e s S c h n i t t s t e l l e n t e s t g e r ä t e s , d a s b e s o n d e r s f ü r die U n t e r s u c h u n g d e r Modemsteuersignale eingesetzt wurde.
Bezeichnungen der Serienschnittstelle Bild 5-8: S c h n i t t s t e l l e n t e s t g e r ä t
5.2 Aufbau und Programmierung des
Schnittstellenbausteins
119
Das Gerät enthält einen seriellen Schnittstellenbaustein ( A Y - 3 - 1 0 1 5 ) , bei dem s i c h die Ü b e r t r a g u n g s p a r a m e t e r d u r c h Hardware an Schaltern einstellen lassen, einen ebenfalls einstellbaren B a u d r a t e n g e n e r a t o r sowie LED-Anzeigen und Schalter f ü r die Modemsteuersignale. Die empfangenen Daten werden an a c h t Leuchtdioden a n g e z e i g t ; die zu sendenden Daten an a c h t Kippschaltern eingestellt. Bild 5-9 zeigt ein Testprogramm, mit dem die serielle Schnittstelle u n t e r s u c h t werden kann. PROGRAM prog5p0; (" Bild 5-9 Schnittstellentest USES Crt, Aushexbi; (' Auswhex, Ausbin WORD; VAE abst, x, rate, teil z : CHAR; wert : BYTE; baud : INTEGER; (* Baudrate einstellen *) PROCEDURE teiler(bd : INTEGER); VAR fakt : WORD; BEGIN 16)); (* Teiler fakt := LONGINT(1843200 DIV (LONGINT(bd) (« 1000 0000: DLAB := 1 Port[x+3] := Porttx+3] OR $80; Port[x+1] := Hi(fakt); Port[x+0] := Lo(fakt); Port[x+3] := Port[x+3] AND $7F; (* 0111 1111: DLAB := 0 END; BEGIN (* H a u p t p r o g ra m m *) WriteLn( Installierte Serienschnittstellen:'); FOR abst := 0 TO 3 DO BEGIN WriteC COM',abst+l, ': '); Auswhex (MemW[ $0040: abst «2]) ; END; WriteLn; WriteC Anfangsdresse hexadezimal $xxxx >'); ReadLn(x); WriteLn; Write('Schnittstelle initialisieren j/n? >'); z := Upcase(ReadKey); WriteLn(z); IF z = 'J' THEN BEGIN Port[x+7] := $55; (* 0101 0101 Test Hilfsregister «) IF Port[x+7] $55 THEN WriteLn('Fehler Hilfsregister !!!'); tei 1er(4800); (* Baudrate 4800 Bd eingest. *) (* 0000 Olli Ohne Par 2 Stp 8 Dat *) Port[x+3] := $07; (* 0000 0000 Int gesp RTS=0 DTR=0 «) Port[x+4] := $00; (* 0000 0000 Interrupts gesperrt *) Port[x+1] := $00; wert := Port[x+0]; (* Empfangsdatenregister leeren *) wert := Port[x+2]; (* Interruptstatus loeschen *) wert := Port[x+6]; (« Moderastatus loeschen *) WriteLn('4800 Bd Ohne Par.2 Stopbit 8 Datenbit Int gesp. RTS=0 DTR=0'); WriteLn; END; REPEAT Port[x+3] := Port[x+3] OR $80; (« 1000 0000 DLAB = 1 *) teil := WORD(Port[x+1]*256) + Port[x+0]; Port[x+3] := Port[x+3] AND $7F; (« Olli 1111 DLAB = 0 «) rate := LONGINT(1843200 DIV (LONGINT(teil) * 16)); Write('Baudrate: ',rate,' Bd Teiler = '.teil); WriteC Hilfsreg = '); Ausbbin(Port[x+7]); WriteLn; Write(' Leitung: Steuerung = '); Ausbbin(Port[x+3]); WriteC Anzeige = '); Ausbbin(Port[x+5]); WriteLn; Write(' Hodem: Steuerung = '); Ausbbin(Port[x+4]); Write(' Anzeige = '); Ausbbin(Port[x+6]); WriteLn; WriteC Interpt.: Steuerung = '); Ausbbin(Port[x+l] ); WriteC Anzeige = '); Ausbbin(Port[x+2]); WriteLn; WriteLn('Senden = S Empfangen = E Baudrate = B Leitung = L'); Write('Modem = M Interrupt = I Hilfsreg. = H Weiter = X Ende = * >');
120
J. Die serielle
Schnittstelle
z := Upcase(ReadKey); WriteLn; CASE z OF 'S' : BEGIN Write('Zeichen hexadezimal $xx >'); ReadLn(wert); WHILE (Port[x+5] AND $60) = $00 DO; (* 0110 0000 *) Port[x+0] := wert; (* Senden *) END; •E' : BEGIN WHILE (Port[x+5] AND $01) = $00 DO; (* 0000 0001 *) wert := Port[x+0]; (* Abholen «) Write('Zeichenmuster: '); ausbbin(wert); WriteLnC Zeichen: ' .CHAR(wert)) ; END; 'B' : BEGIN Write('Baudrate dezimal eingeben >'); ReadLn(baud); teiler(baud); END; 'L' : BEGIN Write('Leitungssteuerbyte hexadezimal $xx >'); ReadLn(wert); wert := wert AND $7F; (* 0111 1111 DLAB = 0 gesetzt !!!! *) Port[x+3] := wert; END; 'H' : BEGIN Write('Hodemsteuerbyte hexadezimal $xx >'); ReadLn(wert); Port[x+4] := wert; END; 'I' : BEGIN Write('Interruptsteuerbyte hexadezimal $xx >'); ReadLn(wert); Port[x+1] := wert; END; 'H' : BEGIN Write('Hilfsregisterbyte hexadezimal $xx >'); ReadLn(wert); Port[x+7] := wert ; END; END; WriteLn; UNTIL z = • *' ; END. Installierte Serienschnittstellen: COMl: $03F8 C0B2: $02F8 COM3: $0000 Anfangsdresse hexadezimal $xxxx >$02f8
COM4: $0000
Schnittstelle initialisieren j/n? >N Baudrate: 2400 Bd Teiler = 48 Hilfsreg = %01010101 Leitung: Steuerung = %00000011 Anzeige = %01100000 Modem: Steuerung = %00000000 Anzeige = %00000000 Interpt.: Steuerung = %00000000 Anzeige = %00000001 Senden = S Empfangen = E Baudrate = B Leitung = L Modem = M Interrupt = I Hilfsreg. = H Weiter = X Ende = * > Zeichen hexadezimal $xx >$55 Bild 5-9: Testprogramm f ü r die s e r i e l l e S c h n i t t s t e l l e
Das Programm s t e l l t z u n ä c h s t f e s t , w e l c h e s e r i e l l e n S c h n i t t s t e l l e n beim S y s t e m s t a r t e r k a n n t w u r d e n u n d i n i t i a l i s i e r t d a n n w a h l w e i s e die a u s g e wählte S c h n i t t s t e l l e mit v o r g e g e b e n e n Ü b e r t r a g u n g s p a r a m e t e r n . Dann
5.3 Serielle
Übertragungsverfahren
121
werden alle Registerinhalte binär angezeigt. In einer Schleife, die durch die Eingabe einer Endemarke ( * ) abgebrochen werden kann, kann nun der Benutzer wahlweise ein Zeichen senden bzw. empfangen, die Baudrate ändern, das Leitungssteuerregister mit neuen Ubertragungsparametern programmieren, Modemsteuersignale ausgeben, die Interrupts freigeben (Abschnitt 5.4) oder das Hilfsregister beschreiben. Bei jedem neuen Schleifendurchlauf erscheinen die aktuellen Registerinhalte. Als Gegenstation diente sowohl das Schnittstellentestgerät (Bild 5-8) als auch ein Ubungsrechner (MVUS 68K), mit dem die tfbertragungsprotokolle des folgenden Abschnitts untersucht wurden.
5.3
Serielle Übertragungsverfahren
Bei der Datenübertragung unterscheidet man den Simplexbetrieb, bei dem das eine Gerät nur als Sender und das andere nur als Empfänger arbeitet (z.B. Druckeranschluß) und den Duplexbetrieb, bei dem beide Geräte über zwei getrennte Datenkanäle miteinander verkehren können. Die folgenden Beispiele arbeiten im Duplexverfahren, um sowohl die Probleme des Sendens als auch des Empfangens darstellen zu können. Die Gegenstation, ein Übungsrechner (MVUS 68K), wurde einmal als "Echo" betrieben, das alle ankommenden Zeichen zurückschickt, zum anderen als Testsender, der einen laufenden Dezimalzähler mit Wagenrücklauf und Zeilenvorschub am Zeilenende an die PC-Schnittstelle überträgt. Das Senden i3t relativ einfach; bevor das Zeichen in das Sendedatenregister geschrieben wird, kontrolliert man, eventuell in einer Warteschleife, die Anzeigebits B6 bzw. B5 des Leitungsstatusregisters, ob das vorhergehende Zeichen schon übertragen wurde. Beim Empfangen werden die ankommenden Datenbits zunächst in einem Schieberegister aufgefangen und dann parallel dem Empfangsdatenregister übergeben. Dabei wird gleichzeitig das Anzeigebit BO des Leitungsstatusregisters auf 1 gesetzt. Wird nun das im Empfangsdatenregister befindliche Zeichen nicht schnell genug vom Programm gelesen, so kann es von nachfolgenden Zeichen überschrieben werden und damit verloren gehen. Dieser Uber lauffehler wird zusammen mit dem Paritätsfehler, dem Stopbitfehler und einer dauernden Leitungsunterbrechung (Break) im Leitungsstatusregister angezeigt. Berücksichtigt man die Laufzeit der Zeichen auf der Leitung, so erscheint bei 4800 Baud und maximaler Sendegeschwindigkeit alle 2 ms ein neues Zeichen. Diese Zeit reicht bei Pascalprogrammen mit Sicherheit aus, die Zeichen fortlaufend im Arbeitsspeicher abzulegen. Bei der Bildschirmausgalfe der ankommenden Zeichen ergibt sich jedoch ein extrem zeitkritisches Problem; das Rollen des Bildschirms am Ende der untersten Zeile durch das Steuerzeichen "Zeilenvorschub" (lf). In diesem Fall müssen nämlich alle Zeilen nach oben verschoben werden, damit am unteren Rand eine Leerzeile entsteht. Dieser Vorgang dauert bei normaler Bildschirmausgabe rund 15 ms, bei schnellen Assemblerprogrammen, die direkt auf den Bildspeicher zugreifen, wurden vom Verfasser immer noch ca. 12 ms für das Rollen des Bildschirms gemessen. Während dieser Zeit könnten also Zeichen bei der seriellen Übertragung verloren gehen.
122
5.3.1
5. Die serielle
Schnittstelle
Die Drei-Draht-Verbindung
Bild 5-10: Die Drei-Draht-Verbindung
Bei der in Bild 5-10 dargestellten Rechnerkopplung verwendet man drei Leitungen: eine Sendeleitung, eine Empfangsleitung und die gemeinsame Masseverbindung. Sind die 25poligen Anschlußstecker beider seriellen Schnittstellen entsprechend der V.24-Norm belegt, so muß der Senderausgang TxD ( S t i f t 2) der einen Schnittstelle mit dem Empfängereingang RxD ( S t i f t 3) der anderen Schnittstelle verbunden werden und umgekehrt. Diese Kreuzung findet normalerweise im Kabel statt und wird als "Nullmodemschaltung" bezeichnet. Da bei der Drei-Draht-Verbindung keine Modemsteuersignale übertragen werden, mußte der Eingang CTS der Gegenstation (MVUS) f e s t auf + 12 V gelegt werden, um den Sender einzuschalten. Bild 5-11 zeigt das Übertragungsprogramm der seriellen PCSchnittstelle.
5.3 Serielle
Übertragungsverfahren
PROGRAM prog5pl; (« Bild 5-11 Drei-Draht-Verbindung *) USES Crt; CONST t = 24; (* 4800 Baud *) p = $07; (* Ohne Par. 8 Daten 2 Stop *) x = $02F8; (« Schnittstelle COM2 *) VAR zein, zaus : BYTE; PROCEDURE init; (« Schnittstelle initialisieren BEGIN Port[x+3] := $80; (* 1000 0000 DLAB := 1 Port[x+1] := Hi(t); Port[x+0] := Lo(t); Port[x+3] := p; (« Oxxx xxxx DLAB := 0 zein := Port[x+0]; (* Empfangsdaten leeren END; PROCEDURE send(z : BYTE); (* Byte senden BEGIN WHILE Port[x+5] AND $20 = $00 DO; (* 0010 0000 warten Port[x+0] := z; (* Zeichen nach Sendedatenregister END; PROCEDURE emp£(VAR z : BYTE); (« Byte abholen BEGIN z Port[x+0]; (* Zeichen von Empfangsdatenregister END; PROCEDURE bild(z : BYTE); (* Bildschirmausgabe BEGIN CASE z OF $08 : GotoXY(WhereX-l,WhereY); (* Cursor links $0C : GotoXY(WhereX+l,WhereY); (* Cursor rechts $0D : GotoXY(l,WhereY); (* CR Wagenrueckl $00 : ; (* Fuel1 zeichen ELSE Write(CHAR(z)); END; END; BEGIN ( » H a u p t p r o g r a m m «) init; (* Serienschnittstelle initialisieren zaus := $00; (* ungleich Abbruchzeichen !!! REPEAT IF KeyPressed THEN (« Tastaturzeichen ? BEGIN zaus := BYTE(UpCase(ReadKey)); (» Klein -> Gross IF zaus $1B THEN send(zaus); (« Serielle Ausgabe END; IF Port[x+5] AND $01 $00 THEN (* 0000 0001 Empf.? BEGIN empf(zein); (« Zeichen abholen bild(zein); (« Bildschirmausg. END; UNTIL zaus = $1B; (* Esc - Taste: Abbruch END.
123
*) «) *) *) *) «) *) *) *) *) *) *) *) *)
*) *) «) «) *) *) *) *) *)
Bild 5-11: Testprogramm der Drei-Draht-Verbindung Nach der Initialisierung des Schnittstellenbausteins werden alle von der Tastatur eingegebenen Zeichen seriell gesendet und alle seriell ankommenden Zeichen auf dem Bildschirm ausgegeben. Die Prozedur b i 1 d der Bildschirmausgabe berücksichtigt besondere Steuercodes der Gegenstation. Das Steuerzeichen "Zeilenvorschub" (lf) wird von der Write-Prozedur ausgeführt.
124
5. Die serielle
Schnittstelle
Im E c h o b e t r i e b s c h i c k t d i e G e g e n s t a t i o n alle a n k o m m e n d e n Z e i c h e n w i e d e r z u r ü c k ; d i e Zeit z w i s c h e n d e r Ü b e r t r a g u n g z w e i e r Z e i c h e n w i r d d u r c h die l a n g s a m e T a s t a t u r e i n g a b e d e s B e n u t z e r s b e s t i m m t . Im S e n d e b e t r i e b s c h i c k t d i e G e g e n s t a t i o n mit maximaler G e s c h w i n d i g k e i t f o r t l a u f e n d e Dezim a l z a h l e n mit einem W a g e n r ü c k l a u f ( e r ) u n d einem Z e i l e n v o r s c h u b ( l f ) am E n d e . D u r c h d a s "Rollen" d e s B i l d s c h i r m s (10 b i s 15 ms) g i n g e n d i e e r s t e n Z e i c h e n am Z e i l e n a n f a n g v e r l o r e n . Als A b h i l f e m a ß n a h m e w u r d e d i e G e g e n s t a t i o n so u m p r o g r a m m i e r t , daß s i e n a c h j e d e m Z e i l e n v o r s c h u b e i n e W a r t e z e i t v o n 15 ms e i n l e g t e .
5.3.2
Das Hardware-Handshake-Verfahren
Das H a n d s h a k e v e r f a h r e n z u r D a t e n ü b e r t r a g u n g l ä u f t a l l g e m e i n in f o l g e n den Schritten ab: - Der E m p f ä n g e r f o r d e r t vom S e n d e r e i n Z e i c h e n a n . - Der S e n d e r s e n d e t d a s Zeichen. - Der E m p f ä n g e r b e s t ä t i g t die Ü b e r n a h m e d e s Z e i c h e n s . D a d u r c h w i r d s i c h e r g e s t e l l t , daß k e i n Z e i c h e n v e r l o r e n g e h t . Dies w i r d mit zusätzlichem L e i t u n g s - u n d Zeitaufwand f ü r die A n f o r d e r u n g s - u n d B e s t ä t i g u n g s s i g n a l e e r k a u f t . Bild 5-12 z e i g t e i n h ä u f i g v e r w e n d e t e s ü b e r t r a g u n g s v e r f a h r e n , d a s n u r mit e i n e r S t e u e r l e i t u n g a r b e i t e t . D e r M o d e m s t e u e r a u s g a n g RTS ( S t i f t 4) d e s E m p f ä n g e r s w i r d mit dem M o d e m s t e u e r e i n g a n g CTS ( S t i f t 5) d e s S e n d e r s v e r b u n d e n . A u c h h i e r i s t w i e d e r e i n e K r e u z u n g d e r L e i t u n g e n im Kabel (Nullmodem) e r f o r d e r l i c h . CTS > + 3 Volt s c h a l t e t d e n S e n d e r e i n , CTS < - 3 Volt s c h a l t e t i h n a u s . I n d e m P C - S c h n i t t s t e l l e n b a u s t e i n 8250 muß CTS d u r c h S o f t w a r e a u s g e w e r t e t w e r d e n , in d e r S e r i e n s c h n i t t s t e l l e 6551A d e r G e g e n s t a t i o n (MVUS) w i r k t CTS d i r e k t auf d e n S e n d e r ( H a r d w a r e ) . Das in Bild 5-13 d a r g e s t e l l t e P r o grammbeispiel zeigt das Übertragungsprogramm der PC-Schnittstelle. Nach d e r I n i t i a l i s i e r u n g d e r S e r i e n s c h n i t t s t e l l e s e n d e t d a s P r o g r a m m alle v o n d e r T a s t a t u r e i n g e g e b e n e n Z e i c h e n s e r i e l l a u s u n d z e i g t alle s e r i e l l a n k o m m e n d e n Z e i c h e n a u f dem B i l d s c h i r m a n . Die S e n d e p r o z e d u r s e n d p r ü f t v o r dem S e n d e n e i n e s Z e i c h e n s d e n M o d e m s t e u e r e i n g a n g CTS, o b d e r E m p f ä n g e r d e n S e n d e r f r e i g e g e b e n h a t , u n d d a n n , ob d a s S e n d e d a t e n r e g i s t e r l e e r i s t . Die B i l d s c h i r m a u s g a b e p r o z e d u r b i l d s p e r r t d e n S e n d e r d e r G e g e n s t a t i o n mit RTS, w e n n e i n Rollen d e s B i l d s c h i r m s ( Z e i l e n v o r s c h u b z e i c h e n $0A) d u r c h g e f ü h r t w i r d . I n d e m v o r l i e g e n d e n A n w e n d u n g s b e i s p i e l s t e h t f ü r d i e V e r a r b e i t u n g d e r a n d e r e n Z e i c h e n g e n ü g e n d Zeit ( c a . 2 ms) z u r V e r f ü g u n g . Ä h n l i c h e ü b e r t r a g u n g s v e r f a h r e n l a s s e n s i c h a u c h mit dem M o d e m s t e u e r a u s g a n g DTR u n d d e n M o d e m s t e u e r e i n g ä n g e n DCD, RI u n d DSR p r o g r a m m i e r e n . A b s c h n i t t 5.4 z e i g t die M ö g l i c h k e i t e n e i n e r I n t e r r u p t s t e u e r u n g .
S. S Serielle
Bild 5-12: Das R T S - C T S - H a n d s h a k e v e r f a h r e n
Übertragungsverfahren
125
126
5. Die serielle Schnittstelle
PROGRAM prog5p3; (* Bild 5-13 RTS-CTS-Handshake «) USES Crt; CONST t = 24; (* 4800 Baud *) p = $07; (* Ohne Par. 8 Daten 2 Stop *) x = $02F8; (« Schnittstelle COM2 «) BYTE; VAR zein, zaus PROCEDURE init; (* Schnittstelle initialisieren BEGIN (* 1000 0000 DLAB := 1 Port[x+3] = $ 8 0 ; Port[x+1] = Hi(t); Port[x+0] := Lo(t); = p; (* Oxxx xxxx DLAB := 0 Port[x+3] (* 0000 0010 RTS =+12V Port[x+4] = $02; (* Empfangsdaten leeren zein := Port [x+0]; END; PROCEDURE send(z : BYTE); (* Byte senden *) BEGIN WHILE Port[x+6] AND $10 = $00 DO; (* 0001 0000 CTS=-12V WHILE Port[x+5] AND $20 = $00 DO; (* 0010 0000 warten Port[x+0] := z; ( * Zeichen nach Sendedatenregister END; PROCEDURE empf(VAR z : BYTE); (* Byte abholen BEGIN z := Port[x+0]; (* Zeichen von Empfangsdatenregister END; PROCEDURE bild(z : BYTE); (* Bildschirmausgabe *) BEGIN CASE z OF $08 GotoXY ( WhereX-1, WhereY) ;(* Cursor links *) $0C GotoXY(WhereX+1,WhereY); (* Cursor rechts *) $0D GotoXY(1,WhereY); (» CR Wagenrueckl *) $00 (* Fue11 zeichen *) $0A BEGIN Port[x+4] := $00; (• 0000 0000 RTS = -12V «) Write(#$0A); (» Bild rollen «) Port[x+4] := $02; (* 0000 0010 RTS = +12V *) END; ELSE Write(CHAR(z)); END; END; BEGIN (»Haupt P r o g r a m m * ) init; ( Serienschnittstelle initialisieren *) (* ungleich Abbruchzeichen ! ! ! *) zaus := $00; REPEAT (* Tastaturzeichen ? IF KeyPressed THEN BEGIN zaus := BYTE(UpCase(ReadKey)) ; (* Klein -> Gross IF zaus $1B THEN send(zaus); (* Serielle Ausgabe END; IF Port[x+5] AND $01 $00 THEN (» 0000 0001 Empf. ? BEGIN (* Zeichen abholen empf(zein) ; bild(zein); (* Bildschirmausgabe END; UNTIL zaus = $1B; (* Esc - Taste: Abbruch ») END. Bild 5-13: Testprogramm f ü r RTS-CTS-Handshake
5.3 Serielle
5.3.3
Übertragungsverfahren
127
Das Software-Handshake-Verfahren
Schnittstelle initialisieren
XON
Taste ?
nein
ja solange Sender belegt warten Zeichen senden Empfänger ?
leer
voll Zeichen abholen und nach Pufferspeicher Puffer ?
leer
voll Zeichen ? lf=$0A
$08
$0C $00 XOFF speichern
EOT $00
Cursor positionieren
sonst Zeichen nach Bild
bis EOT Bild rollen XON bis Esc-Taste P r o g r a m m e n d e
Bild 5-14: Der Ablauf des XON-XOFF-Protokolls (Sender)
Anstelle der Modemsteuersignale lassen sich auch Steuerzeichen zum Einund Ausschalten des Senders verwenden, die über den fast immer vorhandenen Datenrückkanal vom Empfänger zum Sender übertragen werden. In dem Beispiel der Bilder 5-14 und 5-15 werden folgende ASCII-Steuerzeichen verwendet: - mit dem Steuerzeichen $ll=XON schaltet der Empfänger den Sender ein - mit dem Steuerzeichen $13=XOFF schaltet der Empfänger den Sender aus
128
S. Die serielle
Schnittstelle
Das Testprogramm sendet alle über die Tastatur eingegebenen Zeichen über die serielle Schnittstelle aus und zeigt alle seriell ankommenden Zeichen auf dem Bildschirm an. Während des zeitkritischen Rollens des Bildschirms durch das Steuerzeichen Zeilenvorschub ($0A) wird der Sender mit XOFF ausgeschaltet und danach mit XON wieder freigegeben. Im Gegensatz zu den Hardware-Handshakesignalen (RTS-CTS), die sofort auf den Sender wirken, muß das Steuerzeichen XOFF erst über den Rückkanal g e sendet und dann vom Sender softwaremäßig ausgewertet werden. Da während dieser Verzögerungszeit jedoch noch Zeichen über den Datenkanal übertragen werden können, mußten in dem Testprogramm zusätzlich ein Pufferspeicher und ein Bestätigungszeichen (Endemarke EOT $04) v e r wendet werden: - alle ankommenden Zeichen werden zunächst in einen Pufferspeicher (Ringpuffer) gebracht. - die Zeichen werden in der Reihenfolge, in der sie in den Puffer g e schrieben wurden, auf dem Bildschirm ausgegeben. - erkennt der Sender (Gegenstation) das Steuerzeichen XOFF, so sendet er das Bestätigungszeichen EOT ($04) und wartet, bis er mit XON wieder eingeschaltet wird. - hat der Empfänger das Steuerzeichen XOFF gesendet, so bringt er alle noch ankommenden Zeichen bis zur Endemarke EOT in den Pufferspeicher. Zwischen Sender und Empfänger lassen sich weitere Übertragungsprotokolle vereinbaren, die z.B. auch eine Fehlerkontrolle mit Prüfsummen oder eine Identifizierung bestimmter Teilnehmer in einem Netzwerk enthalten können. PROGRAM prog5p2; (* Bild 5-15 XON-XOFF-Protokoll *) USES Crt; (* 4800 Baud *) CONST t = 24; P = $07; (* Ohne Par. 8 Daten 2 Stop *) x = $02F8; (* Schnittstelle COH2 *) xon = $11; (* Steuerzeichen bereit *) xoff = $13; (* Steuerzeichen belegt *) eot = $04; (* Steuerzeichen Endemarke *) np = 1024; (* Pufferlaenge *) VAR zpuf ARRAY[l..np] OF BYTE; (* Empfangspuffer ezeig azeig : WORD; (* Pufferzeiger ende : BOOLEAN; PROCEDURE init; (* Schnittstelle initialisieren *) BEGIN Port [x+3] := $80; (* 1000 0000 DLAB := 1 *) Port[x+1] := Hi(t); Port[x+0] := Lo(t); Port [x+3] := p; (* Oxxx xxxx DLAB := 0 *) zpuf[1] := Port [x+0]; (* Empfangsdaten leeren *) END; PROCEDURE send(z : BYTE); (* Byte senden *) BEGIN IF z = $1B THEN ende := TRUE ELSE BEGIN WHILE Port[x+5] AND $60 = $00 DO; (* 0110 0000 warten Port[x+0] := z; (* Zeichen nach Sendedatenregister END; END;
5.4 Die Interruptsteuerung
der
Serienschnittstelle
129
PROCEDURE erapf; (* Byte abholen und nach Puffer *) BEGIN zpuf[ezeig] := Port[x+0]; IF ezeig = np THEN ezeig := 1 ELSE Inc(ezeig); END; PROCEDURE bild; (* Bildschirmausgabe «) VAR y,z : BYTE; BEGIN z := zpuf[azeig]; IF azeig = np THEN azeig := 1 ELSE Inc(azeig); CASE z OF $08 : GotoXY(WhereX-l,WhereY); (» Cursor links *) $0C : GotoXY(WhereX+l,WhereY); (« Cursor rechts *) $0D : GotoXY(l,WhereY); (* CR Wagenrueckl «) $00 : ; (* Fuel 1 zeichen *) $0a : BEGIN send(xoff); (« nicht bereit «) REPEAT IF Port[x+5] AND $01 $00 THEN BEGIN y := Port[x+0]; zpuf[ezeig] := y; IF ezeig = np THEN ezeig := 1 ELSE Inc(ezeig); END; UNTIL y = eot; Write(#$0A); send(xon); (* wieder bereit *) END; eot : ; ELSE Write(CHAR(z)); END; END; BEGIN ( * H a u p t p r o g r a m m * ) init; ende := FALSE; send(xon); (* Initialisieren XON senden*) ezeig := 1; azeig := 1; (* Index Pufferspeicher *) REPEAT IF KeyPressed THEN send(BYTE(UpCase(ReadKey))); (* senden *) IF Port[x+5] AND $01 $00 THEN empf; (* Zeichen holen *) IF (ezeig azeig) THEN bild; (* Puffer ausgeben *) UNTIL ende; (« Esc-Taste: Ende «) END. Bild 5-15: Testprogramm des XON-XOFF-Protokolls
5.4
Die Interruptsteuerung der Serienschnittstelle
Die besonders beim seriellen Empfang auftauchenden Zeitprobleme lassen sich einfach mit Hilfe der Interrupttechnik lösen: jedes ankommende Zeichen unterbricht das laufende Programm und startet ein Unterbrechungsprogramm, das es vom Empfänger abholt. Bild 5-16 zeigt ein Modell f ü r die Interruptsteuerung der Serienschnittstelle.
130
5. Die serielle
Schnittstelle
1
£
t
t
t
Modemstatussignale —r" DCD RI DSR CTS
X X X X 0UT2 X X X
0: gesperrt 1: frei Modemsteuerreg i ster x+4
Modemstatusreg i ster x+6
Priorität
\
CO
INTfiPI
> 1
-
B6 B5 B4 B3 B2 B1 BO
SendeDatenRegister leer
&
8 -,
Fehler: BreakRahmenParitätüberlauf
EmpfangsDatenRegister voll
Leitungsstatusregister x+5 0 Interrupt 0: gesperrt 1: frei
EmpfDaten SendeDaten EmpfängerFehler Modemstatus
Interruptfreigaberegister x+1
0
0
0
0
kein Interrupt Empfänqerfehler Empfangsdaten Sendedaten Modemstatus
X
X
X
0 0 1 1 1 0 1 0 0 0 1 0 0 0 0
Interruptanzeigeregister x+2
COM2 IRQ7|IRQ6 IRQ5 IRQ4 IRQ3 IRQ2 IRQ1 IRQO r|I7 116115114 |I3 112 | II 110 $21: Interruptfreigabe IRQ4: Maske $EF frei Maske $10 gesperrt IRQ3: Maske $F7 frei Maske $08 gesperrt IRQ4: Vektor $0C IRQ3: Vektor $0B
0
1 1 0
0
$20: Interruptbestätigung IRQ4: $64 bestätigt IRQ3: $63 bestätigt IRQ4: C0M1
IRQ3: COM2
Interruptcontroller PIC 1
Bild 5-16: Das Modell d e r I n t e r r u p t s t e u e r u n g
5.4 Die Interruptneuerung
der
Serienschnittstelle
131
Ein I n t e r r u p t kann durch mehrere " E r e i g n i s s e " bei der seriellen Datenü b e r t r a g u n g mit f o l g e n d e r P r i o r i t ä t ausgelöst werden: - es wird ein ü b e r t r a g u n g s f e h l e r erkannt, - es ist ein neues Zeichen im E m p f a n g s d a t e n r e g i s t e r erschienen, - das S e n d e d a t e n r e g i s t e r w u r d e g e l e e r t oder - die Modemsteuereingänge haben sich g e ä n d e r t . Treten mehrere Ereignisse g l e i c h z e i t i g auf, so wird das mit höherer P r i o r i tät b e v o r z u g t . Die v i e r I n t e r r u p t q u e l l e n lassen sich im I n t e r r u p t f r e i g a b e r e g i s t e r der Schnittstelle einzeln s p e r r e n und f r e i g e b e n . Das I n t e r r u p t a n z e i g e r e g i s t e r z e i g t die Quelle des I n t e r r u p t s an. Es wird beim Lesen w i e der z u r ü c k g e s e t z t . Die Art d e s Fehlers wird im L e i t u n g s s t a t u s r e g i s t e r a n g e z e i g t , das auslösende Modemsteuersignal im Modemstatusregister. Der Schnittstellenbaustein hat f ü r alle I n t e r r u p t q u e l l e n einen gemeinsamen I n t e r r u p t a u s g a n g . Das I n t e r r u p t s i g n a l wird durch einen auf d e r Schnittstellenkarte befindlichen besonderen Treiberbaustein und Brücken auf die I n t e r r u p t l e i t u n g e n des PC-Sytembus geschaltet. Der T r e i b e r muß durch den Ausgang OUT2 des Modemsteuerregisters mit einer 1 f r e i g e g e ben werden. Standardmäßig sind f ü r die Schnittstelle "COM1" ( " A U X " ) d e r I n t e r r u p t "IRQ4" und f ü r "COM2" d e r I n t e r r u p t "IRQ3" v o r g e s e h e n . Diese müssen im Maskenregister des Interruptsteuerbausteins PIC f r e i g e g e b e n werden. In d e r Vektortabelle des Betriebssystems ist der Vektor auf das entsprechende I n t e r r u p t p r o g r a m m umzulenken. Jede Annahme eines I n t e r r u p t s muß im S t e u e r r e g i s t e r des I n t e r r u p t s t e u e r b a u s t e i n s PIC b e s t ä t i g t werden. Bild 5-17 z e i g t ein Testprogramm, in dem alle seriell ankommenden Zeichen durch einen I n t e r r u p t gelesen werden. Es wird die in Bild 5-10 dargestellte Drei-Draht-Verbindung ohne Modemsteuersignale und Softwarehandshake v e r w e n d e t .
PROGRAM prog5p4; (« Bild 5-17 Empfaengerinterrupt ») USES Crt, Dos; CONST t = 24; (• 4800 Baud P = $07; (' Ohne Par. 8 Daten 2 Stop X = $02F8; (' Schnittstelle C0H2 (* Haske PIC IRQ3 freigeben irqena = $F7; irqdis = $08; (' Maske PIC IRQ3 sperren irqack = $63; (' PIC IRQ3 bestaetigen irqvec = $0B; (' Vektor fuer IRQ3 np = 1024; (" Pufferlaenge VAR zpuf : ARRAY[l..np] OF BYTE; (* Empfangspuffer ezeig, azeig : WORD; (* Pufferzeiger ende : BOOLEAN; PROCEDURE init; (» Schnittstelle initialisieren BEGIN Port[x+3] := $80; (* 1000 0000 DLAB := 1 Port[x+1] := Hi(t); Port[x+0] := Lo(t);(* Baudrate Port[x+3] := p; (* Oxxx xxxx DLAB := 0 zpuf[l] := Port[x+0]; (* Empfangsdaten leeren Port[x+1] := $01; (* 0000 0001 Empf.-Int. Port[x+4] := $08; (* 0000 1000 0UT2 Int. frei zpuffl] Port[x+2]; (» Interruptanzeige loeschen Port [$21] := Port [$21] AND irqena; (» PIC IRQ frei END;
132
5. Die serielle
Schnittstelle
PROCEDURE send(z : BYTE); (« Byte senden «) BEGIN IF z = $1B THEN ende := TRUE ELSE BEGIN WHILE Port[x+5] AND $60 = $00 DO; (* 0110 0000 n *) Port[x+0] := z; (* Zeichen n. Sendedatenregister *) END; END; PROCEDURE empf; INTERRUPT; (* Byte nach Puffer *) BEGIN zpuf[ezeig] := Port[x+0]; IF ezeig = np THEN ezeig := 1 ELSE Inc(ezeig); Port[$20] := irqack; (« PIC Interrupt bestaetigen *) END; PROCEDURE bild; (* Bildschirmausgabe «) VAS y,z : BYTE; BEGIN z := zpuf[azeig]; IF azeig = np THEN azeig := 1 ELSE Inc(azeig); CASE z OF $08 : GotoXY(WhereX-1,WhereY); (* Cursor links ») $0C : GotoXY(WhereX+l,WhereY); (* Cursor rechts *) $0D : GotoXY(1,WhereY); (* CR Wagenrueckl *) $00 : ; (* Fuel1 zeichen ») ELSE Write(CHAR(z)); END; END; BEGIN ( * H a u p t p r o g r a m m * ) i n i t ; ende := FALSE; (* I n i t i a l i s i e r e n *) ezeig := 1; azeig := 1; (* Index Pufferspeicher *) SetIntVec(irqvec,Addr(erapf)); (* Interruptvektor uml.*) REPEAT IF KeyPressed THEN send(BYTE(UpCase(ReadKey))); IF (ezeig azeig) THEN bild; (* Puffer ausgeben *) UNTIL ende; (* Esc-Taste: Ende ») Port[$21] := Port[$21] OR irqdis; (» PIC Int. sperren*) END. Bild 5-17: Testprogramm f ü r den Empfängerinterrupt Zu der üblichen Initialisierung der Serienschnittstelle mit den Ü b e r t r a gungsparametern kommt die Initialisierung der I n t e r r u p t s t e u e r u n g sowohl im Schnittstellenbaustein ( I n t e r r u p t f r e i g a b e r e g i s t e r ) als auch auf d e r Schnittstellenkarte (Modemsteuerausgang OUT2), im I n t e r r u p t s t e u e r b a u stein PIC (Maskenregister) und in der Vektortabelle ( S e t l n t V e c ) des Betriebssystems. Alle ankommenden Zeichen werden vom i n t e r r u p t g e s t e u e r t e n Empfangsprogramm empf zunächst in einen Pufferspeicher (Ringp u f f e r ) g e b r a c h t und in d e r Hauptprogrammschleife auf dem Bildschirm ausgegeben. Da das "zeitkritische" Rollen des Bildschirms beliebig u n t e r brochen werden kann, können keine ankommenden Zeichen mehr verloren gehen. Besondere Handshakeverfahren sind daher nicht erforderlich. Der Abschnitt 1.6 über die I n t e r r u p t s t e u e r u n g enthält in den Bildern 1-24 und 1-25 ein Anwendungsbeispiel, bei dem ein DCD-Interrupt der seriellen Schnittstelle f ü r den Abbruch einer Ausgabeschleife verwendet wird.
5. J Die serielle
5.5
Mausschnittstelle
133
Die serielle Mausschnittstelle
Die Maus besteht aus einer Rollkugel, deren Lage von zwei Lichtschranken abgetastet wird. Dadurch lassen sich Bewegungen in X- und in Y-Richtung erkennen. Dazu kommen zwei bzw. drei Steuertasten ("Fire Button"). Die Übertragung der Mausdaten erfolgt meist über die serielle Schnittstelle. Dann wird oft eine Diskette mit einem Auswerteprogramm (Treiber) mitgeliefert, das eine einfache Einbindung der Maus in Anwendungssoftware (z.B. Textverarbeitung) und in Benutzerprogramme (z.B. Pascalprogramme) ermöglicht. Als Verbindung zwischen der mitgelieferten Software und dem Mausanwender dient meist der Interrupt $33. Einzelheiten der Parameterübergabe finden sich in den Unterlagen der Maushersteller. Die folgenden Programmbeispiele gehen davon aus, daß der Maustreiber installiert ist, d.h. daß der Interruptvektor $33 auf das geladene Maustreiberprogramm zeigt, und daß die Maus angeschlossen ist. Beides ließe sich auch durch das Programm über Parameter prüfen. PROGRAM prog5p6; (* Bild 5-18: Haussteuerung ") USES Dos, Crt; CONST maus = $33; (* Maus-Interrupt «) VAR reg : Registers; z : CHAR; xvert, ywert : INTEGER; BEGIN ClrScr; GotoXY(l,25); Write(' * * * Maus bitte bewegen! Abbruch mit Esc-Taste * * *':65); xwert := 40; ywert := 12; z := #00; ( « ungleich Esc *) REPEAT reg.ax := 11; Intr(maus,reg); (* relative Mausbewegung *) xwert := xwert + INTEGER(reg.cx) DIV 8; ywert := ywert + INTEGER(reg.dx) DIV 8; IF xwert < 1 THEN xwert := 1; (* Grenze linker Rand *) IF xwert >80 THEN xwert := 80; (« Grenze rechter Rand *) IF ywert < 1 THEN ywert := 1; (* Grenze oberer Rand *) IF ywert >24 THEN ywert := 24; (« Grenze unterer Rand ' ) GotoXY(xwert,ywert); (* Cursor positionieren ») IF KeyPressed THEN BEGIN z := ReadKey; Write(z) END UNTIL z = #$1B; (» Abbruch durch Esc *) ClrScr END. Bild 5-18: Beispiel einer Maussteuerung Das in Bild 5-18 dargestellte Programmbeispiel zeigt die Anwendung einer Maustreiberfunktion zur Ermittlung der relativen Mausbewegung, ü b e r gibt man dem Interrupt $33 im AX-Register den Kennwert II, so erhält man im CX-Register die Bewegung der Maus in X-Richtung und im DX-Register die Bewegung in Y-Richtung. Die Werte haben die Einheit Bildpunkte (z.B. 1/200 Zoll). Das Vorzeichen enthält die Bewegungsrichtung (rechts/links bzw. oben/unten). Die Funktion ermittelt die Abweichung der augenblicklichen Mausposition gegenüber der vorhergehenden Abfrage. Das Beispielprogramm steuert damit den Cursor Innerhalb des Bildschirmfensters, über die vordefinierte Eingabefunktion ReadKey kann ein beliebiges Zeichen über die Tastatur eingegeben und an der Cursorposition auf den Bildschirm gebracht werden.
134
5. Die serielle
Schnittstelle
PROGRAM prog5p7; (* Bild 5-19: Cursorsteuerung *) USES Dos, Crt; CONST maus = $33; (« Ilaus-Interrupt «) VAR reg : Registers; z : CHAR; xalt, yalt, taste : WORD; links, mitte, rechts : BOOLEAN; BEGIN reg.ax := 1; Intr(maus,reg); (* Bauscursor ein «) reg.cx := 0; reg.dx := 23*8; (» Zeile 0 bis 23 *) reg.ax := 8; Intr(maus,reg); (* Vertikale Cursorgrenze *) reg.ax := 3; Intr(maus,reg); (* Cursorausgangsposition *) xalt := reg.cx; yalt := reg.dx; taste := reg.bx AND $07; z := #0; ClrScr; GotoXY(l,25); Write('Abbruch mit Esc ! Xpos = ',xalt DIV 8:2,' Ypos = ',yalt DIV 8:2); REPEAT GotoXY(17,25); reg.ax := 3; Intr(maus,reg);(* Cursor und Taste «) IF (reg.cx xalt) THEN (* Änderung Xpos ? *) BEGIN xalt := reg.cx; GotoXy(26,25); Write(xalt DIV 8:2) END; IF (reg.dx yalt) THEN (* Änderung Ypos ? *) BEGIN yalt := reg.dx; GotoXY(36,25); Write(yalt DIV 8:2) END; IF ((reg.bx AND $07) taste) THEN (* Änderung Maustaste ?«) BEGIN taste := reg.bx AND $07; links := (taste AND $01) = 1; GotoXY(39,25); IF links THEN Write('') ELSE WriteC ':8); mitte := (taste AND $04) = 4; GotoXY(47,25); IF mitte THEN Write('') ELSE Write(' •:8); rechts := (taste AND $02) = 2; GotoXY(55,25);IF rechts THEN Write('') ELSE WriteC ':9) END; IF KeyPressed THEN (* Tastatureingabe ? *) BEGIN z := ReadKey; GotoXY(66,25); IF z #0 THEN Write( 'Taste: \ z ) ELSE Write('Taste:*' .ReadKey) END UNTIL z = #$1B; (* Abbruch durch Esc «) reg.ax := 2; Intr(maus,reg); (* Mauscursor aus *) ClrScr END. Bild 5-19: Beispiel eines Mauscursors
Die mit der Maus gelieferte Treibersoftware erlaubt meist auch die Positionierung eines besonderen "Mauscursors", der mit der Maus über den Bildschirm bewegt werden kann. Davon unabhängig ist der gewohnte Ein/Ausgabecursor des Betriebssystem (ReadLn, W r i t e L n ) . Das in Bild 5-19 dargestellte Programmbeispiel schaltet mit der Funktion AX = 1 den Mauscursor ein und mit der Funktion AX = 2 den Mauscursor wieder aus. Die Funktion AX = 8 legt den vertikalen Bereich fest. Für den horizontalen Bereich bleibt der Vorgabewert erhalten; er ließe sich mit der Funktion
135
5.5 Die serielle Mausschnittstelle
AX = 7 ändern. Die Funktion AX = 3 ermittelt die augenblickliche absolute Cursorposition und den Zustand der Maustasten. Sie werden durch das Programmbeispiel in d e r untersten Bildschirmzeile a n g e z e i g t . Die Tastatureingaben erscheinen in der rechten unteren Ecke an der Position des Ein/Ausgabecursors.
PROGRAM prog5p8; (* Bild 5-20 serieller Hausanschluss *) USES Crt, Aushexbi; CONST t = 96; (* 1200 Baud *) p = $03; (» Ohne Par. 8 Daten 1 Stop *) VAR z : CHAR; x : WORD; PROCEDURE init; (* Schnittstelle initialisieren *) BEGIN Portfx+31 := $80; (« 1000 0000 DLAB := 1 *) Port[x+1] := Hi(t); Port[x+0] := Lo(t); Port[x+3] := p; (* Oxxx xxxx DLAB := 0 *) (* Empfangsdaten leeren *) z : CHAR(Port[x+0]); END; (* H a u p t p r o g r a m m * ) BEGIN REPEAT «rite('Schnittstelle ? COH1 = 1 C0H2 = 2 >'); z := ReadKey; WriteLn(z); IF z = '1' THEN x := $03F8; IF z = '2' THEN x := $02F8; UNTIL (z—11') OR (z =l 2'); ClrScr; init; z := #00; (* initialisieren REPEAT IF (Port[x+5] AND $01) $00 THEN Ausbhex(Port[x+0]); IF KeyPressed THEN BEGIN z := ReadKey; ClrScr END UNTIL z = #$1B (* Esc - Taste: Abbruch *) END. $83 $86 $87 $87 $87
$00 $00 $01 $FE $01
$00 $00 $00 $00 $00
$00 $00 $00 $FE $00
$00 $00 $00 $00 $00
$87 $86 $87 $87 $87
$00 $01 $FF $FE $01
$00 $00 $FF $01 $00
$00 $00 $FF $FE $00
$00 $00 $00 $FF $00
$85 $87 $87 $87
$00 $FF $FF $FF
$00 $00 $00 $FF
$00 $00 $00 $00
$00 $00 $00 $00
$87 $87 $87 $87
$00 $01 $FF $FF
$00 $00 $FF $FF
$00 $01 $FF $00
Bild 5-20: Die Rohdaten der seriellen Mau3schnittstelle
Das in Bild 5-20 dargestellte Programmbeispiel l i e f e r t die "Rohdaten", die die Maus über die serielle Schnittstelle an das Treiberprogramm sendet. Im Gegensatz zu dem T r e i b e r , der mit einem Empfängerinterrupt gesteuert wird, übernimmt das Programmbeispiel die ankommenden Daten durch Auswertung der Bitposition B0 des L e i t u n g s s t a t u s r e g i s t e r s und g i b t 3ie hexadezimal auf dem Bildschirm aus. Die in dem Beispiel untersuchte Maus sendete bei j e d e r Bewegung und bei j e d e r Änderung der Tasten 5 Zeichen. Es g i b t jedoch auch Bauformen von Mäusen, die nicht über die serielle Schnittstelle, sondern wie ein Steuerknüppel ( J o y s t i c k ) angeschlossen und betrieben werden (Kapitel 6).
$00 $00 $00 $00
6. Der Spieleadapter (Gameport) Die a l s S p i e l e a d a p t e r o d e r G a m e p o r t b e z e i c h n e t e S c h n i t t s t e l l e d e s PC d i e n t z u m A n s c h l u ß v o n S t e u e r k n ü p p e l n ( J o y s t i c k s ) , m i t d e n e n z.B. B i l d s c h i r m s p i e l e b e t r i e b e n w e r d e n k ö n n e n . D a b e i u n t e r s c h e i d e t m a n digitale Geräte m i t e i n e r m e i s t 9 p o l i g e n B u c h s e u n d analoge G e r ä t e m i t e i n e r m e i s t 1 5 p o l i g e n B u c h s e . Bei e i n e m d i g i t a l e n J o y s t i c k s c h a l t e t d e r S t e u e r k n ü p p e l l e d i g lich v i e r S c h a l t e r in d e n v i e r v e r s c h i e d e n e n R i c h t u n g e n ein bzw. a u s . Er k a n n z.B. a n d e n S t e u e r e i n g ä n g e n d e r D r u c k e r s c h n i t t s t e l l e b e t r i e b e n w e r d e n . Der S p i e l e a d a p t e r d e s PC b e n ö t i g t j e d o c h e i n e n analogen Joystick, b e i dem d e r S t e u e r k n ü p p e l zwei P o t e n t i o m e t e r b e w e g t , d i e j e n a c h A u s l e n k u n g unterschiedliche Widerstandswerte liefern.
6.1
Die Schaltung des analogen Joysticks %
Reset
Bild 6-1: W i d e r s t a n d s m e s s u n g mit e i n e m M o n o f l o p
Die v o n e i n e m a n a l o g e n J o y s t i c k g e l i e f e r t e n W i d e r s t a n d s w e r t e w e r d e n v o n d e m S p i e l e a d a p t e r mit d e r i n Bild 6-1 d a r g e s t e l l t e n S c h a l t u n g g e m e s s e n . Nach einem Z u r ü c k s e t z e n (Reset) d u r c h d a s E i n s c h a l t e n d e r V e r s o r g u n g s s p a n n u n g l i e g t d e r A u s g a n g ( S t i f t 1) z u n ä c h s t a u f L o w - P o t e n t i a l . Der i n v e r t i e r t e A u s g a n g ist High u n d s c h a l t e t d e n i n t e r n e n T r a n s i s t o r d u r c h u n d l e g t d a m i t d e n A n s c h l u ß RC ( S t i f t 2) a u f L o w - P o t e n t i a l . D a d u r c h i s t d e r K o n d e n s a t o r k u r z g e s c h l o s s e n . Ein T r i g g e r i m p u l s (Auslöseimpuls) k i p p t d a s M o n o f l o p k u r z z e i t i g um. Der A u s g a n g ( S t i f t 1) g e h t a u f H i g h , d e r I n v e r t i e r t e A u s g a n g w i r d Low, u n d d e r T r a n s i s t o r s p e r r t . D a d u r c h k a n n
6.1 Die Schaltung
des analogen
Joysticks
137
PC - Erweiterungsstecker IOW AEN |
A9..A0 l 11 ^
IOR
D7 D6 D5 D4 D3 D2 D1 DO I I I I I I I I
IH
(14) (10)
(7)
(2)
(13)
Gameportkarte Adresse $201 7U LS 2 «
rTH
X*"*
H h C = 10 nF
0 M U (11) (6) (3)
R=2 2kû
'
Buchse 15polig
(1) (4)
(14) (10)
(7)
(2)
(13)
(11)
(6)
J
(3)
Stecker
t -Y
analoge Potentiometer 0 .. 140 KOhm
Steuerknüppel (Joystick) Bild 6-2: S p i e l e a d a p t e r k a r t e u n d a n a l o g e r J o y s t i c k
s i c h n u n d e r K o n d e n s a t o r ü b e r d e n Widerstand a u f l a d e n . Beim E r r e i c h e n e i n e s S c h w e l l w e r t e s wird d a s Monoflop w i e d e r z u r ü c k g e s e t z t . Der A u s g a n g wird w i e d e r Low, u n d d e r T r a n s i s t o r s c h a l t e t d e n K o n d e n s a t o r w i e d e r k u r z . Die Länge d e s A u s g a n g s i m p u l s e s i s t p r o p o r t i o n a l d e r Z e i t k o n s t a n t e n T = R-C d e r ä u ß e r e n R C - S c h a l t u n g ; b e i k o n s t a n t e m C a l s o proportional dem Widerstand R u n d damit d e r A u s l e n k u n g d e s J o y s t i c k s . Die W i d e r s t a n d s m e s s u n g wird a u f e i n e M e s s u n g d e r Länge e i n e s Ladeimpulses z u r ü c k g e f ü h r t . Bild 6-2 z e i g t d e n A u f b a u e i n e r S p i e l e a d a p t e r k a r t e u n d die S c h a l tung eines analogen Joysticks. Ein a n a l o g e r J o y s t i c k e n t h ä l t e i n e n S t e u e r k n ü p p e l f ü r die b e i d e n P o t e n t i o m e t e r in X- u n d Y - R i c h t u n g sowie zwei d i g i t a l e T a s t e r , die auch "Fire Button" o d e r F e u e r t a s t e n g e n a n n t w e r d e n . An die Karte l a s s e n s i c h zwei d i e s e r Geräte a n s c h l i e ß e n . Die b e i d e n P o t e n t i o m e t e r w e r d e n ü b e r die in Bild 6 - 1 e r l ä u t e r t e S c h a l t u n g an die b e i d e n D a t e n b i t s DO u n d Dl a n g e s c h l o s s e n , die b e i d e n T a s t e r a n die D a t e n b i t s D4 u n d D5. Die v i e r a n d e r e n
138
6. Der Spieleadapter
(Gameport)
B i t p o s i t i o n e n d i e n e n z u r Kontrolle e i n e s zweiten J o y s t i c k s . F ü r d e n S p i e l e a d a p t e r (Gameport) i s t im PC d e r Bereich v o n $200 b i s $20F d e r P e r i p h e r i e p o r t a d r e s s e n v o r g e s e h e n . U b e r e i n e A d r e ß d e c o d i e r l o g i k e r h ä l t d i e in dem Beispiel Bild 6 - 2 g e z e i g t e Karte d i e P o r t a d r e s s e $201. Ein S c h r e i b b e f e h l auf die P o r t a d r e s s e $201 löst e i n e n T r i g g e r i m p u l s f ü r alle v i e r Monof l o p s a u s ; Daten w e r d e n d a b e i n i c h t ü b e r n o m m e n . Ein L e s e b e f e h l auf d i e P o r t a d r e s s e $201 l i e s t d e n a u g e n b l i c k l i c h e n Z u s t a n d d e r v i e r F e u e r t a s t e n u n d d e r v i e r Monoflops. Das f o l g e n d e Beispiel s t a r t e t d e n M e ß v o r g a n g u n d mißt d e n W i d e r s t a n d d e s X - P o t e n t i o m e t e r s (Maske 0000 0001) mit einem Zähler. VAR z a e h l : LONGINT; BEGIN z a e h l := 0 ; (« Z ä h l e r l ö s c h e n *) P o r t [ $ 2 0 1 ] := 0 ; (* T r i g g e r i m p u 1 s *) WHILE ( P o r t [ $ 2 0 1 ] AND $ 0 1 ) 0 DO I n c ( z a e h l ) ;
6.2
Die Programmierung über das Betriebssystem
PROGRAH progöpO; (« Bild 6-3: BlOS-Joysticktest *) USES Dos, C r t ; VAR reg : R e g i s t e r s ; x a , y a , x p , y p : WORD; t a s t e : BYTE; oben,unten : BOOLEAN; BEGIN ClrScr; r e g . a h := $84; reg.dx := 0; I n t r ( $ 1 5 , r e g ) ; (« Tasten *) t a s t e := r e g . a l ; r e g . a h := $84; reg.dx := 1; I n t r ( $ 1 5 , r e g ) ; (* Knüppel *) xa := r e g . a x ; ya := r e g . b x ; GotoXY(l,25); Write('Knüppel 1: X = ' , x a : 4 , ' Y = ' , y a : 4 , ' • : 8 ) ; REPEAT r e g . a h := $84; reg.dx := 1; I n t r ( $ 1 5 , r e g ) ; (» Knüppel *) r e g . a x := r e g . a x AND $FFF0; reg.bx := reg.bx AND $FFF0; IF xa r e g . a x THEN BEGIN xa := r e g . a x ; GotoXY(15,25); Write(xa:4) END; IF ya r e g . b x THEN BEGIN ya := reg.bx; GotoXY(23,25); Write(ya:4) END; xp := Round(xa/2.5); yp := Round(ya/8); IF xp < 1 THEN xp := 1; IF xp > 80 THEN xp := 80; IF yp < 1 THEN yp := 1; IF yp > 24 THEN yp := 24; GotoXY(xp,yp); r e g . a h := $84; reg.dx := 0; I n t r ( $ 1 5 , r e g ) ; (* Tasten *) IF t a s t e r e g . a l THEN BEGIN t a s t e := r e g . a l ; oben := t a s t e AND $10 = 0; unten := t a s t e AND $20 = 0; GotoXY(30,25); IF oben THEN Write('') ELSE W r i t e ( ' ' : 6 ) ; GotoXY(40,25); IF unten THEN W r i t e ( ' ') ELSE WriteC ' :7) END UNTIL KeyPressed END. Bild
6-3: T e s t p r o g r a m m mit dem B I O S - I n t e r r u p t $15
6.3 Die Programmierung
über den Peripherieport
139
Das in Bild 6-3 dargestellte Testprogramm benutzt den BIOS-Interrupt $15 zur Auswertung eines Joysticks. Mit den Kennwerten AH = $84 und DX = 1 liefert der Interrupt $15 in den Wortregistern AX, BX, CX und DX Zähler f ü r die Länge des Ladeimpulses zurück. Sie sind ein Maß f ü r den Widerstand der Potentiometer und damit für die Stellung der Steuerknüppel. Für den Joystick Nr. 1 enthält AX die Position des X-Potentiometers und BX die Position des Y-Potentiometers. Die Kennwerte AH = $84 und DX = 0 lief e r n den Status der vier möglichen Feuertasten im Byteregister AL. Für den Joystick Nr. 1 steht der Zustand der Taste 1 in der Bitposition B5, der Zustand der Taste 2 in B4. Eine 0 bedeutet gedrückt, eine 1 bedeutet nicht gedrückt. Das Programmbeispiel zeigt die beiden Positionszähler und den Zustand der beiden Feuerknöpfe in der untersten Bildschirmzeile an. Mit dem Steuerknüppel läßt sich der Cursor wie mit einer Maus über den Bildschirm bewegen.
6.3
Die Programmierung über den Peripherieport
PROGRAM prog6p2; (* Bild 6-4 Port-Joysticktest *) USES Crt,Aushexbi; (* enthält Ausbbin *) CONST jadr = $201; (* Portadresse Joystick *) VAR zaehl : WORD; BEGIN ClrScr; REPEAT zaehl := 0; WHILE (Port[jadr] AND $03) 0 DO; INLINE($FA); (* Interrupt gesperrt ») Port[jadr] := $00; (* Triggerimpuls *) WHILE (Port[jadr] AND $01) 0 DO Inc(zaehl); INLINE($FB); (* Interrupt frei *) GotoXY(l,25); Write('X = \ zaehl:5); zaehl := 0; WHILE (Port[jadr] AND $03) 0 DO; INLINE($FA); (* Interrupt gesperrt *) Port[jadr] := $00; (* Triggerimpuls «) WHILE (Port[jadr] AND $02) 0 DO Inc(zaehl); INLINE($FB); (* Interrupt frei ") GotoXY(15,25); Write('Y = \ zaehl:5); GotoXY(25,25); IF (Port[jadr] AND $10) = 0 THEN Write('') ELSE Write(• ' :6); GotoXY(35,25); IF (Port[jadr] AND $20) = 0 THEN Write('') ELSEWriteC ':7); GotoXY(45,25); Ausbbin(Port[jadr]); UNTIL KeyPressed END. Bild 6-4: Testprogramm mit Portzugriff
Das in Bild 6-4 dargestellte Programmbeispiel g r e i f t unter der Portadresse $201 direkt auf den Spieleadapter zu. In der untersten Bildschirmzeile
140
6. Der Spieleadapter
(Gameport)
werden die Position des Steuerknüppels in X- und in Y-Richtung sowie der Zustand der beiden Feuertasten angezeigt. Vor jeder Widerstandsmessung wird der Zähler gelöscht. Die erste WHILE-DO-Schleife wartet gegebenenfalls auf das Ende noch laufender Ladeimpulse. Vor Beginn der Messung werden alle I n t e r r u p t s mit dem Assemblerbefehl CLI (Code $FA) gesperrt. Die Ausgabeanweisung ( P o r t [ j a d r ] := 0) liefert den Triggerimpuls f ü r alle vier Monoflops. Die zweite WHILE-DO-Schleife wartet auf das Ende des jeweils ausmaskierten Ladeimpulses und zählt dabei den Zähler aufwärts. Nach der Freigabe der Interrupts mit dem Assemblerbefehl STI (Code $FB) wird der Zählerstand als Maß für den gemessenen Widerstand und damit als Position des Steuerknüppels angezeigt. Die Ausgabe der Tastenzustände erfolgt d u r c h Ausmaskierung der entsprechenden Bitpositionen nach dem Lesen des Ports. Aus dem zusätzlich binär angezeigten Portzustand läßt sich ersehen, ob ein zweiter Joystick angeschlossen ist. Der folgende Abschnitt zeigt, daß sich die Länge des Ladeimpulses auch mit dem Timer des PC messen läßt.
6.4
Die Impulslängenmessung mit dem Timer
PROGRAM prog6pl; (* Bild 6-5: Widerstandsraessung «) OSES Crt; CONST jport = $201; (* Portadresse des Joysticks *) korr =33; (* Korrekturwert *) VAR x,ha,he,la,le : BYTE; i,wa,we : WORD; summe,zeit : LONGINT; BEGIN ClrScr; REPEAT
summe := 0; FOR i := 1 TO 10 DO BEGIN x := Hem[$40:$6C]; (* Warten -) WHILE x = Hem[$40:$6C] DO; (« bis Start Timer 0 «) INLINE($FA); (* CLI Interruptsperre *) Port[$43] := $04; la := Port[$40]; ha := Port[$40]; Port[jport] := 0; (* Triggerimpuls *) WHILE (Port[jport] AND $01) 0 DO; (* warten «) Port[$43] := $04; le := Port[$40]; he := Port[$40]; INLINE($FB); (* Interruptfreigabe *) wa := (WORD(la) OR (WORD(ha) SHL 8)); we := (WORD(le) OR (WORD(he) SHL 8)); summe := summe + (wa-we); END; zeit := Round(summe/10*0.419) - korr; GotoXY(30,12); Write(zeit:6,' us => ' ) ; IF zeit < 10 THEN Write(zeit*100:8,' Ohm'); IF (zeit >= 10) AND (zeit < 10000) THEN Write(zeit/10:8:3, ' kOhrn'); IF zeit >= 10000 THEN Write(zeit/10000:8:3, ' HOhm') UNTIL KeyPressed END. Bild 6-5: Widerstandsmessung mit dem Spieleadapter
6.4
Die Impulslängenmessung
mit dem
Timer
141
Das in Bild 6-5 dargestellte Programmbeispiel verwendet anstelle eines Joysticks einen einstellbaren Drehwiderstand (Potentiometer) zwischen den Anschlüssen Stift (1) (+5V) und Stift (3) (X-Achse) des Spieleadapters. Der Widerstand wird einmal als Impulslänge in JJS und als Widerstandswert in Ohm auf dem Bildschirm angezeigt. Die Messung der Länge des Ladeimpulses erfolgt durch den Timer 0 des Systembausteins 8 2 5 3 (Abschnitt 3 . 3 ) . Der Quarz von 1 . 1 9 3 1 8 2 MHz liefert die Periodendauer von 0 . 8 3 8 0 9 5 1 f i s und eine Länge der Halbperiode von 0 . 4 1 9 0 4 7 6 / J S . In der voreingestellten Betriebsart 3 (Schrittweite 2 und Rechteckausgang) entspricht ein Timerschritt einer Zeit von ca. 0.419 fis und ein Timerdurchlauf einer Zeit von 0 . 4 1 9 - 6 5 5 3 6 = 2 7 . 4 6 ms. Zwei Durchläufe ergeben einen Timer Tic von ca. 5 5 ms. Das Testprogramm wartet durch Kontrolle der Timer Tic Variablen auf den Start des Timers, sperrt alle Interrupts (Befehl CLI) und liest den Anfangswert des Timers. Der Ausgabebefehl auf den Spieleadapterport triggert das Monoflop. Am Ende des Ladeimpulses werden der Timerstand e r neut ausgelesen und die Interrupts wieder freigegeben (STI). Die Zählerdifferenz mal 0.419 ergibt die Impulslänge in ßs. Wegen der starken Streuung der Meßergebnisse wird ein Mittel aus 10 Messungen gebildet. Der Korrekturwert k o r r berücksichtigt, daß auf der Karte bereits ein Widerstand von 2.2 KOhm in Reihe liegt. Er wurde aus einer Kurzschlußmessung ermittelt. Auf der Karte befindet sich ein Ladekondensator von 10 nF. Nach der Formel für die Zeitkonstante bzw. Impulslänge T = R-C ergibt sich der Widerstand R = T / C. Mit C = 10 nF und T in der Einheit fis erhält man den Widerstand R = 100-T in Ohm. Die maximale Meßzeit beträgt ca. 27 ms entsprechend 2.7 MOhm.
7. Der Anschluß von Peripheriekarten Die bisher behandelten Schnittstellen (Parallele Schnittstelle, serielle Schnittstelle und Spieleadapter) befinden sich meist auf einer Peripheriekarte, die innerhalb des Rechnergehäuses installiert ist. Dort gibt es weitere Steckplätze f ü r den Einbau zusätzlicher Karten. Dazu muß jedoch das Gehäuse geöffnet werden. Für Messungen der Bussignale und f ü r den häufigen Wechsel von Karten empfiehlt es sich, über ein Flachbandkabel eine Buserweiterungsplatine anzuschließen, auf die dann zusätzliche Peripheriekarten außerhalb des Rechnergehäuses aufgesteckt werden können. Ein Wechsel der Karten sollte in jedem Fall nur bei ausgeschaltetem Rechner vorgenommen werden.
7.1
Die Adressierung der Peripherie
PROGRAM p r o g 7 p l ; ( * B i l d 7 - 1 : T e s t s c h l e i f e Timing USES Crt; CONST k a r t e = $318; ( « K a r t e n a d r e s s e A4=A3=1 BEGIN P o r t [ k a r t e + 3 ] : = 0; ( * Reset Ausgänge High REPEAT MOV DX,031AH INLINE($BA/$lA/$03/ (* $EC/ IN AL,DX ( * LOOP $EE/ OUT DX, AL C $EB/$FC) JHP LOOP UNTIL KeyPressed END.
lesen
!
schreiben
*) «) *) *) *)
I
Refresh
AEN
IORD
IOWR
Adresse 1
Daten
DC
Portadresse
~ X ~
I
Portadresse
X A
Refreshadresse '
I
- { v o n B a u s t e i n V j — { v o m Prozessor^jBild 7-1: Testschleife und Timing des Peripheriezugriffs
i t
r •I
7.1 Die Adressierung
der
Peripherie
143
Auch beim E i n b a u f e r t i g e r P e r i p h e r i e k a r t e n i s t d a r a u f zu a c h t e n , daß i h r e A d r e s s e n n i c h t mit d e n A d r e s s e n b e r e i t s i n s t a l l i e r t e r P e r i p h e r i e b a u s t e i n e k o l l i d i e r e n . Daher wird z u n ä c h s t d a s V e r f a h r e n d e s P e r i p h e r i e z u g r i f f s u n d d e r B a u s t e i n a d r e s s i e r u n g im PC d a r g e s t e l l t . Bild 7-1 z e i g t ein T e s t programm, mit d e s s e n Hilfe d e r z e i t l i c h e Verlauf (Timing) d e r S i g n a l e auf dem e x t e r n e n P e r i p h e r i e b u s g e m e s s e n w e r d e n k a n n . In T u r b o P a s c a l e r f o l g t d e r Zugriff auf die P e r i p h e r i e ü b e r d a s P s e u d o f e l d P o r t [ a d r e s s e ] . E r s c h e i n t d a s Feld in einem a r i t h m e t i s c h e n A u s d r u c k , s o e r z e u g t d e r Compiler d e n P e r i p h e r i e l e s e b e f e h l IN. Wird d i e s e r M a s c h i n e n b e f e h l z u r L a u f z e i t d e s Programms a u s g e f ü h r t , s o l e g t d e r P r o z e s s o r die P o r t a d r e s s e auf d e n A d r e ß b u s u n d e r z e u g t e i n L e s e s i g n a l IORD. D a d u r c h wird e i n B a u s t e i n ( P o r t ) a u s g e w ä h l t , d e r s e i n e n I n h a l t (Wert) auf d e n D a t e n b u s l e g t . D i e s e r wird vom P r o z e s s o r ü b e r n o m m e n . E r s c h e i n t d a s P s e u d o f e l d P o r t [ a d r e s s e ] auf d e r l i n k e n Seite e i n e r W e r t z u w e i s u n g , so e r z e u g t d e r Compiler d e n P e r i p h e r i e s c h r e i b b e f e h l OUT. Bei d e r A u s f ü h r u n g d i e s e s Maschinenbefehls zur Laufzeit des Programms legt der Proz e s s o r die P o r t a d r e s s e auf d e n A d r e ß b u s , d a s E r g e b n i s d e r r e c h t e n S e i t e d e r A n w e i s u n g a l s Datum auf d e n D a t e n b u s u n d e r z e u g t d a s S c h r e i b s i g n a l IOWR. Der a d r e s s i e r t e P o r t b a u s t e i n ü b e r n i m m t d e n Wert vom D a t e n b u s u n d s p e i c h e r t i h n . 10 b e d e u t e t I n p u t ( E i n g a b e ) bzw. O u t p u t ( A u s g a b e ) . RD s t e h t f ü r Read ( l e s e n ) u n d WR f ü r Write ( S c h r e i b e n ) . Beide S i g n a l e s i n d "aktiv Low" u n d b e s t i m m e n s o w o h l d i e R i c h t u n g als a u c h d e n z e i t l i c h e n Ablauf d e s P e r i p h e r i e z u g r i f f s . Bei S p e i c h e r z u g r i f f e n s i n d b e i d e S i g n a l e High. Gleiches g i l t f ü r d a s W i e d e r a u f f r i s c h e n ( R e f r e s h ) d y n a m i s c h e r S p e i c h e r b a u s t e i n e . In d i e s e n B u s z y k l e n l i e g t d a s S t e u e r s i g n a l AEN ( A d d r e s s Bus E n a b l e = A d r e ß b u s f r e i g a b e ) auf High. Die T e s t s c h l e i f e d e s B i l d e s 7 - 1 k ö n n t e a n s t e l l e d e r mit INLINE e i n g e f ü g t e n M a s c h i n e n b e f e h l e a u c h - a l l e r d i n g s l a n g s a m e r - mit dem P s e u d o f e l d P o r t p r o g r a m m i e r t w e r d e n : REPEAT P o r t [karte + 2] := P o r t [karte + 2] UNTIL KeyPressed P e r i p h e r i e k a r t e n (Bild 7-2) w e r d e n f a s t immer ü b e r e i n e n b i d i r e k t i o n a l e n B u s t r e i b e r a n d e n u n t e r e n D a t e n b u s DO b i s D7 a n g e s c h l o s s e n , a u c h w e n n d e r PC mit einem 1 6 - o d e r 3 2 - b i t - P r o z e s s o r a u s g e r ü s t e t i s t . Von d e r 16 b i t l a n g e n P o r t a d r e s s e w e r d e n n u r d i e u n t e r e n 10 bit v e r w e n d e t ( A b s c h n i t t 1.5). Die o b e r e n A d r e ß l e i t u n g e n (A9 a b w ä r t s ) b e s t i m m e n ü b e r e i n e A d r e ß a u s w a h l s c h a l t u n g ( A d r e ß v e r g l e i c h e r ) d i e B a s i s a d r e s s e d e r Karte. Sie k a n n mit B r ü c k e n o d e r S c h a l t e r n i n n e r h a l b b e s t i m m t e r G r e n z e n auf d e r Karte e i n g e s t e l l t w e r d e n . Die u n t e r e n A d r e ß l e i t u n g e n (AO a u f w ä r t s ) b e s t i m m e n ü b e r e i n e n A d r e ß d e c o d e r d i e A d r e s s e d e r B a u s t e i n e auf d e r Karte ( A b s t a n d v o n d e r B a s i s a d r e s s e ) . Die S i g n a l e z u r B a u s t e i n a u s w a h l w e r d e n z u s ä t z l i c h mit d e n L e s e - u n d S c h r e i b s i g n a l e n v e r k n ü p f t . In d e n t e c h n i s c h e n Unterlagen, die jedem Rechner u n d j e d e r Peripheriekarte mitgeliefert w e r d e n , f i n d e n s i c h T a b e l l e n mit f r e i e n A d r e s s e n , d i e d e r B e n u t z e r mit z u s ä t z l i c h e n P e r i p h e r i e k a r t e n b e l e g e n k a n n . Bild 7-3 z e i g t B e i s p i e l e f r e i e r Portadressen.
144
7. Der Anschluß
von
Peripheriekarten
Bild 7-2: Der A u f b a u e i n e r P e r i p h e r i e k a r t e
Bereich $ 100..$1EF $200..$20F $270. „$27F $2F0..$2FF $300. .$31F
Anwendung frei für Anwenderperipherie Spieleadapter (Gameport) 2. Paralleldrucker (LPT2) 2. Serienschnittstelle (COM2) Prototyp-Adapter-Karte
Bild 7-3: B e i s p i e l e f r e i e r P e r i p h e r i e a d r e s s e n
7.2 Die Entwicklung
7.2
einer Peripheriekarte
145
Die Entwicklung einer Peripheriekarte
AnalogAusgabe
Bild 7-4: Karten- u n d Bausteinauswahl
Die in Bild 7-4 d a r g e s t e l l t e Schaltung w u r d e auf einer L o c h r a s t e r p l a t i n e a u f g e b a u t , die lediglich die S t e c k e r a n s c h l ü s s e f ü r den PC-Bus enthielt. Alle Verbindungen w u r d e n mit Draht g e f ä d e l t u n d angelötet. Die K a r t e n a d r e s s e wird nicht mit einem Vergleicher, sondern mit einer Logikverk n ü p f u n g d e r Adreßleitungen A9 bis A3 u n d dem Signal AEN gebildet. Sie liegt im Bereich d e r P r o t o t y p - A d a p t e r - K a r t e ab Adresse $300. Die Adreßleit u n g e n A3 u n d A4 lassen sich mit Brücken umschalten. Mit den drei u n t e r e n Adreßleitungen A0 bis A2 werden a c h t B a u s t e i n a d r e s s e n decodiert. Auf den d r e i u n t e r s t e n Adreßplätzen Y0, Y1 u n d Y2 liegen je zwei Bausteine, ein 8 - b i t - R e g i s t e r zur Ausgabe von Daten u n d ein 8 - b i t - B u s t r e i b e r zum
146
7. Der Anschluß
von
Peripheriekarten
Lesen v o n Daten. Die U n t e r s c h e i d u n g e r f o l g t d u r c h eine V e r k n ü p f u n g d e r F r e i g a b e s i g n a l e mit d e n L e s e - und S c h r e i b s i g n a l e n IORD u n d IOWR, die z u s ä t z l i c h f ü r d a s k o r r e k t e Timing z u s t ä n d i g s i n d . Der Adreßplatz Y3 d i e n t , v e r k n ü p f t mit dem S c h r e i b s i g n a l IOWR, zum Löschen d e r A u s g a b e s p e i c h e r (Reset). Auf dem Adreßplatz Y4 liegt, v e r k n ü p f t mit dem S c h r e i b s i g n a l IOWR, ein 8 - b i t - D i g i t a l / A n a l o g w a n d l e r . Die d r e i o b e r s t e n Adreßplätze s i n d f r e i f ü r E r w e i t e r u n g e n . Bild 7-5 zeigt d e n Adreßplan.
Kartenadresse AEN A9 A8 A7 A6 A5 A4 A3 A2 A1 A0 x = $300 $307 x = $308 x = $30 F x = $310
0 t -0~
0.1 •!•
0 0 0!
0
•-t -
Baustein Adresse A2 A1 AO E/A 1 x + 0 0 0 0 E/A 2 x + 1 0 0 1 E/A 3 x + 2 0 1 0 Reset x + 3 0 1 1 ZN 428 x + 4 1 0 0 frei x + 5 1 0 1 frei x + 6 1 1 0 frei x + 7 1 1 1
x = $317 x = $318 x = $31F
Bild 7-5: Adreßplan d e r Karte und d e r B a u s t e i n e
D u r c h die U m s c h a l t u n g d e r Adreßleitungen A3 u n d A4 mit B r ü c k e n l a s s e n s i c h v i e r v e r s c h i e d e n e K a r t e n a d r e s s e n e i n s t e l l e n . Damit k a n n die Karte zusammen mit a n d e r e n K a r t e n gleicher Bauform im A d r e ß b e r e i c h d e r P r o t o t y p - A d a p t e r - K a r t e n v o n $300 bis $31F b e t r i e b e n w e r d e n . Auf d e n d r e i u n t e r s t e n A d r e ß p l ä t z e n x+0 bis x+2 l i e g e n je zwei Bausteine. Sie w e r d e n in P a s c a l u n t e r d e r g l e i c h e n P o r t a d r e s s e a n g e s p r o c h e n . Das Lesen g e s c h i e h t in einem a r i t h m e t i s c h e n A u s d r u c k auf d e r r e c h t e n Seite, d a s S c h r e i b e n auf d e r l i n k e n Seite e i n e r Wertzuweisung. Das f o l g e n d e Beispiel liest d e n Leit u n g s z u s t a n d d e s E/A-Kanals 2 u n d g i b t ihn auf Kanal 1 a u s : CONST k a r t e = $ 3 0 0 ; (* K a r t e n a d r e s s e f ü r A3 = A4 = 0 «) BEGIN P o r t [ k a r t e + 0 ] := P o r t [ k a r t e + 1 ] ; (* K a n a l 1 2.4 Volt. Die Belastbarkeit der Ausgänge muß den Unterlagen der Bausteinhersteller entnommen werden. Standard-TTL-Logik mit einem fan-out von 10 nimmt bei Low einen Strom von 16 mA auf und liefert bei High einen Strom von 0.4 mA. LS-Bustreiber nehmen üblicherweise bei Low 48 mA auf; Ausgänge mit offenem Kollektor (O.C.) maximal 40 mA. Bei höheren Belastungen und anderen Pegeln (z.B. CMOS) sind besondere Treiberbausteine erforderlich. Die Belastbarkeit der MOS- und CMOS-Schnittstellenbausteine ist wesentlich geringer. Die MOS-Ausführung der Parallelschnittstelle 8255 (Abschnitt 7.3.1) nimmt bei Low ein Strom von 1.7 mA auf und liefert bei High 0.2 mA; die CMOS-Ausführung 82C55 bei beiden Pegeln ca. 2.5 mA. Die Serienschnittstelle nach V.24 bzw. RS 232C arbeitet bipolar mit Spannungen < -5 Volt bzw. > +5 Volt sowohl bei den Datenkanälen als auch bei den Modemsteuersignalen. Die Ausgänge der V.24-Treiber haben üblicherweise eine Strombegrenzung auf ca. 10 mA bei Belastungswiderständen > 300 Ohm.
9.1.1
Die Messung von Zeiten
Bild 9-1 zeigt eine typische Versuchsanordnung für die Messung der Zeit zwischen zwei Impulsen. Das Steuersignal "S" löst den zu messenden Vorgang aus, in dem Beispiel den Fall einer Kugel. Der Durchgang durch die erste Lichtschranke ergibt den ersten Impuls, der Durchgang durch die zweite Lichtschranke ergibt den zweiten Impuls. Die Fallgeschwindigkeit kann aus der Zeit zwischen den steigenden Flanken der Impulse bestimmt werden. Bei derartigen Meßaufgaben muß man zwischen Langzeitmessungen im Sekundenbereich und Kurzzeitmessungen im Millisekundenbereich unterscheiden. Bild 9-2 zeigt die Simulation einer Langzeitmessung.
173
9.1 Beispiele aus der Digitaltechnik
®
O
< l
®o
El
E2
s
u
Vorgang
At
starten
Bild 9-1: Zeitmessung zwischen zwei Impulsen
I
i
drQcken
B6
»CK ( 1 0 ) PE
(12)
i
lösen
- f
T
drucken
c
.
I
B5
Abtastungen von B5 und B6 I I I I I I I i 11111 11111 11111 11111111.1
B6
B5
-AI
x+1 lesen x = Adresse Druckerport
Bild 9-2: Versuchsschaltung für Langzeitmessung
Die Dauer der zu messenden Zeit wird bestimmt durch das Drücken und das Loslassen eines Tasters. Dabei ist es wichtig, daß die Signale wie in der vorliegenden Schaltung durch ein RS-Flipflop entprellt werden. Die beiden Impulse, die beim Drücken und beim Loslassen des Tasters entstehen, werden den Steuereingängen ACK und PE einer Druckerschnittstelle zugeführt und softwaremäßig abgetastet. Bild 9-3 zeigt das Programm.
174
9.
Anwendungsbeispiele
Portadresse
x
lesen
Meldung: "bereit" | Leitung B6 lesen bis B6 = High ti = Startzeit Leitung B5 lesen bis B5 = High t 2 = Endezeit Ergebnis berechnen und auf Bildschirm ausgeben Testschleife bis Abbruch
PROGRAH prog9p5; (* Bild 9-3: Langzeitmessung GetTime *) USES Dos, Crt; (* enthält GetTime-Prozedur *) CONST b5 = $20; (* Baske 0010 0000 PE-Eingang b6 = $40; (* Maske 0100 0000 ACK-Eingang VAR x , a : WORD; h l , m l , s l , x l , h2,ra2,s2,x2 WORD; t l , t 2 , d t : REAL; z : CHAR; BEGIN Write('Versuch b e r e i t an LPT 1, 2, 3 oder 4 - > ' ) ; ReadLn(x); x := MemW[$40 : 2»x+6]; a := x+l; REPEAT WriteLn(#$0A,#$0D,'Vorgang starten ! ' ) ; REPEAT UNTIL (Port[a] AND b6) = b6; (« Flanke -> High GetTime(hl,ral,sl,xl); (* Anfangszeit REPEAT UNTIL (Port[a] AND b5) = b5; (* Flanke -> High GetTime(h2,m2,s2,x2); (* Endzeit t l := ( ( ( h l * 6 0 . 0 + ml)*60.0) + s l ) * 1 0 0 . 0 + x l ; (« 1/100 t2 := (((h2*60.0 + m2)*60.0) + s2)*100.0 + x2; (* 1/100 dt := ( t 2 - t l ) / 1 0 0 ; (* sek IF dt = 0 THEN Write('Heßzeit zu kurz ! ! ! ' ) ELSE W r i t e ( ' Z e i t : \ d t : 8 : 2 , ' sek ( ' , l / d t : 8 : 4 , • Hz)'); Write(' weiter mit er - > ' ) ; z := ReadKey; UNTIL z #$0D END.
Bild 9-3: Langzeitmessung mit der Prozedur G e t T i m e
Das Programm setzt voraus, daß sich der Eingang ACK (B6) zunächst auf Low-Potential befindet und tastet die Leitung ab. Nach der steigenden Flanke des Anfangsimpulses wird die Systemuhr mit der vordefinierten Prozedur G e t T i m e gelesen (USES Dos erforderlich!). Sie liefert die Zeit in den Einheiten Stunde, Minute, Sekunde und Hundertstelsekunde. Bei der steigenden Flanke am Eingang PE (B5) wird die Systemuhr erneut a u s gelesen. Die Zeiten werden für die Berechnung der Differenz in Hundertstelsekunden als REAL-Größen umgerechnet. Die Genauigkeit des Verfahr e n s hängt besonders bei kurzen Zeiten von der Abtastrate der Warteschleifen REPEAT . . UNTIL ab. Eine Verbesserung ließe sich durch Verwendung von Maschinencode mit INLINE erzielen. Durch die periodischen
9.1 Beispiele aus der
175
Digitaltechnik
Interrupts des Systemtimers 8253 (Timer Tic und Refresh) entstehen Lükken bei der Abtastung. Sie lassen sich durch Sperren und anschließendes Freigeben der Interrupts z.B. mit den Maschinenbefehlen CLI und STI unterdrücken; vorausgesetzt, daß bei dem verwendeten Rechnermodell ein Refresh des Arbeitsspeichers weiterhin gewährleistet ist. Für die Simulation von Kurzzeitmessungen kann entsprechend Bild 9-4 ein Rechteckgenerator herangezogen werden. Der TTL-Ausgang wird direkt an die Druckerporteingänge ACK und PE angeschlossen. Für bipolare CMOS-Signale könnten die Modem-Steuereingänge der seriellen Schnittstelle verwendet werden. Sie haben gegenüber der Druckerschnittstelle den Vorteil, daß sie flankenempfindlich sind und einen Interrupt auslösen können.
© B6 B5 S
b
R Q)
.TLJ:
¡5 Timerdurchlauf (27ms): - A
t-
x+1 lesen x = Adresse Druckerport Bild 9-4: Versuchsschaltung f ü r Kurzzeitmessung
Da der Rechteckgenerator auf beiden Leitungen fortlaufend Impulse sendet, werden zuerst der Anfangsimpuls auf der Leitung B6 und dann der Endimpuls auf der Leitung B5 durch Flankenabtastung herausgegriffen. Die Zeit zwischen den beiden steigenden Flanken wird durch Auslesen des Systemtimers Timer 0 bestimmt, der entsprechend Abschnitt 3.3 Bild 3-8 mit einem Takt von 1.193182 MHz (Periode 0.8380951 fjs) betrieben wird. Da wegen der Betriebsart 3 nur maximal 32 768 Durchläufe ausgewertet werden können, beträgt die Meßzeit ca. 27.5 ms, wenn die Messung beim Neuladen des Timers begonnen wird. Rechteckgenerator und Timer laufen asynchron. Durch das Warten auf die steigende Flanke des Startimpulses reduziert sich die zu messende Zeit (ungünstigster Fall) auf maximal 13.5 ms. Die kleinste mit genügender Genauigkeit zu messende Zeit hängt wieder von der Abtastrate der Warteschleifen (Programm Bild 9-5) ab und kann von Rechnermodell zu Rechnermodell verschieden sein. Sie liegt in der Größenordnung von 10 bis 200 113.
176
9.
Anwendungsbeispiele
Portadresse x lesen Meldung: "bereit" Timer Tic lesen bis Neuladen Leitung B6 lesen C D bis B6 = Low Leitung B6 lesen bis B6 = High (2) Timer lesen ti Leitung B5 lesen bis B5 = Low (D Leitung B5 lesen bis B5 = High Timer lesen t 2 Ergebnis berechnen und auf Bildschirm ausgeben Testschleife bis Abbruch
©
PROGRAM prog9p6; (* Bild 9-5: Kurzzeitmessung Timer 0 «) USES Crt; CONST b5 = $20; (* Maske 0010 0000 PE-Eingang *) b6 = $40; (* Maske 0100 0000 ACK-Eingang *) VAR x,a : WORD; tic, tll.tlh, t21,t2h : BYTE; tl,t2 : LONGINT; dt : REAL; z : CHAR; BEGIN Write('Versuch bereit an LPT 1, 2, 3 oder 4 ->'); ReadLn(x); x := MemW[$40 : 2*x + 6 ] ; a := x+1; Port[x+0] := $00; REPEAT WriteLn(#$0A,#$0D,'Vorgang starten !'); tic := Mem[$40 : $6C]; WHILE tic = Mem[$40 : $6C] DO; (» bis Timerstart *) REPEAT UNTIL (Portfa] AND b6) = $00; (* bis B6 = Low *) REPEAT UNTIL (Port[a] AND b6) = b6; (* Flanke -> High *) Port[$43]:=$00; til:=Port[$40]; tlh:=Port[$40]; (* Anf. *) REPEAT UNTIL (Portfa] AND b5) = $00; (« bis B5 = Low *) REPEAT UNTIL (Port[a] AND b5) = b5; (* Flanke -> High «) Port[$43]:=$00; t21:=Port[$40]; t2h:=Port[$40]; (« Ende *) tl := WORD(tlh SHL 8) OR WORD(tll); t2 := WORD(t2h SHL 8) OR WORD(t21); dt := (tl-t2)*0.419; (* in usek *) IF dt '); z := ReadKey; WriteLn UNTIL z #$0D END. Bild
9-5: Kurzzeitmessung mit d e m Systemtimer 0
9.1 Beispiele
aus der Digitaltechnik
177
D a s P r o g r a m m Bild 9-5 w a r t e t d u r c h A b f r a g e d e r T i m e r T i c V a r i a b l e n a u f d e n Z e i t p u n k t , zu dem d e r Timer 0 n e u g e l a d e n w i r d . D a n n s t e h e n maximal 27.5 ms f ü r d i e M e s s u n g z u r V e r f ü g u n g . Sie b e g i n n t d u r c h A u s l e s e n d e s T i m e r s , w e n n d i e s t e i g e n d e F l a n k e am E i n g a n g ACK ( B 6 ) e r k a n n t w u r d e u n d e n d e t m i t d e r s t e i g e n d e n F l a n k e am E i n g a n g P E ( B 5 ) . D a s B e i s p i e l v e r z i c h t e t mit R ü c k s i c h t auf e i n e mögliche B e e i n t r ä c h t i g u n g d e s S y s t e m s auf eine Umprogrammierung des Timers auf eine a n d e r e B e t r i e b s a r t bzw. auf e i n e U m l e n k u n g d e s Timer Tic I n t e r r u p t s a u f e i n e n p r o g r a m m g e s t e u e r t e n Z ä h l e r , d e r d i e T i m e r ü b e r l ä u f e z ä h l t u n d d a m i t d i e Meß z e i t b e l i e b i g v e r l ä n gern würde. Durch die s o f t w a r e g e s t e u e r t e Abtastung der Signalleitungen e r g e b e n sich S c h w i e r i g k e i t e n b e i k u r z e n I m p u l s e n , d i e b e i d e n z w i s c h e n 10 u n d 200 fis l i e g e n d e n A b t a s t r a t e n d e r W a r t e s c h l e i f e n n i c h t e r k a n n t w e r d e n . Bild 9-6 zeigt eine Schaltung zur Verlängerung der Impulse.
D1 Impulsverlängerung E 1
i _ f — l _ t
L c
1 Q1 D2
+ i D2
E2
CK
PR
2 CLR
E2 Q2
Q2 0V
Q2
&
&
f
| I
_
1
I
^
1
L i
!
H _.1
n
1 L = j
i '
.1
(E2)
® At •
Bild
l
1
(E1)
f
= 1 THEN W r i t e ( ' f = ' ,f:7:3, 1 kHz':4); IF f < 1 THEN Write( 1 f = ' , f * l e 3 : 7 : 3 , ' Hz':4) UNTIL KeyPressed; ClrScr; END. Bild 9-10: Programm zur Frequenzmessung mit dem Systemtimer
Bei jedem Timerinterrupt (ca. alle 55 ms) zählt die benutzerdefinierte Prozedur t i m e r die globale Variable z e i t um 1 herab. Die Variable z e i t wird in der Schleife, die die Flanken des Meßsignals zählt, als Abbruchbedingung ausgewertet. Bei einem Vorgabewert v o n 18 beträgt die Meßzeit ca. 1 sek. Sie beginnt erst nach einem Neuladen des Timers (Änderung der Timer Tic Variablen). Das Erkennen einer Signaländerung (Flanke) geht wesentlich einfacher und schneller als das in den Bildern 9-3 und 9-5 v e r wendete Verfahren, das steigende bzw. fallende Flanken bestimmt. Für die Berechnung der Frequenz ist jedoch die Anzahl der gemessenen Flanken durch 2 zu teilen. Das Programm lieferte bis zu einer Frequenz von ca. 40 kHz brauchbare Ergebnisse. Darüber hinaus war die Abtastrate zu niedrig, um alle Flanken des Meßsignals zu erfassen. Für sehr niedrige Frequenzen müßte die Meßzeit verlängert werden. Das in den Bildern 9-11 und 9-12 g e zeigte Beispiel ermöglicht es dem Benutzer, die Meßzeit als Variable einzugeben.
183
9.1 Beispiele aus der Digitaltechnik
Uhrenbaustein RTC (AT) t BIOS - Interrupt $15 [AH = $831 CX:DX= Wartezeit ps ES: Segment OX: Offset Benutzer -B7
Testbyte
Bild 9-11: P e g e l u m f o r m u n g u n d Messung mit dem U h r e n b a u s t e i n
Die in Bild 9-11 g e z e i g t e S c h a l t u n g e n t h ä l t v o r dem E i n g a n g ACK des D r u k k e r p o r t s einen Pegelumformer, d e r am A u s g a n g TTL-Pegel l i e f e r t . E r b e s t e h t a u s e i n e r Zener-Diode mit V o r w i d e r s t a n d , die bei allen n e g a t i v e n S p a n n u n g e n (< 0 Volt) Low-Potential l i e f e r t u n d alle positiven S p a n n u n g e n auf 4.7 Volt (High-Pegel) b e g r e n z t . Der V o r w i d e r s t a n d muß g e g e b e n e n f a l l s d e r Amplitude d e s Signals a n g e p a ß t w e r d e n . Als Zeitbasis d i e n t d e r a u c h in PC- u n d XT-Rechnern o f t v e r w e n d e t e U h r e n b a u s t e i n RTC. Der BIOSI n t e r r u p t $15 mit dem K e n n w e r t AH = $83 g e s t a t t e t die Vorgabe e i n e r Wartezeit, nach d e r d a s h ö c h s t e Bit B7 e i n e r vom B e n u t z e r zu b e s t i m m e n d e n B y t e v a r i a b l e n auf 1 g e s e t z t wird. L a u t S y s t e m b e s c h r e i b u n g wird im Regis t e r CX d e r High-Teil u n d im R e g i s t e r DX d e r Low-Teil d e r Wartezeit in d e r Einheit /js ü b e r g e b e n . Bei V e r s u c h e n zeigte es sich j e d o c h , daß die Wartezeit n u r in d e r Einheit ms e i n s t e l l b a r ist. Bild 9-12 zeigt d a s Programm.
PROGEWI prog9p9; (* Bild 9-12: Frequenzmessung mit RTC *) USES Dos, Ort; VAR Reg : Registers; (* Dos P r o z e s s o r r e g i s t e r *) t e s t : BYTE; (* von I n t r $15 g e s e t z t «) nr, x, a : WORD; a l t : BYTE; flanke, z e i t : LONGINT; f , mess : REAL; BEGIN Write('Versuch b e r e i t an LPT 1, 2, 3 oder 4 - > ' ) ; ReadLn(nr); x := HemW[$40 : 2*nr + 6 ] ; a := x+1; Write('Heßzeit [sek] - > ' ) ; ReadLn(mess); z e i t := Round(mess * le6); ClrScr; GotoXy(20,10); Write('Abbruch mit b e l i e b i g e r Taste! ' ) ;
P. Anwendungsbeispiele
184
REPEAT flanke := 0; test := 0; (* Flankenzähler löschen Reg.cx := zeit DIV $10000; Reg.dx := zeit MOD $10000; test := 0; Reg.es := Seg(test); Reg.bx := Ofs(test); Reg.ah := $83; Reg.al := 0; Intr($15,Reg); (* starten alt := Port[a] AHD $40; (* Ausgangszustand ACK REPEAT IF alt (Port[a] AND $40) THEN (* Flanken zählen BEGIN Inc(flanke); alt := (Port[a] AND $40) END UNTIL test = $80; (* bis Ende Meßzeit f := flanke * 0.5/mess; GotoXY(25,15); IF f >= le3 THEN Write('f = ' ,f*le-3:7:3,' kHz':4); IF f < le3 THEN Write(*f = \ f : 7 : 3 , ' Hz':4); UNTIL KeyPressed; ClrScr; END.
*) *) *) *) «)
Bild 9-12: Programm zur Frequenzmessung mit dem Uhrenbaustein
Die Variable t e s t des Programms wird von dem Interrupt $ 15 nach Ablauf der eingestellten Wartezeit in der werthöchsten Bitposition B7 auf 1 g e setzt. Dies dient als Abbruchbedingung für eine Schleife, die die Flanken am Druckerporteingang ACK (B6) zählt. Die Übergabe der Variablenadresse erfolgt in den Registern ES (Segment) und BX (Offset). Wegen der durch den Uhrenbaustein ausgelösten Interrupts (jede ms) zeigte es sich bei Versuchen, daß das Verfahren nur bis zu einer Frequenz von ca. 2 kHz brauchbar ist. Dagegen liefert die in Bild 9-13 dargestellte Serienschnittstelle eine Zeitbasis, die ohne Interrupts arbeitet.
- TxD TTL
B i t z e i t 100 ms
Sto
Start
r "
BO B1 B2 B3 B'i 85 B6 B7
0
0 0 0
0 0
R
10 Hz,
t /
0
Senderschieberegister Daten = $00
: 16
Senderdatenregister x+0 160 Hz
Teiler:
11 520
Teilerregister x+1 x+0
DLAB
B6 B5
Steuerregister x+3
Statusregister x+5
1.8^32 MHz Quarz
Bild 9-13: Die serielle Schnittstelle als Zeitbasis
B6 - 1: Senderschieberegister leer B5 = 1: Senderdatenregister leer
9.1 Beispiele aus der Digitaltechnik
185
Der S e n d e - u n d E m p f a n g s t a k t d e r S e r i e n s c h n i t t s t e l l e wird v o n einem q u a r z s t a b i l i s i e r t e n T a k t g e n e r a t o r a b g e l e i t e t . Ein p r o g r a m m i e r b a r e r T e i l e r t e i l t d i e Q u a r z f r e q u e n z v o n m e i s t 1.8432 MHz a u f d a s 1 6 f a c h e d e s S c h i e b e t a k t e s h e r u n t e r u n d bestimmt d a d u r c h die Bitzeit [sek] bzw. die B a u d r a t e [ b i t / s e k ] . Die F o r m e l l a u t e t : 1.8432-10' Teiler
1.8432-10*.Bitzeit
=
[s]
= Baudrate
= 115200
•
16
• Bitzeit
16 [s]
D e r T e i l e r i s t vom D a t e n t y p WORD u n d k a n n maximal 65535 b e t r a g e n . Dies e n t s p r i c h t e i n e r B i t z e i t v o n ca. 1.76 s (0.57 b i t / s ) . N a c h A n g a b e n d e s B a u s t e i n h e r s t e l l e r s b e t r ä g t d i e maximal z u l ä s s i g e B a u d r a t e 56000 (57600) B a u d . Das e n t s p r i c h t b e i e i n e m T e i l e r v o n 2 e i n e r B i t z e i t v o n c a . 17.36 f/s. Bild 9-14 z e i g t e i n P r o g r a m m b e i s p i e l , d a s d i e s e r i e l l e S c h n i t t s t e l l e a l s Z e i t b a s i s f ü r e i n e F r e q u e n z m e s s u n g am D r u c k e r p o r t v e r w e n d e t .
PROGRAM p r o g 9 p l l ; (* B i l d 9 - 1 4 : H e ß z e i t mit S e r i e n s c h n i t t s t . *) USES Crt; CONST t e l l e r = 11520; (* B i t z e i t 0 . 1 sek *) muster = $00; (* Sendemuster 0000 0000 *) VAS n r , x, a , y, b : WORD; a l t : BYTE; f l a n k e : LONGINT; f : REAL; BEGIN W r i t e ( ' V e r s u c h b e r e i t an LPT 1, 2, 3 o d e r 4 - > ' ) ; ReadLn(nr); x := MemW[$40 : 2*nr + 6 ] ; a := x+1; W r i t e ( ' Z e i t m e s s u n g durch COM 1, 2, 3 o d e r 4 - > ' ) ; ReadLn(nr); y := MemW[$40 : 2 * ( n r - l ) ] ; b := y+5; P o r t [ y + 3 ] := $80; (* DLAB = 1 *) P o r t [ y + 1 ] := H i ( t e i l e r ) ; P o r t [ y + 0 ] := L o ( t e i l e r ) ; P o r t [ y + 3 ] := $03; (* DLAB = 0 , 8 Daten 1 Stop 0 P a r i t . *) ClrScr; GotoXy(20,10); W r i t e ( ' A b b r u c h m i t b e l i e b i g e r T a s t e ! ' ) ; REPEAT f l a n k e := 0; INLINE($FA); (* CLI I n t e r r u p t s g e s p e r r t *) P o r t [ y + 0 ] := m u s t e r ; (» Muster senden *) a l t := P o r t [ a ] AND $40; (» Ausgangszustand ACK *) REPEAT IF a l t ( P o r t [ a ] AND $40) THEN (* Flanken ACK zählen *) BEGIN I n c ( f l a n k e ) ; a l t := ( P o r t t a ] AND $40) END UNTIL ( P o r t [ b ] AND $20) 0; (» b i s Muster g e s e n d e t *) INLINE($FB); (« STI I n t e r r u p t s f r e i *) f := f l a n k e * 0 . 5 ; GotoXY(25,15); IF f >= l e 3 THEN W r i t e ( ' f = ' , f * l e - 3 : 7 : 3 , ' k H z ' : 4 ) ; IF f < l e 3 THEN W r i t e ( ' f = ' , f : 7 : 3 , • H z ' : 4 ) ; UNTIL KeyPressed; C l r S c r ; END. Bild 9-14: P r o g r a m m mit S e r i e n s c h n i t t s t e l l e a l s Z e i t b a s i s
186
9.
Anwendungsbeispiele
Zur A u s g a b e e i n e s Zeichen s c h r e i b t man es in d a s S e n d e d a t e n r e g i s t e r auf d e r P o r t a d r e s s s e x+0. Von d o r t g e l a n g t e s a u t o m a t i s c h in d a s e i g e n t l i c h e S e n d e s c h i e b e r e g i s t e r u n d w i r d s e r i e l l mit d e m w e r t n i e d r i g s t e n Bit z u e r s t h e r a u s g e s c h o b e n . E i n e 1 in d e r B i t p o s i t i o n B6 d e s L e i t u n g s s t a t u s r e g i s t e r s zeigt a n , daß sowohl d a s D a t e n r e g i s t e r als a u c h d a s S c h i e b e r e g i s t e r leer s i n d . E i n e 1 i n d e r B i t p o s i t i o n B5 z e i g t , d a ß d a s D a t e n r e g i s t e r l e e r i s t u n d n e u e D a t e n a n n e h m e n k a n n . S t a r t e t m a n a l s o d i e Meßzeit d u r c h U b e r g a b e e i n e s b e l i e b i g e n B i t m u s t e r s a n d a s D a t e n r e g i s t e r , so k a n n man d u r c h l a u f e n d e B e o b a c h t u n g d e s L e i t u n g s s t a t u s r e g i s t e r s d a s E n d e d e r Meßzeit e r m i t t e l n . Das P r o g r a m m b e i s p i e l p r o g r a m m i e r t d i e S c h n i t t s t e l l e f ü r e i n e B i t z e i t v o n 0.1 s e k u n d d i e Ü b e r t r a g u n g s k e n n w e r t e 8 D a t e n b i t s , 1 S t o p b i t u n d ohne P a r i t ä t s b i t . U n t e r B e r ü c k s i c h t i g u n g des S t a r t b i t s b e t r ä g t die Zeit f ü r d a s S e n d e n e i n e s Z e i c h e n s a l s o 1 0 - 1 0 0 ms = 1 S e k u n d e . Bei V e r s u c h e n z e i g t e e s s i c h , d a ß d i e B i t p o s i t i o n B6 e r s t n a c h e i n e r g e w i s s e n V e r z ö g e r u n g s z e i t d a s E n d e d e r Z e i c h e n a u s g a b e a n z e i g t e ( K o r r e k t u r f a k t o r 0.91). Die A b f r a g e d e r B i t p o s i t i o n B5 ( S e n d e s c h i e b e r e g i s t e r u n d D a t e n r e g i s t e r l e e r ) l i e f e r t e b i s z u e i n e r F r e q u e n z v o n ca. 40 kHz b r a u c h b a r e E r g e b n i s s e ohne Korrektur. Alle Z e i t - u n d F r e q u e n z m e s s u n g e n , b e i d e n e n S i g n a l e d u r c h P r o g r a m m schleifen a b g e t a s t e t w e r d e n , sind sowohl d u r c h R e f r e s h - u n d I n t e r r u p t u n t e r b r e c h u n g e n als a u c h d u r c h die A b t a s t r a t e d e r Schleife f e h l e r b e h a f t e t . Die i n d e n B e i s p i e l e n a n g e g e b e n e F r e q u e n z g r e n z e v o n c a . 40 kHz e n t s p r i c h t e i n e r A b t a s t r a t e v o n ca. 25 \is. Sie w u r d e a n e i n e m 8 0 3 8 6 - R e c h n e r b e i e i n e r T a k t f r e q u e n z v o n 16 MHz g e m e s s e n . Bei 20 MHz ( T u r b o s c h a l t e r ! ) z e i g t d e r g l e i c h e R e c h n e r e i n e o b e r e G r e n z e v o n ca. 50 kHz. Wie b e i d e r M e s s u n g v o n Z e i t e n muß a l s o a u c h f ü r e i n e r e c h n e r u n a b h ä n g i g e F r e q u e n z m e s s u n g e i n e x t e r n e r T i m e r h e r a n g e z o g e n w e r d e n . Bild 9-15 z e i g t d a z u eine Schaltung. T i m e r 0 a r b e i t e t in d e r B e t r i e b s a r t (Mode) 3 a l s V o r t e i l e r f ü r d e n T i m e r 1, d e r in d e r B e t r i e b s a r t 1 (Monoflop) A n f a n g u n d E n d e d e r Meßzeit b e s t i m m t . Beispielsweise liefert eine externe T a k t f r e q u e n z (Quarztaktgenerator) von 1 MHz b e i e i n e m V o r t e i l e r v o n 1000 ( T i m e r 0) u n d e i n e m M e ß z e i t f a k t o r v o n 1000 ( T e i l e r T i m e r 1) e i n e Meßzeit v o n 1 s e k . W ä h r e n d d e r M e ß z e i t w i r d d e r T i m e r 2 f r e i g e g e b e n , d e r in d e r B e t r i e b s a r t 0 alle am T a k t e i n g a n g a n l i e g e n d e n f a l l e n d e n F l a n k e n z ä h l t . Bei e i n e m Ü b e r l a u f w i r d d e r A u s g a n g OUT 2 auf 1 g e s e t z t . Das in Bild 9-16 d a r g e s t e l l t e P r o g r a m m b e i s p i e l v e r w e n d e t d i e P a r a l l e l s c h n i t t s t e l l e 8255 z u r S t e u e r u n g d e s F r e q u e n z m e s s e r s . Der A u s g a n g PA0 s t a r t e t d i e M e ß z e i t , am E i n g a n g PB0 w i r d d a s E n d e d e r Meßzeit k o n t r o l l i e r t . E i n Z ä h l e r ü b e r l a u f e r s c h e i n t a l s 1 am E i n g a n g PB1. D e r F r e q u e n z m e s s e r a r b e i t e t v ö l l i g u n a b h ä n g i g vom T a k t u n d v o n P r o g r a m m u n t e r b r e c h u n g e n d e s R e c h n e r s . Die o b e r e F r e q u e n z g r e n z e w i r d a l l e i n d u r c h d i e A u s f ü h r u n g d e s T i m e r b a u s t e i n s b e s t i m m t . Bei d e r A u s f ü h r u n g 8253 b e t r ä g t s i e 2.6 MHz, b e i d e n A u s f ü h r u n g e n 8 2 5 4 - 2 u n d 82C54 l i e g t s i e b e i 10 MHz. Die u n t e r e F r e q u e n z g r e n z e l ä ß t s i c h d u r c h d i e b e i d e n T e i l e r in w e i t e n G r e n z e n e i n stellen.
1 8 7
9.1 Beispiele aus der Digitaltechnik
Start
Überlauf
1A-Port • JA0| x+12
j Ende
B-Port JB 1|B0| x+13
1. .8 MHz TTL
Zeitbasis
Isteuerport 8255 x+15 Adresse x=$170
TimerO x+8 00110110 Mode $36 Timerl x+9 01110010 Mode $72 Timer2 x+10 10110000 Mode $B0
neu laden Zähler 0
GateO
Nulldurchg. neu laden Zähler 1
1 MHz = 1 000 000 (is
2 Speichertiefe (max 2048) -> 100 Verzögerungszähler -> 2 Interruptsperre j = ja -> J tlaske (1 = Trigger) $xx -> $80 Vorgang am Druckerporteingang 2 starten! Anfang der Ausgabe (min 1) -> 1 Ende des Ausgabe (max 100) ->100 Anzahl der Marker (max 10 ) -> 2 1.Muster $xx -> $80 1.Harker x -> # 2.Muster $xx -> $88 2.Marker x -> # 1.AufZeichnung 2.Aufzeichnung 3.AufZeichnung 4.Aufzeichnung 5.Aufzeichnung 6.AufZeichnung 7.Aufzeichnung S.Aufzeichnung 9.AufZeichnung 10.Aufzeichnung 11.Aufzeichnung 12.AufZeichnung 13.Aufzeichnung 14.Aufzeichnung 15.AufZeichnung 16.Aufzeichnung 17.AufZeichnung 18.AufZeichnung 19.AufZeichnung 20.Aufzeichnung 21.AufZeichnung 22.Aufzeichnung 23.AufZeichnung 24.AufZeichnung Weiter mit er -> Bild
$00 $00 $80 $80 $88 $88 $88 $88 $80 $80 $80 $00 $08 $88 $88 $88 $80 $80 $80 $00 $08 $88 $08 $08
SfcOOOOO %00000 fclOOOO %10000 %10001 %10001 %10001 %10001 %10000 %10000 %10000 %00000 %00001 %10001 %10001 %10001 %10000 %10000 %10000 %00000 ifcOOOOl %10001 %00001 %00001
9-25: Die A u f z e i c h n u n g v o n T a s t e n p r e l l u n g e n
9.2 Beispiele aus der
Mikrocomputertechnik
199
Der BUSY-Eingang (Bit B7) des Druckerports wurde durch einen Pull-UpWiderstand auf High-Potential gehalten und nach dem Start des Programms mit einem Schalter auf Low-Potential gebracht. Diese erste Änderung der Eingabe wurde mit der Maske $80 (1000 0000) ausmaskiert und löste die Aufzeichnung aus. Tastenprellungen entstehen, wenn sich die Kontakte des Schalters kurzzeitig wieder voneinander entfernen und dadurch die Leitung wieder auf High liegt. Ein Rechteckgenerator von 10 kHz am Eingang ERROR (Bit B3) lieferte die Zeitbasis von 0.1 ms / Periode. Die Prellungen wurden mit dem Marker "#" gekennzeichnet. Sie treten in dem v o r liegenden Beispiel innerhalb der e r s t e n 300 ¡is nach der Betätigung des Schalters auf. Bei weiteren U n t e r s u c h u n g e n zeigte es sich, daß bei der v e r w e n d e t e n Anordnung mit einer Prellzeit von maximal 1 ms je nach Betät i g u n g w e i s e des Schalters g e r e c h n e t werden muß.
9.2.2
Der Aufbau eines externen Peripheriebus
Ziel d i e s e s Abschnitts ist, am Druckerport den Peripheriebus des PC so zu simulieren, daß normale PC-Peripheriekarten - allerdings mit verminderter Zugriffszeit - an ihm betrieben werden können. Dazu ist es erforderlich, die in Abschnitt 7.1 (Bilder 7-1 und 7-2) behandelten Signale d e s PC-Bus nachzubilden.
Steuerbus
g
Adreß/Datenbus
WR RD AEN AB IRQ [ J U Ü Ö B7 B6 B5 B4 B3 B2 B1 BO + -CDO.C.
&
1
1
1
1
1 1 1
Datenregister x+0 schreiben
Statusregister x+1 lesen
Steuerregister x+2 lesen
Steuerregister x+2 schreiben
200
0.
Anwendungsbeispiele
PROGRAM prog9pl; (* Bild 9-26 Test Peripheriebus am Druckerport *) USES Crt; VAR nr.padr : WORD; (* nr und padr sind global *) elk,i : INTEGER; (« clk ist global *) raode.daten : BYTE; (* mode ist global *) z : CHAR; irq : BOOLEAN; PROCEDURE ausport(x : BYTE); (* mode WR RD AEN AB und padr sind global *) BEGIN Porttpadr+0] := ((x xor $FB) AND $F0) OR mode; (« High-Teil*) Port[padr+2] := ((x XOR $FB) AND $0F) (* Low-Teil *) END; PROCEDURE einport(VAR x : BYTE; VAR irq : BOOLEAN); BEGIN x := ((Port[padr+1] AND $F0) OR (Port[padr+2] AND $0F)) XOR $8B; irq := BOOLEAN((Port[padr+1] SHR 3) AND $01) END; Bild 9-26: Bidirektionaler Bus am D r u c k e r p o r t
Peripheriekarte Peripheriebaustein
Buskarte
A15.....A8 A7 AO Ü. I I Adreßlatch U" Adreßlatch \s High Low
x x x x WR RD AEN AB rîi rÎ7 rtl UJ uJ 0 0 0 0 0 0 1 0 1 0 1 1 Druckerport
DatenbusTreiber
Kartenauswahl und Decoder
IOWR IORD A C H
0 1 x x
D7.
B7 B6 B5 B4 B3 B2 B1 BO
• DO
x x x x IRQ x x x
Adreßspeicher Low schreiben Adreßspeicher High schreiben Datenbus schreiben Datenbus lesen
(Bidirektionaler Bus am Druckerport Bild 9-26)
Bild 9-27: E x t e r n e r P e r i p h e r i e b u s mit Adreßspeichern
o IRQ
9.2 Beispiele aus der
201
Mikrocomputertechnik
Bei d e r In Bild 9-26 d a r g e s t e l l t e n Beschattung der P o r t l e i t u n g e n mit zusätzlichen Open-Collector-Ausgängen und f ü r die gewählte Anordnung d e r L e i t u n g e n entsteht am D r u c k e r p o r t ein 8-bit-Bus, d e r bidirektional, d.h. in beiden Richtungen b e t r i e b e n werden kann. Zusätzlich bleiben v i e r A u s g ä n g e f ü r Steuersignale und eine Leitung f ü r einen Steuereingang f r e i . Das Bild zeigt die beiden P r o z e d u r e n a u s p o r t und e i n p o r t , die jeweils ein Byte (8 bit) über den Bus ausgeben bzw. einlesen. Dabei ist zu b e a c h ten, daß wegen d e r Open-Collector-Schaltungen ein Lesen nur dann möglich ist, wenn die Ausgänge auf High-Potential liegen. Zur Nachbildung d e r A d r e s s e n dienen die in Bild 9-27 dargestellten Adreßspeicher. Für die Adressierung eines P e r i p h e r i e p o r t s wird zunächst die P o r t a d r e s s e über d i e Druckerschnittstelle ausgegeben und während d e r gesamten Zug r i f f s z e i t In den beiden Adreßspeicherbausteinen (74LS273) f e s t g e h a l t e n . Das Signal AEN l i e f e r t das F r e i g a b e - und Taktsignal f ü r die f l a n k e n g e s t e u e r t e n Adreßspeicher. I h r e Auswahl e r f o l g t durch das Signal AB. Währ e n d d e r Datenübertragung s p e r r t das Signal AEN die Speicher und g i b t die P e r i p h e r i e k a r t e n f r e i . Die beiden Signale RD und WR bestimmen auf d e r P e r i p h e r i e k a r t e Zeitpunkt und Richtung d e r Datenübertragung. Für einen P e r i p h e r i e z u g r i f f sind also d r e i Schritte e r f o r d e r l i c h : - L o w - T e i l d e r Adresse aussenden, - High-Teil der Adresse aussenden und - Daten ü b e r t r a g e n .
LU
1 t
$FF iriit,
IT5 IT6 L I ? IT3 IT4 — I —1 —I ~1 1
T7
T8
T1
T2
T3
T4
T5
T6
T7
T8
le sen
Adr. Low Adr. High Aus; abedaten 1— i ' 1
Adr. Low Adr. High $FF Date $xx $FF 1 l 1 PIÌ0CEDURE b u s e i n
/
-
$FF
PROCEC URE busaus
(* Bild 9-28: Buszugriffe Grundstellung lesen schreiben *) PROCEDURE init; (* clk, mode WR = High RD = High AEN = Low AB = Low global *) BEGIN z := #0; clk := 1; mode := $02; ausport($FF); (* alle Busleitungen High «) WriteLn('Bustakt ',clk,' ms Halt und neuer Takt mit Esc 1 ) END;
202
9.
Anwendungsbeispiele
PROCEDURE takt(rw : CHAR; i : INTEGER); (* 2 und clk = Busttakt sind global *) BEGIN IF elk > 0 THEN Delay(clk); (* verzögern *) IF elk < 0 THEN BEGIN WriteLn(rw,'-Zyklus Takt T\i); z := UpCase(ReadKey) END; IF (elk >= 0) AND KeyPressed THEN z := UpCase(ReadKey); (* neue elk") IF z = #$1B THEN BEGIN Write('Takt [ms]:1); ReadLn(clk); z := #0 END END; PROCEDURE busein(adr : WORD; VAR x : BYTE; VAR irq : BOOLEAN); (* mode ist global *) BEGIN mode := $00; ausport(Lo(adr)); takt('R',l); (* T1 = Adresse Low mode := $02; ausport(Lo(adr)); takt('R',2); (* T2 = übernehmen mode := $01; ausport(Hi(adr)); takt('R',3); (* T3 = Adresse High mode := $03; ausport(Hi (adr) ) ; takt('R\4); (« T4= übernehmen mode := $02; ausport($FF); takt('R',5); (« T5 = Datenbus High mode := $06; ausport($FF); takt('R\6); (* T6 = RD Low einport(x,irq); takt('R\7); (* T7 = Datenbus lesen mode := $02; ausport($FF) ; takt('R\8); (* T8 = RD High END; PROCEDURE busaus(adr : WORD; x : BYTE); (* mode ist global *) BEGIN $00; ausport(Lo(adr)); takt('WM); (* T1 = Adresse Low mode mode $02; ausport(Lo(adr)); takt('W',2); (* T2 = übernehmen mode $01; ausport(Hi(adr)); takt('W\3); (* T3 = Adresse High mode $03; ausport(Hi(adr)); takt('W',4); (* T4 = übernehmen mode $02; ausport(x); takt('W\5); (* T5 = Daten auf Bus mode (* T6 = WR = Low $0A; ausport(x); takt('W\6); mode (* T7 = WR = High $02; ausport(x); takt('W',7); mode $02; ausport($FF); takt('W\8); (» T8 = Datenbus High END; Bild 9-28: P r o z e d u r e n f ü r Bus Zugriffe im M u l t i p l e x v e r f a h r e n
Bild 9-28 z e i g t d a s Zeitdiagramm d e r a l s M u l t i p l e x v e r f a h r e n b e z e i c h n e t e n z e i t l i c h e n V e r s c h a c h t e l u n g v o n A d r e s s e n u n d Daten a u f dem Bus. Es wird i n ä h n l i c h e r Form b e i d e n P r o z e s s o r e n 8085, 8086 u n d 8088 v e r w e n d e t . Die P r o z e d u r init b r i n g t d e n Bus in e i n e n d e f i n i e r t e n G r u n d z u s t a n d u n d s t e l l t d e n B u s t a k t a u f 1 ms ein. Die P r o z e d u r takt a r b e i t e t als Z e i t g e b e r u n d b e s t i m m t d i e G e s c h w i n d i g k e i t d e r B u s z u g r i f f e . Die Variable clk bestimmt die Betriebsart: - F ü r clk < 0 (z.B. - 1 ) a r b e i t e t d e r Bus im E i n z e l s c h r i t t . - F ü r clk = 0 a r b e i t e t d e r B u s mit maximaler G e s c h w i n d i g k e i t . - F ü r clk > 0 a r b e i t e t d e r Bus mit e i n e r V e r z ö g e r u n g s z e i t [ms]. D u r c h B e t ä t i g e n d e r E s c - T a s t e k a n n j e d e r z e i t e i n e n e u e B e t r i e b s a r t bzw. e i n e n e u e V e r z ö g e r u n g s z e i t e i n g e s t e l l t w e r d e n . Im E i n z e l s c h r i t t b e t r i e b w i r d d e r n ä c h s t e T a k t e r s t nach B e t ä t i g e n e i n e r b e l i e b i g e n T a s t e (außer Esc) a u s g e f ü h r t . D a d u r c h l a s s e n s i c h die B u s s i g n a l e z.B. d u r c h L e u c h t d i o d e n a n z e i g e n u n d S i g n a l e auf d e n Karten mit einem Voltmeter s t a t i s c h m e s s e n . Die b e i d e n P r o z e d u r e n busein u n d busaus e n t s p r e c h e n dem A u f r u f d e s P s e u d o f e l d e s Port [ . . ] . B e i s p i e l e : bus ein ( x , dat en , i ) e n t s p r i c h t daten := Port[x] busaus (x , d a t e n ) e n t s p r i c h t Port[x] := d a t e n
9.2 Beispiele aus der
Mikrocomputertechnik
203
Die Prozedur b u s e i n liefert als dritten Parameter zusätzlich den Zustand der Eingabeleitung, an die die Interruptleitungen des Peripheriebus angeschlossen sind. Das in Bild 9-29 dargestellte Hauptprogramm zeigt als Beispiel ein Testprogramm f ü r die in Abschnitt 7.2 beschriebene Peripheriekarte. Die an den Eingabeports anliegenden Daten werden auf den Ausgabeports wieder ausgegeben. Es arbeitet ähnlich wie das in Bild 7-9 dargestellte Testprogramm.
(* Bild 9-29: Testschleife Port lesen und ausgeben *) BEGIN ( * H a u p t p r o g r a m m * ) Write('LPT1, 2, 3, oder 4 > ' ) ; ReadLn(nr); padr := HemW[$40 : nr*2 + 6]; WriteLnCAbbruch mit X ' ) ; init; (* clk und Bus i n i t i a l i s i e r e n *) busaus($303,$00); REPEAT
busein($300,daten,irq); WriteLn(*Daten von $300 ',daten); busaus($301,daten); busaus($302,daten); busaus($304,daten); UNTIL z = 'X' END. Bild 9-29: Testschleife f ü r eine Peripheriekarte
204
9.2.3
9.
Anwendungsbeispiele
Der Aufbau eines Hardware-Emulators ( 8 0 8 5 )
Die bei d e r Untersuchung von Mikrocomputerschaltungen a u f t r e t e n d e n Hardwareprobleme lassen sich o f t nur durch den Einsatz v o n o f t r e c h t teuren Entwicklungssystemen lösen. Dabei wird d e r P r o z e s s o r aus d e r Schaltung e n t f e r n t und durch Software in Verbindung mit I n t e r f a c e s c h a l tungen nachgebildet (emuliert). Die anderen Teile d e r Schaltung wie z.B. S p e i c h e r - und Peripheriebausteine bleiben u n v e r ä n d e r t . Der Emulator simuliert - meist mit v e r m i n d e r t e r A r b e i t s g e s c h w i n d i g k e i t o d e r sogar im Einzelschritt - das Verhalten des P r o z e s s o r s . Dieser Abschnitt z e i g t die Arbeitsweise eines solchen Emulators am Beispiel des P r o z e s s o r s 8085 in einem Übungssystem. Eine vollständige Simulation d e r Hardware und aller Befehle w ü r d e den Umfang dieses Buches s p r e n g e n . Daher ist dieser Simulator nur als "Modell" zu v e r s t e h e n . Bild 9-30 z e i g t die Hardware.
Übungssystem MVUS 8085 Speicherbereich
Peripheriebereich Schaltereingabe
$1000 (RAM) $0000 (EPR0M)
$10
Steuerbus _ I0/M WR RD
A15
$18
Leuchtdiodenausgabe
$00 I $01 $02 I $03 Schnittstelle 8255
Adreßbus
Datenbus D7 DO
A0 i 1 ALE Adreßlatch
M i k r o p r o z e s s o r
JL
8085
Takt D/A
Steuereingange
Steuerausgange
Adreßbus High
Adr.Low/ Daten sehr.
Datenbus (lesen)
x+4
x+2 lesen
x+2 sehr,
x+1 sehr.
x+0 sehr.
x+0 lesen
P e r i p h e r i e k a r t e
Abschnitt 7.2 Bild 7-4
Kartenadresse x=$300 Bild 9-30: Die Hardware des 8085-Emulators
9.2 Beispiele aus der Mikrocomputertechnik
205
Als Interface dient die in Abschnitt 7.2 (Bild 7-4) behandelte Peripheriekarte. Für den Betrieb am Druckerport wären wieder besondere Speicher f ü r Adressen und Steuersignale erforderlich. Der mit dem Datenbus gemultiplexte Low-Teil des Adreßbus wird am bidirektionalen Port 0 der Karte betrieben, der High-Teil des Adreßbus nur in einer Richtung am Port 1. Die beiden Teile des unidirektionalen Ports 2 dienen zum Lesen und Ausgeben der Steuersignale. Mangels weiterer Leitungen mußte der D/A-Wandler f ü r den Takt verwendet werden, der jedoch in dem untersuchten Übungssystem nicht benötigt wird. Die wichtigste Aufgabe eines Emulators ist die Nachbildung der Bussignale, die j e nach Betriebsart und Befehl durchaus unterschiedlich verlaufen können. Bild 9-31 zeigt als Beispiel den Verlauf des ersten Maschinenzyklus ( M l ) , mit dem der Code eines Befehls über den Datenbus in den Prozessor gelesen wird.
MI Clk. JiL
TL _S2_
T2 S3 r ~ s T
T3 _SÉ_
T4 S 7 I SB
S1 SO HLDA ÏNTÂ ALE lesen
RD WR IO/M Adr.Hr Adr.L Daten
Adresse
Adresse Low
frei
High
frei
Code
frei
Bild 9-31: Das Bustiming in einem Ml-Zyklus (Code lesen)
206
9.
Anwendungsbeispiele
Ein Ml-Zyklus verläuft in den vier Takten T1 bis T4, die in acht Schritte von S1 bis S8 unterteilt wurden. Anders als bei den Bussignalen des im vorigen Abschnitt behandelten Peripheriebuszugriffs werden bei dem v o r liegenden Simulator die Steuersignale des Mikroprozessors und die Steuergrößen des Buszugriffs einer Tabelle entnommen. Das zweidimensionale Feld t a b enthält in der 1. Indexposition die Nummer des Schrittes und in der 2. Indexposition f ü r jeden Schritt drei Steuerbytes. Das erste Steuerbyte enthält in dem vorliegenden Beispiel nur den Takt, das zweite die Steuerausgänge des Prozessors und das dritte Simulator Steuer großen f ü r den Adreß- und Datenbus. Bild 9-32 zeigt ein vereinfachtes Modell des simulierten Mikroprozessors 8085.
Bild 9-32: Registersatz und Bussteuerung
Von dem Registersatz des Prozessors werden in dem vorliegenden Beispiel nur der Befehlszähler, ein Hilfsregister, der Akkumulator und das Befehlsregister verwendet. Die einzelnen Bitpositionen des dritten Steuerbytes bestimmen beispielsweise in jedem Schritt, ob der Adreßbus eine Adresse oder Daten überträgt oder zum Lesen frei (tristate) geschaltet ist, und wann der Datenbus gelesen wird. Die Übergabe erfolgt in den Variablen a d r e s s e und d a t e n . Die gelesenen Daten können je nach Art des Befehls in eins von vier Registern geschrieben werden. Die Auswahl könnte wieder durch eine Tabelle gesteuert werden. Bild 9-33 zeigt als Beispiel den A u f bau der Tabelle f ü r einen Ml-Zyklus.
9.2 Beispiele aus der
Clk Schritt S1 S2 S3 S4 S5 S6 57 58 Endem.
S t e u e r s i g n a l e
A/ /D
207
Mikrocomputertcchnik
Bussteuerung
[i.1] S1 so HLDA INTA ALE RD WR I0/M [i.2]
A.H,
$00 $80 $00 $80 $00 $80 $00 $80
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 0
1 1 0 0 0 1 1 1
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0
$DE $D6 $D2 $02 $D2 $D6 $D6 $D6
00010001 00010001 00010000 00010000 00011100 00010000 00000000 00000000
11111111 $FF
1
1
1
1
1
1
1
1
$FF
11111111 $FF
00000000 10000000 00000000 10000000 00000000 10000000 00000000 10000000
°- A L [i,3] $11 $11 $10 $10 $1C $10 $00 $00
Bild 9-33: Steuertabelle für einen Ml-Zyklus Da die Tabelle auch die Steuergrößen für die Buszustände "Speicher lesen (mrd)", "Speicher schreiben (mwr)", "Peripherie lesen (iord)" und "Peripherie schreiben (iowr)" enthält, wird jede Teiltabelle durch einen Zeiger mit dem Anfangsindex und eine Endemarke gekennzeichnet, die aus Einerbits ($FF) besteht. Dadurch können die Teiltabellen und damit die durch sie beschriebenen Befehlsabläufe beliebig lang sein. Bild 9-34 zeigt die Gesamttabelle. PROGRAH prog9p2; (« Bild 9-34: 8085 - Emulator *) USES Crt; CONST fmax = 3 7 ; x = $300; (* Kartenadresse *) TYPE ftyp = ARRAY [1..fmax,1..3] OF BYTE; CONST tab : ftyp = (* Funktionstabelle «) (($00,$DE,$11),($80,$D6,$11),($00,$D2,$10),($80,$D2,$10),($00,$D2,$1C), ($80, $D6, $10), ($00, $D6, $00), ($80,$D6, $00), ($FF, $FF, $FF), (* tll-Zyklus ($00,$9E,$11),($80,$96,$11),($00,$92,$10),($80,$92,$10), ($00,$92,$1C),($80,$96,$10),($FF,$FF,$FF), (* MRD-Zyklus ($00,$5E,$11),($80,$56,$11),($00,$54,$12),($80,$54,$12), ($00,$54,$12),($80,$56,$12),($FF,$FF,$FF), (* MVR-Zyklus ($00,$9F,$11),($80,$97,$11),($00,$93,$10),($80,$93,$10), ($00,$93,$1C),($80,$97,$10),($FF,$FF,$FF), (* IORD-Zyklus ($00,$5F,$11),($80,$57,$11),($00,$55,$12),($80,$55,$12), ($00,$55,$12),($80,$57,$12),($FF,$FF,$FF)); (* IOUR-Zyklus (* Index Zyklen ml = 1; mrd = 10; mwr = 17; iord = 24; iowr = 31; clk : INTEGER = 1 ; (* Bustakt 1 ms vorbesetzt VAR padre, daten, status, akku, temph, templ, code, mzyk : BYTE; adresse, befzae : WORD; z : CHAR;
*) ») *) *) «) *) *)
bei : STRING[3]; ende : BOOLEAN;
Bild 9-34: Tabelle der Steuersignale und Buszugriffe Der Aufbau der Tabellen ist zunächst sehr mühsam, da «ille Signale binär aufgestellt und dann hexadezimal zusammengefaßt werden müssen (Bild 9-33). Sie bieten jedoch den Vorteil, daß sie beliebig geändert und erweit e r t werden können, um Änderungen im Befehlsablauf durchzuführen oder um neue Befehle aufzunehmen oder sogar um Befehle zu erfinden, die der reale Prozessor nicht kennt.
208
9.
Anwendungsbeispiele
(* Bild 9-35: Taktgenerator und hexadezimale Ausgabe * ) PROCEDURE takt; (* Taktgenerator clk = Bustakt i s t global * ) BEGIN IF elk > 0 THEN Delay(clk); (* verzögern [ms] « ) IF elk < 0 THEN z := UpCase(ReadKey); (* warten auf Taste *) END; PROCEDURE ausbyte(x:BYTE); (* Byte hexadezimal ausgeben *) VAR nib : BYTE; BEGIN nib := (x SHR 4) AND $0F; IF nib < 10 THEN Write(CHAR(nib + $30)) ELSE Write(CHAR(nib + $37)); nib := x AND $0F; IF nib < 10 THEN Write(CHAR(nib + $30)) ELSE Write(CHAR(nib + $37)) END; PROCEDURE anzeige; (* Prozessorzustand: a l l e Variablen global * ) BEGIN WriteC H\mzyk,': PC=$'); ausbyte(Hi(befzae)); ausbyte(Lo(befzae)); Write(' TempH=$1); ausbyte(temph); Write(' TempL=$'); ausbyte(tempi); WriteC Code=$'); ausbyte(code); WriteC Befehl:' ,bef, ' Akku=$'); ausbyte(akku); WriteLn END; Bild 9-35: Taktsteuerung und Ausgabe des Prozessorzustandes
Die in Bild 9-35 dargestellte Prozedur t a k t liefert den Prozessortakt und bestimmt dadurch die Arbeitsgeschwindigkeit des Simulators. Dabei ist neben einer Verzögerung in der Einheit Millisekunde ein Einzelschrittbetrieb möglich, bei dem nach jedem Schritt auf die Eingabe einer beliebigen Taste gewartet wird. Die Prozedur a n z e i g e gibt die in dem vorliegenden Simulator verwendeten Register des Prozessors aus, die nur eine Teilmenge der tatsächlich vorhandenen Register darstellen. Sie genügen j e doch, den Ablauf einiger Befehle zu demonstrieren. Das folgende Beispiel zeigt ein Programm in der Assemblerschreibweise des Prozessors 8085; jedoch mit dem Zeichen "$" f ü r hexadezimale Werte. Es wird mit dem Busmonitor (Bild 9-38) eingegeben. Bild 9-42 zeigt den Ablauf des Testprogramms.
Adresse
Inhalt
$1000 $1001 $1002 $1003 $1004 $1005 $1006
$DB $10 $ D3 $18 $C3 $00 $10
Name B e f e h l Operand Bemerkung $1000 Startadresse ORG LOOP IN $10 P o r t $10 l e s e n OUT
$18
Port
JMP
LOOP
springe
END
$18
ausgeben immer
9.2 Beispiele aus der
Mikrocomputertechnik
209
(* Bild 9-36: Tabellengesteuerte Buszugriffe *) PROCEDURE init; (* Schnittstellenkarte initialisieren BEGIN Port[x+0] := BYTE(NOT $FF); (* Adreßbus-Low/Datenbus High *) Port[x+1] := BYTE(NOT $FF); (« Adreßbus-High High *) Port[x+2] := $16; (* 0001 0110 Steuerbus inaktiv «) Port[x+4] := $00 (* Takt Low *) END; PROCEDURE bus(tab:ftyp; ta: INTEGER; adr:WORD; VAR daten, status -.BYTE); VAR i,n : INTEGER; (* Feldindex = Tabellenschritt ») BEGIN (* Steuereingänge lesen status := Port [x+2]; (* Anfangsschritt Tabelle i := ta; n := 1; (* Endemarke der Tabelle WHILE tab[i,3] $FF DO BEGIN Port [x+4] : = tab[i,1]; (* Konstante Steuersignale Port[x+2] := tab[i,2]; (* Konstante Steuersignale IF (tab[i,3] AND $F0) $10 THEN Port[x+1] = NOT Hi(adr); IF (tab[i,3] AND $F0) BYTE(NOT $FF); $00 THEN Port[x+1] IF (tab[i,3] AND $03) NOT Lo(adr); $01 THEN Port[x+0] IF (tab[i,3] AND $03) NOT daten; $02 THEN Port[x+0] IF (tab[i,3] AND $03) $00 THEN Port[x+0] := BYTE(NOT $FF); IF elk < 0 THEN Urite('S',n); takt; (* Taktgenerator *) IF (tab[i,3] AND $0C) = $0C THEN daten := NOT Port[x+0]; Inc(i); Inc(n) (* Nächster Tabellenschritt *) END END;
Bild 9-36: T a b e l l e n g e s t e u e r t e B u s z u g r i f f e Die in Bild 9-36 d a r g e s t e l l t e P r o z e d u r b u s b i l d e t d e n Kern d e s E m u l a t o r s . Nach Ü b e r g a b e d e r A n f a n g s a d r e s s e d e r T a b e l l e n s c h r i t t e ü b e r d e n P a r a m e t e r t a a r b e i t e t sie s e l b s t ä n d i g alle S c h r i t t e e i n e s B u s z y k l u s b i s z u r E n d e m a r k e $FF a b . Die S t e u e r s i g n a l e in d e n I n d e x p o s i t i o n e n X u n d 2 w e r d e n d i r e k t a u s g e g e b e n , l e d i g l i c h f ü r d i e S i m u l a t o r s t e u e r u n g in d e r I n d e x p o s i tion 3 s i n d I F - T H E N - A b f r a g e n e r f o r d e r l i c h . Im E i n z e l s c h r i t t b e t r i e b ( c l k < 1) w i r d z u s ä t z l i c h d i e Nummer d e s S c h r i t t e s a u s g e g e b e n , damit bei e i n e r M e s s u n g d e r Signale in d e r S c h a l t u n g d e r a u g e n b l i c k l i c h e B u s z u s t a n d u n d damit d i e zu e r w a r t e n d e n Meßwerte b e k a n n t s i n d . I n dem u n t e r s u c h t e n Ü b u n g s s y s t e m w e r d e n die Z u s t ä n d e d e s A d r e ß - u n d D a t e n b u s auf S i e b e n s e g m e n t a n z e i g e n u n d die S t e u e r s i g n a l e (z.B. RD u n d WR) d u r c h L e u c h t d i o d e n b i n ä r a n g e z e i g t . Bild 9-37 z e i g t d a s H a u p t p r o g r a m m z u s a m m e n mit d e r S t r u k t u r d e s Emulator P r o g r a m m s . Die Auswahl d e r B e t r i e b s a r t e n e r f o l g t d u r c h e i n e n K e n n b u c h s t a b e n . Der K e n n b u c h s t a b e "X" b e e n d e t d a s P r o g r a m m . Mit dem K e n n b u c h s t a b e n "T" w i r d d e r T a k t e i n g e s t e l l t . Ein n e g a t i v e r Wert (z.B. - 1 ) b e d e u t e t E i n z e l s c h r i t t b e t r i e b , bei dem d a s P r o g r a m m in jedem S c h r i t t w a r t e t , b i s d e r B e n u t z e r d u r c h E i n g a b e e i n e r b e l i e b i g e n T a s t e d e n Z y k l u s f o r t s e t z t . Bei maximaler G e s c h w i n d i g k e i t ( T a k t = 0) w u r d e ein S c h r i t t in ca. 50 /js a u s g e f ü h r t . Dies e n t s p r i c h t e i n e r T a k t p e r i o d e v o n 0.1 ms e n t s p r e c h e n d e i n e r T a k t f r e q u e n z v o n 10 kHz. Der e c h t e P r o z e s s o r 8085 w i r d mit T a k t f r e q u e n z e n v o n 2 b i s 6 MHz b e t r i e b e n . I n d e r B e t r i e b s a r t "G" ( P r o g r a m m a u s f ü h r u n g ) wird j e d o c h n a c h jedem B u s z y k l u s d e r Z u s t a n d d e r P r o z e s s o r r e g i s t e r a u s g e g e b e n . Dies d a u e r t ca. 16 ms.
210
9.
Anwendungsbeispiele
Meldung |"M
P
G
T
oder X
eingeben"!
Benutzereingabe ? G
kein Kennbuchst.
Busmonitor Speicher
Busmonitor Peripherie
Programm ausführen
Betriebsart der Ausfüh.
Speicheradresse
Portadresse
Startadresse
Betriebsart eingeben
Inhalt anzeigen
< 0 I > 0
Eingabe
Eingabe
N
A
+
Takt ?
Meldung
rsi
N
ro
+
< 0 : Einzel
FehlerMeldung ausgeben
=0: schnell > 0 : verzog.
_
c 0>
r-
H-» 4>
«
C
c 0»
4-» «
bis "X"
ReadLn(klf); Write('Fenster 1 2 oder 3 Teile -> ReadLn(klm); Write('Null-Linie 0 128 256 -> ReadLn(k2a); Write('Kanal 2: Anfangspunkt -> ReadLn(k2f); Write('Fenster 1 2 oder 3 Teile -> ReadLn(k2m); Write('Null-Linie 0 350 478 -> ReadLn(xf); Write('X-Faktor bei Druck 1 2 -> ReadLn(yf); Urite('Y-Faktor bei Druck 1 2 -> ReadLn(schrift); Write('Beschriftung bei Druck -> Write('Bild drucken mit D löschen mit er weiter mit ->cr'); ReadLn; graphstart; SetColor(15); (* Graphikbetrieb umschalten *) REPEAT Rectangle(0,0,xmax,ymax); Line(0,klm,xmax,klm); Line(0,k2m,xmax,k2m); MoveTo(0,256-k[kla'klf+1, 0]); FOR i := 0 TO xmax DO LineTo(i,256 - k[(i+kla)*klf+l,0]); MoveTo(0,478-k[k2a*k2f+l,1]); FOR i 0 TO xmax DO LineTo(i,478 - k[(i+k2a)*k2f+l,1]); zd := UpCase(ReadKey); IF zd = #0 THEN BEGIN zd := ReadKey; ClearViewPort END; IF zd = #77 THEN BEGIN Inc(kla); Inc(k2a) END; IF zd = #75 THEN BEGIN Dec(kla); Dec(k2a) END; IF zd = 'D' THEN druck(xf,yf); UNTIL (zd = 'D') OR (zd = #$0D); CloseGraph; IF zd = 'D' THEN WriteLn(Lst,schrift); WriteLn('Kanal 1: Anfang = \kla:4, ' Bild: \klf, ' Null: ' ,klm); HriteLn('Kanal 2: Anfang = ',k2a:4,' Bild: ',k2f,' Null: ',k2m) END; Bild 9-46: Graphische Bildschirmausgabe
Die in Bild 9-47 dargestellte Betriebsart "D" (Dateiverwaltung) ermöglicht das Abspeichern von Aufzeichnungen, die dadurch auch von anderen Programmen ausgewertet werden können. Umgekehrt ist es möglich, Ergebnisse anderer Programme zu laden, auf dem Bildschirm darzustellen, mit Aufzeichnungen des Speicheroszilloskops zu vergleichen und auszudrukken. Von diesen Anwendungen wird in späteren Beispielen Gebrauch g e macht werden. Mit dem Kommando "M" gelangt der Benutzer, ähnlich wie im Turbo Pascal File Menü mit der Option OS S h e l l , auf die Kommandoebene des Betriebssystems, um Dateioperationen durchzuführen. Die Rückkehr erfolgt durch das Betriebssystemkommando ex i t . Bild 9-48 zeigt eine Aufzeichnung von Tastenprellungen (Kanal 1 oben) zusammen mit einer Rechteckfrequenz von 10 kHz (Kanal 2 unten) als Zeitbasis. Derselbe Vorgang wurde gleichzeitig mit dem in Abschnitt 9.2.1 beschriebenen "Logikanalysator" am Druckerport aufgenommen. Ein Vergleich zeigt, daß vom "Logikanalysator" wegen der geringen Abtastrate von ca. 5.5 /js/Aufzeichnung kurze Impulse nicht erkannt wurden, was durchaus auch f ü r das Speicheroszilloskop mit einer Abtastrate von 50 ns/Aufzeichnung der Fall sein kann.
220
9.
Anwendungsbeispiele
(* Bild 9-47: Dateiverwaltung Speichern und Laden von Aufzeichnungen *) 'D' : BEGIN (* Dateiverwaltung *) REPEAT WriteLn; Write('Datei S = Speichern L = Laden H = HS-DOS X = Ende ->'); zd := UpCase(ReadKey); WriteLn(zd); CASE zd OF 'S' : BEGIN (* Speichern Kanal nach Datei Byte DAten *) FOR nr := 0 TO 1 DO BEGIN Write('Kanal ',nr+l,' speichern j/n? ->'); zd := UpCase(ReadKey); IF zd = 'J' THEN BEGIN Write('Dateiname xxxxxxxx.BDA:1); ReadLn(name); Assign(daten,name); Rewrite(daten); FOR i := 1 TO pmax DO Write(daten,k[i,nr]); Close(daten) END END END; 'L' : BEGIN (* Laden Kanal von Datei Byte DAten *) FOR nr := 0 TO 1 DO BEGIN Write('Kanal ',nr+l,' laden j/n ->'); zd := UpCase(ReadKey); IF zd = 'J' THEN BEGIN REPEAT Write('Dateiname xxxxxxxx.BDA:'); ReadLn(name); Assign(daten,naine); (*$I-*) Reset(daten) (*$I+*); UNTIL IOResult = 0; i := 1; REPEAT Read(daten,k[i,nr]); Inc(i) UNTIL Eof(daten) OR (i > pmax); WriteLn(i-l,' Werte geladen'); Close(daten) END END END; •H' : BEGIN (* Nach Dateiverwaltung HS-Dos *) WriteLn('*** MS-DOS-Kommandoebene zurück mit .,->exit er'); SwapVectors; Exec(GetEnv('COHSPEC'),''); SwapVectors; W r i t e L n ( ' W i e d e r Pasca1-Programm ***') END; 'X' : WriteLn('Ende der Dateiverwaltung ') END UNTIL zd = 'X' ; END ELSE WriteLn('Eingabefehler !!!!') END UNTIL az = 'X' END. Bild
9-47:
Dateiverwaltung für Aufzeichnungen
9.2 Beispiele aus der
Gesamtaufzeichnung (Fenster 3 Teile)
50 us/cm lV/cm Kanal2: 10 kHz
Mikrocomputertechnik
Teilausschnitt (Fenster 1 Teil)
T = lOOus
Tastenprellungen gemessen mit einem Speicheroszilloskop
* * * * * * * * * * * * * * * * *
*
*
* * * * *
*
*
* *
Tastenprellungen gemessen mit dem Programm Bild 9-25 Bild 9-48: A u f z e i c h n u n g e n v o n T a s t e n p r e l l u n g e n
221
222
9. Antvcndungsbeispielc
9.2.5
Die Ansteuerung von Schrittmotoren
Ein S c h r i t t m o t o r b e s t e h t im P r i n z i p a u s einem Rotor mit m e h r e r e n am Umf a n g v e r t e i l t e n D a u e r m a g n e t e n u n d einem S t a t o r mit M a g n e t p o l e n , d i e v o n s t r o m d u r c h f l o s s e n e n Wicklungen e r r e g t w e r d e n . Dabei f o l g e n d i e D a u e r m a g n e t e d e s R o t o r s dem S t a t o r f e l d . Bei j e d e r A n s t e u e r u n g d e r S t a t o r w i c k l u n g e n b e w e g t 3ich d e r Rotor um g e n a u e i n e n W i n k e l s c h r i t t w e i t e r . Diese s c h r i t t g e n a u e P o s i t i o n i e r u n g wird z.B. f ü r d i e S t e u e r u n g v o n P l o t t e r n , Druckern, Scannern, Robotern u n d a n d e r e n elektromechanischen Antrieb e n v e r w e n d e t . D u r c h Mitzählen d e r S c h r i t t e k a n n man j e d e r z e i t g e n a u d i e P o s i t i o n e n d e s A n t r i e b s bestimmen. Bild 9-49 z e i g t d a s P r i n z i p e i n e s Z w e i p h a s e n s c h r i t t m o t o r s mit v i e r W i c k l u n g s s t r ä n g e n bei e i n e r u n i p o l a r e n Ansteuerung.
Bild 9-49: A n s t e u e r u n g e i n e s S c h r i t t m o t o r s im U n i p o l a r b e t r i e b A u s g e h e n d vom T T L - P e g e l e i n e r S c h n i t t s t e l l e w e r d e n ü b e r eine T r e i b e r s t u f e S c h a l t t r a n s i s t o r e n a n g e s t e u e r t , die den E r r e g e r s t r o m g e t r e n n t f ü r j e d e E r r e g e r w i c k l u n g l i e f e r n . D u r c h U m s c h a l t u n g d e s S t r o m e s in d e n W i c k l u n g s s t r ä n g e n k e h r t sich a u c h d i e R i c h t u n g d e s m a g n e t i s c h e n F l u ß e s a n d e n S t a t o r p o l e n um. Die R e i h e n f o l g e d e r A n s t e u e r u n g i s t so zu wählen, d a ß im S t a t o r ein r o t i e r e n d e s M a g n e t f e l d e n t s t e h t , d a s die D a u e r m a g n e t e n d e s R o t o r s " m i t z i e h t " . B e t r a c h t e t man die Zeitdiagramme f ü r d e n in Bild 9 - 4 9 d a r g e s t e l l t e n V o l l s c h r i t t b e t r i e b , so b e d e u t e t d i e A n s t e u e r u n g d e s
9.2 Beispiele aus der Mikrocomputertechnik
223
Motors programmtechnisch nichts weiter als die Ausgabe bestimmter Bitmuster (0 = Strom ein, 1 = Strom aus): Stellung 1: 1100 = $C Stellung 2: 1001 = $9 Stellung 3: 0110 = $6 Stellung 4: 0011 = $3 Die Reihenfolge, in der die Bitmuster die Statorwicklungen ansteuern, entscheidet über die Drehrichtung (Linkslauf bzw. Rechtslauf). Bild 9-50 zeigt als Demonstrationsbeispiel die Ansteuerung der Schrittmotoren eines Trommelplotters. Zeichenpapier Schlitten
Schlittenmotor
Papiermotor Papierwalze
I n t e r f a c e Papiermotor
D7
D6
D5
D4
Schlittenmotor
D3
D2
D1
Datenregister x+0 schreiben
r
DO
DS
Steuerregister x+2 schreiben
x = Adresse Druckerport
Stift oben : 0 Stift unten: 1
Bitmustertabellen 0 pos. 1 $CF 2 $6F 3 $3F 4 $9F
c c
0 pos. 1 $FC 2 $F6 j; 3 $F3 2 4 $F9
Bild 9-50: Ansteuerung der Schrittmotoren eines Plotters
224
9.
Anwendungsbeispiele
Der "Papiermotor" b e w e g t die Antriebsachse f ü r das Papier. Er w u r d e ü b e r ein I n t e r f a c e an die linke Hälfte des Druckerportausgangs a n g e schlossen. Der "Schlittenmotor" b e w e g t einen Schlitten f ü r den Zeichens t i f t und l i e g t an d e r rechten Hälfte des Druckerports. Der Zeichenstift wird mit dem Ausgang DS des Steuerports angehoben und abgesenkt. Die Bitmustertabellen bestehen aus den v i e r Bitmustern f ü r die Ansteuerung im Vollschrittbetrieb. Sie enthalten in einem zusätzlichen Element die zul e t z t a u s g e g e b e n e Indexposition der Tabelle, also die Position des Rotors. Die Zeit zwischen zwei Ansteuerungen bestimmt die Schrittfrequßnz des Motors, also die Anzahl der Schritte in d e r Sekunde. Beim Anlaufen und beim Abbremsen muß d e r Motor zur Erhöhung des Drehmomentes mit v e r minderter S c h r i t t f r e q u e n z g e g e n ü b e r dem kontinuierlichen Lauf betrieben werden. Dies b e d e u t e t entsprechend Bild 9-51 eine l ä n g e r e Wartezeit z w i schen d e r Ausgabe d e r Steuermuster.
Laufwert 35 30 25 20 15 10 15 20125 30 35
An lauframpe-
-Laufwert -
Wartezeit 35 ms 30 ms 25 ms 20 ms 15 ms 10 ms 5 ms
[ms]
- Abbremsrampe -
z 1
2
3
'i
5
6
7
8
Schritt n-7 n-6 n-5 n-1! n-} n-2 n-1 n-0
Bild 9-51: Hochlauf- und Abbremstabellen
Für die Untersuchung des Anlauf- und Abbremsverhaltens kann es zweckmäßig sein, die e r f o r d e r l i c h e n Rampen in Tabellenform abzuarbeiten. Die Tabelle des Beispiels enthält im v o r d e r e n Teil die Anlauframpe. Dann f o l g t die V e r z ö g e r u n g s z e i t f ü r die B e t r i e b s f r e q u e n z und die Abbremsrampe in d e r Einheit Millisekunde. Die Rampentabelle kann zusammen mit den Ansteuertabellen d e r Motoren als konstantes Feld im Steuerprogramm a b g e l e g t werden.
9.2 Beispiele aus der
Mikrocomputertechnik
225
PROGRAM prog9pl8; (« Bild 9-52: Schrittraotorsteuerung *) USES Crt; CONST nmuster = 4; nrampe = 5; s t i f t = 200; muster : AKRAY[0. .nmuster, 1..2] OF BYTE =• ((1,1),($CF,$FC),($6F,$F6),($3F,$F3),($9F,$F9)); rampe : ARKAY[1..2*nrampe+l] OF BYTE = (35,30,25,20,15,10,15,20,25,30,35); VAR nr, x : WORD; zl, z2 : CHAR; n : INTEGER; PROCEDURE motor(ds:INTEGER; nr:BYTE); VAR sw, ns, nra, i, s : INTEGER; BEGIN ns := Abs(ds); i := 1; s := 0; (* Rampenpositionen *) nra := ns DIV 2; IF nra > nrampe THEN nra := nrampe; IF ds < 0 THEN sw := +1 ELSE su := -1; (* Drehrichtung *) WHILE ds 0 DO BEGIN muster[0,nr] := muster[0,nr] + sw; IF muster[0,nr] < 1 THEN muster[0,nr] := nmuster; IF muster[0,nr] > nmuster THEN muster[0,nr] := 1; Port[x+0] := muster[ muster[0,nr] , nr]; (* Schrittausgabe *) Delay(rampe[i]); Inc(s); (* Rampenfunktion *) IF s (ns-nra) THEN Inc(i); ds := ds + sw (* Schrittzähler *) END END; PROCEDURE bewege(dx, dy : INTEGER); BEGIN IF dx 0 THEN motor(dx,l); (* 1 = Papiermotor «) IF dy 0 THEN motor(dy,2) (» 2 = Schlittenmotor *) END; Bild 9-52: Tabellen und Ansteuerunterprogramme
Das in Bild 9-52 dargestellte Programmbeispiel enthält die Ansteuer- und Rampentabellen f ü r die Bewegung der Schrittmotoren eines Plotter3. Die Wertparameter dx und dy bzw. ds enthalten die Anzahl der Schritte sowie im Vorzeichen die Richtung der Bewegung (rechts/links und oben/unten). Dadurch, daß die Steuerfunktionen in Tabellenform vorliegen, ist es möglich, durch eine Änderung der Eintragungen z.B. auf den Halbschrittbetrieb überzugeben oder die Anlauf- und Abbremsrampen zu verändern. Das in Bild 9-53 dargestellte Hauptprogramm hat lediglich die Aufgabe, die Motor- und Stiftfunktionen über die Cursortasten zu überprüfen.
226
9.
Anwendungsbeispiele
(* Bild 9-53: Handsteuerung des Plotters mit Cursortasten *) BEGIN ( » H a u p t p r o g r a m m * ) Write('Plotter bereit an LPT 1, 2, 3 oder 4 -> '); ReadLn(nr); x := HemW[$40 : nr*2 + 6]; Port[x+0] := $FF; (* beide Motore aus *) (* Stift oben *) Port[x+2] := $00; Write('Schrittweite -> '); ReadLn(n); (* n = Schrittweite *) WriteLn('Schleifenabbruch mit X '); REPEAT z2 := #0; zl := UpCase(ReadKey); If zl = 'N' THEN BEGIN Write('Schrittweite -> '); ReadLn(n) END; IF zl = #0 THEN z2 := UpCase(ReadKey); IF z2 = #81 THEN Port[x+2] := $01; (* Stift senken *) IF z2 = #73 THEN Port[x+2] := $00; (* Stift heben *) IF z2 = #77 THEN bewege(0,-n); (* Schlitten links *) IF z2 = #75 THEN bewege(0,+n); (* Schlitten rechts «) IF z2 = #80 THEN bewege(-n,0); (* Papier oben «) IF z2 = #72 THEN bewege(+n,0); (* Papier unten *) UNTIL zl = 'X' END. Bild. 9-53: Handsteuerung d e r Motoren und des Stiftes
9.3
Beispiele aus der analogen Meßtechnik
Gegenüber d e r " d i g i t a l e n " Meßtechnik b i r g t die "analoge" Meßtechnik eine Fülle v o n zusätzlichen elektrotechnischen Problemen. S t ö r u n g s f r e i e , l a n g zeitkonstante und r e p r o d u z i e r b a r e Ergebnisse lassen sich nur mit e r h e b lichem Aufwand erzielen. Dazu zählen z.B. die Messung mit Multimetern und Speicheroszilloskopen über den IEC-Bus (Kapitel 8) oder d e r Einsatz v o n speziellen a b g e g l i c h e n e n analogen P e r i p h e r i e k a r t e n (Abschnitt 7.3). Die f o l g e n d e n orientierenden Versuche werden mit analogen Schaltungen am D r u c k e r p o r t d u r c h g e f ü h r t . Für den Aufbau der Schaltungen sollten einige Hinweise beachtet werden: - Die Netzteile müssen genaue, konstante und ausreichend gesiebte V e r s o r g u n g s s p a n n u n g e n liefern. - Digitale und analoge Erdung (Ground) sind zunächst zu trennen und an einem Punkt zusammenzuführen. - Durch die Verwendung v o n Optokopplern lassen sich Rechner und das zu messende Objekt galvanisch trennen. - Es sind Meßwiderstände und Kapazitäten g e n ü g e n d e r Genauigkeit und Konstanz zu v e r w e n d e n ! - Die Schaltung sollte nicht in Stecktechnik oder Fädeltechnik, sondern möglichst als g e d r u c k t e Schaltung nach analogtechnischen Gesichtspunkten ( V e r s o r g u n g s l e i t u n g e n , Masseflächen, L e i t u n g s f ü h r u n g , Siebk o n d e n s a t o r e n ) a u f g e b a u t werden.
9.3 Beispiele aus der analogen
9.3.1
Meßtechnik
227
Die Messung von Widerständen
Die Messung nichtelektrischer Größen läßt sich oft auf die elektrische Messung von Widerständen z u r ü c k f ü h r e n . Ein Beispiel ist die E r f a s s u n g einer Temperatur ü b e r einen temperaturabhängigen Widerstand (NTC = Negativ e r Temperatur Coefficient), d e r seinen Widerstandswert mit steigender Temperatur verkleinert. Der Zusammenhang zwischen d e r physikalischen Meßgröße (z.B. der Temperatur) und dem Widerstandswert ist in vielen Fällen nicht linear, so daß es einer Korrektur b e d a r f , die zusammen mit d e r Kalibrierung der Anordnung von einem Programm d u r c h g e f ü h r t werden kann. Dabei wird der Zusammenhang zwischen dem Widerstandswert und d e r Temperatur, gemessen mit einem Thermometer, in einer Tabelle f e s t gehalten. Für e r s t e orientierende Messungen ist es jedoch zweckmäßig, anstelle des Meßfühlers einen f e s t e n Widerstand oder ein Potentiometer im Einstellbereich der zu erwartenden Widerstandsänderung zu verwenden. Für die Messung eines Widerstandes bietet sich zunächst e n t s p r e c h e n d dem Ohmschen Gesetz eine Strom/Spannungsmessung an, f ü r die jedoch Analog/Digitalwandler erforderlich sind. Im Kapitel 6 wurde am Beispiel des Spieleadapters (Gameport) gezeigt, daß sich eine Widerstandsmessung auf die Messung d e r Aufladezeit einer RC-Schaltung z u r ü c k f ü h r e n läßt (Bild 6-1). Das in Bild 6-5 dargestellte Programmbeispiel f ü h r t am Spielea d a p t e r eine Widerstandsmessung d u r c h und läßt sich d u r c h e n t s p r e c h e n de Kalibrierung auch z u r Messung physikalischer Größen wie z.B. einer Temperatur verwenden. Bild 9-54 zeigt den Versuch, das Meßprinzip d e r Aufladung eines Kondensators d u r c h den zu messenden Widerstand mit rein digitalen Bausteinen am Druckerport nachzuvollziehen.
berechnet: dt = T in U-— o - Us = T-lny^-•y-j = R-C-0.38 -6 = 0.38-10-10 1-10 = 38 ms I R=10K0hn
I
7US06
1
JjVM p
x+0 schreiben
x+1 lesen
x = Adresse Druckerport
berechnet
228
9.
Anwendungsbeispiele
PROGRAM prog9pl9; ( « Bild 9-54: Meßfühler am Druckerport *) USES Ort; CONST ack = $40; ( « Maske 0100 0000 ACK-Eingang *) VAR x,a : WORD; t i c , t l l . t l h , t21,t2h : BYTE; t l , t 2 : LONGINT; dt : REAL; z : CHAR; BEGIN Write('Versuch bereit an LPT 1, 2, 3 oder 4 - > ' ) ; ReadLn(x); x := MemW[$40 : 2«x + 6]; a := x+1; Port[x+0] : = $01; (* Druckerport High Hesspunkt Low *) REPEAT t i c := Mem[$40 : $6C] ; WHILE t i c = Kern[$40 : $6C] DO; (* bis Timerstart *) Port[x+0] := $00; ( « Druckerport Low Messpunkt High *) Port[$43]:=$00; t l l : = P o r t [ $ 4 0 ] ; tlh:=Port[$40]; REPEAT UNTIL (Port[a] AND ack) = ack; (* Flanke -> High * ) Port [$43]:=$00; t21:=Port[$40]; t2h:=Port[$40]; (* Ende *) t l := WORD(tlh SHL 8) OR WORD(tll); ( « Startzeit *) t2 := WORD(t2h SHL 8) OR WORD(t21); (* Stopzeit *) dt : = ( t l - t 2 ) * 0 . 4 1 9 * l e - 3 ; (* Zeit in msek «) W r i t e ( 1 t l = ' , t l : 5 , 1 t 2 = ' , t 2 : 5 , ' Messzeit: ' , d t : 6 : 3 , ' msek ' ) ; Port[x+0] := $01; (* Druckerport High Messpunkt Low *) Write(' weiter mit er ->').' z := ReadKey; WriteLn UNTIL z #$0D END. Versuch bereit an LPT 1, 2, 3 oder 4 ->2 tl=65324 t2=59248
Messzeit:
2.546 msek
weiter mit er ->
Bild 9-54: "digitale" Widerstandsmessung am Druckerport Am Druckerportausgang DO liegt ein Treiber mit offenem Kollektor mit dem zu messenden Widerstand im Arbeitszweig g e g e n High und dem Ladekondensator gegen Low. Ist der Ausgang DO zunächst High, so schaltet der I n v e r t e r durch ( L o w ) und schließt den Kondensator kurz. Durch ein Low am Ausgang DO und Sperren des Ausgangstransistors kann sich nun der Kondensator über den Widerstand aufladen. Erreicht die Ladespannung die obere Schwellspannung (ca. 1.6 V) des I n v e r t e r s mit Schmitt-TriggerVerhalten, so wird nach nochmaliger Invertierung d e r Eingang ACK des Druckerports High. Damit ist die Widerstandsmessung (oder Temperaturmessung) auf eine Zeitmessung zurückgeführt, f ü r die in Abschnitt 9.1.1 mehrere Meßmethoden g e z e i g t wurden. Das Programmbeispiel arbeitet mit dem Systemtimer 0 ähnlich Bild 9-5. Bei der Auswertung der Ergebnisse zeigte es sich, daß statt der zu erwartenden Ladezeit von ca. 3.8 ms eine wesentlich g e r i n g e r e Zeit (ca. 2.53 ms) gemessen wurde. Ursache dafür sind das nicht-ideale Verhalten des Ausgangsschalters (74LS06) und des Pegelumschalters (74LS14). Eine Messung der Ladekurve ohne Belastung zeigte, daß die Schwellspannung von 1.6 V tatsächlich nach der zu erwartenden Zeit von ca. 3.8 ms erreicht wird. Trotz Wartens auf das Neuladen des Timers lieferte das erste Auslesen eine relativ große Streuung der Anfangswerte von 65 318 bis 65 334. Das in Bild 9-55 gezeigte Beispiel v e r zichtet daher auf das Auslesen des Startwertes und setzt ihn konstant auf einen Anfangswert von 65 320.
9.3 Beispiele aus der analogen
Meßtechnik
+
PROGRAM prog9p20; (* Bild 9-55: Impulslängenmessung * ) USES Crt; CONST ack = $40; (* Baske 0100 0000 ACK-Eingang *) VAR x,a : WORD; t i c , t l l . t l h , t21,t2h : BYTE; t l , t 2 : LONGINT; r,c : REAL; z : CHAR; BEGIN Wri te('Monof1opscha1tung Ladekondensator [uF] -> ' ) ; ReadLn(c); Write('Versuch bereit an LPT 1, 2, 3 oder 4 - > ' ) ; ReadLn(x); x := tlemW[$40 : 2*x + 6]; a := x+l; Port [x+0] := $01; (* Trigger High * ) REPEAT t i c := Hem[$40 : $6C]; WHILE t i c = Hem[$40 : $6C] DO; (* bis Timerstart *) Port[x+0] := $00; Port[x+0] := $01; (* Triggerimpuls * ) REPEAT UNTIL (Port[a] AND ack) = $00; ( « Flanke -> Low *) Port[$43]:=$00; t21:=Port[$40]; t2h:=Port[$40]; (* Ende *) t l := 65320; (* Startzeit k o r r . * ) t2 := WORD(t2h SHL 8) OR WORD(t21); (* Stopzeit *) r := ( t l - t 2 ) * 0 . 4 1 9 / ( 1 . l * c ) ; (* Widerstand Ohm * ) Write('t2 = ' , t 2 : 6 , ' Widerstand: ' , r : 6 : 3 , ' [Ohm]•); Write(' weiter mit er - > ' ) ; z := ReadKey; WriteLn UNTIL z #$0D END. Monoflopschaltung Ladekondensator [uF] ->1 Versuch bereit an LPT 1, 2, 3 oder 4 ->2 t2 = 40092 Widerstand: 9609.575 [Ohm] weiter mit er -> Bild 9-55: Widerstandsmessung mit Monoflop am Druckerport
229
230
9.
Anwendungsbeispiele
Der in dem Beispiel Bild 9-55 als Schalter verwendete Timer 555 enthält am Eingang zwei "hochohmige" Operationsverstärker. Im Ausgangszustand ist der interne Schalttransistor zunächst durchgeschaltet und schließt den Ladekondensator kurz. Ein Triggerimpuls am Ausgang DO des Druckerports schaltet das Flipflop um und sperrt den Transistor. Erreicht die Ladespannung des Kondensators den Schwellwert des oberen Operationsverstärkers, so kippt das Flipflop wieder in den Ausgangszustand zurück. Der Rechteckimpuls am Ausgang ist proportional dem zu messenden Widerstand. Seine Länge wurde mit dem Systemtimer 0 gemessen. Bei der praktischen Anwendung ist zu beachten, daß sich mit dem verwendeten Timer nur Zeiten bis zu 27.5 ms messen lassen. Dies läßt sich durch die Auswahl eines geeigneten Ladekondensators erreichen. Das in Bild 9-56 gezeigte Verfahren verwendet wieder den gleichen Baustein 555 zur WiderstandsFrequenz-Umsetzung.
+
Timer
555
1.W (R. • 2-R H 1 x = 68 Hz
n
x+0 schreiben
x+1 lesen
x+2 lesen
n
Rx = 10 KOhm
n
n . r
x+2 schreiben
x = Adresse Druckerport
PROGRAM USES CONST VAS
prog9p2l; (» Bild 9-56: Widerstands-Frequenzumsetzung *) Dos, Crt; ntic = 18; (* faktor * 54.9254 ms *) nr,x,a : WORD; zeit,alt,tic : BYTE; flanke : LONGINT; f,rl,rx,c : REAL; PROCEDURE timer; INTERRUPT; BEGIN Dec(zeit) END; BEGIN («Hauptprogramm*) Write('Multivibrator Widerstand Rl [kOhm] ->'); ReadLn(rl); Write('Ladekondensator Kapazität C [uF] ->'); ReadLn(c); Write('Versuch bereit an LPT 1, 2, 3 oder 4 ->'); ReadLn(nr); x := BemW[$40 : 2*nr +6]; a := x+1;
9.3 Beispiele aus der analogen
Meßtechnik
231
SetIntVec($lC,Addr(timer)); (* Timer Tic Benutzerinterrupt *) ClrScr; GotoXy(20,10); Write('Abbruch mit beliebiger Taste! •); REPEAT flanke := 0; (* Flankenzähler löschen tic := Hem[$40 : $6C]; WHILE tic = Mem[$40 : $6C] DO; (* Warten auf Neuladen *) zeit := ntic; (* Faktor * 55 ms *) alt := Port[a] AND $40; (* Ausgangszustand ACK *) REPEAT IF alt (Port[a] AND $40) THEN (* Flanken zählen *) BEGIN Inc(flanke); alt := Port[a] AND $40 END UNTIL zeit = 0; f := flanke * 0.5/(ntic*54.9254*le-3); (« Frequenz in Hz «) IF f = 0 THEN rx := le37 ELSE rx := 0.5*(1.44/(f*c*le-6) - rl*le3); GotoXY(25,15); IF rx < le6 THEN Write('f =',f:8:l,' Hz Rx =',rx:8:l,' Ohm') ELSE Write('f =',f:8:l,' Hz Rx= , ,rx:8,' 0hm') UNTIL KeyPressed; ClrScr; END.
Abbruch mit beliebiger Taste!
f =
80.9 Hz
Rx =
8397.9 Ohm
Bild 9-56: W i d e r s t a n d s - F r e q u e n z - U m s e t z u n g am D r u c k e r p o r t Die S c h a l t u n g a r b e i t e t a l s M u l t i v i b r a t o r ( F r e q u e n z g e n e r a t o r ) . Der Widers t a n d Rx b e s t i m m t d i e E n t l a d e z e i t d e s K o n d e n s a t o r s b i s z u r u n t e r e n Ums c h a l t s c h w e l l e ( 1 / 3 Vcc). Die R e i h e n s c h a l t u n g d e r b e i d e n W i d e r s t ä n d e (R1 + Rx) b e s t i m m t d i e L a d e z e i t d e r K o n d e n s a t o r s b i s z u r o b e r e n U m s c h a l t s c h w e l l e ( 2 / 3 Vcc). Am A u s g a n g e r g i b t s i c h e i n e R e c h t e c k s c h w i n g u n g . Bei R1 k l e i n g e g e n Rx i s t d a s T a s t v e r h ä l t n i s a n n ä h e r n d 1:1. Die A u s g a n g s f r e q u e n z läßt s i c h mit einem d e r i n A b s c h n i t t 9.1.2 b e s c h r i e b e n e n V e r f a h r e n m e s s e n . Sie i s t p r o p o r t i o n a l dem W i d e r s t a n d Rx u n d damit d e r z u m e s s e n d e n p h y s i k a l i s c h e n Größe ( T e m p e r a t u r ) . Das B e i s p i e l v e r w e n d e t d a s i n Bild 9 - 1 0 d a r g e s t e l l t e F r e q u e n z m e ß v e r f a h r e n mit dem S y s t e m t i m e r 0. Die o b e r e F r e q u e n z g r e n z e l i e g t j e n a c h v e r w e n d e t e m R e c h n e r b e i 20 b i s 40 kHz. D i e s e B e d i n g u n g läßt s i c h d u r c h d i e Wahl e i n e s g e e i g n e t e n L a d e k o n d e n s a t o r s e r r e i c h e n . Der V o r w i d e r s t a n d R1 s o l l t e s o g e w ä h l t w e r d e n , daß s i c h e i n T a s t v e r h ä l t n i s v o n a n n ä h e r n d 1:1 e r g i b t . F ü r e i n e r e c h n e r u n a b h ä n g i g e M e s s u n g müßte e i n e x t e r n e r T i m e r b a u s t e i n (Bild 9 - 1 5 ) h e r a n g e z o gen werden. Die V e r f a h r e n z u r M e s s u n g v o n W i d e r s t ä n d e n mit R C - S c h a l t u n g e n l a s s e n s i c h a u c h f ü r d i e M e s s u n g v o n K a p a z i t ä t e n v e r w e n d e n , w e n n d i e Größe d e s L a d e w i d e r s t a n d e s b e k a n n t i s t . Der n ä c h s t e A b s c h n i t t z e i g t W i d e r s t a n d s m e s s u n g e n mit A n a l o g / D i g i t a l w a n d l e r n z.B. z u r A u f n a h m e v o n K e n n l i n i e n nichtlinearer Widerstände.
232
9.3.2
9.
Anwendungsbeispiele
Die Messung von Spannungen und Strömen
Orientierenden Versuche können mit d e r in Bild 9-57 dargestellten Analogperipherie d u r c h g e f ü h r t werden. Die Wandlerbausteine wurden bereits im Abschnitt 4.3 (Bild 4 - 7 ) besprochen. Der Digital/Analogwandler dient zur Erzeugung einer veränderlichen Betriebsspannung ( - 2 . 5 V bis +2.5 V), wie sie z.B. für die Aufnahme von Kennlinien von Dioden und Transistoren b e nötigt wird. Die Spannung wird mit einem Analog/Digitalwandler ebenfalls im Bereich von - 2 . 5 V bis +2.5 V gemessen. Die Strommessung wird auf die Messung der Spannung an einem bekannten Widerstand zurückgeführt. Der Widerstandswert ist so zu wählen, daß sich eine genügend große Meßspannung ergibt. Sein Einfluß läßt sich r e c h n e r i s c h eliminieren.
x = Adresse Druckerport
PROGRÄM prog9p22; (* Bild 9-57: Kalibrierung der Wandler *) USES Iecbus; (* Init, Auslist, Eintalk, Frei *) VAR status,daten,xl,x2 : BYTE; nr,x : WORD; name, wert : STRING; tab : ARRAY[0..255,1..3] OF REAL; fehler,i,j : INTEGER; udaten,idaten : FILE OF REAL; 2 : CHAR; BEGIN Write('Hultimeter bereit ? Hit er bestätigen! -> '); ReadLn; Init(status,daten); (* IEC-Bus und Gerät initialisieren *) Write('Wandler bereit an LPT 1, 2, 3 oder 4 -> '); ReadLn(nr); x := MemW[$40 : nr*2 +6];
9.3 Beispiele aus der analogen
Meßtechnik
233
Port[x+2] := $04; (* CS = High ") Port[x+2] := $0C; (* CS = Low *) xl := Port[x+1]; x2 := Port[x+2]; (* auslesen *) Port[x+2] := $04; (* CS = High *) UriteLn('Aus Ein Diff Ugem Igem Rgem ' ) ; FOR i := 0 TO 255 DO BEGIN Port[x+0] := i ; (* Ausgangsspannung e i n s t e l l e n *) INLINE($FA); (* CLI = Interrupts gesperrt *) Port[x+2] := $0C; (* 0000 1100 B3 = CS = Low *) FOR j := 1 TO 100 DO; (* Warten auf Einstellung *) (* AD/Wandler lesen *) xl := Port[x+1]; x2 := Port[x+2]; t a b [ i , 1 ] := ((xl XOR $80) AND $F8) OR ((x2 XOR $03) AND $07); Port[x+2] := $04; (* 0000 0100 B4 = CS = High *) INLINE($FA); (* STI = Interrupts f r e i *) Auslist(7,'VD AI T3 S1 LO QO M0\#$0D); (* Kanal 0 Spannung *) Eintalk(7,wert,#$0A); (* Vergleichsspannung messen *) Val(wert,tab[i,2].fehler); (" nach REAL umwandeln Tabelle *) IF fehler 0 THEN VriteLn('U-Umwandlungsfehler ! ! ! ! ! ! • ) ; Auslist(7, 1 ID AI T3 S1 LO QO H1',#$0D); (» Kanal 1 Strom *) Eintalk(7,wert,#$0A); (* 1 kOhm Nennwert *) Val(wert,tab[i,3],fehler); (« nach REAL umwandeln Tabelle *) If f e h l e r 0 THEN WriteLn('I-Umwandlungsfehler ! ! ! ! ! ! ! ' ) ; W r i t e L n ( i : 3 , t a b [ i , 1 ] : 5 : 0 , i - t a b [ i , l ] : 5 : 0 , t a b [ i , 2 ] : 8 : 3 , ' [V]', t a b [ i , 3 ] * l e 3 : 8 : 3 , ' [ m A ] ' , t a b [ i , 2 ] / t a b [ i , 3 ] : 1 0 : 3 , ' [Ohm]'); END; Aus l i s t (7, 'VD AI T3 S1 LO QO tIO',#$OD); (« Voltmeter *) frei(7,status,daten); Write('Kennlinien a l s Datei speichern? j a = j er - > ' ) ; ReadLn(z); IF (z = ' J ' ) OR (z = ' j ' ) THEN BEGIN Write('Spannungskennlinie Dateiname xxxxxxxx.RDA:1); ReadLn(name); Assign(udaten,name); Rewrite(udaten); FOR i := 0 TO 255 DO Write(udaten,tab[i,2]); Close (udaten); Write('Stromkennlinie Dateiname xxxxxxxx.RDA:1); ReadLn(name); Assign(idaten,name); Rewrite(idaten); FOR i := 0 TO 255 DO W r i t e ( i d a t e n , t a b [ i , 3 ] ) ; Close(idaten) END END. Hultimeter b e r e i t ? Hit er bestätigen! -> Wandler bereit an LPT 1, 2, 3 oder 4 -> 2 Aus Ein Diff Ugem Igem Rgem 0 0 0 - 2 . 5 0 5 [V] -2.490 [mA] 1006.064 [Ohm] 1 0 1 - 2 . 4 8 5 [V] -2.470 [mA] 1006.219 [Ohm] 2 0 2 - 2 . 4 6 6 [V] -2.450 [mA] 1006.445 [Ohm] Bild
9-57:
Die Kalibrierung d e r Wandler
Die Kalibrierung d e r Anordnung e r f o l g t in dem Beispiel Bild 9-57 mit einem Multimeter ü b e r den IEC-Bus (Kapitel 8), sonst wären die Ablesewerte von Meßgeräten ü b e r die T a s t a t u r einzugeben. Die als Dateien abgelegten Kalib r i e r t a b e l l e n b e s t e h e n jeweils aus einem Feld von 256 REAL-Größen. Der Wandlerwert vom Datentyp BYTE im Bereich von 0 bis 255 l i e f e r t dabei die Indexposition f ü r den S p a n n u n g s w e r t als REAL-Zahl im Bereich von -2.5
234
9.
Anwendungsbeispiele
bis +2.5 Volt. Gleiches gilt für die Stromtabelle, die f ü r jeden Strommeßwiderstand neu aufgenommen werden muß. Bild 9-58 zeigt ein Beispiel f ü r die Verwendung der Spannungstabelle bei der Messung der Kennlinie eines "spannungsgesteuerten" Widerstandes.
Ub = +2.5V
PROGRAM prog9p23; (* Bild 9-58: Kennlinienaufnahme * ) VAU wert,xl,x2 : BYTE; nr,x : WORD; spann : ARRAY[0..255] OF REAL; i,j,u,ua,ue,us : INTEGER; spandatei : FILE OF REAL; uaus,uein,r2,rl,uges : REAL; z : CHAR; BEGIN Assign(spandatei,'nspan.RDA'); (* Kalibrierung Bild 9-57 *) ( * $ I - * ) Reset(spandatei) (*$I+*); (* Spannungen [V] ") IF IOResult 0 THEN WriteLn('Datei >NSPAN.RDA< f e h l t ' ) ; FOR i := 0 TO 255 DO Read(spandatei,spann[i]); WriteLn(Filesize(spandatei),' Kalibrierwerte gelesen'); Close(spandatei); Write('Versuch bereit an LPT 1, 2, 3 oder 4 -> ' ) ; ReadLn(nr); x := HemW[$40 : nr*2 +6]; Port[x+2] := $04; (* CS = High * ) Port[x+2] := $OC; (* CS = Low * ) xl := P o r t [ x + l ] ; x2 := Port[x+2]; (* auslesen * ) Port[x+2] := $04; (* CS = High * ) Write('Uges [V] Rvor [Ohm] - > ' ) ; ReadLn(uges,rl); REPEAT WriteLnCO = ', spann[0] :6:3, ' [V] 255 = ', spann[255] :6:3, ' [V] ' ) ; Write('Ua üe Us eingeben als Index (0. .255) - > ' ) ; ReadLn(ua,ue,us); WriteLnC Analog-Ausgang Analog-Eingang Widerstand'); u := ua; (* Anfangswert Ausgangsspannung *)
9.3 Beispiele aus der analogen
Meßtechnik
235
WHILE u ' ) ; ReadLn(z); UNTIL (z ' j ' ) AND (z ' J ' ) END. 256 Kalibrierwerte gelesen Versuch bereit an LPT 1, 2, 3 oder 4 -> 2 Uges [V] Rvor [Ohm] ->2.43 1000 0 = -2.505[V] 255 = 2.505[V] Ua Ue Us eingeben als Index (0..255) ->0 127 10 Analog-Ausgang Analog-Eingang Widerstand 2 387 [V] 55696 220 [Ohm] ( 0) Ua= -2 505 [V] Ue= ( 10) Ua= -2 310 [V] Ue= 2 387 [V] 55696 220 [Ohm] 2 349 [V] 28848 913 [Ohm] ( 20) Ua= -2 113 [V] Ue= 2 270 [V] 14179 910 [Ohm] ( 30) Ua= -1 917 [V] Ue= 2 093 [V] 6205 978 [Ohm] ( 40) Ua= -1 723 [V] Ue= 1 839 [V] 3111 786 [Ohm] ( 50) Ua= -1 526 [V] Ue= ( 60) Ua= -1 330 [V] Ue= 1 525 [V] 1685 475 [Ohm] 920 716 [Ohm] 1 165 [V] ( 70) Ua= -1 127 [V] Ue= 598 696 [Ohm] 0 910 [V] ( 80) Ua= -0 931 [V] Ue= 432 796 [Ohm] 0 734 [V] ( 90) Ua= -0 668 [V] Ue= (100) Ua= -0 537 [V] Ue= 0 636 [V] 354 146 [Ohm] 284.430 [Ohm] 0 538 [V] (110) Ua= -0 350 [V] Ue= 245 930 [Ohm] (120) Ua= -0 155 [V] Ue= 0 480 [V] Noch eine Messung? ja = j er ->n Bild 9-58: Kennlinie eines spannungsgesteuerten Widerstandes Nach dem Einlesen der Kalibriertabelle f ü r die Spannungen gibt der Benutzer den Bereich der Ausgangsspanung nicht als Spannungswert, sondern nur als Index an. Dies hat den Vorteil, daß keine aufwendigen Tabellensuch- und Interpolationsverfahren erforderlich sind. Für die Berechnung des veränderlichen Widerstandes aus der Teilerformel sind Angaben über die konstante Betriebsspannung und den Vorwiderstand einzugeben. Der Bereich der Steuerspannung (Anfangswert, Endwert und Schrittweite) läßt sich beliebig oft verändern, bis ein f ü r den Benutzer interessanter Ausschnitt aus der Kennlinie erreicht ist. Die aufgenommene Kennlinie ließe sich in einem Feld speichern und auch als Datei ablegen, um sie graphisch auszugeben (Programme Bilder 9-46 und 9-47) oder zur Linearisierung von Messungen zu verwenden.
236
9.
Anwendungsbeispiele
2 Analogausgaben
Bild
8 analoge
5 digitale
Eingang
9-59: E r w e i t e r t e A n a l o g p e r i p h e r i e am D r u c k e r p o r t
Die i n Bild 9-59 d a r g e s t e l l t e S c h a l t u n g z e i g t u n i v e r s e l l v e r w e n d b a r e A n a l o g s c h a l t u n g e n am b i d i r e k t i o n a l e n B u s d e s D r u c k e r p o r t s (Bild 9 - 2 6 ) . S i e b e s t e h e n a u s zwei Digital/Analogwandlern z u r A u s g a b e v o n B e t r i e b s - u n d S t e u e r s p a n n u n g e n , einem Analog/Digital Wandler, d e r sich d u r c h einen Analogmultiplexer auf m e h r e r e Meßkanäle e r w e i t e r n läßt, einem 8 - b i t S p e i c h e r f ü r digitale A u s g a n g s s i g n a l e u n d einem digitalen E i n g a n g mit Schmitt-Trigger-Verhalten.
9.3 Beispiele aus der analogen
9.3.3
Meßtechnik
237
Die Aufzeichnung analoger Größen
Trigger-
8 analoge Eingänge
Trigger-
Die in Bild 9-60 d a r g e s t e l l t e S c h a l t u n g d i e n t z u r A u f z e i c h n u n g a n a l o g e r Größen. Sie b e s t e h t a u s dem b e r e i t s b e h a n d e l t e n Analog/Digitalwandler mit S a m p l e - A n d - H o l d - S c h a l t u n g u n d einem z u s ä t z l i c h e n 8-Kanal-Multiplexer, d e r von d e n d r e i u n t e r s t e n Bitpositionen des D r u c k e r p o r t a u s g a n g s g e s t e u e r t wird. Die h ö c h s t e Bitposition übernimmt d a s Auslesen d e s Wandlers u n d l i e f e r t gleichzeitig ein S t e u e r s i g n a l , daß die A u f z e i c h n u n g b e r e i t i s t . D a d u r c h e n t f ä l l t j e d o c h d e r A n a l o g a u s g a n g ü b e r d e n Digital/Analog Wandler. Der E i n g a n g ERROR d e s S t e u e r p o r t s l i e f e r t ü b e r einen P e g e l u m s e t z e r d a s T r i g g e r s i g n a l f ü r d e n S t a r t d e r A u f z e i c h n u n g . Die S c h a l t u n g f o r m t ein Analogsignal in ein T T L - R e c h t e c k s i g n a l um. Der V o r w i d e r s t a n d (20 kOhm) muß g e g e b e n e n f a l l s d e r Amplitude d e s Analogsignals a n g e p a ß t w e r d e n , damit sich am A u s g a n g ein s a u b e r e s Rechteck e r g i b t . Bild 9-61 zeigt die A u f z e i c h n u n g l a n g s a m e r Vorgänge mit allen a c h t Kanälen, wie sie z.B. f ü r die Messung d e r T e m p e r a t u r v e r t e i l u n g in Räumen v e r w e n d e t w e r d e n k a n n . Die A u s g a b e d e r Kanäle e r f o l g t in dem Beispiel als Ablesewert d e s Wandlerb a u s t e i n s u n d müßte ü b e r eine Kalibriertabelle in eine S p a n n u n g o d e r e i n e n Strom o d e r eine p h y s i k a l i s c h e Meßgröße (z. B. eine T e m p e r a t u r ) u m g e f o r m t w e r d e n (Beispiel Bild 9-58). Durch Eingabe e i n e r Wartezeit in d e r Einheit Millisekunde l a s s e n sich a u c h langsame Ä n d e r u n g e n im Z e i t r a f f e r a u f n e h m e n . Die A u f z e i c h n u n g b e g i n n t ohne e x t e r n e T r i g g e r u n g n a c h d e r E i n g a b e d e r A b t a s t r a t e . Das in Bild 9-46 d a r g e s t e l l t e P r o g r a m m b e i s p i e l zeigt, wie sich die E r g e b n i s s e a u c h als K u r v e n auf dem G r a p h i k b i l d s c h i r m darstellen lassen.
238
9.
Anwendungsbeispiele
PROGRAH prog9p24; (* Bild 9-61: 8-Kanal-AnalogaufZeichnung *) USES Crt; VAR x,nr,warte : WORD; kanal : ARRAY[1..8] OF BYTE; i,runess,nkanal,j : INTEGER; BEGIN Write('8 Kanäle an LPT 1, 2, 3 oder 4 -> '); ReadLn(nr); x := MemW[$40 : nr«2 + 6] ; Port[x+0] := $80; (* 1000 0000 CS High Kanal 000 *) Port[x+2] := $04; (* 0000 0100 Ausgänge High *) Write(' Anzahl der Aufzeichnungen -> '); ReadLn(nmess); Write(' Aufzeichnungsrate [ms] -> '); ReadLn(uarte); WriteLnC Nr. Kanall Kanal2 Kanal3 Kanal4 Kanal5 Kanal6 Kanal7 Kanals'); FOR i := 1 TO nmess DO BEGIN FOR j := 0 TO 7 DO BEGIN Port[x+0] := j OR $80; (* CS = HIGH Kanalauswahl *) Port[x+0] := j; (* CS = Low «) kanal[j+l]:= ((Port[x+l] XOR $80) AND $F0) OR ((Port[x+2] XOR $0B) AND $0F); Port[x+0] := j OR $80; (* CS = High *) END; Write(i:4); FOR j := 1 TO 8 DO Write(kanal[j]:7); WriteLn; Delay(warte); (* Warten auf nächste nessung *) END END. 8 Kanäle an LPT 1, 2, 3 oder 4 -> 2 Anzahl der Aufzeichnungen -> 19 Aufzeichnungsrate [ms] -> 1 Nr. Kanall Kanal2 Kanal3 Kanal4 Kanal5 Kanal6 Kanal7 Kanal8 54 54 55 55 54 55 54 54 1 117 117 117 117 116 117 116 2 119 179 178 179 178 178 178 178 3 181 230 229 229 230 4 227 230 229 229 165 166 165 165 166 166 166 165 5 103 102 103 103 102 103 103 6 102 40 40 40 41 40 41 7 39 41 94 93 93 93 8 88 93 93 93 156 155 155 155 155 155 155 9 158 218 218 218 218 218 219 218 10 219 190 189 190 189 189 190 189 11 186 128 128 112 142 128 112 125 142 12 79 65 65 65 49 64 65 13 79 71 70 69 71 69 14 65 70 70 133 132 133 133 133 132 15 135 132 194 194 194 194 194 194 194 16 197 213 211 214 214 214 214 213 214 17 151 151 151 151 150 18 150 151 151 88 89 89 90 89 19 87 88 89 Bild 9-61: Langsame 8-Kanal-Analogauf Zeichnung
9.3 Beispiele aus der analogen Meßtechnik
239
PROGRAM prog9p25; (* Bild 9-62: Schnelle Analogaufzeichnung *) CONST nmax = 2048; (* max. Speichertiefe *) VAR x , a , b , n r , i , i a , i e , j , n m e s s : WORD; x l , x 2 , x 3 , x 4 : ARRAY[1..nmax] OF BYTE; aus : ARRAY[0..63] OF CHAR; k : BYTE; name,schrift : STRING; z : CHAR; daten : FILE OF BYTE; BEGIN Write('Versuch: -> ' ) ; ReadLn(schrift); Write('Vorgang an LPT 1, 2, 3 oder 4 -> '); ReadLn(nr); x := HemW[$40 : nr*2 + 6 ] ; a := x+1; b := x+2; Port[b] := $04; (* 0000 0100 Ausgänge High *) REPEAT Write('Anzahl der Aufzeichnungen ( 1 . . ' , n m a x , ' ) -> '); ReadLn(nmess); UNTIL nmess '); ReadLn(name); Assign(daten,name); Rewrite(daten); FOR i := 1 TO nmess DO Write(daten,xl[i]); Close(daten); END; Write('Kanall [*] als Datei speichern? n/j er -> '); ReadLn(z); IF (z='j') OR (z='J') THEN BEGIN Write('Dateiname xxxxxxxx.BDA -> '); ReadLn(name); Assign(daten,name); Rewrite(daten); FOR i := 1 TO nmess DO Write(daten,x3[i]); Close(daten); END END. Versuch: -> KanalO: 1 kHz Dreieck Kanall: TTL-Pegel und Trigger Vorgang an LPT 1, 2, 3 oder 4 -> 2 Anzahl der Aufzeichnungen (1..2048) -> 2048 KanalO: 1 kHz Dreieck Kanall: TTL-Pegel und Trigger Anfangsindex und Endindex [1..2048] -> 1 24 Nr. Trigger KanalO: Harke e Kanal_l: Marke * 6
1
2
3 4 5 6
7 8 9
10
11 12
13 14 15 16
17 18
19 20 21 22
23 24
e e
e
Noch eine Ausgabe? n/j er -> n KanalO [6] als Datei speichern? n/j er -> j Dateiname xxxxxxxx.BDA -> testO.bda Kanall [*] als Datei speichern? n/j er -> j Dateiname xxxxxxxx.BDA -> testl.bda Bild 9-62: Schnelle 2-Kanal-Analogaufzeichnung
9.3 Beispiele aus der analogen
Meßtechnik
241
Das in Bild 9-62 dargestellte Programmbeispiel dient zur Aufzeichnung analoger Vorgänge ähnlich einem Speicheroszilloskop, nur wesentlich langsamer! Es lassen sich sowohl periodische als auch einmalige Vorgänge aufzeichnen. Mit den beiden Kanälen wurde eine Abtastrate von ca. 15 fis/ Kanal erreicht. Die Schaltung Bild 9-60 erlaubt die Abtastung von bis zu 8 Kanälen, jedoch vermindert sich dabei die Abtastrate. Bei dem verwendeten Rechner war es erforderlich, die Zugriffszeit auf den Wandlerbaustein künstlich zu verlängern (3 Anweisungen P o r t [ x ] := $00;)! Die gewandelten Daten werden f ü r beide Kanäle zunächst in zwei Feldern getrennt nach den beiden Eingabeports abgespeichert und erst in einer Aufbereitungsschleife richtig zusammengesetzt. Dabei ergibt sich ein dritter "digitaler" Triggerkanal. Die Ausgabe erfolgt zunächst in einem groben Raster auf dem Zeichenbildschirm ähnlich Bild 9-25 mit Blockgraphikzeichen. Dabei läuft die Zeitachse senkrecht. Anhand dieser Darstellung kann der Benutzer entscheiden, ob die Aufzeichnungen als Dateien f ü r eine weitere Auswertung abgespeichert werden sollen. Bild 9-63 zeigt die Anzeige mit dem in den Bildern 9-44 bis 9-48 dargestellten Programm auf dem Graphikbildschirm mit Druckerausgabe. Dabei läuft die Zeitachse waagerecht.
Auswertung Bild 9-62 1 kHz Dreieck / TTL-Pegel Bild 9-63: Ausgabe der Aufzeichnung auf dem Graphikbildschirm
242
9.3.4
9.
Anwendungsbeispiele
Die Ausgabe analoger Größen Analogausgang
1
Zuordnung d i g i t a l analog $00 -2.5 V $7F 0 V $FF +2.5 V
Abbruch
Ö
TriggerAusgang
[t] X X X
x+0 schreiben
x+1 lesen
X
x+2 lesen
X X X
X X X 0
[t]
0 X X
x+2 schreiben
x = Adresse Druckerport
Bild 9-64: Digital/Analogwandler am Druckerport
Mit der in Bild 9-64 dargestellten Schaltung lassen sich analoge Werte an der Druckerschnittstelle ausgeben. Der 8-bit-Digital/Analogwandler liegt am Datenausgang und ist dauernd freigegeben. Alle Ausgabewerte werden im Wandlerbaustein digital gespeichert und erscheinen nach einer Umsetzzeit von ca. 1 fis am analogen Ausgang. In der angegebenen Schaltung entspricht der digitale Wert $00 einer analogen Ausgangsspannung von -2.5 Volt, der Wert $7F entspricht 0 Volt und der Wert $FF liefert +2.5 Volt. Anstelle des als Beispiel verwendeten einfachen Ausgangs ließen sich weitere Schaltungen anschließen wie z.B.: - eine Leistungsendstufe (Operationsverstärker mit einem Ausgangsstrom von z.B. 4 A) bzw. - ein unipolarer Ausgang (z.B. 0 bis + 10 Volt) bzw. - ein Verstärker mit einstellbarer Amplitude z.B. über einen zweiten Digital/Analogwandler bzw. - ein Ausgangskondensators zum Abblocken des Gleichspannungsanteils bzw. - ein analoges Tiefpassfilter zum Glätten der Kurvenform. Die Ausgabe der analogen Funktionen erfolgt periodisch. Der Anfang einer Ausgabeperiode wird durch ein Triggersignal am Ausgang DS angezeigt, das zum Triggern eines Oszilloskops bzw. zur Messung der Frequenz des Ausgangssignals verwendet werden kann. Der Eingang SLCT IN dient in den Programmbeispielen zum Abbruch der Ausgabeschleife, da während der Ausgabe alle Interrupts gesperrt werden.
9.3 Beispiele aus der analogen
Meßtechnik
PROGRAH prog9p26; (* Bild 9-65: Analoge Ausgabe am Druckerport *) CONST nmax = 20000; (* max. Anzahl von Aufzeichnungen *) VAR werte : ARRAY[1..nmax] OF BYTE; i, nwert,x,a,nr : WORD; name : STRING; daten : FILE OF BYTE; BEGIN WriteC Analoge Ausgabe an LPT 1, 2, 3 oder 4 -> '); ReadLn(nr); x := HemW[$40 : nr*2 + 6 ] ; a := x+2; Port[a] := $01; (* 0000 0001 Abbruch: SLCT IN High Trigger DS Low «) REPEAT Write('BYTE-AufZeichnung Dateiname xxxxxxxx.BDA -> '); ReadLn(name); Assign(daten,name); (*$I-*) Reset(daten) (*$I-*); UNTIL IOResult = 0; i := 1; REPEAT Read(daten,werte[i]); Inc(i) UNTIL Eof(daten) OR (i > nmax); nwert := i-l; Close(daten); WriteLn(nwert,' Werte geladen Abbruch mit SLCT IN = Low '); INLINE($FA); (* CLI Interrupt gesperrt ») REPEAT Port[a] := $00; Port[a] := $01; (* Triggerimpuls an DS *) FOR i := 1 TO nwert DO Port[x] := werte[i] UNTIL (Port[a] AND $08)= $08; (* Abbruch durch SLCT IN !!!*) INLINE($FB); (* STI Interrupt frei *) END. Analoge Ausgabe an LPT 1, 2, 3 oder 4 -> 2 BYTE-AufZeichnung Dateiname xxxxxxxx.BDA -> testo.bda 2048 Werte geladen Abbruch mit SLCT IN = Low
Ausgabe Bild 9-65 Aufnahme Bild 9-62 Bild 9-65: A u s g a b e v o n Dateien a m Druckerport
243
244
9.
Anwendungsbeispiele
In den Programmbeispielen zum "Logikanalysator" (Bild 9 - 2 4 ) und zum "Speicheroszilloskop" (Bild 9 - 6 2 ) war e s möglich, die g e s p e i c h e r t e n Werte als Datendatei abzulegen. Sie können mit dem in Bild 9-65 d a r g e s t e l l t e n Programmbeispiel geladen, analog a u s g e g e b e n und auf einem Oszilloskop s i c h t b a r gemacht werden. Der Ausgang DS liefert einen kurzen T r i g g e r impuls am Beginn einer Ausgabeperiode. Die Ausgabe am Digital/Analogwandler erfolgt in dem gleichen Datenformat (Datentyp B Y T E ) wie bei d e r Aufnahme am digitalen 8 - b i t - P o r t bzw. am Analog/Digitalwandler. Die Änd e r u n g des Zeitmaßstabs sowohl bei d e r Abtastung und als auch bei d e r Ausgabe kann d u r c h eine Kalibrierung mit einer bekannten Meßfrequenz b e r ü c k s i c h t i g t werden. PROGRAM prog9p27; (* Bild 9-66: Analoger Funktionsgenerator *) CONST nwert = 360; (* Anzahl der Funktionswerte pro Periode *) VAR byteaus : ARRAY[1..nwert] OF BYTE; realaus : ARRAY[1..nwert] OF REAL; i,j,x,a,nr,verz : WORD; trigger : BYTE; rmax,rmin : REAL; name : STRING; bytedaten : FILE OF BYTE; realdaten : FILE OF REAL; z : CHAR; (* ***** Ausgabefunktion als FUNCTION vom Datentyp REAL **** *) FUNCTION ausgabe(x : REAL) : REAL; BEGIN ausgabe := sin(x*Pi/180) + sin(3*x*Pi/180)/3 END; BEGIN Write('Analoge Ausgabe an LPT1, 2, 3 oder 4 -> '); ReadLn(nr); x := HemW[$40 : nr*2 + 6]; a := x+2; trigger := $01; Port[a] := trigger; (* SLCT IN = High DS = Low *) (» Ausgabefunktion vom Datentyp REAL aufbauen FUNCTION ausgabe ») FOR i:= 1 TO nwert DO realaus[i] := ausgabe(i-l); (* Umwandeln nach Datentyp BYTE fii- Ausgabe Digital/Analogwandler*) rmax := realaus[l]; rmin := realausfl]; FOR i := 2 TO nwert DO (* Extremwerte suchen für Normierung *) BEGIN IF realaus[i] < rmin THEN rmin := realaus[i]; IF realaus[i] > rmax THEN rmax := realaus[i] END; FOR i := 1 TO nwert DO (* Ausgabebereich 0..255 normieren *) byteaus[i] := Round(255*(realaus[i] - rmin)/(rmax - rmin)); Write('Verzögerung pro Ausgabewert eingeben -> '); ReadLn(verz); WriteLnCAbbruch der Ausgabe durch SLCT IN !!! ! '); INLINE($FA); (* CLI Interrupt gesperrt *) REPEAT trigger ;= trigger XOR $01; (* Trigger-Rechtecksignal *) Port[a] := trigger; (* ausgeben an DS *) FOR i := 1 TO nwert DO BEGIN Portfx] := byteausfi]; FOR j := 1 TO verz DO; (« Verzögerung *) END UNTIL (Port[a] AND $08) = $08; (* Abbruch SLCT IN *) INLINE($FB); (* STI Interrupt frei *)
9.3 Beispiele aus der analogen
Meßtechnik
245
Write('REAL-Funktionswerte als Datei speichern? j/n er -> '); ReadLn(z); IF (z = • j') OR (z = ' J") THEN BEGIN Write('Dateiname xxxxxxxx.RDA -> '); ReadLn(name); Assign(realdaten,name); Rewrite(realdaten); FOR i := 1 TO nwert DO Write(realdaten,realaus[i]); Close(realdaten) END; Write('BYTE-Wandlerausgabe als Datei speichern? j/n er -> '); ReadLn(z); IF (z = 'j') OR (z = 'J') THEN BEGIN Write('Dateiname xxxxxxxx.BDA -> '); ReadLn(name); Assign(bytedaten,name); Rewrite(bytedaten); FOR i := 1 TO nwert DO Write(bytedaten,byteaus[i]); Close(bytedaten) END END. Analoge Ausgabe an LPT1, 2, 3 oder 4 -> 2 Verzögerung pro Ausgabewert eingeben -> 0 Abbruch der Ausgabe durch SLCT IN !!!! REAL-Funktionswerte als Datei speichern? j/n er -> j Dateiname xxxxxxxx.RDA -> analog.rda BYTE-Wandlerausgabe als Datei speichern? j/n er -> j Dateiname xxxxxxxx.BDA -> analog.bda
"1
r "
Bild 9-66: Kanal_l: Funktion
Kanal_2: Trigger-Rechteck
Bild 9-66: Analoger F u n k t i o n s g e n e r a t o r am D r u c k e r p o r t
Mit dem in Bild 9-66 d a r g e s t e l l t e n Programmbeispiel l a s s e n s i c h als Formel v o r g e b b a r e F u n k t i o n e n analog a u s g e b e n . Die Formel sowie die Anzahl u n d d e r Bereich d e r F u n k t i o n s w e r t e m ü s s e n j e w e i l s im Programm g e ä n d e r t w e r d e n . Das Beispiel g i b t die Grundwelle d e r S i n u s f u n k t i o n u n d die d r i t t e Oberwelle a n a l o g a u s . Aus dem FUNCTION-Unterprogramm e n t s t e h t z u n ä c h s t e i n e F u n k t i o n s t a b e l l e vom D a t e n t y p REAL u n d d a n n n a c h e i n e r Normierung die e i g e n t l i c h e A u s g a b e t a b e l l e f ü r d e n D i g i t a l / A n a l o g w a n d l e r
246
9.
Anwendungsbeispiele
vom Datentyp BYTE. Beide Tabellen lassen sich auch als Datendateien für weitere Untersuchungen ablegen. Der Zeitmaßstab läßt sich durch die Eingabe eines Verzögerungswertes in Stufen einstellen. Als Triggersignal erscheint eine Rechteckfunktion mit der halben Ausgabefrequenz, mit der sich die Anordnung kalibrieren läßt. Bei dem verwendeten Rechner ergab sich bei einem Verzögerungswert von 0 eine Frequenz von ca. 370 Hz am Ausgang (Sinus mit 3. Oberwelle). Die in den Bildern 9-63, 9-65 und 9-66 dargestellten Ergebnisse wurden mit einem "echten" Speicheroszilloskop aufgenommen, mit dem Programmbeispiel Abschnitt 9.2.4 ausgelesen und auf dem Drucker ausgegeben. Die deutlich erkennbaren Unregelmäßigkeiten zeigen die Schwierigkeiten, die an den Schnittstellen zwischen der analogen und der digitalen Welt auftauchen können.
9.3.5
Beispiel eines digitalen Filters
In der Analogtechnik werden passive Filter aus Induktivitäten und Kapazitäten sowie aktive Filter aus Kapazitäten, Widerständen und Operationsverstärkern aufgebaut. Ein Beispiel für ein Filter ist ein Tiefpaß, der die tiefen Frequenzanteile eines Signals durchläßt und die höheren Frequenzanteile oberhalb der Grenzfrequenz stark dämpft. Bei einem digitalen Filter wird das analoge Eingangssignal mit einem Analog/Digitalwandler abgetastet, einem Berechnungsverfahren unterworfen und mit einem Digital/ Analogwandler wieder analog ausgegeben. Bei einem rekursiven Filter werden für die Berechnung eines Ausgangswertes sowohl der aktuelle Abtastwert als auch alte Abtast- und Ausgangswerte verwendet. Für ein Filter 1. Ordnung gilt: Y(k)
= D l - X ( k ) + DO-X(k-l) -
CO-Y(k-l)
Y ( k ) = Ausgangswert der Abtastung k X ( k) = Abtastwert der Abtastung k Y ( k - l ) = Ausgangswert der vorhergehenden Abtastung k-1 X ( k - l ) = Abtastwert der vorhergehenden Abtastung k-1 Dl, DO, CO = Koeffizienten (Filtertyp, Güte, Grenzfrequenz) Die Koeffizienten lassen sich aus dem Filtertyp (Tiefpaß), der gewünschten Grenzfrequenz, der Abtastfrequenz und der Filtergüte berechnen. Rekursive digitale Filter höherer Ordnung berücksichtigen noch weiterzurückliegende Ausgangs- und Abtastwerte. Bild 9-67 zeigt eine Schaltung mit Wandlern am Druckerport sowie ein Beispielprogramm, mit dem sich die Arbeitsweise eines digitalen Filters demonstrieren läßt.
9.3 Beispiele aus der analogen
x+0 schreiben
x+1 lesen
x+2 lesen
Meßtechnik
x+2 schreiben
x = Adresse Druckerport
L. PROGRAM prog9p30; (* B i l d 9-67: Digitaler Tiefpass *) (*$N+*) (* Numerikprozessor *) VAR xp,a,b,nr,i,abt : WORD; xl,x2,ein,aus : BYTE; alt,dO,dl,cO,x,y : EXTENDED; 2 : CHAR; BEGIN Write('Signal an LPT 1, 2, 3 oder 4 - > ' ) ; ReadLn(nr); xp := MemW[$40 : nr*2 + 6 ] ; a := xp + 1; b := xp + 2; Port[b] := $04; (* 0000 0100 CS = High REPEAT WriteLn('Filter 1. Ordnung y(k) = Dl*X(k) + D0*X(k-l) - C 0 * Y ( k - l ) ' ) ; WriteC Dl DO CO eingeben -> ' ) ; ReadLn(dl,dO,cO); Write(' Abtastverzögerung -> ' ) ; ReadLn(abt); WriteLnCAbbruch durch Signal SLCT IN = Low ! ! ! ! ! ' ) ; INLINE($FA); CLI Interrupt gesperrt x := 1; y := 1; Startwerte *) REPEAT alt := dO*x - c0*y; (* alter Anteil *) FOR i := 1 TO abt DO; (* Abtastverzögerung *) Port [b] := $0C; (* 0000 1100 CS = Low xl Port[a]; x2 := Port[b]; (* Wandler lesen Port [b] := $04; (* 0000 0100 CS = High *) ein := ((xl XOR $80) AMD $F8) OR ((x2 XOR $03) AND $07); x := ein - 127; (* Eingabewert -127..+127 *) y := dl*x + a l t ; (* Ausgabewert -127..+127 *) Port[xp]:=Round(y) + 127; (« Wandlerausgabe $00..$FF*) UNTIL (Port[b] AND $08) = $08; (* Abbruchsignal ? «) INLINE($FB); (* STI Interrupt frei *) Write('Neue Koeffizienten? ja = j er -> ' ) ; ReadLn(z); (* Programmabbruch *) UNTIL (z ' J ' ) AND (z ' j ' ) END.
247
248
9.
Anwendungsbeispiele
Signal an LPT 1, 2, 3 oder 4 ->2 Filter 1. Ordnung y(k) = Dl*X(k) + D0*X(k-l) - CO*Y(k-l) Dl DO CO eingeben -> 0.1 0.1 -0.98 Abtastverzögerung -> 0 Abbruch durch Signal SLCT IN = Low !!! !! Neue Koeffizienten? ja = j er -> n Bild 9-67: Schaltung und Programm f ü r ein digitales Filter
Die Schaltung besteht aus einem Analog/Digitalwandler mit Abtast- und Halteglied (Sample-And-Hold) zur Abtastung des Analogsignals sowie einem Analog/Digitalwandler zur Ausgabe des gefilterten Signals. Die Abtastrate wird im Programm durch eine programmierbare Verzögerungsschleife eingestellt und muß durch eine oszilloskopische Messung kalibriert werden. Der in dem Beispiel verwendete Rechner lieferte mit Arithmetikprozessor bei einem Verzögerungswert von 0 eine Abtastrate von ca. 100 /iS (10 kHz). Durch Eingabe der Filterkoeffizienten und der Abtastrate lassen sich v e r schiedene Filter programmieren. Das Beispiel zeigt ein Tiefpaßfilter mit den Koeffizienten Dl = 0.1, DO = 0.1 und CO = -0.98 bei einer Abtastfrequenz von 10 kHz (Verzögerung 0) und einer Grenzfrequenz von ca. 100 Hz. Der als Meßsender verwendete Wobbeigenerator lieferte eine Anfangsfrequenz von ca. 50 Hz und eine Endfrequenz von ca. 200 Hz (Oberer Kanal). Das im unteren Kanal dargestellte Ausgangssignal zeigt bei höheren Frequenzen eine starke Dämpfung (Tiefpaß). Das Verhalten des digitalen Filters läßt sich durch analoge Tiefpaßfilter zur Bandbegrenzung am Eingang bzw. A u s gang der Wandler sowie durch Programmierung eines Filterverfahrens höherer Ordnung weiter verbessern.
Bild 9-67 Tiefpass
9,4 Beispiele für die Auswertung von Meßergebnissen
249
Eingang: Sinus
Ausgang
Bild 9-67 Tiefpass
Eingang: Dreieck
Ausgang
Bild 9-67 Tiefpass
9.4
Beispiele für die Auswertung von Meßergebnissen
Dieser Abschnitt beschränkt sich auf die Untersuchung von Funktionen, die in Tabellenform in einer Datei enthalten sind. Durch die Trennung von Aufzeichnung und Auswertung Ist es möglich, Ergebnisse nach verschiedenen Gesichtspunkten auszuwerten und miteinander zu vergleichen. Für den Test der Verfahren ist es zweckmäßig, zunächst aus Formeln berechnete Funktionstabellen zu verwenden, von denen die Ergebnisse als geschlossene Lösungen existieren. Erst dann sollten auch Aufzeichnungen physikalischer Vorgänge mit Analog/Digitalwandlern untersucht werden. Bild 9-68 zeigt das bei der Auswertung verwendete Integrationsverfahren.
250
9. Anwendungsbeispiele
A 2
Y,
>3
F2
P 4 \ y5
>4
F3
\ f
5
Y 6 F6 Y 7 F7 Y 8 F j j / ^ Y,
— H , — — H2 — — H j — — H 4 X,
— H6 — — h 7 — X7
X, X„
x9 x„
Flächenberechnung: F, = ( X 2 - X , ) - ^
=
+
F2 = ( X 3 - X 2 ) . H ± I i = i l l . ( y 2
+
y3)
F7 = ( X 8 - X 7 ) . l i ± l » = i l i . ( y 7
+ y8)
F8 = ( X , - X 8 ) . Ä ± ^ = i i i . ( y 8
+
8 H[ 1 F = J f(x)dx = F, + F2 + - F 7 + F 8 = - ^ y, + y, + 2- 2 y j ; 2 l k=2 J
H
Xo_ x I
Allgemein bei n Stützstellen: J f(x)dx=äiy1 x 2 l
+
2 . 2 yi + yn] ¡«2 J
n— 1
Für periodische Funktionen (yi = y„) und eine Periode: X
f'tM, X -X "v Xe - XaJ v J f (x) dx = - ic — ^a • Z y r 2 y. n— 1 i=i N ,=i
N = Zahl der Flächen n = Zahl der Stützstellen
Arithmetischer Mittelwert: X m = 1 j f(x)dx = — i Ti i„ \Xc e•- X a
X„-X, 2 v = —- 2 yv N ¡=i y ' N ¡-i '
Quadratischer Mittelwert
Fourieranalyse: f (x) = a„ + a, • cosx + a2 • cos2x + ••• b! • sinx + b2 • sin2x + ••• ^
r
f (x) • cos k Bild 9-69: Auswahlmenü zur Auswertung v o n Meßergebnissen
Das in Bild 9-69 d a r g e s t e l l t e Programmbeispiel ermöglicht die Auswertung v o n Meßergebnissen a n d e r e r Programme nach v e r s c h i e d e n e n Gesichtspunkten. Die einzelnen Möglichkeiten werden in einem Menü ausgewählt und in den f o l g e n d e n Bildern näher erläutert. Da das Programm w e d e r Meßwerte d i r e k t einliest noch aus Funktionen berechnet, muß zunächst eine Datendatei entsprechend Bild 9-70 geladen werden.
252
9.
Anwendungsbeispiele
(* Bild 9-70: Laden der Funktionen von Datendateien *) 'L' : BEGIN FOR i := 1 TO pmax DO BEGIN rx[i] := 0; bx[i] 127 END; n := 0; WriteLn('REAL-Dateien werden im Bereich von 0 .. 255 ausgegeben'); WriteLn('BYTE-Dateien werden im Bereich von -1 .. +1 ausgewertet'); Write( 1 REAL- oder BYTE-Format? R/B -> '); z := UpCase(ReadKey); WriteLn(z,'DA'); : IF z = 'R' THEN BEGIN REPEAT Virite('Dateiname xxxxxxxx.RDA: '); ReadLn(name); Assign(rdaten.name); C$1-*) Reset(rdaten) (*$I+*); UNTIL IOResult = 0; i := 1; REPEAT Read(rdaten,rx[i]); Inc(i) UNTIL Eof(rdaten) OR (i > pmax); n := i-1; UriteLn(n,' Werte geladen 1 ); ia := 1; ie := n; Close(rdaten); max := rx[l]; min := rx[l]; (* Umwandlung nach BYTE 0..255 *) FOR i := 2 TO n DO BEGIN IF rx[i] > max THEN max := rx[i]; IF rx[i] < min THEN min := rx[i] END; FOR i := 1 TO n DO bx[i] := Round(255*(rx[i] - min)/(max - min)); END; IF z = 'B' THEN BEGIN REPEAT Write('Dateiname xxxxxxxx.BDA:'); ReadLn(name); Assign(bdaten,name); (*$I-*) Reset(bdaten) C$1-»); UNTIL IOResult = 0; i := 1; REPEAT Read(bdaten,bx[i]); rx[i] := (bx[i]-127.5)/127.5; Inc(i) UNTIL Eof(bdaten) OR(i > pmax); n := i-l; WriteLn(n,' Werte geladen 1 ); ia := 1; ie := n; Close(bdaten) END; IF (z 'R') AND (z 'B') THEN WriteLn('Eingabefehler!!') END; L/T/G/S/H/F/E -> L REAL-Dateien werden im Bereich von 0 .. 255 BYTE-Dateien werden im Bereich von -1 .. +1 REAL- oder BYTE-Format? R/B -> RDA Dateiname xxxxxxxx.RDA:sinus.rda 360 Werte geladen
ausgegeben ausgewertet
Bild 9-70: Laden der auszuwertenden Datendatei Beim Laden der Dateien muß zwischen den Datenformaten BYTE und REAL unterschieden werden. Beim Auslesen des Speicheroszillo3kops (Abschnitt 9.2.4) und bei der Abtastung von Signalen mit einem A/D-Wandler (Bild 9-62) ergaben sich die Meßwerte als vorzeichenlose Dualzahlen vom Datentyp BYTE. Die in diesem Datenformat aufgebauten Dateidateien erhielten
9.4 Beispiele für die Auswertung
den Zusatz Ordnung: digital 0 = $00 127 = $7F 255 = $ F F
von Meßergebnissen
253
BDA (Byte DAten). Entsprechend Bild 9-64 gilt folgende Zuanalog Volt Volt Volt +2
BYTE-Dateien . BDA können direkt f ü r die graphische Ausgabe verwendet werden. Für eine numerische Auswertung (Extremwerte, Mittelwerte, Fourieranalyse) werden sie nach dem Einlesen zusätzlich in REAL-Zahlen im Bereich von -1.0 ($00) bis +1.0 ($FF) umgewandelt. In dem Programmbeispiel Bild 9-66 (Analoger Funktionsgenerator) wurde eine als Formel gegebene Funktion zunächst als REAL-Tabelle berechnet. Die Ausgabe erfolgte aus einer umgewandelten BYTE-Tabelle auf dem Digital/Analogwandler. Die Funktion konnte in der REAL-Darstellung als Datei mit dem Zusatz . RDA gespeichert werden. Datendateien mit dem Zusatz .RDA (Real DAten) enthalten REAL-Zahlen und werden nach dem Laden zusätzlich f ü r die graphische Ausgabe der beiden folgenden Bilder in das BYTE-Format im Bereich von $00 (Minimalwert) bis $FF (Maximalwert) umgeformt. Bei der Ausgabe der Funktionswerte (Bild 9-71) erscheint neben dem REAL-Zahlenwert auch der Index und zur Orientierung eine graphische Darstellung in einem groben Raster von 64 Positionen. Dabei kann der Benutzer den Anfangs- und Endindex der auszugebenden Funktionswerte verändern. Die Zeitachse verläuft von oben nach unten. Mit dieser Darstellung ist es möglich, den Bereich einer Funktion zu festzulegen, für den die Mittelwerte oder die Fourierkoeffizienten berechnet werden sollen. Für eine Beurteilung des Funktionsverlaufes ist die in Bild 9-72 dargestellte Feingraphik besser geeignet. (* Bild 9-71: Ausgabe der Funktion als Tabelle mit Blockgraphik *) f «J* i
.
BEGIN IF n = 0 THEN WriteLn('Keine Funktion geladen !') ELSE BEGIN REPEAT Write(#$0A,#$0D,'Anfangsindex [',1,'..] -> '); ReadLn(ia); Write('Endindex [..\n, '] -> '); ReadLn(ie); WriteC Index REAL-Wert'); ni := 1; IF (ian) THEN ia:=l; IF (ien) THEN ie := n; FOR i := ia TO ie DO BEGIN Write(#$0A,#$0D,i:3,rx[i]:11:6,' '); FOR j := 0 TO 63 DO aus[j] := ' '; aus[0] := #186; aus[31] := #179; aus[63] := #186; aus[bx[i] DIV 4] := #233; FOR j := 0 TO 63 DO Write(aus[j]); Inc(ni); IF(ni MOD 24) = 0 THEN ReadLn END; Write(#$0A,#$0D,'Noch eine Ausgabe? Ja = j -> ');z:=UpCase(ReadKey); UNTIL z 'J' END END;
254
9.
Anwendungsbeispiele
L/T/G/S/H/F/E -> T Anfangsindex [ 1 . . ] -> 1 Endindex [..360] -> 19 Index REAL-Wert 1 2
3 4 5 6 7 8
9
10 11 12 13 14
15 16 17 18 19
0 000000 0 017452 0 034899 0 052336 0 069756 0 087156 0 104528 0 121869 0 139173 0 156434 0 173648 0 190809 0 207912 0 224951 0 241922 0 258819 0.275637 0 292372 0 309017
Noch eine Ausgabe? Ja = j Bild
9-71:
e e e e e 9 e e e e e e e e e e e e e
Ausgabe der Funktionswerte mit Blockgraphik
(* Bild 9-72: Ausgabe der Funktion auf dem Graphikbildschirm *) 'G' : BEGIN IF n = 0 THEN WriteLn('Keine Funktion geladen ! ' ) ELSE BEGIN Write('Null-Linie (50 .. 239 .. 429) -> ' ) ; ReadLn(null); fak := (n DIV 639) + 1; Write ('Bereichsfaktor (1 .. \ f a k , ' ) -> ' ) ; ReadLn(fak); Write('Dehnungsfaktor (1 .. 2 -> ' ) ; ReadLn(d); Write('Anfangsindex (1 .. ' , n , ' ) -> ' ) ; ReadLn(ia); " + " : + 15') "->" : + 1 WriteLn('Bild verschieben —> "0.0) THEN Cwink := +90.0; IF (x.re=0.0) AND (x.im0.0) THEN Cwink := Arctan(x.im/x.re)*180.0/Pi; IF (x.re