Listing 3.3 zeigt alle erforderlichen Prozeduren für die Verwendung der ersten seriellen Schnittstelle COM1 in Turbo Pascal unter DOS zusammen mit einem kleinen Hauptprogramm. Das Programm verwendet die direkte Registerprogrammierung des UART über Port-Befehle. Dieses Verfahren empfiehlt sich nur noch für ältere DOS-Rechner, nicht mehr aber für Anwendung im DOS-Fenster ab Windows 98, da hier direkte Portzugriffe gesperrt werden.
Die Prozedur "Oeffnen" entspricht in ihrer Wirkungsweise dem OPEN-Befehl in Basic. Zunächst muss die Übertragungsrate an den UART übergeben werden. Sie soll hier 1200 Baud betragen. Nachdem das höchstwertige Bit des (DLAB) in 3FB gesetzt wurde, können die beiden Baudratenregister geladen werden. Gleichzeitig mit dem Festlegen weiterer Parameter der Schnittstelle werden die Baudratenregister verriegelt, indem DLAB zurückgesetzt wird. Bit 0 und 1 im Leitungs-Steuerregister stellen die Datenbreite 8 Bit ein, Bit 2 das einfache Stopbit. Zusammen ergibt sich der Wert 3. Damit werden die Leitungen RTS und DTR an der Schnittstelle beim Öffnen automatisch hochgesetzt. Zur Sicherheit wird das Empfangs-Halteregister ausgelesen, um es zu leeren.
Die Prozedur "Schliessen" dient zur Beendigung der Datenübertragung. Alle eingestellten Parameter des UART dürfen beibehalten werden. Es ist lediglich nötig, das Modem-Steuerregister auf Null zu setzen. Damit werden die Leitungen RTS und DTR zurückgesetzt, um einem angeschlossenen Gerät das Ende des Datenaustauschs anzuzeigen.
Die Prozedur "Senden" erhält ein zu sendendes Byte in der Variablen "Wert". Um es zu senden, muss es nur in das Sende-Halteregister geschrieben werden. Der Schreibvorgang selbst startet den Sendevorgang im UART. Damit aber erst dann ein Byte übergeben wird, wenn das Register leer ist, das letzte Byte also verarbeitet wurde, wird zuvor das Leitungs-Statusregister so lange abgefragt, bis das Bit 5 (TBE) Die Bereitschaft für eine neue Datenaufnahme signalisiert.
PROGRAM Ausgabe;
uses CRT;
var
Wert : Byte;
Ch : Char;
procedure Oeffnen;
var Wert : Byte;
begin
Port [$3FB]:=128; { Baudeingabe aktivieren }
Port [$3F8]:= 96; { Baudrate - LSB, 1200 Baud }
Port [$3F9]:= 0; { Baudrate - MSB }
Port [$3FB]:= 3; { 8 Bits, No Parity, 1 Stop }
Port [$3FC]:= 3; { DTR = 1, RTS = 1 }
Wert := Port [$3F8] { Empfangsregister leeren }
end;
procedure Schliessen;
begin
Port [$3FC]:= 0; { DTR = 0, CTS = 0 }
end;
procedure Senden ( Wert : Byte );
begin
repeat
until Port [$3FD] and 32 = 32; { Sendepuffer leer? }
Port [$3F8]:= (Wert); { Byte ausgeben }
end;
procedure Empfangen ( var Wert : Byte );
begin
repeat until (Keypressed or
((Port [$3FD] and 1) = 1)); { Zeichen empfangen? }
Wert := Port [$3F8]; { Byte lesen }
end;
begin
Oeffnen;
Ch := ReadKey;
Wert := Integer (Ch);
Senden (Wert);
Schliessen
end.
Listing 3.3 Senden und Empfangen in Turbo-Pascal
Die Prozedur "Empfangen" liest ein empfangenes Byte und übergibt es an die globale Variable Wert. Zuvor wird aber Bit 0 (RXDR) des Leitungs-Statusregisters so lange abgefragt, bis ein Zeichen empfangen wurde. Man muss beachten, dass hier keine Timeout vorgesehen ist. Bei Ausbleiben eines Bytes bleibt die Empfangsprozedur daher in einer Endlosschleife hängen.
Das Hauptprogramm demonstriert die Verwendung der Prozeduren "Oeffnen", "Senden" und "Schließen". Ein einzelnes Zeichen wird von der Tastatur gelesen und gesendet.
Die folgende allgemeine Unit COM2_96 verwendet eine verbesserte Empfangsfunktion "Empfang" mit einem einfachen Timeout durch eine Zählschleife. Diese Schleife muss eventuell an die Geschwindigkeit des verwendeten Prozessors angepasst werden.
UNIT COM2_96; {COM2_96.PAS}
Interface
uses DOS, CRT;
const BA : Integer = $02F8; { $03F8=COM1, $02F8=COM2}
procedure Sende (Zeichen :Byte);
function Empfang :Byte;
procedure Init;
procedure DTR (An : Boolean);
procedure RTS (An : Boolean);
Implementation
procedure Sende (Zeichen :Byte);
begin
while (Port[BA+5] AND 32) = 0 do;{Sende-Halteregister leer?}
Port[BA]:=Zeichen;
end;
function Empfang :Byte;
var i :Word;
begin
i:=0;
while ((Port[BA+5] AND 1)=0) AND (i<10000) DO Inc(i);
if i < 10000 {Timeout erreicht?}
then Empfang := Port[BA]
else Empfang := 0;
end;
procedure Init;
var i, Dummy :Byte;
begin
Port[BA+3]:=128;
Port[BA+0]:=12; { 12: 9600 Baud, 6 :19200 Baud }
Port[BA+1]:=0;
Port[BA+3]:=7; { 8-Bit, n-Parity, 2 Stopbits }
Port[BA+1]:=0; { keine Interrupts }
Port[BA+4]:=0; { DTR = 0, RTS = 0}
for i:= 1 to 3 do
Dummy:=Port[BA]; { UART leeren }
end;
procedure DTR (An : Boolean);
begin
If An then Port[BA+4] := (Port[BA+4] OR 1) else
Port[BA+4] := (Port[BA+4] AND 254);
end;
procedure RTS (An : Boolean);
begin
If An then Port[BA+4] := (Port[BA+4] OR 2) else
Port[BA+4] := (Port[BA+4] AND 253);
end;
begin
Init
end.
Listing 3.4 Eine Unit für die RS232
Die Unit enthält zusätzlich Prozeduren zur direkten Ausgabe an DTR und RTS. Die Initialisierung erfolgt bereits in der TPU. Listing 3.5 zeigt die Anwendung in einem einfachen Testprogramm. Hier wird zunächst die DTR-Leitung einmal kurz eingeschaltet. Damit kann z.B. ein Reset-Signal für ein Mikrocontrollersystem erzeugt werden. Dann werden in einer endlosen Schleife 255 Bytes in aufsteigender Folge gesendet und empfangene Bytes am Bildschirm angezeigt.
program TestCom; {COMTEST.PAS}
uses CRT, COM2_96;
var n : Byte;
begin
DTR (1);
delay (100)
DTR (0)
delay (100)
repeat
for n := 0 to 255 do begin
Sende (n);
Write (Empfang,' ');
end;
until KeyPressed;
end.
Listing 3.5 Anwendung der Unit COM2_96.TPU
Download: TP6-Beispiele