Wir haben aber noch lange nicht fertig, denn jetzt wird's ja erst interessant......
Zuerst trennen wir mal den gelesenen Wert und den Ausgabewert, indem wir für den Ausgabewert ein zweites Editfeld einbauen und der Ausgabe dieses übergeben:
Delphi-Quellcode:
WriteLPTPort := Str_To_Byte(Edit2.Text);
asm
Mov DX, $378
Mov AL, WriteLPTPort
Out DX, AL
end;
Deklarieren wir weitere globale Variablen
Delphi-Quellcode:
Work_Str_In : string;
Work_Str_out : string; // In CreateForm wird Wert "00000000" zugewiesen
So, und nun kann ich auf dem Weg, Relais anzusteuern mit den gelesenen Bit einiges anstellen....
z.B.
Delphi-Quellcode:
Work_Str_In := Edit1.Text;
if ((Work_Str_In[2] = '1') and (Work_Str_In[5] = '1') or (Work_Str_In[7] = '1')) and (FormatDateTime('hh:nn:ss', Time) = '11:00:00') then Work_Str_Out[1] := '1' else ... ???
(neee,
else hier bitte nicht, da ihr sonst u.U. aufgrund der Zeitabfrage nix zu sehen bekommt)....
besser ist da die eigene Rücksetzbedingung.....
if (Work_Str_In[2] = '0') then Work_Str_Out[1] := '0';
Aber da könnt ihr euch ja nun mächtig austoben und allemöglichen Kreuz- und Knüppelschaltungen ausprobieren. Nur nicht vergessen:
Delphi-Quellcode:
Edit2.Text := Work_Str_Out;
WriteLPTPort := Str_To_Byte(Edit2.Text);
asm
Mov DX, $378
Mov AL, WriteLPTPort
Out DX, AL
end;
Ach ja, ich glaube, hier ist es angebracht,
WriteLPTPort zur Procedure zu machen....
Delphi-Quellcode:
procedure WriteLPTPort(Port: Word; Byte_Out: Byte);
begin
asm
Mov DX, Port
Mov AL, Byte_Out
Out DX, AL
end;
end;
... und
ReadLPTPort zur Function
Delphi-Quellcode:
function ReadLPTPort(Port: Word): Byte;
begin
asm
Mov DX, Port
// Portadresse in DX Register schreiben
In AL, DX
// Port in AL Register lesen
Mov ReadLPTPort, AL
// Wert aus AL Register in Variable eintragen
end;
end;
Jetzt heißt es :
Delphi-Quellcode:
WriteLPTPort($378, Str_to_Byte(Edit2.Text));
..........
Edit1.Text := Byte_To_Str(ReadLPTPort($378));
..........
Tja, wenn da nicht...
Der Parallelport von Hause aus ein Ausgabeport wäre und es ist nicht immer gesagt, das
ReadLPTPort
($378) das gewünschte Ergebnis bringt. Aber der Hersteller hat sich etwas einfallen lassen und in
den meisten Fällen sollte es funktionieren....
Man setze Bit 5 im Steuerregister auf '1'. Nicht jedes teure Buch verrät diesen Trick, aber wie sonst sollte ein Scanner der alten Generation z. B. Daten über den Parallelport in den PC schieben...
So setzt man vor die Zeile
Edit1.Text := Byte_To_Str(ReadLPTPort($378));
Eine Anweisung:
WriteLPTPort($37A, Str_to_Byte('00100xx1'));
Diese 2 'x' sind Bits, mit denen ich den Eingabekanal adressiere, also das CS-Signal bilde, und die Portbuffer in Richtung zum Parallelport durchschalte. Um zu verhindern, das der Portbuffer gegen den Parallelport durchschaltet, gibt es 2 Möglichkeiten:
Einmal: Ich schalte den Portbuffer immer auf Ausgabe, nur für die kurze Zeit zum Einlesen gebe ich die
Richtung zum Port frei, oder ich lege 100 Ohm – Widerstände in die Datenleitung zwischen Portbuffer und Parallelport. Das brät mir wenigstens den Portbaustein nicht weg, falls die Signale mal gegeneinander stehen....
So, nun mal ein kompletter Einlesevorgang:
Delphi-Quellcode:
WriteLPTPort(37Ah, Str_to_Byte('00100xx1'));
Edit1.Text := Byte_To_Str(ReadLPTPort($378));
WriteLPTPort(378h, Str_to_Byte('00000xx0'));
Aber wieso muss nun Bit 5 und Bit 0 gesetzt, bzw. zurückgesetzt werden. Ganz einfach, Bit 5 steht am Parallelport nicht zur Verfügung und ist intern zur Steuerung im Portchip verschaltet. Bit 0 hat aber für Drucker die Bedeutung, dass Daten abgeholt werden können. Wir müssen dem Portchip sagen, es kommen
Daten von außen und die Portbuffer in die Richtung schalten.
Also, Bit 5 für den Portchip und Bit 0 für die Portbuffer.
Mit den Bit 1 und 2 werden die Kanäle selektiert. Die Erklärung und Beispiele folgen später.
Da es mit einem Interrupt auf dem LPT-Port nicht ganz so einfach ist, muss die Funktion
ReadLPTPort zyklisch von einer Timerroutine aufgerufen werden. Also, 10ms sollten nicht unterschritten werden, damit das Programm nicht zu sehr ausgebremst wird. Für viele Anwendungen reicht
eine 100ms Abtastung völlig aus. Die Zuweisung eines Ausgangs wird vom Programm ausgelöst.
Um mal ein Beispiel zu nennen, Steuerungen von Maschinen lesen zuerst die Eingangskarten und legen die Information in einem Speicher ab. Dann erfolgt die Bearbeitung mit Ablage der Ergebnisse in einem weiteren Speicherbereich. Nach Abarbeitung wird der gesamte bearbeitete Speicher zu den Ausgangskarten
übertragen.
Kurz:
- Eingänge lesen
- Programm bearbeiten
- Ausgänge schreiben
Und wieder erneut
- Eingänge lesen
...........
und genau dies können wir auch mit einem Programm erreichen, aber ein PC ist nun mal keine Maschinensteuerung und da kommt's schon mal vor, die Festplatte möchte sich mal wieder drehen, die Grafik hätte auch gern wieder etwas Bewegung im Speicher und auch sonst sind diverse nützliche und unnütze Treiber lustig dabei, Zeit für sich zu beanspruchen. Aus diesem Grund ist es Sinnvoll, einen Timer zu benutzen und in regelmäßigen Zeitspannen auf Änderungen der gelesenen Information zu reagieren.
Schließlich soll der Zug ja im Bahnhof anhalten und nicht zufällig auf irgendeinem Teilstück der riesigen Modelbahnanlage......