unit Port; interface uses Windows,Messages,SysUtils,Classes,Graphics,Controls,Forms, Dialogs; type EPortError = class(Exception); TPort = class(TComponent) private procedure Outport(Address,Data:Word); function InPort(Address:Word):Word; public constructor Create(AOwner:TComponent);override; property Port[index:Word]:Word read InPort write OutPort; default; end;procedure Register;implementationprocedure TPort.OutPort(Address,Data:Word); asm mov dx,Address mov ax,Data out dx,ax end; function TPort.InPort(Address:Word):Word; asm mov dx,Address in ax,dx end;constructor TPort.Create(AOwner:TComponent); var h : Integer; begin Inherited Create(AOwner); { load the driver } h:=CreateFile('\\.\\giveio',GENERIC_READ,0,nil,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0); { warn if driver not there } if H=INVALID_HANDLE_VALUE then raise EPortError.Create('GiveIO Driver Not Installed'); { we don't actually need the handle, as loading the driver enables the free port access for the period of the program } CloseHandle(h); end; procedure Register; begin RegisterComponents('AndyC', [TPort]); end; end.注意: 这个控件应该在Windows 95 下工作而不需要驱动,只要移开Create 过程就可以。我没有声称完全理解了这个驱动程序,实际上我还在使用 Windows 3.11,对NT的内核更是一点都不了解,但是已经为一个用NT的同事把这些标志在一起,看起来工作正常。对我来说这足够好了 :)如果你发现上面的代码有明显的错误请告诉我,我宁愿被一耳光也不愿我的同事因为它的程序死翘翘而被周围的人咂嘴!!! [email protected] 6. 红外线接口一个演示如何写并行端口和控制红外线遥控设备的例子。 { A pair of diodes are necesary: - An infra-red emmiter LED. - A infrared receiver diode. infrared LED must be conected to bit 5 of the parallel port (pin 7) receiver diode must be conected o pin 12 of the parallel port of course, two diodes must be conected to ground (pin 20). With this imple circuit you can control any infraredm device (TVs,etc) Unit: IRU Version: 1.0=B7 Description: This unit allows you to control infrared devices, such as TVs, videos, etc., simply utting a pair of diodes in the parallel port. Date: December, 1995. Programmed by: MACRO ([email protected]) You can use and modify this code on your programs, but remember to give me credit :-) }unit iru; interface const IRcodeLength = 300; {Memory in bytes for each code, can be increased to obtain more resolution} rate = 20; {Is a delay that defines the sample frequency, 20 value works well in a DX2, must be decreased or slower systems} type Ircode = 3Darray[1..IRcodeLength] of byte;procedure receiveIRcode(var x:IRcode); {This procedure waits until a IR code is received, then hold it in 'x' IRcode type variable. Be sure f put the emitter LED very close to the receiver DIODE.}procedure sendIRcode(var x:IRcode); {This procedure dumps the IR code specified in 'x' thru the IR LED}implementationprocedure receiveIRcode(var x:IRcode); var i,j : word; begin for i := 1 to IRcodeLength do x[i] := 0; repeat until (port[$379] AND 32) = 0; asm cli; end; for i := 1 to IRcodeLEngth DO begin asm mov cx,rate; @1: in al,$61 and al,0 out dx,al loop @1 end; x[i] := port[$379]; end; asm sti; end; j := 0; for i := 1 to IRcodeLength do x[i] := (x[i] and 32) xor 32; end;procedure sendIRcode(var x:IRcode); var i : word; v : byte; begin port[$61] := port[$61] or 1; port[$43] := 182; port[$42] := 30; port[$42] := 0; for i := 1 to IRCodeLength DO begin v := x[i]; asm mov dx,$378 mov cx,rate @1: in al,$61 and al,v out dx,al loop @1 end; end; port[$61] := port[$61] and 252; end;begin end.
Re: 端口指令和 win95 ,一份概要。
Martin Larsson([email protected] ) 提交于 10/08/1996 01:57:45
Eric Liptrot 写道:
过去的几个月里,关于这个主题已经有很大的一致性,所以这绝对是一个普遍的问题。有人能用逻辑方式总结一下这种情况么?
对这个问题我不是高手,但是我作出一点尝试。
1.1. 辩护假定这是一份快速概要,它最终会很长。希望它不会令你太厌烦……
1.2. 问题在MS-DOS模式下,一个应用程序对整个机器有控制权,这给了程序员很大的自由。为了加快执行速度,有必要的话你可以直接访问硬件。
在Windows 3.x下,这个自由在某种程度上受到了限制,尤其是不能直接写屏幕。问题很明显:用户可能运行着其他的应用程序,不能保证它们没有同时访问同一个硬件。
出现的其他问题就是你不得不对其他同时运行的应用程序友好一点。Windows 3.x 是合作式的多任务系统,这意味着每个程序决定自己何时执行而其他程序也能运行。长时间扰乱CPU被认为是不好的。
但是事实是除非我们程序员这么说程序是不会运行的,在访问硬件时这对我们是有利的。因为程序获取CPU,混乱I/O端口或内存,只要它愿意它就能保证完全控制机器,在结束前它不会放弃控制。
不幸的是,进度赶上了我们,现在出现了Win32(Windows NT和 Windows 95/98/2000)。它们是真正的操作系统,利用抢先式的多任务。每个线程(执行单元)得到处理器的一定时间。当时间结束或有更高优先权的线程执行时,系统将切换到下一个线程,尽管前一个线程还没有执行完毕。这种切换可以发生在任何两个汇编命令下,不能保证一个线程在它被清空前能够完成结束任何数量的命令,到下一个时间段可能要很长时间。
这产生一个直接访问硬件的实际问题。例如,一个典型的 I/O 读取由几个汇编命令组成:
mov dx, AddressPort
mov al, Address
out dx, al
jmp Wait
Wait:
mov dx, DataPort
in al, dx
只要所有的登记状态都在线程切换时被保护好,I/O 端口状态就不是保护好的了。因此,很可能有程序善于在上面的“out”和“in”命令间对付“你”的 I/O 端口。
1.3. 有文件证明的方法这个问题的解决方法就是以某种方式告诉其他程序:现在我的程序使用着546端口,其他人最好靠边站。现在需要的是人工干预。不幸的是,为了使用人工干预,所有程序必须为这个人工干预使用一致的名字。但是,即使这是可能的,你还会轻易遇到一些棘手的问题。假定有两个程序App1 和 App2 App1 首先申请AddressPortMutex ,App2 首先申请DataPortMutex 。一个可悲的巧合,App1 取得AddressPortMutex ,系统切换到App2,它需要DataPortMutex ,僵持出现了。App2不能取得端口地址 ,因为App1拥有它;而App1又不能取得数据端口,因为App2拥有它。我们还在等着……
这个问题的正确解决方法就是建立一个拥有端口/内存地址的设备驱动程序,支持通过一个API访问硬件。一个典型的函数应该是:
GetIOPortData(AddressPort, DataPort : word) : Byte;
GetIOPortData 需要一个人工干预来保护这两个(有可能是全部)端口,然后访问这些端口,最后在返回调用前释放人工干预。如果有不同的线程同时调用这个函数,一个将先得到,另一个必须等着。
写一个设备驱动并不容易,它们必须由汇编或C来完成,而且很难调试。为了安全起见,一个Windows 9x 的设备驱动程序(VxD)和Windows NT的设备驱动程序(VDD,虚拟设备驱动)并不兼容。据说它们要被聚合,也许Windows NT 6.0 Windows 2000会兼容这些设备驱动,但是直到现在,我们不得不写两个独立的代码片断。
为了获取更多的信息请参考(举例):
* Microsoft's Windows 95 设备驱动程序工具
* Microsoft's Windows NT设备驱动程序工具
* 《Systems Programming for Windows 95》,作者 Walter Oney
* http://www.vireo.com/ 网站上Vireo的《 VtoolsD library for writing VxD's in C》
1.4. 无文件证明的方法上面的问题还不是很实际。一个程序直接访问硬件通常使用一些专用硬件。一个机器配置倾向与只运行一个程序,唯一目的是问了访问这个硬件。在这种设想下,写设备驱动程序显得太麻烦了。毕竟,程序运行在Windows下,只是为了获得好的GUI界面,不是为了10个程序能同时运行。
幸运的是,Windows 95和Windows 3.x是兼容的。这意味着直接读取I/O 必须被许可,因为许多Win 3.x程序需要使用它。为了访问I/O端口,简单使用汇编就可以。下面的代码由Arthur Hoornweg ([email protected]) 提供:function getport(p:word):byte; stdcall;
begin
asm
push edx
push eax
mov dx,p
in al,dx
mov @result,al
pop eax
pop edx
end;
end;Procedure Setport(p:word;b:byte);Stdcall;
begin
asm
push edx
push eax
mov dx,p
mov al,b
out dx,al
pop eax
pop edx
end;
end;
Francois Piette 也提供利一些I/O直接访问的函数于http://rtfm.netline.be/fpiette/portiofr.htm (参见第三节) ,Anatoly Podgoretskt 也提供了一些 (参看第四节)。1.5. 但是NT呢?上面的代码在Windows NT下不能工作。NT是一个强大得多的操作系统,任何人在任何需要的时候访问硬件的许可都将认真约束稳定性。
此外,NT 是一个交叉的平台,在不同的处理器上访问 I/O 端口可能有很大的不同。
尽管如此,在NT 系统下 x86系列的处理器上访问I/O 端口还是有可能的。这是完全没有文件证明的,可能在将来版本的操作系统里消失。
对于处理器我掌握的信息不多,但是D. Roberts在1996年5月的论文提及的Dr. Dobb的日志看上去有希望��“Direct Port I/O and Windows NT”。看上去只有 DDJ 我忽略了,因此我不能证明这一点。请参看 http://www.ddj.com 来订阅背景问题。
Windows 开发者日志确实有一篇文章关于Windows下的 I/O 端口。作者为 Karen Hazzah,出现在1996年6月的问题里。
1.6. 资源(注意:我对这些资源知之甚少,请自己检查它们。)
这里是关于写VxD和VDD 专题的有用的新闻组:
* comp.os.ms-windows.programmer.nt.kernel-mode (VDD)
* comp.os.ms-windows.programmer.vxd (VxD)
interface
uses
Windows,Messages,SysUtils,Classes,Graphics,Controls,Forms, Dialogs;
type
EPortError = class(Exception);
TPort = class(TComponent)
private
procedure Outport(Address,Data:Word);
function InPort(Address:Word):Word;
public
constructor Create(AOwner:TComponent);override;
property Port[index:Word]:Word
read InPort
write OutPort;
default;
end;procedure Register;implementationprocedure TPort.OutPort(Address,Data:Word);
asm
mov dx,Address
mov ax,Data
out dx,ax
end;
function TPort.InPort(Address:Word):Word;
asm
mov dx,Address
in ax,dx
end;constructor TPort.Create(AOwner:TComponent);
var
h : Integer;
begin
Inherited Create(AOwner);
{ load the driver }
h:=CreateFile('\\.\\giveio',GENERIC_READ,0,nil,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0);
{ warn if driver not there }
if H=INVALID_HANDLE_VALUE then
raise EPortError.Create('GiveIO Driver Not Installed');
{ we don't actually need the handle, as loading the driver
enables the free port access for the period of the
program }
CloseHandle(h);
end;
procedure Register;
begin
RegisterComponents('AndyC', [TPort]);
end;
end.注意: 这个控件应该在Windows 95 下工作而不需要驱动,只要移开Create 过程就可以。我没有声称完全理解了这个驱动程序,实际上我还在使用 Windows 3.11,对NT的内核更是一点都不了解,但是已经为一个用NT的同事把这些标志在一起,看起来工作正常。对我来说这足够好了 :)如果你发现上面的代码有明显的错误请告诉我,我宁愿被一耳光也不愿我的同事因为它的程序死翘翘而被周围的人咂嘴!!!
[email protected]
6. 红外线接口一个演示如何写并行端口和控制红外线遥控设备的例子。
{ A pair of diodes are necesary:
- An infra-red emmiter LED.
- A infrared receiver diode.
infrared LED must be conected to bit 5 of the parallel port (pin 7) receiver diode must be conected
o pin 12 of the parallel port of course, two diodes must be conected to ground (pin 20). With this
imple circuit you can control any infraredm device (TVs,etc)
Unit: IRU
Version: 1.0=B7
Description: This unit allows you to control infrared devices, such as TVs, videos, etc., simply
utting a pair of diodes in the parallel port.
Date: December, 1995.
Programmed by: MACRO ([email protected])
You can use and modify this code on your programs, but remember to give me credit :-) }unit iru;
interface
const
IRcodeLength = 300;
{Memory in bytes for each code, can be increased to obtain more resolution}
rate = 20;
{Is a delay that defines the sample frequency, 20 value works well in a DX2, must be decreased
or slower systems}
type
Ircode = 3Darray[1..IRcodeLength] of byte;procedure receiveIRcode(var x:IRcode);
{This procedure waits until a IR code is received, then hold it in 'x' IRcode type variable. Be sure
f put the emitter LED very close to the receiver DIODE.}procedure sendIRcode(var x:IRcode);
{This procedure dumps the IR code specified in 'x' thru the IR LED}implementationprocedure receiveIRcode(var x:IRcode);
var
i,j : word;
begin
for i := 1 to IRcodeLength do x[i] := 0;
repeat until (port[$379] AND 32) = 0;
asm
cli;
end;
for i := 1 to IRcodeLEngth DO begin
asm
mov cx,rate;
@1:
in al,$61
and al,0
out dx,al
loop @1
end;
x[i] := port[$379];
end;
asm
sti;
end;
j := 0;
for i := 1 to IRcodeLength do x[i] := (x[i] and 32) xor 32;
end;procedure sendIRcode(var x:IRcode);
var
i : word;
v : byte;
begin
port[$61] := port[$61] or 1;
port[$43] := 182;
port[$42] := 30;
port[$42] := 0;
for i := 1 to IRCodeLength DO begin
v := x[i];
asm
mov dx,$378
mov cx,rate
@1:
in al,$61
and al,v
out dx,al
loop @1
end;
end;
port[$61] := port[$61] and 252;
end;begin
end.