Sign in Join
Wiki copytemporary

Hardware Access/de: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
1-\
21Zurück zu den [[Additional information/de|Zusätzlichen Informationen]].\
3-\
42
53## Überblick
64
75Diese Seite ist der Beginn eines Tutorials über den Zugriff auf Hardware Geräte mit Lazarus. Diese Geräte enthalten, ohne darauf beschränkt zu sein: ISA, PCI, USB, paralleler und serieller Anschluss.
86
97Der Zugriff auf Hardware Geräte auf einer komplett plattformunabhängigen Weise ist nicht implementiert durch die Free Pascal Runtime Library oder durch die LCL, daher umfasst dieses Tutorial grundsätzlich Hardware Zugriffsmethoden auf verschiedenen Plattformen. Der Code kann unter verschiedenen Umgebungen kompiliert werden unter Verwendung bedingter Kompilierung, etwa so:
108
119``` pascal
1210 uses
1311 Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, ExtCtrls,
1412 {$IFDEF WIN32}
1513 Windows;
1614 {$ENDIF}
1715 {$IFDEF Linux}
1816 ports;
1917 {$ENDIF}
2018```
2119
2220Hilfe ist willkommen, speziell zu MacOS.
2321
2422## Vergleich Parallel \<-\> Seriell
2523
2624ISA Karten, PCI Karten und der parallele Anschluss kommunizieren mit dem Computer unter Verwendung eines **parallelen** Protokolls. Der serielle Anschluss und USB Geräte arbeiten mit einem **seriellen** Protokoll. Da der Prozessor und damit auch alle Programmiersprachen auf Daten parallel zugreifen, ist es wesentlich einfacher solche Protokolle softwareseitig zu programmieren. Beispielsweise erfolgt der Zugriff auf eine Ganzzahl-Variable (INTEGER) nur durch einen einzelnen Befehl. Mit einem seriellen Protokoll kann jedoch nur jeweils auf ein Bit zugegriffen werden. Im Nachhinein ist es notwendig, die Teildaten zusammen zu fügen um sie zu verwenden.
2725
2826Serielle Kommunikation ist schwierig direkt zu programmieren. Wenn allerdings eine fertige Komponente zur Verfügung steht wird es deutlich einfacher. Auch hardwareseitig sind serielle Schnittstellen deutlich umständlicher, daher benötigen die meisten seriellen Schnittstellen spezielle IC-Bausteine oder Microcontroller für die Kommunikation.
2927
3028Hier eine kurze Gegenüberstellung der Hardware-Zugriffsprotokolle:
3129
3230| | Geschwindigkeit | Hardwaredesign |
3331|----------------------|------------------------------|----------------|
3432| Serieller Anschluss | sehr langsam (\< 100 kBit/s) | mittel |
3533| Paralleler Anschluss | langsam (~ 1 MBit/s) | einfach |
3634| ISA Karte | mittel (~ 10 MBit/s) | mittel |
3735| USB 1.x | mittel (~ 1.6 MBit/s) | komplex |
3836| USB 2.0 | schnell (~ 480 MBit/s) | sehr komplex |
3937| PCI Karte | sehr schnell (\> 1 GBit/s) | sehr komplex |
4038
4139## Parallele Kommunikation
4240
4341### Verwendung von inpout32.dll für Windows
4442
4543Windows hat verschiedene Wege für die Ansteuerung von Hardware Geräten bei der 9x Serie und bei der NT Serie, und dies kann wirklich problematisch sein. Die 9x Serie (95, 98, Me) erlaubt den Programmen direkten Zugriff auf die Ports, genau wie unter DOS. Windows NT, jedoch, verhindert dies komplett, und erlaubt nur den Zugriff durch die Gerätetreiber auf die Ports. Dies ist ein Sicherheitsmechanismus, der aber nervig sein kann, wenn ein Gerätetreiber zu komplex für ein kleines Projekt ist, das Zugriff auf den parallelen Port benötigt.
4644
4745Glücklicherweise gibt es eine Bibliothek, die einen Gerätetreiber enthält. Wenn Windows NT erkannt wird, dann dekomprimiert sie das Gerät und installiert den Hwinterface.sys Kernel Gerätetreiber. Wenn Windows 9x erkannt wird, dann benutzt sie einfach Assembler Opcodes für den Zugriff auf die Hardware.
4846
4947Aber wie benutzt man die Bibliothek? Einfach! Sie hat nur zwei Funktionen, Inp32 und Out32, und deren Benutzung ist ganz intuitiv.
5048
5149Wir werden die Bibliothek dynamisch laden, so lassen sie uns zuerst beide Funktionen definieren:
5250
5351``` pascal
5452 type
5553 TInp32 = function(Address: ShortInt): ShortInt; stdcall;
5654 TOut32 = procedure(Address: ShortInt; Data: ShortInt); stdcall;
5755```
5856
5957- Address ist die Adresse des Ports, auf den sie zugreifen wollen. Out32 sendet Daten zu dem Port, den sie mit Adress spezifiziert haben. Inp32 gibt ein Byte von dem Port zurück, den sie mit Address spezifiziert haben.
6058
6159Nun können wir die Bibliothek laden. Dies kann implementiert werden an einer Stelle wie der OnCreate Methode des Hauptformulars ihres Programms:
6260
6361``` pascal
6462 type
6563 TMyForm = class(TForm)
6664 .........
6765 private
6866 { private declarations }
6967 Inpout32: THandle;
7068 Inp32: TInp32;
7169 Out32: TOut32;
7270 .........
7371 implementation
7472 .........
7573 procedure TMyForm.FormCreate(Sender: TObject);
7674 begin
7775 {$IFDEF WIN32}
7876 Inpout32 := LoadLibrary('inpout32.dll');
7977 if (Inpout32 <> 0) then
8078 begin
8179 // needs overtyping, plain Delphi's @Inp32 = GetProc... leads to compile errors
8280 Inp32 := TInp32(GetProcAddress(Inpout32, 'Inp32'));
8381 if (@Inp32 = nil) then Caption := 'Error';
8482 Out32 := TOut32(GetProcAddress(Inpout32, 'Out32'));
8583 if (@Out32 = nil) then Caption := 'Error';
8684 end
8785 else Caption := 'Error';
8886 {$ENDIF}
8987 end;
9088```
9189
9290Wenn sie die Bibliothek bei OnCreate laden, vergessen sie nicht, sie bei OnDestroy zu entladen:
9391
9492``` pascal
9593 procedure TMyForm.FormDestroy(Sender: TObject);
9694 begin
9795 {$IFDEF WIN32}
9896 FreeLibrary(Inpout32);
9997 {$ENDIF}
10098 end;
10199```
102100
103101Hier ist ein einfaches Beispiel, wie man die Inp32 Funktion benutzt:
104102
105103``` pascal
106104 {$IFDEF WIN32}
107105 myLabel.Caption := IntToStr(Inp32($0220));
108106 {$ENDIF}
109107```
110108
111109Dieser Code wurde getestet mit einer maßgeschneiderten ISA Karte auf Port \$0220, unter Verwendung von Lazarus 0.9.10 mit Windows XP. Natürlich müssen sie Windows in ihrem uses Abschnitt haben damit dieser Code läuft. Für den Einsatz müssen sie nur "inpout32.dll" in das selbe Verzeichnis wie ihre Anwendung einfügen.
112110
113111Dies ist die Homepage für die Bibliothek: [www.logix4u.net/inpout32.htm](http://www.logix4u.net/inpout32.htm)
114112
115113### Verwendung von Assembler unter Windows 9x
116114
117115Unter Windows 9x können sie auch Assembler Code verwenden. Suppose you with to write \$CC to the \$320 port. Der folgende Code erledigt das:
118116
119117``` pascal
120118 {$ASMMODE ATT}
121119 ...
122120 asm
123121 movl $0x320, %edx
124122 movb $0xCC, %al
125123 outb %al, %dx
126124 end ['EAX','EDX'];
127125```
128126
129127### Mögliche Fehlerquellen in Windows
130128
131129Eine mögliche Fehlerquelle in Windows bezüglich parallel verwendeter Hardware, die kein "Plug and Play" unterstützt kann darin liegen, dass Windows den von der Hardware benötigten Port einem anderen Gerät zugewiesen hat. Unter der folgenden Adresse können Sie Informationen darüber finden, wie man Windows daran hindern kann, den benötigten Port zu vergeben:
132130
133131<http://support.microsoft.com/kb/135168>
134132
135133### Verwendung von ioperm zum Zugriff auf Ports unter Linux
136134
137135Der beste Weg um auf Hardware unter Linux zuzugreifen, ist durch Gerätetreiber, aber, wegen der Komplexität der Aufgabe, einen Treiber zu erstellen, ist manchmal eine schnelle Methode sehr nützlich.
138136
139137Damit sie die "ports" Unit unter Linux benutzen können, muss ihr Programm als root laufen, und IOPerm muss aufgerufen werden, um eine angemessene Erlaubnis für den Portzugriff zu setzen. Sie können die Dokumentation über die "ports" Unit [hier](http://www.freepascal.org/docs-html/rtl/ports/index.html) finden.
140138
141139Zunächst müssen sie auf glibc verlinken und IOPerm aufrufen. Eine Unit, die auf das ganze glibc verlinkt, existiert in Free Pascal, aber diese Unit macht Probleme, wenn sie direkt von der Anwendung benutzt wird und das statische Verlinken auf die gesamte glibc Bibliothek ist keine sehr gute Idee für eine Multiplattform Anwendung. Die Verwendung plattformspezifischer Funktionen sollte auf ein Minimum reduziert werden.
142140
143141``` pascal
144142 {$IFDEF Linux}
145143 function ioperm(from: Cardinal; num: Cardinal; turn_on: Integer): Integer; cdecl; external 'libc';
146144 {$ENDIF}
147145```
148146
149147- "from" repräsentiert den ersten Port auf den zugegriffen wird.
150148- "num" ist die Anzahl (number) der Ports nach dem ersten Port, auf den zugegriffen wird, daher wird ioperm(\$220, 8, 1) Zugriff ermöglichen für das Programm auf alle Ports zwischen \$220 and \$227 (einschließlich).
151149
152150Nach dem Verlinken auf OIPerm können sie port\[\<Address\>\] eingeben für den Zugriff auf die Ports.
153151
154152``` pascal
155153 {$IFDEF Linux}
156154 i := ioperm($220, 8, 1);
157155 port[$220] := $00;
158156 myLabel.Caption := 'ioperm: ' + IntToStr(i);
159157 i := Integer(port[$220]);
160158 myOtherLabel.Caption := 'response: ' + IntToStr(i);
161159 {$ENDIF}
162160```
163161
164162Dieser Code wurde mit einer maßgeschneiderten ISA Karte auf Port \$0220 getestet, unter Verwendung von Lazarus 0.9.10 unter Mandriva Linux 2005 und Damn Small Linux 1.5
165163
166164PS: Bei aktuellen Lazarus-Versionen, ist in der Unit "x86", die sowieso von der Unit "ports" aufgerufen wird, die Funktion "ioperm" schon vorhanden, sie hat nur einen anderen Namen "fpIOperm"
167165
168166### Der übliche UNIX Hardwarezugriff
169167
170168``` pascal
171169{$IFDEF Unix}
172170Uses
173171 Clib; // retrieve libc library name.
174172{$ENDIF}
175173
176174{$IFDEF Unix}
177175function ioperm(from: Cardinal; num: Cardinal; turn_on: Integer): Integer; cdecl; external clib;
178176{$ENDIF}
179177```
180178
181179**Beachten** sie, dass FPC eine Abstraktion für ioperm genannt "fpioperm" bietet in der [[doc:rtl/x86/index.html|Unit x86]], und auch out und import Funktionen. Diese Funktionen sind gegenwärtig für Linux/x86 und FreeBSD/x86 implementiert.
182180
183181Es wird nicht empfohlen *to link to libc unless absolutely necessary due to possible deployment and portability functions. Also manual linking to libc (by declaring ad hoc libc imports for functions that are available elsewhere) like done above is not recommended (e.g. the above libc import line will unnecessarily fail if the standard C lib is not called libc, wie z.B. libroot unter BeOS (Zeta), oder auf Plattformen mit a non standard C symbol mangling).*
184182
185183**Anmerkung 2** Die Verwendung von unit_ libc wird nicht empfohlen unter anderen Umständen als der Kylix Kompatibilität. Dies ist so, weil die Unit relativ unportierbar ist (wegen der übermäßigen Beanspruchung von Strukturen und anderen privaten Symbolen) und must only be modified as little as possible out of Kylix compability issues.
186184
187185## Serielle Kommunikation
188186
189187Dies sollte ein einfach zu verstehendes Beispiel sein, wie man mithilfe der [Synaser-Bibliothek](http://synapse.ararat.cz/doku.php) auf eine serielle Schnittstelle zugreifen kann. Für zusätzliche Informationen bitte die [Synaser - Dokumentation](http://synapse.ararat.cz/doc/help/synaser.html) zu verwenden.
190188
191189Wichtig ist, das Programm nicht mit STRG-C zu beenden bzw. die Console zu schließen. Dies ist der Grund, weshalb hier am Anfang auch relativ viel Code steht, der im Prinzip nichts anderes zur Aufgabe hat, als den User noch einmal daran zu erinnern.
192190
193191Wirklich interessant wird es erst in der Prozedur "RS232_connect", in der mit TBlockSerial die Klasse aufgerufen wird und anschließend eine Verbindung zu der unter "ser.Connect" angegebenen Schnittstelle aufgebaut wird (im Beispiel wurde ein USB zu Seriell - Adapter verwendet, deshalb /dev/ttyUSB0 und nicht etwa COM0 o.ä.). Ebenfalls wichtig ist die Zeile mit "ser.Config", in der die serielle Schnittstelle konfiguriert wird (Übertragungsgeschwindigkeit in bits/s, data bits, parity bit, stop bit, handshake, ...).
194192
195193Die Konfiguration in dem angegebenen Beispiel ist so ausgelegt, dass das Programm einfach mit einer seriellen Maus, welche an die serielle Schnittstelle angeschlossen ist, getestet werden kann.
196194
197195``` pascal
198196program serialtest;
199197
200198{$mode objfpc}{$H+}
201199
202200uses
203201 {$IFDEF UNIX}{$IFDEF UseCThreads}
204202 cthreads,
205203 {$ENDIF}{$ENDIF}
206204 Classes,SysUtils,Synaser,Crt
207205 { you can add units after this };
208206
209207 var l:boolean;
210208
211209 function check_affirmation():boolean;
212210 var k:string;
213211 begin
214212 Writeln('Zum Abbrechen der Anwendung bitte nicht STRG-C verwenden, sondern'+
215213 ' irgendeine Taste drücken. Bitte bestätigen sie diesen Hinweis, bevor das Programm'+
216214 ' fortgeführt wird: [0]=Beenden, [1]=Bestätige, fahre fort! ');
217215 Writeln('Ihre Eingabe: ');
218216 Read(k);
219217 if StrtoInt(k) = 1 then
220218 begin
221219 check_affirmation:=true;
222220 Writeln('OK, fahre fort');
223221 end
224222 else
225223 begin
226224 check_affirmation:=false;
227225 Writeln('Abbruch');
228226 end
229227 end;
230228
231229 procedure RS232_connect;
232230 var
233231 ser: TBlockSerial;
234232 begin
235233 ser:=TBlockSerial.Create;
236234 try
237235 ser.Connect('/dev/ttyUSB0');
238236 Sleep(1000);
239237 ser.config(1200, 7, 'N', SB1, False, False);
240238 Write('Device: ' + ser.Device + ' Status: ' + ser.LastErrorDesc +' '+
241239 Inttostr(ser.LastError));
242240 Sleep(1000);
243241 repeat
244242 Write(IntToHex(ser.RecvByte(10000), 2), ' ');
245243 until keypressed;
246244 finally
247245 Writeln('Serielle Schnittstelle wird freigegeben...');
248246 ser.free;
249247 Writeln('Serielle Schnittstelle erfolgreich freigegeben!');
250248 end;
251249 end;
252250
253251 begin
254252 l:=check_affirmation();
255253 if l=true then
256254 RS232_connect()
257255 else
258256 Writeln('Programm beendet');
259257 end.
260258```
261259
262260Der [[Hardware Access|Externe Links]] Abschnitt enthält UNIX und Windows Tutorials über den seriellen Anschluss.
263261
264262### Raspberry Pi
265263
266264Leider gibt es beim Raspberry Pi ab Zeile 232 bei Synaser eine Fehlermeldung. Dies betrifft bis und mit Version 007.006.001 von Synaser.
267265
268266Dies kann man umgehen, wen den fehlerhaften Const-Block durch folgenden ersetzt.
269267
270268``` pascal
271269const
272270{$IFDEF UNIX}
273271 {$IFDEF DARWIN}
274272 MaxRates = 18; // MAC
275273 {$ELSE}
276274 {$IFDEF CPUARM} // <------- hier
277275 MaxRates = 19;
278276 {$ELSE}
279277 MaxRates = 30; // UNIX
280278 {$ENDIF}
281279 {$ENDIF}
282280{$ELSE}
283281 MaxRates = 19; // WIN
284282{$ENDIF}
285283 Rates: array[0..MaxRates, 0..1] of cardinal = (
286284 (0, B0),
287285 (50, B50),
288286 (75, B75),
289287 (110, B110),
290288 (134, B134),
291289 (150, B150),
292290 (200, B200),
293291 (300, B300),
294292 (600, B600),
295293 (1200, B1200),
296294 (1800, B1800),
297295 (2400, B2400),
298296 (4800, B4800),
299297 (9600, B9600),
300298 (19200, B19200),
301299 (38400, B38400),
302300 (57600, B57600),
303301 (115200, B115200),
304302 (230400, B230400)
305303{$IFNDEF DARWIN}
306304 ,(460800, B460800)
307305 {$IFDEF UNIX}
308306 {$IFNDEF CPUARM} // <------- und hier
309307 ,(500000, B500000),
310308 (576000, B576000),
311309 (921600, B921600),
312310 (1000000, B1000000),
313311 (1152000, B1152000),
314312 (1500000, B1500000),
315313 (2000000, B2000000),
316314 (2500000, B2500000),
317315 (3000000, B3000000),
318316 (3500000, B3500000),
319317 (4000000, B4000000)
320318 {$ENDIF}
321319 {$ENDIF}
322320{$ENDIF}
323321 );
324322{$ENDIF}
325323```
326324
327325## USB
328326
329327### libusb
330328
331329Eine Cross-Platform-Möglichkeit für Linux, BSDs und macOS ist [libusb](http://libusb.sourceforge.net/).
332330
333331Header gibt es in <http://www.freepascal.org/contrib/db.php3?category=Miscellaneous>:
334332
335333| Name | Autor | Version | Datum | Link | Anmerkungen |
336334|----|----|----|----|----|----|
337335| libusb.pp | nowrap \| Uwe Zimmermann | 0.1.12 | nowrap \| 29.06.2006 | <http://www.sciencetronics.com/download/fpc_libusb.tgz> | |
338336| libusb.pas | Johann Glaser | | nowrap \| 02.01.2021 | <https://github.com/hansiglaser/pas-libusb/tree/libusb-1.0> | enthält auch einen objektorientierten Wrapper |
339337| fpcusb | Joe Jared | 0.11-14 | nowrap \| 02.02.2006 | <http://relays.osirusoft.com/fpcusb.tgz> | nowrap \| Download-Link geht nicht |
340338
341339### FTDI
342340
343341Verwendet man Chips von [FTDI](http://www.ftdichip.com/), kann man die Pascal Header für ihr dll Interface benutzen.
344342
345343## Externe Links
346344
347345Kommunikationsprotokolle Geschwindigkeitsvergleich:
348346
3493471. <http://en.wikipedia.org/wiki/Serial_port#Speed>
3503482. <http://www.lvr.com/jansfaq.htm> - Jan Axelson's Parallel Port FAQ
3513493. <http://en.wikipedia.org/wiki/USB#Transfer_Speed>
3523504. <http://en.wikipedia.org/wiki/PCI#Conventional_PCI_bus_specifications>
353351
354352Serielle Kommunikation Links:
355353
3563541. Unter UNIX: [1](http://www.easysw.com/~mike/serial/serial.html)
3573552. Unter Windows: <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnfiles/html/msdn_serial.asp>
3583563. Synaser Komponente: <http://synapse.ararat.cz/>
3593574. Comport Delphi package: <http://sourceforge.net/projects/comport/>
360358
361359ISA Digital Oscilloscope - Ein Beispiel für Hardwarezugriff mit dem vollständigen Source-Code:
362360
363361[2](http://eletronicalivre.incubadora.fapesp.br/portal/english/oscilloscope/)\
364-\
365362
366363---
367364*From the Free Pascal wiki, page "Hardware Access/de", as it stood on 2021-01-02 after a change by Hansiglaser, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history