Hier soll beschreiben werden wie die parallele Schnittstelle via C/C++ angesteuert wird.
Dieser Beitrag ist an jene gerichtet die einzelne Signale der Schnittstelle ansteuern wollen.
Es wird gezeigt wie man unter DOS, Win95/98, NT,
Win2000,
XP und LINUX auf die Schnittstele zugreift.
Am Ende habe ich den Quellcode meiner Lpt-Tools
für Win98, NT, Win2000 und XP samt Treiber zum downloaden bereit gestellt.
Die Schnittstelle besteht aus 8 Datenleitungen, 5 Statuseingängen und 4 Steuerleitungen.
Diese Leitungen sind nach dem folgenden Schema belegt:
Die Leitungen D0 bis D7 sind die Datenausgänge, auf ihnen lassen sich TTL Signale ausgeben.
Low entspricht 0 Volt, und High entspricht 5 Volt.
Strobe, Autofeed, Initial und Select Input sind ebenfalls Ausgänge. Diese
Ausgänge sind aber bis auf Initial alle invertiert. Das bedeutet wenn man ein High-Bit ausgibt,
geht der Ausgang auf 0 Volt.
Die parallele Schnittstelle besitzt auch 5 Eingänge: Error,Select,Paper out,
Acknowlege und Busy. Legt man an diese Eingänge eine Spannung kleiner 0.7 Volt an
so bedeutet das Low, und eine Spannung größer 2 Volt an dem Eingang beteutet High.
Die einzige Ausnahme ist der Busy Eingang, dieser ist invertiert.
Die Steuerung dieser Eingänge erfolgt durch einen Zugriff auf ein IO-Port des
PC's.
Die parallele Schnittstelle hat 3 IO-Ports für ihre Steuerung.
Die Adressen dieser Ports sind im normal Fall auf :
Anmerkung zu Port 2:
Wenn man Bit 4 in Port 2 auf High setzt, dann ist es möglich über den Acknowlege Eingang
einen Interrupt auszulösen. Dazu muss Acknowlege auf High gesetzt werden. Im normal Fall
wird Irq7 ausgelöst (Interruptvektor 15). Es darf dabei nicht vergessen werden diesen Interrupt
auch auf dem Motherboard frei zugeben (für ISA !).
Die Bits 5 bis 7 in Port 2 sollten immer auf Low gestellt werden, da sie für
EPP-Erweiterungen, der Schnittstelle
benutzt werden. Mit diesen Erweiterungen ist es möglich die Datenleitungen D0 bis D7 auch als Eingänge zu benutzen.
Die EPP-Erweiterungen aktiviert man über Port 0x402. In den Bits 5 bis 7 stellt man den Modus für die Schnittstelle ein.
000 = Standard-Parallel-Port-Modus (SPP)
001 = PS/2 Parallel-Port-Modus
010 = FIFO-Modus
011 = Extended Capabilities Port (ECP)
100 = Enhanced Parallel Port (EPP)
101 = Reserviert
110 = Test-Modus
111 = Configuration-Modus
Ich will nur auf den Modus 1 (PS/2 Parallel-Port-Modus) näher eingehen. Wenn man den Modus aktiviert, in dem man auf Port 402h den Wert 20h schreibt, kann man die Datenleitungen als bidirektionelle Leitungen nutzen. Über das Bit 5 im Port 2 ist es möglich die Signalrichtung einzustellen. Wenn das 5. Bit auf Null stellt, sind die Datenleitungen (D0 bis D7) Ausgänge, wenn das Bit auf Eins ist dann sind die Datenleitungen Eingänge. Hier ist ein Beispiel dazu.
Ein Link zu weiteren Informationen zu den EPP-Modes: http://cc.uni-paderborn.de unter IEEE1284.
Bei diesen Betriebssystemen ist es möglich die Ports direkt anzusprechen. Mit den beiden Funktionen
void outp(int Port,int Data) und void inp(int Port,int Data)
kann einen Wert in ein Port schreiben bzw. lesen. Ein kleines Beispiel das unter QuickC oder Visual C++ läuft
soll das zeigen.
Noch eine Anmerkung, bei manchen Compilern muss man statt outp / inp die Funktionen _outp / _inp
verwenden.
#include <conio.h> #include <stdio.h> int main() { unsigned char port1,port2,i; outp( 0x378, 0x01 ); /* D0 auf High setzen Rest auf Low */ outp( 0x378, 0x02 ); /* D1 auf High setzen Rest auf Low */ outp( 0x378, 0x07 ); /* D0,D1,D2 auf High setzen Rest auf Low */ port1 = inp( 0x379 ); printf("\n Error ist auf %s",(port1&0x08)? "high":"low" ); printf("\n Select ist auf %s",(port1&0x10)? "high":"low" ); printf("\n Paper out ist auf %s",(port1&0x20)? "high":"low" ); printf("\n Acknowlege ist auf %s",(port1&0x40)? "high":"low" ); printf("\n Bussy ist auf %s",(port1&0x80)? "low" :"high"); port2 = inp( 0x37A ); outp( 0x37A, port2^1 ); /* Strobe invertieren */ for(i=0;i<20;i++) /* D3 im Sekundentakt ein ausschalten */ { outp (0x378,0x08); /* Nur D3 auf 'High' setzen bei LPT1 */ Sleep(500); outp (0x378,0x00); /* Alle Pins auf 'Low' setzen bei LPT1 */ Sleep(500); } return 0; }
Unter NT kann man auf die Ports nicht direkt zugreifen, da sonst das Betriebssystem eine Schutzverletzung
ausgeben würde. Auf die Ports kann nur indirekt über einen Device-Treiber zugegriffen werden.
Microsoft hat zu diesem Thema in seinem NT-DDK ein kleines Beispiel namens
Portio, das zeigt wie man einen
solchen Port-Zugriff macht.
Ein fertiger Treiber und ein API zum ansprechen der
LPT Ports findet man in den Lpt-Tools.
Unter LINUX verhält es sich so ähnlich wie unter DOS. Der einzige Unterschied ist das man bei Linux zuerst
die Port-Adressen freigeben muss, hierfür ist die Funktion ioperm(...) zuständig. Das ist aber nur dann möglich
wenn das Programm Superuser-Rechte besitzt, und kein anderes Programm auf die Ports zugreift (z.B. ein Drucker Treiber).
Das heißt der LINUX-Kernel muss ohne Gerätetreiber für die parallele Schnittstelle kompiliert werden, bzw. der
Gerätetreiber darf nicht gemounted werden !
Falls das nicht möglich ist gibt es noch die Möglichkeit die
parallele Schnittstelle indirekt über einen Gerätetreiber
anzusprechen, über die ioctl Funktion.. Das funktioniert nach einem
ähnlichen Schema wie unter NT. Auf diese Möglichkeit gehe ich aber
hier nicht genauer ein.
Die beiden Port-Zugriffsfunktionen void outp(int Port,int
Data) und void inp(int Port,int Data)
sind hier als inline Assembler realisiert.
#include <sys/perm.h> #include <stdio.h> inline void outp( unsigned short port , unsigned char value ) { __asm__ __volatile__ ( "outb %b0,%w1" : : "a" (value), "d" (port) ); } inline unsigned char inp(unsigned short port) { unsigned char vv; __asm__ __volatile__ ( "inb %w1,%b0" : "=a" (vv) : "d" (port) ); return vv; } int main() { unsigned char port1,port2; ioperm( 0x378 ,8,1); /* Ports freigeben */ outp( 0x378, 0x01 ); /* D0 auf High setzen */ outp( 0x378, 0x02 ); /* D1 auf High setzen */ outp( 0x378, 0x07 ); /* D0,D1,D2 auf High setzen */ port1 = inp( 0x379 ); printf("\n Error ist auf %s",(port1&0x08)? "high":"low" ); printf("\n Select ist auf %s",(port1&0x10)? "high":"low" ); printf("\n Paper out ist auf %s",(port1&0x20)? "high":"low" ); printf("\n Acknowlege ist auf %s",(port1&0x40)? "high":"low" ); printf("\n Bussy ist auf %s",(port1&0x80)? "low" :"high"); port2 = inp( 0x37A ); outp( 0x37A, port2^1 ); /* Strobe invertieren */ ioperm( 0x378 ,8,0); /* Ports wieder sperren */ return 0; }
Die Tools bestehen aus sechs Funktionen:
LptDetectPorts Ports aufzählen
LptInit Treiber initialisieren
LptExit Treiber deinitialisieren
LptPort Portadresse abfragen
LptPortIn Port einlesen
LptPortOut Port-Ausgabe
Um ein Port ansprechen zu können muss man mit LptInit
den Treiber zuerst initialisieren. Unter NT und Win2000 wird ein
Systemtreiber automatisch installiert, sofern das Programm
Administratorrechte besitzt, und der Systemtreiber
LptDriver.sys sich im selben Verzeichnis
befindet wie die EXE-Datei. Wenn das nicht der Fall ist muss man die
Datei LptDriver.sys von Hand ins Verzeichnis C:\WINNT\SYSTEM32
kopieren.
Für Linux muss man die Datei LptToolsLinux.cpp mit kompilieren statt LptTools.cpp.
Hier ist ein kleines Beispiel wie man die Lpt-Tools anwendet:
#include <windows.h>
#include "LptTools.h"
#define LPT1 0
#define LPT2 1
int main()
{
int i;if(!LptInit()) // Treiber initialisieren
{
printf("Der Treiber ist nicht installiert.");
return -1;
}
LptPortOut(LPT1,0,0x01); // D0 auf 'high' setzen bei LPT1
LptPortOut(LPT2,0,0x01); // D0 auf 'high' setzen bei LPT2
LptPortOut(LPT1,0,0x02); // D1 auf 'high' setzen bei LPT1
LptPortOut(LPT1,0,0x03); // D0 und D1 auf 'high' setzen bei LPT1
i=LptPortIn (LPT1,2); // Diverse Bits einlesen
LptPortOut(LPT1,2,i| 0x01); // Strobe auf LPT1 setzen
LptPortOut(LPT1,2,i&~0x01); // Strobe auf LPT1 löschen
i=LptPortIn (LPT1,1); // Diverse Bits einlesen
for(i=0;i<20;i++) // D3 im Sekundentakt ein ausschalten
{
LptPortOut(LPT1,0,0x08); // Nur D3 auf 'high' setzen bei LPT1
Sleep(500);
LptPortOut(LPT1,0,0x00); // Alle Pins auf 'low' setzen bei LPT1
Sleep(500);
}
LptExit(); // Treiber deinitialisierenreturn 0;
}
Anmerkung die Datei LptTools.cpp muss dem Projekt hinzugefügt werden.
Bei LptPortOut gibt der erste Parameter an auf welche Schnittstelle man zugreifen will (0=LPT1 1=LPT2 ... usw. ...). Der Zweite Parameter gibt an auf welches Port der Schnittstelle man schreiben will (siehe Tabelle). Der dritte Parameter ist der Wert der auf das Port geschrieben wird. Bei Port 0 ist das Bit0 der Zustand der Leitung D0, Bit1 ist der Zustand der Leitung D1 und so weiter. Will man z.B. die Leitungen D1 und D4 auf HIGH setzen, so muss man den Wert 0x12 ( (1<<1) + (1<<4) ) auf Port 0 schreiben. Die anderen Leitungen ( D0,D2,D3,D5,D6,D7) werden dabei auf LOW gesetzt.
Der Treiber LptDriver.sys gibt den direkten
Zugriff aus die IO-Ports der parallelen Schnittstelle frei.
Mit dem Treiber kann wie unter Win95/98, mit outp, nach dem Aufruf von LptInit,
direkt auf die Ports zugegriffen werden. Die Assembler-Befehle out und in kann man auch benutzten.
Es ist auch möglich andere Ports frei zu schalten, z.B. von anderen ISA-Buskarten. Dazu gibt es die Funktion
BOOL LptMapPorts(unsigned uPort,unsigned uSize) in den LptTools.
Will man nur den Treiber auf einen Rechner ohne Administratorrechten
installieren, geht man wie folgt vor:
1. Sich als Administrator einloggen.
2. Diesen Code ausführen:#include "LptTools.h"
int main()
{
if(!LptDriverInstall()) // Treiber initialisieren
{
printf("Der Treiber wurde nicht installiert.");
}
else
{
printf("Der Treiber wurde erfolgreich installiert.");
}
return 0;
}3. Als Benutzer ohne Administratorrechte einloggen.
Download der Lpt-Tools des Treibers und eines Demo-Programms: Lpt-Tools. Bevor das Beispiel LptDemo in den Tools gestartet werden kann, muss man den Treiber (LptDriver.sys) ins Verzeichnis ./LptDemo___Win32_Debug kopieren !
Ein kleiner Beispiel-Dialog ist unter dem Namen LptWizard in den Tools ebenfalls enthalten:
"LptTools.h"#include
int main()
{
int
i;
if(!LptInit())
// Treiber initialisieren
{
printf("Der
Treiber ist nicht installiert.");
return -1;
}
LptPortOut(LPT1,0x402,0x20);
//
return 0;
}
Anton Zechner
![]() |