Difference between revisions of "Hardware Access/pl"

From Lazarus wiki
Jump to navigationJump to search
m (Fixed syntax highlighting)
 
(23 intermediate revisions by 7 users not shown)
Line 1: Line 1:
 
{{Hardware Access}}
 
{{Hardware Access}}
 
__TOC__
 
__TOC__
==Przegląd==
+
==Wstęp==
Ta strona jest początkiem lekcji na temat dostępu do urządzeń sprzętowych na Lazarus. Urządzenia te obejmują, ale nie są ograniczone do: ISA, PCI, USB, port równoległy, port szeregowy.
+
Ta strona stanowi początek podręcznika o uzyskiwaniu dostępu do urządzeń sprzętowych w Lazarus. Urządzenia te to między innymi: ISA, PCI, USB, port równoległy, port szeregowy.
  
Jednolity wieloplatformowy dostęp do urządzeń sprzętowych nie jest realizowany przez Free Pascal Runtime Library lub przez LCL. Więc ten tutorial w zasadzie obejmuje metody dostępu do sprzętu, na różnych platformach. Kod może być kompilowany w różnych środowiskach za pomocą warunkowej kompilacji, jak poniżej:
+
Jednolity wieloplatformowy dostęp do urządzeń sprzętowych nie jest zaimplementowany ani we Free Pascal Runtime Library, ani w LCL. Podręcznik ten więc przede wszystkim obejmuje metody dostępu do sprzętu na różnych platformach. Kod może być kompilowany w różnych środowiskach za pomocą warunkowej kompilacji, np:
  
<delphi>
+
<syntaxhighlight lang=pascal>
 
  uses
 
  uses
 
   Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, ExtCtrls,
 
   Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, ExtCtrls,
Line 15: Line 15:
 
   ports;
 
   ports;
 
  {$ENDIF}
 
  {$ENDIF}
</delphi>
+
</syntaxhighlight>
  
Jeszcze nie wiadomo , w tej chwili, czy Mac OS X/x86 pozwoli uzyskać sprzętowi dostęp. It can disallow it, though I assume in that case, in time, drivers like io.dll will appear.
+
W tej chwili jeszcze nie wiadomo, czy macOS/x86 pozwoli uzyskać dostęp do sprzętu. System może na to nie pozwalać, aczkolwiek można przypuszczać że stosowne sterowniki jak io.dll z czasem się pojawią.
  
 
==Porównanie portów Równoległych i Szeregowych==
 
==Porównanie portów Równoległych i Szeregowych==
 
ISA Cards, PCI Cards and the Parallel Port communicate with the computer using a '''parallel''' protocol. The Serial Port and USB devices work with a '''serial''' protocol. Because the processor and thus programming languages all work on a parallel approach to data, access to this kinds of protocols is easier to be implemented on the software side. When you access an Integer variable, for example, you can access it's value with a single command. With a serial protocol, however, you can only know one bit at a time, and you need to glue the pieces together to understand the data.
 
ISA Cards, PCI Cards and the Parallel Port communicate with the computer using a '''parallel''' protocol. The Serial Port and USB devices work with a '''serial''' protocol. Because the processor and thus programming languages all work on a parallel approach to data, access to this kinds of protocols is easier to be implemented on the software side. When you access an Integer variable, for example, you can access it's value with a single command. With a serial protocol, however, you can only know one bit at a time, and you need to glue the pieces together to understand the data.
  
Komunikacja szeregowa jest trudna do realizacji bezpośrednio, ale może być całkiem prosta, jeśli używasz gotowego komponentu. Jest to także trudniejsze od strony sprzętowej, więc wiele urządzeń używa specjalnych układów scalonych lub nawet Mikrokontlorelów do jego realizacji.
+
Komunikacja szeregowa jest trudna w implementacji bezpośrednio, ale może być całkiem łatwa, jeśli użyjesz gotowego komponentu. Jeszcze trudniej jest od strony sprzętowej, więc wiele urządzeń używa specjalizowanych układów scalonych, a nawet mikrokontrolerów do jego realizacji.
  
Teraz krótkie porównanie protokołów dostępu do sprzętu:
+
Przedstawmy krótko porównanie protokołów urządzeń i dostępu do nich:
  
 
{| border=2 width="100%"
 
{| border=2 width="100%"
Line 31: Line 31:
 
!
 
!
 
! Prędkość
 
! Prędkość
! Hardware implementation difficulty
+
! Stopień trudności implementacji
  
 
|-
 
|-
! Port Szeregowy
+
! Port szeregowy
| align="center" | Very slow (< E5 bit/s)
+
| align="center" | bardzo niska (< E5 bit/s)
| align="center" | Medium
+
| align="center" | średnio trudny
  
 
|-
 
|-
! Port Równoległy
+
! Port równoległy
| align="center" | Slow (~ E6 bit/s)
+
| align="center" | niska (~ E6 bit/s)
| align="center" | Easy
+
| align="center" | łatwy
  
 
|-
 
|-
  
 
! Karta ISA
 
! Karta ISA
| align="center" | Medium (~ E7 bit/s)
+
| align="center" | średnia (~ E7 bit/s)
| align="center" | Medium
+
| align="center" | średnio trudny
  
 
|-
 
|-
 
! USB
 
! USB
| align="center" | Medium (~ E7 bit/s)
+
| align="center" | średnia (~ E7 bit/s)
| align="center" | Hard
+
| align="center" | trudny
  
 
|-
 
|-
 
! Karta PCI
 
! Karta PCI
| align="center" | Very Fast (> E9 bit/s)
+
| align="center" | bardzo duża (> E9 bit/s)
| align="center" | Very Hard
+
| align="center" | bardzo trudny
  
 
|}
 
|}
Line 68: Line 68:
 
Happily there is a library that solves this problem. If Windows NT is detected, it decompresses HWInterface.sys kernel device driver and installs it. If Windows 9x is detected, it simply uses assembler opcodes to access the hardware.
 
Happily there is a library that solves this problem. If Windows NT is detected, it decompresses HWInterface.sys kernel device driver and installs it. If Windows 9x is detected, it simply uses assembler opcodes to access the hardware.
  
Ale jak korzystać z tej biblioteki? Proste! Ona ma tylko dwie funkcje, Inp32 i Out32, a ich wykorzystanie jest dość intuicyjne.
+
Ale jak korzystać z tej biblioteki? Proste! Ma ona tylko dwie funkcje, Inp32 i Out32, a ich wykorzystanie jest dość intuicyjne.
 
Będziemy załadowywać biblioteki dynamicznie, więc potrzeba zdefiniować obie te funkcje:
 
Będziemy załadowywać biblioteki dynamicznie, więc potrzeba zdefiniować obie te funkcje:
  
<delphi>
+
<syntaxhighlight lang=pascal>
 
  type
 
  type
 
   TInp32 = function(Address: SmallInt): SmallInt; stdcall;
 
   TInp32 = function(Address: SmallInt): SmallInt; stdcall;
 
   TOut32 = procedure(Address: SmallInt; Data: SmallInt); stdcall;
 
   TOut32 = procedure(Address: SmallInt; Data: SmallInt); stdcall;
</delphi>
+
</syntaxhighlight>
  
 
* Address represents the address of the port you desire to access
 
* Address represents the address of the port you desire to access
Line 83: Line 83:
 
Now we can load the library. This can be implemented in a place like the OnCreate method of your program's main form:
 
Now we can load the library. This can be implemented in a place like the OnCreate method of your program's main form:
  
<delphi>
+
<syntaxhighlight lang=pascal>
 
  type
 
  type
 
   TMyForm = class(TForm)
 
   TMyForm = class(TForm)
Line 110: Line 110:
 
  {$ENDIF}
 
  {$ENDIF}
 
  end;
 
  end;
</delphi>
+
</syntaxhighlight>
  
Jeśli załadować biblioteki na onCreate tylko nie zapomnij, aby zwolnić go w OnDestroy:
+
Jeśli załadowano biblioteki na onCreate tylko nie zapomnij, aby zwolnić je w OnDestroy:
  
<delphi>
+
<syntaxhighlight lang=pascal>
 
  procedure TMyForm.FormDestroy(Sender: TObject);
 
  procedure TMyForm.FormDestroy(Sender: TObject);
 
  begin
 
  begin
Line 121: Line 121:
 
  {$ENDIF}
 
  {$ENDIF}
 
  end;
 
  end;
</delphi>
+
</syntaxhighlight>
  
 
Oto prosty przykład jak używać funkcji Inp32:
 
Oto prosty przykład jak używać funkcji Inp32:
  
<delphi>
+
<syntaxhighlight lang=pascal>
 
  {$IFDEF WIN32}
 
  {$IFDEF WIN32}
 
   myLabel.Caption := IntToStr(Inp32($0220));
 
   myLabel.Caption := IntToStr(Inp32($0220));
 
  {$ENDIF}
 
  {$ENDIF}
</delphi>
+
</syntaxhighlight>
  
 
This code was tested with a custom ISA card on port $0220, using Lazarus 0.9.10 on Windows XP. Of course you will need to have Windows on your uses clause in order for this code to run. For deployment you only need to include "inpout32.dll" in the same directory of our application.
 
This code was tested with a custom ISA card on port $0220, using Lazarus 0.9.10 on Windows XP. Of course you will need to have Windows on your uses clause in order for this code to run. For deployment you only need to include "inpout32.dll" in the same directory of our application.
Line 135: Line 135:
 
This is the homepage for the library: [http://www.logix4u.net/inpout32.htm www.logix4u.net/inpout32.htm]  *see discussion*
 
This is the homepage for the library: [http://www.logix4u.net/inpout32.htm www.logix4u.net/inpout32.htm]  *see discussion*
  
===Using assembler on Windows 9x===
+
===Korzystanie z asemblera w systemie Windows 9x===
  
On Windows 9x you can also use assembler code. Suppose you wish to write $CC to the $320 port. The following code will do it:
+
W Windows 9x można również użyć kodu asemblera. Załóżmy, że chcemy zapisać $ CC do portu $ 320 .Poniższy kod to wykona:
  
<delphi>
+
<syntaxhighlight lang=pascal>
 
  {$ASMMODE ATT}
 
  {$ASMMODE ATT}
 
  ...
 
  ...
Line 147: Line 147:
 
         outb %al, %dx
 
         outb %al, %dx
 
     end ['EAX','EDX'];
 
     end ['EAX','EDX'];
</delphi>
+
</syntaxhighlight>
  
===Troubleshooting on Windows===
+
===Rozwiązywanie problemów w systemie Windows===
  
One possible source of trouble using parallel hardware that does not support Plug And Play on Windows is that Windows may assign the port utilized by your hardware to another device. You can find instructions on the URL below about how to tell Windows not to assign the address of your device to Plug And Play devices:
+
Jednym z możliwych źródłem kłopotów przy użyciu równoległego sprzętu, który nie obsługuje technologii Plug and Play w systemie Windows jest to, że Windows może przypisać port wykorzystywany przez sprzęt do innego urządzenia. You can find instructions on the URL below about how to tell Windows not to assign the address of your device to Plug And Play devices:
  
 
http://support.microsoft.com/kb/135168
 
http://support.microsoft.com/kb/135168
  
===Using ioperm to access ports on Linux===
+
===Uzyskiwanie dostępu do portów w systemie Linux za pomocą ioperm===
  
The best way to access the hardware on Linux is through device drivers, but, due to the complexity of the task of creating a driver, sometimes a quick method is very useful.
+
Najlepszym sposobem, aby uzyskać dostęp do sprzętu w systemie Linux jest użycie sterowników urządzeń, ale ponieważ tworzenie sterowników jest kłopotliwe, czasami szybka metoda jest bardziej przydatna.
  
In order to use the "[[doc:rtl/ports|ports]]" unit under Linux your program must be run as root, and IOPerm must be called to set appropriate permissions on the port access. You can find documentation about the "[[doc:rtl/ports|ports]]" unit [http://www.freepascal.org/docs-html/rtl/ports/index.html here].
+
Aby użyć modułu "[[doc:rtl/ports|ports]]" w systemie Linux, twój program musi być uruchomiony jako root, a funkcja IOPerm musi być wywołana w celu ustawienia uprawnień w dostępie do portu. Dokumentację do modułu "[[doc:rtl/ports|ports]]" znajdziesz [http://www.freepascal.org/docs-html/rtl/ports/index.html tutaj].
  
 
The first thing to do is link to (g)libc and call IOPerm. A unit that links to the entire (g)libc exists on free pascal, but this unit gives problems when used directly by application and linking statically to the entire (g)libc library is not a very good idea because it changes often between version in an incompatible manner. Functions like ioperm, however, are unlikely to change.
 
The first thing to do is link to (g)libc and call IOPerm. A unit that links to the entire (g)libc exists on free pascal, but this unit gives problems when used directly by application and linking statically to the entire (g)libc library is not a very good idea because it changes often between version in an incompatible manner. Functions like ioperm, however, are unlikely to change.
  
<delphi>
+
<syntaxhighlight lang=pascal>
 
  {$IFDEF Linux}
 
  {$IFDEF Linux}
 
  function ioperm(from: Cardinal; num: Cardinal; turn_on: Integer): Integer; cdecl; external 'libc';
 
  function ioperm(from: Cardinal; num: Cardinal; turn_on: Integer): Integer; cdecl; external 'libc';
 
  {$ENDIF}
 
  {$ENDIF}
</delphi>
+
</syntaxhighlight>
  
* "from" represents the first port to be accessed.
+
* "from" reprezentuje pierwszy port, który ma być dostępny.
* "num" is the number of ports after the first to be accessed, so ioperm($220, 8, 1) will give access for the program for all ports between and including $220 and $227.
+
* "num" to liczba portów jaka ma być dostępna licząc od pierwszego, np. ioperm($220, 8, 1) daje programowi dostęp do wszystkich portów licząc od $220 do $227.
  
After linking to IOPerm you can port[<Address>] to access the ports.
+
Po podłączeniu do ioperm można użyć port[<adres>], aby uzyskać dostęp do portu o podanym adresie.
  
<delphi>
+
<syntaxhighlight lang=pascal>
 
  {$IFDEF Linux}
 
  {$IFDEF Linux}
 
   i := ioperm($220, 8, 1);
 
   i := ioperm($220, 8, 1);
Line 182: Line 182:
 
   myOtherLabel.Caption := 'response: ' + IntToStr(i);
 
   myOtherLabel.Caption := 'response: ' + IntToStr(i);
 
  {$ENDIF}
 
  {$ENDIF}
</delphi>
+
</syntaxhighlight>
  
This code was tested with a custom ISA card on port $0220, using Lazarus 0.9.10 on Mandriva Linux 2005 and Damn Small Linux 1.5
+
Ten kod został przetestowany na zwyczajnej karcie ISA na porcie $0220, przy użyciu Lazarus 0.9.10 w systemie Mandriva Linux 2005 i Damn Small Linux 1.5
  
 
===General UNIX Hardware Access===
 
===General UNIX Hardware Access===
  
<delphi>{$IFDEF Unix}
+
<syntaxhighlight lang=pascal>{$IFDEF Unix}
 
Uses Clib;  // retrieve libc library name.
 
Uses Clib;  // retrieve libc library name.
 
{$ENDIF}
 
{$ENDIF}
Line 194: Line 194:
 
{$IFDEF Unix}
 
{$IFDEF Unix}
 
function ioperm(from: Cardinal; num: Cardinal; turn_on: Integer): Integer; cdecl; external clib;
 
function ioperm(from: Cardinal; num: Cardinal; turn_on: Integer): Integer; cdecl; external clib;
{$ENDIF}</delphi>
+
{$ENDIF}</syntaxhighlight>
  
  
Line 204: Line 204:
 
'''Note 2''' Using '''unit''' libc is not recommended under any circumstances other than Kylix compatibility. See [[libc unit]]
 
'''Note 2''' Using '''unit''' libc is not recommended under any circumstances other than Kylix compatibility. See [[libc unit]]
  
==Serial Communication==
+
==Komunikacja Szeregowa==
  
It is very easy to build a serial communication software using the [http://synapse.ararat.cz/doku.php Synaser library]. The example when used together with the [http://synapse.ararat.cz/doc/help/synaser.html Synaser documentation] should be trivial to understand. The most important part is TBlockSerial.Config to configure the speed (in bits per second), data bits, parity bits, stop bits and handshake protocol, if any. The following code was tested with a serial mouse connected to COM 1.
+
Jest bardzo łatwa do budowania komunikacji szeregowej przy wykorzystaniu  [http://synapse.ararat.cz/doku.php Synaser library]. Przykład przy stosowaniu [http://synapse.ararat.cz/doc/help/synaser.html Synaser documentation] should be trivial to understand. The most important part is TBlockSerial.Config to configure the speed (in bits per second), data bits, parity bits, stop bits and handshake protocol, if any. The following code was tested with a serial mouse connected to COM 1.
  
<delphi>
+
<syntaxhighlight lang=pascal>
 
program comm;
 
program comm;
  
Line 229: Line 229:
 
   end;
 
   end;
 
end.
 
end.
</delphi>
+
</syntaxhighlight>
  
 
The following code-example is an alternative version of the example above. The example above seems to have a critically fault in its main concept, to be exactly, it is the part with "while true do...". On the Test - System (Asus A6T Laptop with Digitus USB to RS232 Adapter, Ubuntu 8.04.1), this part caused the following error: The application ran only one time successfully per session, when the application was started again, the application was unable to connect to the serial port. Thus, a reboot was necessary everytime the user tried to relaunch the application, which is/was a really annoying bug.  
 
The following code-example is an alternative version of the example above. The example above seems to have a critically fault in its main concept, to be exactly, it is the part with "while true do...". On the Test - System (Asus A6T Laptop with Digitus USB to RS232 Adapter, Ubuntu 8.04.1), this part caused the following error: The application ran only one time successfully per session, when the application was started again, the application was unable to connect to the serial port. Thus, a reboot was necessary everytime the user tried to relaunch the application, which is/was a really annoying bug.  
Line 237: Line 237:
 
There is a bit code around the main application to make every user clear, not to press CTRL-C. If anyone is worrying, why /dev/ttyUSB0 is used for com-port: this is due to the USB to Serial Adapter (from Digitus) on the test-system. If you have an built-in serial port, please use the 'Com0' - declaration like in the code - example above.  
 
There is a bit code around the main application to make every user clear, not to press CTRL-C. If anyone is worrying, why /dev/ttyUSB0 is used for com-port: this is due to the USB to Serial Adapter (from Digitus) on the test-system. If you have an built-in serial port, please use the 'Com0' - declaration like in the code - example above.  
  
<delphi>
+
<syntaxhighlight lang=pascal>
  
 
program serialtest;
 
program serialtest;
Line 302: Line 302:
 
   end.
 
   end.
  
</delphi>
+
</syntaxhighlight>
Ponadto,[[Hardware Access#Zewnętrzne Linki | Zewnętrzne Linki]] sekcja ma tutoriale portów szeregowych UNIX i Windows.
+
Ponadto,[[Hardware Access/pl#Zewnętrzne Linki | Zewnętrzne Linki]] sekcja ma tutoriale portów szeregowych UNIX i Windows.
  
 
It is also worth noting the function of the TBlockSerial.LinuxLock parameter under linux. When set to default of True, a connect will try to create a lock file (eg. "LCK..ttyUSB0") under /var/lock and fail if a lock already exists for the requested port. The lock file will be left over if Free was not called. Setting LinuxLock to False will make Synaser ignore port locking.
 
It is also worth noting the function of the TBlockSerial.LinuxLock parameter under linux. When set to default of True, a connect will try to create a lock file (eg. "LCK..ttyUSB0") under /var/lock and fail if a lock already exists for the requested port. The lock file will be left over if Free was not called. Setting LinuxLock to False will make Synaser ignore port locking.
Line 317: Line 317:
 
===libusb===
 
===libusb===
  
A cross platform possibility for Linux, BSDs and Mac OS X is [http://libusb.sourceforge.net/ libusb].
+
A cross platform possibility for Linux, BSDs and macOS is [http://libusb.sourceforge.net/ libusb].
  
 
Headers are listed in http://www.freepascal.org/contrib/db.php3?category=Miscellaneous:
 
Headers are listed in http://www.freepascal.org/contrib/db.php3?category=Miscellaneous:
Line 360: Line 360:
  
 
* [http://eletronicalivre.incubadora.fapesp.br/portal/english/oscilloscope/|ISA Digital Oscilloscope] - A example of hardware access with full source included.
 
* [http://eletronicalivre.incubadora.fapesp.br/portal/english/oscilloscope/|ISA Digital Oscilloscope] - A example of hardware access with full source included.
 
[[Category:Tutorials]]
 

Latest revision as of 12:20, 16 February 2020

Deutsch (de) English (en) español (es) français (fr) magyar (hu) 日本語 (ja) 한국어 (ko) polski (pl) português (pt) русский (ru) slovenčina (sk) 中文(中国大陆)‎ (zh_CN)

Wstęp

Ta strona stanowi początek podręcznika o uzyskiwaniu dostępu do urządzeń sprzętowych w Lazarus. Urządzenia te to między innymi: ISA, PCI, USB, port równoległy, port szeregowy.

Jednolity wieloplatformowy dostęp do urządzeń sprzętowych nie jest zaimplementowany ani we Free Pascal Runtime Library, ani w LCL. Podręcznik ten więc przede wszystkim obejmuje metody dostępu do sprzętu na różnych platformach. Kod może być kompilowany w różnych środowiskach za pomocą warunkowej kompilacji, np:

 uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, ExtCtrls,
 {$IFDEF WIN32}
   Windows;
 {$ENDIF}
 {$IFDEF Unix}
   ports;
 {$ENDIF}

W tej chwili jeszcze nie wiadomo, czy macOS/x86 pozwoli uzyskać dostęp do sprzętu. System może na to nie pozwalać, aczkolwiek można przypuszczać że stosowne sterowniki jak io.dll z czasem się pojawią.

Porównanie portów Równoległych i Szeregowych

ISA Cards, PCI Cards and the Parallel Port communicate with the computer using a parallel protocol. The Serial Port and USB devices work with a serial protocol. Because the processor and thus programming languages all work on a parallel approach to data, access to this kinds of protocols is easier to be implemented on the software side. When you access an Integer variable, for example, you can access it's value with a single command. With a serial protocol, however, you can only know one bit at a time, and you need to glue the pieces together to understand the data.

Komunikacja szeregowa jest trudna w implementacji bezpośrednio, ale może być całkiem łatwa, jeśli użyjesz gotowego komponentu. Jeszcze trudniej jest od strony sprzętowej, więc wiele urządzeń używa specjalizowanych układów scalonych, a nawet mikrokontrolerów do jego realizacji.

Przedstawmy krótko porównanie protokołów urządzeń i dostępu do nich:

Prędkość Stopień trudności implementacji
Port szeregowy bardzo niska (< E5 bit/s) średnio trudny
Port równoległy niska (~ E6 bit/s) łatwy
Karta ISA średnia (~ E7 bit/s) średnio trudny
USB średnia (~ E7 bit/s) trudny
Karta PCI bardzo duża (> E9 bit/s) bardzo trudny

Komunikacja Równoległa

Korzystanie z biblioteki inpout32.dll w Windows

Windows ma różne sposoby dostępu do urządzeń sprzętowych z serii 9x na serię NT. W serii 9x (95, 98, Me) programy mogą mieć dostęp do sprzętu bezpośrednio, tak jak zrobili na DOS. Seria NT (Windows NT i XP), jednak nie pozwalają na takie podejście. Na tej architekturze, cała komunikacja z portami sprzętu musi być obsługiwana przez sterownik urządzenia. Jest to mechanizm bezpieczeństwa, ale rozwijanie sterownika może kosztować zbyt wiele pod względem czasu i pieniędzy dla małych projektów.

Happily there is a library that solves this problem. If Windows NT is detected, it decompresses HWInterface.sys kernel device driver and installs it. If Windows 9x is detected, it simply uses assembler opcodes to access the hardware.

Ale jak korzystać z tej biblioteki? Proste! Ma ona tylko dwie funkcje, Inp32 i Out32, a ich wykorzystanie jest dość intuicyjne. Będziemy załadowywać biblioteki dynamicznie, więc potrzeba zdefiniować obie te funkcje:

 type
   TInp32 = function(Address: SmallInt): SmallInt; stdcall;
   TOut32 = procedure(Address: SmallInt; Data: SmallInt); stdcall;
  • Address represents the address of the port you desire to access
  • Out32 wysyła dane do portu który można określić na podstawie adresów
  • Inp32 zwraca bajt z portu który można określić na podstawie adresów

Now we can load the library. This can be implemented in a place like the OnCreate method of your program's main form:

 type
   TMyForm = class(TForm)
   .........
   private
     { private declarations }
     Inpout32: THandle;
     Inp32: TInp32;
     Out32: TOut32;
   .........
 implementation
   .........
 procedure TMyForm.FormCreate(Sender: TObject);
 begin
 {$IFDEF WIN32}
   Inpout32 := LoadLibrary('inpout32.dll');
   if (Inpout32 <> 0) then
   begin
     // needs overtyping, plain Delphi's @Inp32 = GetProc... leads to compile errors
     Inp32 := TInp32(GetProcAddress(Inpout32, 'Inp32'));
     if (@Inp32 = nil) then Caption := 'Error';
     Out32 := TOut32(GetProcAddress(Inpout32, 'Out32'));
     if (@Out32 = nil) then Caption := 'Error';
   end
   else Caption := 'Error';
 {$ENDIF}
 end;

Jeśli załadowano biblioteki na onCreate tylko nie zapomnij, aby zwolnić je w OnDestroy:

 procedure TMyForm.FormDestroy(Sender: TObject);
 begin
 {$IFDEF WIN32}
   FreeLibrary(Inpout32);
 {$ENDIF}
 end;

Oto prosty przykład jak używać funkcji Inp32:

 {$IFDEF WIN32}
   myLabel.Caption := IntToStr(Inp32($0220));
 {$ENDIF}

This code was tested with a custom ISA card on port $0220, using Lazarus 0.9.10 on Windows XP. Of course you will need to have Windows on your uses clause in order for this code to run. For deployment you only need to include "inpout32.dll" in the same directory of our application.

This is the homepage for the library: www.logix4u.net/inpout32.htm *see discussion*

Korzystanie z asemblera w systemie Windows 9x

W Windows 9x można również użyć kodu asemblera. Załóżmy, że chcemy zapisać $ CC do portu $ 320 .Poniższy kod to wykona:

 {$ASMMODE ATT}
 ...
    asm
        movl $0x320, %edx
        movb $0xCC, %al
        outb %al, %dx
    end ['EAX','EDX'];

Rozwiązywanie problemów w systemie Windows

Jednym z możliwych źródłem kłopotów przy użyciu równoległego sprzętu, który nie obsługuje technologii Plug and Play w systemie Windows jest to, że Windows może przypisać port wykorzystywany przez sprzęt do innego urządzenia. You can find instructions on the URL below about how to tell Windows not to assign the address of your device to Plug And Play devices:

http://support.microsoft.com/kb/135168

Uzyskiwanie dostępu do portów w systemie Linux za pomocą ioperm

Najlepszym sposobem, aby uzyskać dostęp do sprzętu w systemie Linux jest użycie sterowników urządzeń, ale ponieważ tworzenie sterowników jest kłopotliwe, czasami szybka metoda jest bardziej przydatna.

Aby użyć modułu "ports" w systemie Linux, twój program musi być uruchomiony jako root, a funkcja IOPerm musi być wywołana w celu ustawienia uprawnień w dostępie do portu. Dokumentację do modułu "ports" znajdziesz tutaj.

The first thing to do is link to (g)libc and call IOPerm. A unit that links to the entire (g)libc exists on free pascal, but this unit gives problems when used directly by application and linking statically to the entire (g)libc library is not a very good idea because it changes often between version in an incompatible manner. Functions like ioperm, however, are unlikely to change.

 {$IFDEF Linux}
 function ioperm(from: Cardinal; num: Cardinal; turn_on: Integer): Integer; cdecl; external 'libc';
 {$ENDIF}
  • "from" reprezentuje pierwszy port, który ma być dostępny.
  • "num" to liczba portów jaka ma być dostępna licząc od pierwszego, np. ioperm($220, 8, 1) daje programowi dostęp do wszystkich portów licząc od $220 do $227.

Po podłączeniu do ioperm można użyć port[<adres>], aby uzyskać dostęp do portu o podanym adresie.

 {$IFDEF Linux}
   i := ioperm($220, 8, 1);
   port[$220] := $00;
   myLabel.Caption := 'ioperm: ' + IntToStr(i);
   i := Integer(port[$220]);
   myOtherLabel.Caption := 'response: ' + IntToStr(i);
 {$ENDIF}

Ten kod został przetestowany na zwyczajnej karcie ISA na porcie $0220, przy użyciu Lazarus 0.9.10 w systemie Mandriva Linux 2005 i Damn Small Linux 1.5

General UNIX Hardware Access

{$IFDEF Unix}
Uses Clib;   // retrieve libc library name.
{$ENDIF}

{$IFDEF Unix}
function ioperm(from: Cardinal; num: Cardinal; turn_on: Integer): Integer; cdecl; external clib;
{$ENDIF}


Note that FPC provides an abstraction for ioperm called "fpioperm" in unit x86, and also defines fpIOPL and out-/inport functions. These functions are currently implemented for Linux/x86 and FreeBSD/x86.

It is not recommended 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, like e.g. libroot on BeOS, or on platforms with a non standard C symbol mangling).

Note 2 Using unit libc is not recommended under any circumstances other than Kylix compatibility. See libc unit

Komunikacja Szeregowa

Jest bardzo łatwa do budowania komunikacji szeregowej przy wykorzystaniu Synaser library. Przykład przy stosowaniu Synaser documentation should be trivial to understand. The most important part is TBlockSerial.Config to configure the speed (in bits per second), data bits, parity bits, stop bits and handshake protocol, if any. The following code was tested with a serial mouse connected to COM 1.

program comm;

{$apptype console}

uses
  Classes, SysUtils, Synaser;

var
  ser: TBlockSerial;
begin
  ser:=TBlockSerial.Create;
  try
    ser.Connect('COM1');
    ser.config(1200, 7, 'N', SB1, False, False);
    while True do
      Write(IntToHex(ser.RecvByte(10000), 2), ' ');
  finally
    ser.free;
  end;
end.

The following code-example is an alternative version of the example above. The example above seems to have a critically fault in its main concept, to be exactly, it is the part with "while true do...". On the Test - System (Asus A6T Laptop with Digitus USB to RS232 Adapter, Ubuntu 8.04.1), this part caused the following error: The application ran only one time successfully per session, when the application was started again, the application was unable to connect to the serial port. Thus, a reboot was necessary everytime the user tried to relaunch the application, which is/was a really annoying bug.

The reason is not difficult to understand: The application is in the while true do - loop, which is, to be more precisely, an endless loop. There is no abort-condition, so the only way to close the application is to close the terminal or to press CTRL-C. But if you quit the application this way, the important part with "ser.free", which frees the serial port, will never be called. This problem is described in the following thread in the German Lazarus-Forum http://www.lazarusforum.de/viewtopic.php?f=10&t=2082

There is a bit code around the main application to make every user clear, not to press CTRL-C. If anyone is worrying, why /dev/ttyUSB0 is used for com-port: this is due to the USB to Serial Adapter (from Digitus) on the test-system. If you have an built-in serial port, please use the 'Com0' - declaration like in the code - example above.

program serialtest;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,SysUtils,Synaser,Crt
  { you can add units after this };

  var l:boolean;

  function check_affirmation():boolean;
  var k:string;
  begin
       Writeln('To quit the application please do NOT use CTRL-C! Instead, please press any key to quit the application! '+
       'Please confirm this notification before the application continues! '+
       '[0]=Quit, [1]=Confirm, please continue! ');
       Writeln('Your decision: ');
       Read(k);
       if StrtoInt(k) = 1 then
       begin
            check_affirmation:=true;
            Writeln('OK, application continues ...');
       end
       else
       begin
            check_affirmation:=false;
            Writeln('Abort');
       end
  end;

  procedure RS232_connect;
  var
     ser: TBlockSerial;
  begin
       ser:=TBlockSerial.Create;
       try
          ser.Connect('/dev/ttyUSB0'); //ComPort
          Sleep(1000);
          ser.config(1200, 7, 'N', SB1, False, False);
          Write('Device: ' + ser.Device + '   Status: ' + ser.LastErrorDesc +' '+
          Inttostr(ser.LastError));
          Sleep(1000);
          repeat
                Write(IntToHex(ser.RecvByte(10000), 2), ' ');
          until keypressed; //Important!!!
       finally
              Writeln('Serial Port will be freed...');
              ser.free;
              Writeln('Serial Port was freed successfully!');
       end;
  end;

  begin
     l:=check_affirmation();
     if l=true then
     RS232_connect()
     else
     Writeln('Program quit! ');
  end.

Ponadto, Zewnętrzne Linki sekcja ma tutoriale portów szeregowych UNIX i Windows.

It is also worth noting the function of the TBlockSerial.LinuxLock parameter under linux. When set to default of True, a connect will try to create a lock file (eg. "LCK..ttyUSB0") under /var/lock and fail if a lock already exists for the requested port. The lock file will be left over if Free was not called. Setting LinuxLock to False will make Synaser ignore port locking.

Alternatives to Synaser:

There is also a Visual component 5dpo that is based in Synaser.

Another very simple fpc Serial unit is now part of freepascal (at least in version 2.2.2), just put Serial in your Uses list however there does not seem to be any documentation other than the Serial.pp source file.

USB

libusb

A cross platform possibility for Linux, BSDs and macOS is libusb.

Headers are listed in http://www.freepascal.org/contrib/db.php3?category=Miscellaneous:

name author version date link remarks
libusb.pp Uwe Zimmermann 0.1.12 2006-06-29 http://www.sciencetronics.com/download/fpc_libusb.tgz
libusb.pas Johann Glaser 2005-01-14 http://www.johann-glaser.at/projects/libusb.pas
fpcusb Joe Jared 0.11-14 2006-02-02 http://relays.osirusoft.com/fpcusb.tgz download link broken
libusb.pp Marko Medic 1.0 2010-12-14 http://www.lazarus.freepascal.org/index.php/topic,11435.0.html

FTDI

If you use one of the chips from FTDI, you can use their pascal headers for their dll interface to the chips.

Zobacz również

Zewnętrzne Linki

  • Communication Protocols speed comparison:
  1. http://en.wikipedia.org/wiki/Serial_port#Speed
  2. http://www.lvr.com/jansfaq.htm - Jan Axelson's Parallel Port FAQ
  3. http://en.wikipedia.org/wiki/USB#Transfer_Speed
  4. http://en.wikipedia.org/wiki/PCI#Conventional_PCI_bus_specifications
  • Serial Communication Links:
  1. On UNIX: [1]
  2. On Windows: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnfiles/html/msdn_serial.asp
  3. Synaser component: http://synapse.ararat.cz/
  4. Comport Delphi package: http://sourceforge.net/projects/comport/