3  Programmierung der seriellen Schnittstelle


Die Arbeit mit der seriellen Schnittstelle setzt geeignete Zugänge in einer Programmiersprache voraus. Hier wird sowohl auf die ältere Programmierung unter DOS als auch auf die Windows-Programmierung eingegangen. Viele Sprachen haben eigene Befehle und Funktionen zur seriellen Datenübertragung. In anderen Fällen muss man die direkte Registerprogrammierung der PC-Hardware anwenden. Hier wird zunächst die Hardware der seriellen Schnittstelle erläutert, die man z.B. für die Programmierung in Turbo Pascal kennen muss.

 
 

3.1  Der UART 8250

 

Jeder PC verfügt über eine oder mehrere serielle RS232-Schnittstellen, die entweder bereits fest auf der Hauptplatine integriert oder aber als Steckkarte ausgeführt sind. Jede serielle Schnittstelle besteht im wesentlichen aus dem UART (Universal Asynchronous Receiver/Transmitter) und nachgeschalteten Leitungstreibern und Leitungsempfängern zur Umsetzung zwischen TTL-Pegeln und RS232-Pegeln (+/-12V-Pegeln). Abb. 3.1 zeigt den prinzipiellen Aufbau einer seriellen Schnittstellenkarte.

 


 

Abb. 3.1  Prinzipschaltbild einer seriellen Schnittstelle im PC

 

Die erste bis vierte Schnittstelle (COM1 ... COM4) werden durch ihre Adresslage im IO-Bereich des PCs und ihre Interruptnummer (IRQ) unterschieden. Die erste Adresse eines UART wird als Basisadresse (BA) bezeichnet. Basisadresse und IRQ können meist über Jumper auf der Schnittstellenkarte oder durch Software-Initialisierung eingestellt werden. Die folgende Tabelle zeigt die übliche Zuordnung:

 

Schnittstelle

Basisadresse

IRQ

COM1

3F8h

IRQ4

COM2

2F8h

IRQ3

COM3

3E8h

(IRQ4)

COM4

2E8h

(IRQ3)

 

 

COM1 und COM3 sowie COM2 und COM4 teilen sich oft einen Interruptkanal. Das bedeutet, dass nur jeweils eine Software zu einer Zeit die Interrupts einer der beiden Schnittstellen benutzen kann. Mehr als zwei Schnittstellen können also nur dann gleichzeitig genutzt werden, wenn man auch Programme ohne Interruptnutzung einsetzt. Dies gelingt z.B. mit DOS-Programmen unter Turbo-Pascal (vgl. Kap. 3.3).  Der Verarbeitung serieller Zeichen unter Windows ist jedoch immer auf Interrupts angewiesen.

 

Die Funktion der Schnittstelle wird vollständig über 10 Register des UART gesteuert. Da nur bis zu acht Adressen zur Verfügung stehen, erfolgt eine interne Umschaltung durch das DLAB-Bit (Bit 7 im Leitungs-Steuerregister). Die Adressen der einzelnen Register sind hier mit ihrem Offset, d.h. mit ihrem Abstand zur Basisadresse angegeben.

 

   Registeradressen des UART 8250

Offset

DLAB

Schreiben

Lesen

0

0

Sende-Haltegegister

Empfangs-Haltegergister

0

1

Baudratenregister (Lowbyte)

 

1

0

Interrupt- Freigaberegister

 

1

1

Baudratenregister

(Highbyte)

 

2

0

 

Interrupt-Erkennungsregister

3

0

Leitungs-            Steuerregister

 

4

0

Modem-              Steuerregister

 

5

0

 

Leitungs-                                     Statusregister

6

0

 

Modem-                                   Statusregister

7

0

Scratchpad-Register  (nur 16450)

Scratchpad-Register

(nur 16450)

 

 

Vor einer Datenübertragung muss der UART zunächst initialisiert werden, indem die einzelnen Steuerregister entsprechend den gewünschten Übertragungsparametern programmiert werden. Die eigentliche serielle Übertragung erfolgt meist in kleinen Blöcken von acht Bits, also als einzelne Bytes. Um ein Byte zu senden, schreibt man es in das Sende-Halteregister:

 

     Sende-Halteregister (Offset=0, DLAB=0)

7

6

5

4

3

2

1

0

D7

D6

D5

D4

D3

D2

D1

D0

 

 

Beim Empfang eines seriell gesendeten Zeichens gelangt dieses parallel in das Empfangs-Halteregister:

 

     Empfangs-Halteregister (Offset=0, DLAB=0)

7

6

5

4

3

2

1

0

D7

D6

D5

D4

D3

D2

D1

D0

 

Für die Übertragung muss man eine Übertragungsgeschwindigkeit wählen, die in Bits pro Sekunde (Baud) angegeben wird. Bei 1200 Baud werden zusammen mit je einem Startbit und einem Stopbit in einer Sekunde bis zu 120 Zeichen mit einer Länge von 8 Bits übertragen. Der UART 8250 verwendet einen Quarz mit 1,8432 MHz. Diese Frequenz wird intern durch einen einstellbaren Teilerfaktor zur 16-fachen Baudrate geteilt. Der erforderliche Teilerfaktor berechnet sich also zu

 

                      1843200            115200

   Teilerfaktor = -----------------  = -------------

                   16  x  Baudrate       Baudrate

 

Der Teilerfaktor muss in Highbyte und Lowbyte zerlegt und in die entsprechenden Register (Offsetadresse 0 und 1 bei gesetztem DLAB-Bit) geschrieben werden.

 

     Baudratenregister, Lowbyte (Offset=0, DLAB=1)

7

6

5

4

3

2

1

0

D7

D6

D5

D4

D3

D2

D1

D0

 

 

     Baudratenregister, Highbyte (Offset=1, DLAB=1)

7

6

5

4

3

2

1

0

D7

D6

D5

D4

D3

D2

D1

D0

 

 

 

 

Die folgende Tabelle zeigt die Einstellungen für die wichtigsten Baudraten:

 

Baudrate

Teilerfaktor

Highbyte

Lowbyte

50

2304

9

0

300

384

1

128

1200

96

0

96

2400

48

0

48

4800

24

0

24

9600

12

0

12

19200

6

0

6

38400

3

0

3

57600

2

0

2

115200

1

0

1

 

 

Von der seriellen Schnittstelle können Interrupts ausgelöst werden. Dazu muss das Interrupt-Freigaberegister programmiert werden. Um einen oder mehrere Interrupts zu aktivieren, muss das entsprechende Bit gesetzt werden.

 

   Interrupt-Freigaberegister (Offset=1)

7

6

5

4

3

2

1

0

0

0

0

0

SINP

ERBK

TBE

RXRD

 

 

Interruptfreigabe für:

 

SINP:             Zustandsänderung einer Handshake-Leitung

ERBK:             Fehler oder BREAK erkannt

TBE:                Sende-Haltepuffer ist leer

RXRD:            Ein Zeichen wurde empfangen

 

Ein Fehler kann beim Empfang eines Zeichens erkannt werden, wenn z.B. die vereinbarte Zeichenlänge oder die Anzahl der Stopbits nicht eingehalten wird. Liegt am Eingang RXD ein anhaltender High-Pegel, dann spricht man von einem BREAK-Zustand. Dieser Zustand würde nach Ablauf der normalen Übertragungszeit der vereinbarten Datenbits wie ein Empfangsfehler gewertet.

 

Um Interrupts auszulösen, müssen noch zwei weitere Bedingungen erfüllt sein: Zum einen muss der Interruptcontroller entsprechend programmiert sein, zum anderen muss die Leitung OUT2 (Bit 3 im Modem-Steuerregister) gesetzt sein.

 

Wenn einer von mehreren möglichen Interrupts aufgetreten ist, kann man im Interrupt-Erkennungsregister die Quelle erfahren:

 

   Interrupt-Erkennungsregister (Offset=2)

D7

D6

D5

D4

D3

D2

D1

D0

0

0

0

0

0

ID1

ID0

PND

 

ID1, ID0:Identifizierungsbits:

00: Zustandsänderung einer Handshake-Leitung

01: Sende-Haltepuffer ist leer

10: Ein Zeichen wurde empfangen

11: Fehler oder BREAK-Bedingung erkannt

PND:   Interrupt ist aufgetreten

 

Ein anhängiger Interrupt nach einer Zustandsänderung einer Handshakeleitung wird durch das Lesen des Modem-Statusregisters wieder gelöscht. Ebenso löscht ein Lesen des Empfangs-Haltegegisters einen Empfangs-Interrupt und das Lesen des Leitungs-Statusregisters einen Fehler- oder BREAK-Interrupt. Der Interrupt durch ein leeres Sende-Halteregister kann entweder durch das Lesen des Interrupt-Erkennungsregisters oder durch Schreiben in das Sende-Halteregister gelöscht werden.

 

Das Leitungs-Steuerregister braucht im Normalfall nur zur Initialisierung der seriellen Schnittstelle beschrieben werden. Es enthält acht Steuerbits zur Festlegung der Übertragungsparameter:

 

 

   Leitungs-Steuerregister (Offset=3)

D7

D6

D5

D4

D3

D2

D1

D0

DLAB

BRK

PAR2

PAR1

PAR0

STOP

DAB1

DAB0

 

 

DLAB:              Zugriff auf das Baudratenregister freigeben  

BRK:   BREAK-Zustand an TXD setzen

PAR2...PAR0: Festlegung des Paritätsbits        

            000: keins

001: ungerade

011: gerade

101: mark

111: space

STOP: Festlegung von zwei Stopbits

DAB1...DAB0: Anzahl der Datenbits

00: 5 Bits

01: 6 Bits

10: 7 Bits

11: 8 Bits

 

Das DLAB-Bits bewirkt eine interne Umschaltung der Register mit den Offsetadressen 0 und 1. Es muss gesetzt werden, um die Baudrate einzustellen, im normalen Betrieb muss es dagegen gelöscht sein. Das BRK-Bit kann verwendet werden, um den Zustand der Leitung TXD als Ausgang völlig unabhängig von der normalen Funktion des UARTs zu steuern.

 

Die übrigen Bits des Registers legen für den Sender und den Empfänger des UART ein eventuelles Paritätsbit, die Anzahl der Stopbits und die Anzahl der Datenbits fest. Ein übliches Format ist z.B. 8 Datenbits, kein Paritätsbit und ein Stopbit. Für diese Einstellung müssen nur die beiden Bits DAB1 und DAB0 gesetzt werden (Registerinhalt = 3). Zusammen mit dem Startbit werden dann insgesamt 10 Bits übertragen, sodass z.B. bei einer Übertragungsgeschwindigkeit von 19200 Baud genau 1920 Zeichen pro Sekunde übertragen werden können.

 

Das Leitungs-Steuerregister dient im Wesentlichen zum Steuern der zusätzlichen Ausgänge des UART. Während DTR und RTS genutzt werden können, sind OUT2 und OUT1 als zusätzliche Mehrzweckausgänge beim PC nur nicht von außen zugänglich. OUT2 erfüllt aber eine wichtige Funktion beim Aktivieren von Interrupts. Diese Leitung muss nämlich gesetzt werden, um überhaupt einen Interrupt weiterzuleiten. (vgl. Abb. 3.1)

 

   Modem-Steuerregister (Offset=4)

D7

D6

D5

D4

D3

D2

D1

D0

0

0

0

LOOP

OUT2

OUT1

RTS

DTR

 

 

LOOP:            Interne Rückkopplung zu Testzwecken  

OUT2: Leitung OUT2 setzen, um Interrupts zu ermöglichen  

OUT1: interne Leitung OUT1 setzen

RTS:    Leitung RTS setzen

DTR:    Leitung DTR setzen

 

Das LOOP-Bit kann sinnvoll eingesetzt werden, um eigene Programme zu testen. Die ausgesendeten Zeichen werden empfangen, ohne dass eine externe Verbindung zwischen TXD und RXD hergestellt werden muss.

 

Das Leitungs-Statusregister enthält sieben Statusbits, über die sich aktuelle Zustände des seriellen Senders und des seriellen Empfängers auslesen lassen.

 

   Leitungs-Statusregister (Offset=5)

D7

D6

D5

D4

D3

D2

D1

D0

0

TXE

TBE

BREK

FRMF

PARF

ÜBLF

RXRD

 

TXE:    Letztes Zeichen ist vollständig ausgesendet

TBE:    Sende-Halteregister ist leer

BREK: BREAK-Zustand an RXD erkannt

FRMF: Format-Fehler erkannt

RARF: Paritätsfehler erkannt

ÜBLF: Überlauffehler erkannt

RXRD: Ein Zeichen wurde empfangen

 

Sobald das TBE-Bit gesetzt ist, darf ein neues Zeichen in das Sende-Haltegegister geschrieben werden. Dieses Zeichen wird aber erst dann in das Schieberegister des seriellen Senders übernommen, wenn kein anderes Zeichen mehr bearbeitet werden muss. Sobald das zuletzt in das Sende-Halteregister geschriebene Zeichen in das Schieberegister übernommen wird, setzt der UART sein TBE-Bit. Das TXE-Bit wird dagegen erst dann gesetzt, wenn das letzte Zeichen vollständig übertragen wurde.

 

Für die Empfangsrichtung zeigt das RXRD-Bit, dass ein Zeichen zur Verfügung steht. Es muss rechtzeitig aus dem Empfangs-Halteregister ausgelesen werden, um nicht von einem folgenden Zeichen überschrieben zu werden. Im letzteren Fall würde durch das ÜBLF-Bit ein Überlauf angezeigt. Überläufe lassen sich verhindern, indem entweder durch ein genügend schnelles "Polling" das RXRD-Bit laufend beobachtet wird, oder indem eine Interruptroutine benutzt wird, die ein ankommendes Zeichen verarbeitet.

 

Der Zustand der Eingänge DCD, RI, DSR und CTS kann über das Modem-Statusregister gelesen werden. Während die oberen vier Bits den Zustand der vier Leitungen direkt widerspiegeln, zeigen die unteren vier Bits an, ob seit dem letzten Lesezugriff auf das Modem-Statusregister eine Zustandsänderung an einer Leitung aufgetreten ist.

 

 

   Modem-Statusregister (Offset=6)

D7

D6

D5

D4

D3

D2

D1

D0

DCD

RI

DSR

CTS

DDCD

DRI

DDSR

DCTS

 

DCD:   Leitung DCD ist gesetzt

RI:       Leitung RI ist gesetzt

DSR:    Leitung DSR ist gesetzt

CTS:    Leitung CTS ist gesetzt

DDCD:            Zustandsänderung an DCD

DRI:     Zustandsänderung an RI

DDSR: Zustandsänderung an DSR

DCTS: Zustandsänderung an CTS

 

Der UART 8250 und sein Nachfolgetyp 16450 verarbeiten jeweils nur ein Zeichen. Wird ein neues Zeichen empfangen, bevor das alte ausgelesen wurde, kommt es zum Datenverlust. Um auch bei höheren Übertragungsgeschwindigkeiten andere Aufgaben parallel durchführen zu können, setzt man den neueren 16550 mit zwei 16-Byte Zwischenspeichern für die Sende- und Empfangsrichtung ein. Die zusätzlichen Speicher sind als sog. FIFO-Speicher (first in first out) ausgelegt, sodass die ausgelesenen Zeichen immer in der Reihenfolge des Empfangs erscheinen.

 

Der FIFO-Speicher ist nach einem Reset zunächst inaktiv und muss bei Bedarf durch das FIFO-Controllregister eingeschaltet werden. Dieses Register ist nur in Schreibrichtung unter der Offsetadresse 2 zugänglich, beim Auslesen befindet sich hier das Interrupt-Erkennungsregister, das ebenfalls eine erweiterte Funktion hat:

 

   FIFO-Steuerregister (Offset=2, schreiben)

D7

D6

D5

D4

D3

D2

D1

D0

TL1

TL0

0

0

0

FRT

FRR

FEN

 

 

TL1, TL0: Triggerlevel, Interrupt nach:            

00:  1 Byte

01:  4 Bytes

10:  8 Bytes

11: 14 Bytes

FRT:    FIFO-Reset für Sender

FRR:    FIFO-Reset für Empfänger

FEN:    FIFO einschalten

 

Will man ohne FIFO arbeiten und eine Kompatibilität zum 8050 erzwingen, dann sollte der Wert 6 in das Register geschrieben werden. Damit erfolgt zugleich ein Reset und ein Ausschalten des FIFO. Ob der FIFO-Modus eingeschaltet wurde, lässt sich an einem zusätzlichen Statusbit des Interrupt-Erkennungsregisters ablesen.

 

 

   Interrupt-Erkennungsregister (Offset=2, lesen)

D7

D6

D5

D4

D3

D2

D1

D0

FON

FON2

0

0

ID2

ID1

ID0

PND

 

FON:   FIFO eingeschaltet

FON2: FIFO eingeschaltet (nur 16550A)

ID2:     Identifizierungsbit: Timeout

ID1, ID0: Identifizierungsbits:

00: Zustansänderung einer Handshake-Leitung

01: Sende-Haltepuffer ist leer

10: Ein Zeichen wurde empfangen

11: Fehler oder BREAK-Bedingung erkannt

PND:   Interrupt ist aufgetreten

 

 


weiter
zurück