BT2kLOGO
Bücher aus eigener Feder
Leseprobe
- -

B. Kainka / H.-J. Berndt
PC-Schnittstellen unter Windows
Messen, Steuern und Regeln über die Standard-Ports
Elektor-Verlag GmbH, 52072 Aachen, 1999 ISBN 3-89576-086-2
www.elektor.de

 


1 Einleitung

Jeder Versuch, mit Computern reale Prozesse zu steuern oder zu überwachen, erfordert zunächst einmal eine geeignete Verbindung zur Außenwelt des Rechners. Ein Programm muß in der Lage sein, Informationen von außen zu erfassen und Steuerungen an äußeren Geräten vorzunehmen. Die verarbeiteten Informationen können in binärer Form, also als Ja/Nein- Entscheidungen, oder als analoge Größen (größer/kleiner) vorliegen.

Das erforderliche Tor zur Außenwelt wird durch Interfaces geöffnet. Für PCs nach dem Industriestandard haben sich folgende Formen von Interfaces durchgesetzt:

- Erweiterungskarten werden in den Rechner gesteckt und erlauben höchste Arbeitsgeschwindigkeiten, sind allerdings auch mit hohen Kosten verbunden.

- Standardschnittstellen verbinden den PC mit externen Interface-Schaltungen. Üblich sind z.B. Interfaces an der seriellen RS232-Schnittstelle, die sich relativ preiswert aufbauen lassen.

- Interfaces mit einem eigenen Prozessor führen Aufgaben weitgehend ohne Datenaustausch mit dem PC durch. Der Anwender muß sich dabei zusätzlich mit der Programmierung dieser Systeme auseinandersetzen.

- Die ohnehin vorhandenen Schnittstellen des PC, also die serielle Schnittstelle, die Druckerschnittstelle und oft auch der Joystick-Anschluß, lassen sich direkt als Interface nutzen. Damit erübrigt sich für zahlreiche Anwendungen jegliche zusätzliche Hardware.

Die direkte Verwendung vorhandener Schnittstellen eignet sich besonders für einfache Versuche. So lassen sich z.B. an die serielle Schnittstelle ohne weiteres Schalter oder Leuchtdioden direkt anschließen, womit viele interessante Projekte möglich werden. Die Druckerschnittstelle stellt eine größere Zahl direkt ansprechbarer Leitungen zu Verfügung, mit denen hohe Übertragungsgeschwindigkeiten zu erreichen sind.

Viele Einschränkungen lassen sich durch einfache Zusatzschaltungen überwinden. So ist die Erfassung von Spannungen mit wenigen zusätzlichen Bauteilen möglich, wenn man etwas komplexere Programme und geringere Geschwindigkeiten in Kauf nimmt. Auch Projekte mit vielen Ein/Ausgabeleitungen lassen sich mit geringem zusätzlichen Aufwand durchführen.

Allgemein werden in diesem Buch Verfahren vorgestellt, die mit weniger Hardware und etwas rechenzeitintensiveren Programmen arbeiten. Der Leser sollte Vorerfahrungen mit einer Programmiersprache haben und über Grundkenntnisse der Elektronik verfügen. Die vorgestellten Schaltungen sind meist so einfach, daß sie problemlos auf Lochrasterplatinen aufgebaut werden können. Alle Projekte in diesem Buch sind in sich geschlossenen und eignen sich für den direkten Nachbau. Darüber hinaus stellen sie Bausteine für weitergehende Entwicklungen zur Verfügung, wobei die komplexeren Verfahren die sichere Anwendung geeigneter Meßgeräte erforderlich machen. Der interessierte Leser sollte z.B. über ein Oszilloskop verfügen.

Die in diesem Buch eingesetzten Programmiersprachen für das Betriebssystem Windows95/98 sind Visual Basic 5 und Delphi 3 und 4. Alle Programmbeispiele befinden sich mit auf der CD zum Buch.



1.1 Die PORT.DLL

Die besondere Schwierigkeit unter Windows ist der Zugang zu den Schnittstellen des PC. Deshalb wird hier eine universell einsetzbare DLL (Dynamic Link Library, eine Windows-Funktionsbibliothek) eingesetzt, die ihrerseits in Delphi 3 geschrieben wurde. Eine DLL erfüllt die Funktion einer Spracherweiterung für unterschiedliche Programmiersprachen. Die speziell für dieses Buch entwickelte PORT.DLL befindet sich auf der CD. Die DLL muß ins Windows-Systemverzeichnis kopiert werden, damit sie von jedem Programm benutzt werden kann. Alternativ kann sie auch im Programmverzeichnis des jeweiligen EXE-Programms stehen. 

Die PORT.DLL erfüllt folgende Aufgaben:

- Öffnen von Schnittstellen 
- Serielle Datenübertragung 
- Zugang zu Schnittstellenleitungen 
- Allgemeine Port- Ein- und Ausgaben 
- Zeitgeberfunktion für genaue Millisekunden 
- Zeitgeberfunktion im Mikrosekundenraster 
- Zugriff auf die Soundkarte 
- Joystickeingaben 

Die DLL kann unter ganz unterschiedlichen Programmiersystemen verwendet werden. Außer den in diesem Buch benutzen Sprachen können ihre Funktionen z.B. auch aus C-Programmen aufgerufen werden. Ein einmal entwickeltes Programm kann daher leicht auf andere Programmiersysteme übertragen werden. Außerdem kann man die DLL in Word- oder Excel-Makros ansprechen (Vgl. Kap 1.2 und Kap. 14, nähere Hinweise finden sich auch in [5]). 

Die Entwicklung einer allgemeinen DLL zum Zugriff auf beliebige Hardware läuft in gewisser Weise der Windows-Philosophie entgegen, alle Hardware-Zugriffe über Treiber zu regeln. Ein Treiber gehört immer zu einem ganz bestimmten Gerät. Für kleine Hardware-Experimente ist da eigentlich kein Platz. Der korrekte Weg der Entwicklung eines Treibers ist aber so aufwendig, daß er praktisch nur von großen Firmen begangen werden kann.

Unter DOS gab es in jeder Programmiersprache Port-Befehle (GWBASIC: INP und OUT, in Turbo Pascal: PORT[..]), mit denen man direkt auf die gesamte Hardware des PC zugreifen konnte. Unter Windows 3.1 waren die Beschränkungen noch relativ begrenzt, so daß man sich leicht daran vorbeimoglen konnte. Sogar Delphi 1 besaß noch den alten PORT-Befehl.

Unter Windows 95 wird es schon schwieriger. In Visual Basic 5 gibt es keine direkte Möglichkeit für allgemeine Portzugriffe mehr. Ab Delphi 3 gelingt ein direkter Zugriff auf Portadressen nur noch mit Hilfe eines Assembler-Inlinecodes. Dieser wird in der DLL verwendet, um einen allgemeinen Zugriff nun auch wieder in Visual Basic zu ermöglichen. Das Betriebssystem läßt sich jedoch nicht mehr ohne weiteres "hintergehen", so daß man z.B. eine Schnittstelle erst ganz ordnungsgemäß anmelden muß, bevor man beliebige Dinge mit der zugehörigen Hardware tun kann.

Unter Windows NT schließlich scheint der Zug für den Hobbyentwickler endgültig abgefahren. Das System ist so auf Sicherheit hin entwickelt, daß niemand mehr direkt auf die Hardware zugreifen darf. Was bleibt, ist noch der ordnungsgemäße Weg über Treiber. Allgemeine Hardware sollte dabei über die serielle Schnittstelle angesprochen werden. Hier sind weiterhin alle Zugriffe möglich, da keine Portzugriffe, sondern ordnungsgemäße Systemroutinen verwendet werden. 

Allgemein muß betont werden, daß es in diesem Buch um die experimentelle Arbeit mit PC-Schnittstellen geht. Die Entwicklung der vorgestellten Programme erfolgte unter Windows95 und Windows98 mit 32-Bit-Systemen (Visual Basic 5 und Delphi 4). Dabei besteht immer das Risiko, daß ein Programm auf bestimmten Rechnern nicht mehr läuft. Eine Schnittstelle könnte z.B. in einem System anders installiert sein, als es vorgesehen war. Oder man gerät an eine neue Windows-Version, die wieder etwas anders mit den Schnittstellenzugriffen umgeht. Man sollte also nicht versuchen, auf dieser Basis professionelle Entwicklungen durchzuführen. Sonst könnte es leicht passieren, daß man vor lauter bösen Anrufen frustrierter Anwender auf eine ferne Insel fliehen muß.



1.2 DLL-Aufrufe in Visual Basic 5

Die grundlegende Verwendung einer DLL soll hier an einem einfachen Beispiel zunächst ohne zusätzliche Hardware gezeigt werden. Der PC-Lautsprecher wird über Bausteine angesteuert, die über Portbefehle gesteuert werden können. Er läßt sich entweder mit einem Timer steuern, um einen Ton mit bestimmter Frequenz auszugeben, oder man steuert ihn über eine Ausgabeleitung des PIO-Bausteins 8255 im PC direkt. Auch so kann man Töne erzeugen, indem man nämlich eine Leitung in schneller Folge ein- und ausschaltet. Dies soll hier geschehen, um einerseits die grundsätzliche Einbindung einer DLL kennenzulernen und andererseits das Zeitverhalten unter Windows zu untersuchen. 

Der Lautsprecher wird über Bit 1 des Port B am 8255 gesteuert. Der Baustein belegt die Adressen ab 60h (96 dez) im I/O-Bereich des PC. Port B liegt an der Adresse 97. Portausgaben sind immer 8 Bit breit, so daß acht Leitungen gleichzeitig geschaltet werden. Es darf jedoch nur die zweite Leitung (Bit 1) verändert werden, denn Bort B des PIO-Bausteins steuert noch vieles andere. Deshalb muß der Portzustand zunächst gelesen werden, um nur ein Bit zu verändern. Wer diese Bitbeißerei bis hierhin noch nicht ganz verstanden hat, der soll sich deshalb keine Gedanken machen, denn erstens befindet sich das fertige Programmbeispiel auf der CD, und zweitens gestaltet sich vieles für die nach außen zugänglichen Schnittstellen wesentlich einfacher. 

Für den Zugang zu den einzelnen Portadressen des PC bietet die DLL zwei spezielle Funktionen:

OutPort adr, dat   Ausgabe von Daten an eine Adresse 
InPort adr            Lesen von einer I/O-Adresse 

In Visual Basic kann OutPort als Sub (Prozedur) eingebunden werden, InPort dagegen muß eine Funktion sein. Die einzelnen Elemente einer DLL werden mit dem DECLARE-Befehl angegeben. Damit die Datenübergabe zwischen Visual Basic und der DLL richtig funktioniert, müssen alle Übergabeparameter ByVal deklariert werden, d.h. als Wert im Gegensatz zur Übergabe einer Referenz-Adresse. Unter dem 32-Bit-Betriebssystem Windows95/98 muß bei der Deklaration die Großschreibung beachtet werden. In der DLL wurden alle Funktionen nur mit Großbuchstaben bezeichnet, was nun auch bei der Bezeichnung im aufrufenden Programm eingehalten werden muß. Die Deklarationen müssen sich in einem eigenen Modul (hier: Module1.bas) befinden, das in das Projekt TON eingebunden wird. 


Abb. 1.1 Das Projekt Ton

Declare Sub OUTPORT Lib "PORT.DLL" (ByVal Adr As Integer, ByVal Dat As Integer)
Declare Function INPORT Lib "PORT.DLL" (ByVal Adr As Integer) As Integer
Declare Sub DELAY Lib "PORT.DLL" (ByVal Zeit As Integer)

Listing 1.1 Die Deklarationen im Module1.bas

InPort und OutPort sind nun im gesamten Projekt verwendbar. Zusätzlich wurde auch gleich die Delay-Prozedur deklariert, die weiter unten verwendet werden soll. Eine erste Tonausgabe soll in einer schnellen Schleife 100 Rechteckimpulse am Lautsprecher erzeugen, die dann als Ton hörbar sein sollten. Die einzelnen Bitmanipulationen der Portausgabe mit OutPort verwenden die logischen Funktionen AND und OR, um jeweils nur eine Leitung des mit InPort gelesenen Ports zu verändern. Auch diese Funktionen werden an späterer Stelle noch genauer erläutert.

Das Programm soll ein einfaches Formular mit einer Schaltfläche "Ton" verwenden. Die Lautsprecherleitung wird 100 mal ein- und ausgeschaltet. Damit man z.B. bei einem PC mit 200 MHz überhaupt einen Ton hören kann, müssen zusätzliche Wartezeiten eingefügt werden. Sie werden hier durch Zählschleifen bis 10000 gebildet. 


Abb. 1.2 Das Programmfenster

Private Sub Command1_Click()
  For n = 1 To 100
    OUTPORT 97, (INPORT(97) Or 2)
    For t = 1 To 10000: Next t
    OUTPORT 97, (INPORT(97) And 253)
    For t = 1 To 10000: Next t
  Next n
End Sub

Listing 1.2 Tonausgabe über den Lautsprecher (TON.FRM)

Betätigt man die Ton-Schaltfläche, dann ist tatsächlich ein Ton zu hören. Die genaue Tonhöhe ist vom verwendeten Rechner abhängig. Außerdem zeichnet sich der Ton nicht gerade durch eine große Reinheit aus. Vielmehr klingt er reichlich verrauscht und kratzig, man könnte auch sagen krächzend. Die Ursache dafür liegt im Zeitverhalten von Windows. 

Die durch die Verzögerungsschleifen gebildeten Wartezeiten können keinesfalls gleichmäßig ausfallen, weil Windows so ganz nebenbei noch viele andere Aufgaben erledigen muß. Es muß z.B. die Maus beobachtet werden, und es müssen eventuell parallel laufende Prozesse verwaltet werden. Man spricht deshalb gern davon, daß Windows nicht "echtzeitfähig" ist, daß man also mit Windows schnelle Prozesse nicht zuverlässig steuern kann. Allerdings ist das relativ, denn es kommt immer darauf an, wie schnell und wie zuverlässig man es braucht. Saubere Töne kann man jedenfalls schon mal nicht erwarten, wenn man wie im vorigen Programmbeispiel vorgeht.

Zählschleifen sind allerdings ohnehin nicht die erste Wahl, wenn es um Zeitverzögerungen geht. Vielmehr liefert Windows selbst bessere Mittel, um genauere Verzögerungen im Millisekundenbereich zu erhalten. Sie werden über die Delay-Funktion der DLL zugänglich. Die Tonausgabe kann daher durch die Verwendung von Delay wesentlich verbessert werden. Leider ist die höchste Ausgabefrequenz nur 500 Hz, wenn man einmal pro Millisekunde den Portzustand wechselt. 

Private Sub Command1_Click()
  For n = 1 To 100
    OUTPORT 97, (INPORT(97) Or 2)
    DELAY 1
    OUTPORT 97, (INPORT(97) And 253)
    DELAY 1
  Next n
End Sub

Listing 1.3 Tonausgabe mit Delay (Ton2.frm)

Der nun erzeugte Ton hört sich schon wesentlich besser an, wenn auch noch immer nicht so rein, wie er rein elektronisch zu erzeugen wäre. Das Ergebnis läßt sich mit der DLL-Prozedur RealTime (true) noch wesentlich verbessern (vgl. Kap3.2). Man erhält hier aber immerhin schon einen groben Eindruck davon, wie weit die Echtzeitfähigkeit von Windows gehen kann. Genauere Untersuchungen könnte man mit einem Oszilloskop durchführen. Aber dafür eignen sich eher Programme, die eine Schnittstellenleitung z. B. an der seriellen COM-Schnittstelle schalten. 

Neben einer Delayfunktion für Millisekunden gibt es in der DLL auch noch eine Verzögerung im Mikrosekundenraster. Auch diese greift intern auf Windows-Aufrufe zurück. 

Alle DLL-Aufrufe sollten in einem externen Basic-Modul PORTS.BAS deklariert werden. Es kann dann problemlos in jedes neue Projekt eingeladen werden. Ohne sich noch um die genauen Konventionen der Deklaration kümmern zu müssen, hat der Programmierer nun den Zugriff auf alle DLL-Funktionen. Die PORT.DLL muß dann mit dem kompilierten Pragramm weitergegeben werden und entweder im Windows-Verzeichnis oder im Verzeichnis des EXE-Programms stehen. 

Declare Function OPENCOM Lib "Port" (ByVal A$) As Integer
Declare Sub CLOSECOM Lib "Port" ()
....
Declare Sub SOUNDCAPIN Lib "Port" ()
Declare Sub SOUNDCAPOUT Lib "Port" ()

Listing 1.4 Das Modul PORTS.BAS mit Deklarationen für VB5

In ähnlicher Weise lassen sich die DLL-Funktionen auch in VBA deklarieren (vgl. [5]). Man kann also prinzipiell alle Versuche aus diesem Buch auch mit Word oder Excel durchführen. Die Programme lassen sich dann als Makro aus der Anwendung heraus starten. Ab Word 7 und Excel 7 lauten die Deklarationen wie in Visual Basic 5. Das folgende Beispiel zur Tonerzeugung mit dem PC-Lautsprecher wurde mit Word 97 gebildet. Weitere VBA-Beispiele finden sich in Kap. 14. 


Abb. 1.3 Ein Makro in Word97

In Word 97 kann auch in einem Makro eine User-Form verwendet werden, die eigene Steuerelemente enthalten kann. Dann muß vor "Declare" das Schlüsselwort "Private" stehen. Ebenso werden alle Funktionen und Prozeduren mit "Private" gebildet. 



1.3 DLL-Aufrufe unter Delphi

Auch in Delphi 4 sollen alle Portzugriffe nur über die PORT.DLL erfolgen. Das erste Beispiel ist wieder eine einfache Tonerzeugung über den PC-Lautsprecher. Das Programm enthält zwei Schaltflächen zur Tonerzeugung, wobei einmal (Ton1) mit einer Zählscheife und einmal (Ton2) mit Delay gearbeitet wird.


Abb. 1.4 Das erste Delphi-Programm

Die DLL-Erweiterungen werden wie normale Prozeduren und Funktionen in der selben Unit angegeben und enthalten statt eines Programmcodes den Hinweis auf die externe DLL. Die Schlüsselworte "stdcall" und "external" regeln die Übergabe der Parameter an die DLL und sind entscheidend für einen korrekten Aufruf. 

Wichtig ist auch die Wahl der geeigneten Typen für die übergebenen Variablen. Es hat sich gezeigt, daß mache Integer-Typen nicht mehr zwischen den einzelnen Delphi-Versionen kompatibel sind. Es kann also insbesondere dann Probleme geben, wenn man einen Quelltext aus Dephi 3 in Delphi 4 verwenden möchte oder umgekehrt. Keine Probleme hat man mit den Typen Word (16 Bit ohne Vorzeichen) und DWord (32 Bit ohne Vorzeichen) sowie Real. 

In Delphi darf die eigentliche Unit (*.pas) nicht den selben Namen wie das Projekt (*.dpr) tragen. In diesem Buch soll daher durchgehend ein P für "Projekt" an den Namen der Projektdatei angehängt werden. Zur Unit TON1.PAS gehört daher das Projekt TON1P.DPR. Beim Compilieren entsteht daher zunächst das ausführbare Programm TON1P.EXE, das aber der besseren Übersicht wegen auf der CD in TON1.EXE umbenannt wurde. 

unit Ton1;
interface

uses Windows, Messages, SysUtils, Classes, Graphics,Controls, Forms, Dialogs, StdCtrls;

type
 TForm1 = class(TForm)
 Ton1: TButton; Ton2: TButton;
 procedure Ton1Click(Sender: TObject);
 procedure Ton2Click(Sender: TObject);
end;

var Form1: TForm1;

implementation

{$R *.DFM}

procedure OUTPORT (adr: Word; Wert: Word); stdcall; external 'PORT.dll';
function INPORT (adr: Word):Integer; stdcall; external 'PORT.DLL';
procedure DELAY (ms: Word); stdcall; external 'PORT.DLL';

procedure TForm1.Ton1Click(Sender: TObject);
var n, t: Integer;
begin
 For n := 1 to 100 do begin
  OutPort (97, (InPort (97) OR 2));
  For t := 1 to 10000 Do;
  OutPort (97, (InPort (97) AND 253));
  For t := 1 to 10000 Do;
 end;
end;

procedure TForm1.Ton2Click(Sender: TObject);
var n: Integer;
begin
 For n := 1 to 100 do begin
  OutPort (97, (InPort (97) OR 2));
  Delay (1);
  OutPort (97, (InPort (97) AND 253));
  Delay (1);
 end;
end;

end.

Listing 1.5 Tonausgaben in Delphi (Ton1.pas)

Wählt man eine Zählschleife zur Zeitverzögerung, dann wird sehr schnell die insgesamt gegenüber Visual Basic etwa 10 mal größere Ausführungsgeschwindigkeit sichtbar. Mit einem 200-MHz-PC ergibt sich für eine Zählschleife bis 10000 eine Frequenz von ca. 5 kHz. Bei noch schnelleren Rechnern ist der Ton kaum noch hörbar.

Viele Anwendungen sind auf einen zuverlässigen Zeitablauf unabhängig vom verwendeten Rechner angewiesen. Über die Delay-Prozedur ergibt sich prinzipiell in jeder Umgebung dasselbe Zeitverhalten. Mit einem Klick auf Ton2 erhält man einen konstanten Ton von 500 Hz, der auf Delay basiert.

Auch in Delphi ist es sinnvoll, alle Deklarationen der DLL in einem eigenen Modul, hier in Form einer Unit unterzubringen. Die Unit PORTINC.PAS (in der compilierten Form PORTINC.DCU) kann dann in jedes neue Projekt eingebunden werden, so daß man sich nie mehr um die einzelnen Deklarations-Konventionen kümmern muß.

unit PORTINC;
interface
uses windows;

const THEDLL='PORT.DLL';

Function OPENCOM(S:PCHAR):Integer;stdcall; external THEDLL;
Procedure RTS(d:WORD);stdcall; external THEDLL;
....
Procedure SOUNDCAPIN; stdcall; external THEDLL;
Procedure SOUNDCAPOUT; stdcall; external THEDLL;

implementation
end.

Listing 1.6. Dekrarationen zur PORT.DLL in der Datei PORTINC.PAS


.
Startseite Bücher Software SatDX Musik Kontakt

Für Inhalt und weitere Verzweigung externer Links sind die Betreiber der dortigen Seiten verantwortlich - H.-J. Berndt