StuBS
Serielle Schnittstelle

Serielle Schnittstellen und RS-232

„Serielle Schnittstelle“ ist eigentlich ein Sammelbegriff für alle Übertragungsarten, die Daten seriell (hintereinander) übertragen, wir beschäftigen uns hier aber mit dem RS-232 Standard. Der Standard ist in den frühen 1960er Jahren entstanden und wurde bspw. für Bildschirmterminals benutzt, und hat in den 80ern regen Zuspruch beim IBM-PC für viele Geräte wie bspw. Mäuse erhalten. Noch heute haben viele PCs den 9-poligen Stecker und Hardware, die sich kompatibel zu den im IBM-PC verbauten Schnittstellen verhält, auch wenn RS-232 eigentlich vom Universal Serial Bus (USB) redundant gemacht wurde. Die RS-232 stellt hardware- und softwareseitig eine einfache Möglichkeit dar, mit entfernten Geräten zu kommunizieren. Bspw. hilft sie Entwicklern bei der Entwicklung von Betriebssystemen auf eingebetteten Systemen, die über keinen Bildschirm verfügen und erlaubt einfachen Datenaustausch zwischen den Systemen.

Wir haben bereits eine Ausgabemöglichkeit mit dem Textmodus der CGA, allerdings ist die serielle Ausgabe in einigen Eigenschaften flexibler. Wir können mit der seriellen Ausgabe nahezu unbegrenzt viele Daten auf unseren Entwicklungs-PC übertragen, während CGA eine sehr begrenzte Zeichenanzahl vorschreibt. Die serielle Ausgabe erlaubt uns allerdings nicht direkt, Zeichen zu platzieren und nur indirekt mit eine Farbe zu versehen.

Die serielle Schnittstelle wird typischerweise von einem UART-Chip bereitgestellt, der die Dekodierung von ankommenden und die Enkodierung von zu sendenden Daten übernimmt. Oftmals können vom UART-Chip nur einzelne Bytes gepuffert werden, weshalb eine Flusskontrolle sinnvoll, aber vom Protokoll nicht nötig ist. Der übliche D-sub-Stecker beinhaltet 9 Pins, bei denen einige Leitungen, neben einer GND-Leitung, einfache Flusskontrolle erlauben. Für uns interessant sind aber lediglich Rx und Tx, also die Empfang- und Sendeleitungen.

Mit der seriellen Schnittstelle werden Oktetts übertragen, oftmals gibt es auch Modi um lediglich 7 Bit zu übertragen, die dann zu einem Zeichen ausgewertet werden. Ein Zeichen oder Oktett auf der Leitung beginnt mit einem Startbit, was eine Synchronisierung der Empfangsseite ermöglichen soll und andeutet, dass ein neues Datum beginnt. Darauf folgen je nach Konfiguration 7, 8 oder mehr Bits an Nutzdaten, die vom UART-Controller ausgewertet werden. Weiter kann ein Paritätsbit folgen, abgeschlossenem vom Stop-Bit. Die Übertragungsgeschwindigkeit wird in Bits per Second angegeben, die so genannte Baudrate. Sie muss bei Empfänger und Sender identisch eingestellt werden.

So ergeben sich folgende folgenden Einstellungen:

  1. Die Baudrate: Sie bezeichnet, wie viele Bits in einer Sekunde übertragen werden (Teiler von 115200).
  2. Die Anzahl der Daten-Bits: Gibt die Größe eines Symbols an (5-8 Bit).
  3. Anzahl der Stop-Bits: Stop-Bits (1-2) markieren das Ende eines Symbolen und dienen zur Überprüfung der Synchronizität.
  4. Paritätsbit: Ein optionales Parity-Bit, mit dessen Hilfe überprüft werden kann, ob die Nachricht fehlerfrei ankam.

Heutzutage ist ein Modus von 8N1 üblich (8 Datenbits, kein Parity-Bit, 1 Stop-Bit).

Implementierung im IBM-PC

Der PC hat 4 eingebaute Serial-Ports, so genannte COM-Ports. Der UART-Chip wird über I/O-Ports konfiguriert. COM1 befindet sich hinter I/O-Port 0x3f8 und COM2 hinter 0x2f8. Weitere Register, die zur Kontrolle notwendig sind, befinden sich direkt hinter der Basis, so kann bspw. das Line Control Register von COM1 mit dem I/O-Port 0x3f8+3, also 0x3fa, angesprochen werden.

Zwei der Register werden durch ein Bit im Line Control Register (das so genannte DLAB oder Divisor Latch Access Bit) umgeschaltet. Ist dieses Bit gesetzt, werden die Register an Offset 0 und 1 als Divisor für die Baudrate gelesen und geschrieben (LSB an +0, MSB an +1). Ist es nicht gesetzt, verbirgt sich hinter +0 das Datenregister, was wir fürs Senden und Empfangen von Daten benötigen, sowie hinter +1 das Interrupt Enable Register.

Versatz (und DLAB Einstellung)Register
+0, DLAB: 0Data Register
+1, DLAB: 0Interrupt Enable Register
+0, DLAB: 1Divisor Latch LSB
+1, DLAB: 1Divisor Latch MSB
+2Interrupt Identification und FIFO Control Register
+3Line Control Register
+4Modem Control Register
+5Line Status Register
+6Modem Status Register
+7Scratch Register

Register

Eine genaue Aufschlüsselung der Register kann im Datenblatt vom 8250A UART-Chips nachgeschlagen werden. Für unsere Zwecke sind lediglich das Line Control Register und das Line Status Register wichtig.

RegisterBit 76543210
Line ControlDLABSet BreakStick ParityEven Parity Select (EPS)Parity Enable (PEN)Stop Bits (STB)Word Length Select 1 (WLS1)Word Length Select 0 (WLS0)
Line Status0Transmitter EmptyTransmitter Holding RegisterBreak InterruptFraming ErrorParity ErrorOverrun ErrorData Ready

Baudrate

Der UART hat einen eingebauten Timer von 115200 Ticks pro Sekunde. Um die Baudrate einzustellen dividieren wir diesen Timer, als halbieren ihn schrittweise. Um also die vollen 115200 Ticks pro Sekunde zu nutzen, benutzen wir einen Divisor von 1, für 57600 Baud einen Divisor von 2, 38400 Baud Divisor von 3, usw.. Um die Baudrate einstellen zu können, muss das oberste Bit des Line Control Registers (also DLAB) gesetzt werden. Dann können wir an Versatz +0 das LSB, an +1 das MSB schreiben. Schließlich wird DLAB zurückgesetzt.

Datenbits

Die Anzahl der Datenbits in einer Nachricht ist variabel. Üblicherweise wird 8N1 verwendet, also 8 Datenbits, die entsprechend in die WLS0 und WLS1-Bits im Line Control Register eingetragen werden.

Zeichen Länge(1) WLS1(0) WLS0
500
601
710
811

Paritätsbit - Fehlerdetektion

Das Parity Enable Bit (PEN) gibt an, ob ein Paritätsbit gesendet oder empfangen werden soll. Das Paritätsbit wird verwendet, um Übertragungsfehler auf Bitebene zu erkennen. Üblicherweise kann man ein Paritätsbit als Zählung der Nullen sehen, wechselt also ein Bit seinen Wert, stimmt das Paritätsbit nicht mehr überein und ein Fehler wird detektiert.

Der 8250A UART-Chip kann mehrere UART-Modi, bspw. kann das Paritätsbit auf 0 oder 1 gesetzt werden, sodass das Paritätsbit immer als 0 (SPACE) oder 1 (MARK) gesendet und empfangen wird. Die Modi EVEN und ODD versichern, dass das Symbol zusammen mit dem Paritätsbit entweder eine gerade oder eine ungerade Quersumme haben. Der übliche Standard 8N1 deaktiviert das Paritätsbit.

Bedeutung(5) Stick Parity(4) EPS(3) PEN
NONE - kein Paritätsbit--0
ODD001
EVEN011
MARK - immer 1101
SPACE - immer 0111

Stopbits

Die Stopbits werden vom Empfänger verwendet, um sicherzustellen, dass der Sender in Phase agiert, also das gleiche (oder ein hinreichend ähnliches) Timing verwendet. Bei 5 Datenbits ist es möglich, 1 oder 1,5 Stopbits zu senden, ansonsten 1 oder 2 Stopbits.

Bedeutung(2) STB
1 Stopbit0
1,5 oder 2 Stopbits1

Line Status

Mit dem Line Status Register ist es möglich, den Zustand des UART-Chips abzufragen. Für uns sind dabei lediglich die Bits 0 und 6 wichtig, die anzeigen, ob Daten empfangen worden sind (Data ready) und ob der Chips bereit ist, Daten zu senden (Transmsitter empty). Diese Bits sollen zunächst durch Polling abgefragt werden.

ANSI Escape Sequences

Die serielle Schnittstelle sendet ausschließlich Zeichen, allerdings müssen wir auch hier nicht auf Farbe oder andere Hervorhebungen verzichten, wenn von beiden Seiten ANSI-Escape-Sequenzen implementiert sind. Die üblichen Terminal-Emulatoren unter Linux implementieren die Escape-Sequenzen, also bleibt es bei euch, in StuBS diese Steuerzeichen auch zu senden.

Es gibt weitere Steuerzeichen, die wir bereits kennen, bspw. sind \n oder \r solche, die den Cursor auf die nächste Zeile bspw. an den Anfang der Zeile verschieben. Wir interessieren uns hier für alles, was mit dem Escape-Steuerzeichen, also ^[, 0x1b oder oktal 33 beginnt. Hinter diesem Steuerzeichen befinden sich für viele Befehle der Control-Sequence-Introducer (in dem Fall [), eine Reihe von Parametern, die mit Semikolon getrennt ist, sowie ein weiteres Steuerzeichen, was den Befehl angibt, der mit den übertragenden Parametern ausgeführt werden soll. Bspw. ist die Zeichenkette \033[J dafür da, den gesamten Bildschirm zu leeren. Mit einem weiteren Parameter kann noch zusätzlich angegeben werden, wo sich der Cursor befinden soll.

Farben sind über den Befehl m zu setzen, wobei 033[0m für das Zurücksetzen der vorigen Einstellungen auf den Standard steht. Die Farbeinstellungen haben, wie im CGA-Display eine Vorder- und eine Hintergrundfarbe. Weiter können Zeichen fett dargestellt, unterstrichen oder blinkend gesetzt werden. Die gesetzten Einstellungen bleiben so lange erhalten, bis sie überschrieben oder zurückgesetzt werden.

VordergrundHintergrundFarbpaletteVordergrundHintergrundFarbpalette
3040Schwarz 90100Dunkelgrau
3141Rot 91101Hellrot
3244Grün 92102Hellgrün
3343Gelb 93103Hellgelb
3444Blau 94104Hellblau
3545Magenta 95105Hellmagenta
3646Cyan 96106Hellcyan
3747Grau 97107Weiß

Weiterführende Informationen