Serielle Schnittstelle
Peter Winkler
Bestimmt haben Sie schon einmal davon gehört, daß Computer an den unterschiedlichsten Orten der Welt miteinander kommunizieren und Daten austauschen können. Man nutzt dabei zum Beispiel das Telefonnetz, welches zwar nur verhältnismäßig geringe Übertragungsraten zuläßt, aber dafür von beinahe überall auf der Erde Zugriff gewährt.
Damit das Telefonnetz genutzt werden kann, muß ein Modem eingesetzt werden, welches die Daten am einem Ende der Leitung in ein akustisches Signal übersetzt und am anderen Ende wieder in digitale Daten zurück konvertiert.
Die Daten werden dabei seriell übertragen, daß heißt: ein Bit nach dem anderen. Es muß dabei aber ein Protokoll eingehalten werden, damit sich die Computer und die Programme verstehen und damit Fehler in der Übertragung aufgedeckt und korrigiert werden können.
Wir wollen uns hier die serielle Übertragung mittels Nullmodemkabel näher ansehen.
Bei einem Nullmodemkabel können die Daten direkt zwischen zwei Computern übertragen werden. Das Nullmodemkabel ist lediglich ein 9– bzw. 25-poliges Kabel, bei dem die Signale paarweise ausgekreuzt sind.
Der Zugriff auf die serielle Schnittstelle erfolgt entweder direkt über die Port–Adressen der gewünschten Schnittstelle oder durch BIOS-Funktionen.
Um die serielle Schnittstelle zu programmieren, muß man zuerst feststellen, wieviele serielle Schnittstellen überhaupt auf dem Computer installiert sind, und an welchen Port–Adressen sich diese befinden.
Dieses Problem kann man mit Hilfe der BIOS-Variablen lösen. Diese Variablen befinden sich in dem Segment 0040h (siehe XT/AT-Booklet in diesem Heft).
Offset |
Beschreibung |
0000h |
Word - Port Adresse von COM1 |
0002h |
Word - Port Adresse von COM2 |
0004h |
Word - Port Adresse von COM3 |
0006h |
Word - Port Adresse von COM4 |
Gibt es zum Beispiel nur 2 serielle Schnittstellen, so sind an 0040:0000h und 0040:0002h die beiden Port Adressen enthalten und an den beiden anderen Adressen stehen Nullen.
Beispielfunktion, die die Portadressen ausließt.
int PortAnz=0; /* Anzahl der Ports */
unsigned int Ports[4]; /* Port Adressen */
/********************************************/
// void Init(void)
// Stellt fest, wieviele serielle Schnittstellen an welchen Ports vorhanden
// sind und schreibt die Ergebnisse in globale Variablen
/********************************************/
void Init(void)
{
unsigned int far* ptr; // Pointer auf
//die BIOS Variablen
int i; // Zähler
// Pointer initialisieren
ptr=(unsigned int far *)MK_FP(0x0040,0);
for(i=0;i;i++) // 4 Adressen durchlaufen
{
Ports[i]=*(ptr+i); // Port Adresse auslesen
if(Ports[i]==0)break; // Überprüfen,
// ob Schnittstelle
else PortAnz++; // vorhanden ist
}
return;
}
Im Laufe der Zeit haben sich verschiedene Übertragungsgeschwindigkeiten und Protokolle entwickelt. Um sicherzustellen, daß beide PCs die selben Einstellungen verwenden, muß man daher zuerst beide Schnittstellen der Übertragungsstrecke je nach Wunsch konfigurieren.
Auch hier hilft uns das BIOS, das uns unter einem Interrupt eine Initialisierungsroutine bietet
Interrupt 14, Funktion 00h
Initialisierung einer seriellen Schnittstelle, Einstellung der Baud - Rate, Parität und Stop - Bits
Eingabe
AH = 00h
DX = Nummer der seriellen
Schnittstelle,
beginnend bei 0
AL = Konfigurationsparameter
Bit 0-1 Datenlänge
10(b) =7 Bits
11(b) =8 Bits
Bit 2 Anzahl der Stop – Bits
0(b)=1
1(b)=1,5 bzw. 2
Bit 3-4 Paritätsprüfung
00(b) =keine
01(b) =ungerade
11(b) =gerade
Bit 5-7 Baud – Rate
000(b) =110 Baud
001(b) =150 Baud
010(b) =300 Baud
011(b) =600 Baud
100(b) =1200 Baud
101(b) =2400 Baud
110(b) =4800 Baud
111(b) =9600 Baud
Eingabe
AH = Status
Bit 0: Daten stehen bereit
Bit 1: Überlauf (nicht bereit zum Schreiben)
Bit 2-7: Fehlerspezifikationen
AL = Modemstatus
Beispielfunktion, die eine serielle Schnittstelle mit dem Konfigurationsparameter – Byte initialisiert.
/******************************************/
//void InitBaud(int COM, unsigned char b)
// Initialisiert COM mit den Parametern b
// Die Nummer der Schnittstelle beginnt bei 0
/******************************************/
void InitBaud(int COM, unsigned char b)
{
asm {
mov AH,0x0 // Funktion 0
mov DX,COM // Schnittstelle, beginnend bei 0
mov AL,b // Konfigurations - Bitfeld
int 0x14 // Interrupt aufrufen
}
return;
}
Um Daten zu senden bzw. Daten zu empfangen, muß man zuerst überprüfen, ob die Schnittstelle überhaupt zum Senden bereit ist bzw. ob Daten überhaupt anstehen.
Man könnte auch hier eine BIOS-Funktion verwenden, aber wir werden hier direkt mit den Ports arbeiten.
Als erstes möchte ich zwei Funktionen vorstellen, die überprüfen, ob Daten anstehen bzw. ob die Schnittstelle bereit ist, Daten zu senden
Dazu wird jeweils ein Status–Bit überprüft, auf das mit der Port Adresse+5 zugegriffen wird.
Portadresse+5
Bit |
Beschreibung |
0 |
Daten stehen an |
6 |
Bereit zum senden |
/**************************************************/
//int ReadReady(int COM)
//Prüft, ob ein Datenbyte anliegt
//liefert 1 zurück, wenn ein Byte anliegt
//liefert sonst 0
/*************************************************/
int ReadReady(int COM)
{
unsigned char b;
b=inportb(Ports[COM]+5);
return (b&1);
}
/*************************************************/
//int WriteReady(int COM)
//prüft, ob ein Byte seriell gesendet werden kann
//liefert 1 zurück, wenn ja
//liefert sonst 0
/*************************************************/
int WriteReady(int COM)
{
unsigned char b;
b=inportb(sPorts[COM]+5);
return (b&64);
}
Jetzt wird’s ernst!!
Um ein Byte zu senden, muß man nur überprüfen, ob die Schnittstelle bereit ist und falls das zutrifft, einfach das zu sendende Byte auf die Port Adresse schreiben.
/**************************************************/
//unsigned char serWrite(unsigned char b,int COM)
//sendet ein Byte b
//liefert 0 zurück, wenn Byte b gesendet wurde
//liefert sonst 0xFF
/**************************************************/
unsigned char serWrite(unsigned char b,int COM)
{
if(WriteReady(COM))
{
outportb(sPorts[COM],b);
return 0;
}
return 0xFF;
}
Das Gleiche gilt für das Lesen von Daten: überprüfen, ob ein Byte ansteht und wenn ja, einfach ein Byte von der Portadresse lesen.
/*************************************************/
//unsigned char Read(void)
//liest ein Byte von der seriellen Schnittstelle
//und liefet dieses zurück
//im Fehlerfall wird 0xFF zurückgeliefert
/**************************************************/
unsigned char Read(void)
{
if(C_sReadReady())
return inportb(sPorts[sAktPort]);
return 0xFF;
}
Mit diesen Funktion steht ihnen das Grundgerüst für jedes Programm, das die serielle Schnittstelle nutzen soll, zur Verfügung! Ich wünsche gutes Gelingen.