想知道VB中怎么控制电灯点亮吗?请看——VB对I/O端口操作技术
一、I/O端口介绍
信号采集与控制是工业控制的最重要组成部分。在工业控制中,通常采集到的信号有两类:一类是电压或电流模拟信号;另一类是开关量或数字脉冲量(开关量、脉冲量都属于数字信号)。通常检测出的信号如果是模拟量的话,必须经过放大、变换变为电压0~10伏或电流0~10mA,这些模拟量必须经过模/数转换器(ADC:Analog-Digital Cnverter)转换成数字量, 才能被计算机所接受。同样输出控制量信号也必须是数字信号,得经过数/模转换器(DAC:Digital-Analog Cnverter),将数字信号转换成模拟信号0~10伏 (或0~+5伏)或变为电流0~10mA, 再送入到控制器去控制生产设备的运行。
而在计算机中,CPU通过总线与输入输出设备相连。系统中的很多其他设备都要通过总线,按照CPU规定的时序分时地与CPU进行指令或数据的传输。因此输入输出设备不能直接与总线相连并占用总线,I/O端口就是在总线和输入输出设备之间进行数据交换的数据中转站,我们与输入输出设备的对话实际上是与I/O端口的对话,下面就详细讲述在Visual BASIC环境下如何进行输出和输入操作。
二、编写操作I/O端口的动态链接库函数
Visual BASIC没有提供直接读写I/O端口的方法,所以只能借助其他语言来编写动态链接库DLL(Dynamic Link Library)或VXD,然后再在Visual BASIC中调用。因此我们不得不先了解如何编写操作I/O端口的动态链接库函数。
1.在汇编语言中,可以用 in、out 指令操作I/O端口,具体示例如下:
输入操作:
MOV DX, Port;Port为端口号
IN AL, DX;读入端口数据到AL寄存器
输出操作:
MOV DX, Port;Port为端口号
MOV AL, ConByte;ConByte为控制字,将控制字送到AL寄存器
OUT DX, AL;送出控制字到端口
2.在C/C++中,通常用inp和_outp函数操作I/O端口,编写动态链接库我们可以编写如下两个函数,并把它编译生成DLL:
/*作用:从指定端口读入一个字节,参数:portid端口号,返回值:读入的字节*/
int _stdcall Inport(short portid)
{
return inp(portid);
}
/*作用:向指定端口写入一个字节,参数:portid端口号*/
void _stdcall Outport(short portid,short value)
{
outp(portid, value);
}
当需要一次操作两个字节时,我们就必须用到inpw和outpw两个函数,具体用法同inp和outp。
同时需要说明的是,_inp和_outp函数和inp和outp函数用法基本上相同,只是在使用时需要<conio.h>头文件,而且本人推荐使用_inp和_outp,而不是使用inp和outp。因为_inp和_outp在Debug和Release都可以使用,而inp和outp只能用于Release设置。如果在Debug设置时使用inp和outp,编译时不会错,但会产生链接错误。
三、Visual BASIC中操作I/O端口
到此我们就可以在Visual BASIC中通过动态链接库技术间接操作I/O端口了。在Visual Basic中动态链接库必须提前申明,其缺省为公有过程或函数。其格式为:“Declare Sub 过程名 Lib ‘库名’ [Alias ‘别名’] [(参数表)]”,或者“Declare Function 过程名 Lib ‘库名’ [Alias ‘别名’] [(参数表)] As 类型”。例如:
Public Declare Function Outport Lib "vcDll.dll" (ByVal portid As Integer, ByVal value As Integer) As Integer //IO输出函数
Public Declare Function Inport Lib "vcDll.dll" (ByVal portid As Integer) As Integer //IO输入函数
这样定义后在程序中就可以直接使用上面定义的函数或过程来操作I/O端口了。
四、Visual BASIC中位操作
上文介绍的I/O端口操作是一次从I/O端口中读取一个后更多字节的信号,而在工业控制领域中,往往是逐个信号的获取或操作,因此我们就有必要在读入信号时将一次读到的信号分离开来,而在输出信号时将不需要输出的其它位屏蔽掉。
1. 分离读取到的I/O端口信号(需要读取D0位信号)
IOvalue=Inport(BASE)//首先读取BASE地址I/O端口信号
IOvaluer=IOvalue AND &1H// (屏蔽掉其他7位,只留下D0位)
2. 屏蔽其它位信号并输出相应信号(D0位置1操作)
IOvalue=Inport(BASE)//首先读取BASE地址I/O端口信号
IOvalue = IOvalue OR &01H //(B00000001,屏蔽掉其他7位,将D0位置1)
CALL Outport(BASE,IOvalue)//输出相应信号
在上面的位操作中,我们用到了逻辑运算符AND和OR,逻辑分析表如下。
AND 1 0
1 1 0
0 0 0
OR 1 0
1 1 1
0 1 0
使用AND运算符可以对指定的位置0,例如:十六进制&H84的二进制为:10000100,它的第三位为1,若要将第三位置为0,且其它位不变,可以使用:&H84 AND &HFB = &H80,&H80的二进制值为B10000000。
使用OR运算符可以对指定的位置1,例如:十六进制&H84的第二位为0,若要将第二位置为1,且其它位不变,可以使用:&H84 OR &H02 = &H86,&H86的二进制值为B10000110。
五、使用计算机LPT打印口做I/O端口
打印口有3个端口:数据端口、状态端口和控制端口,常用的打印口为LPT1,它的3个端口的地址分别为:378H、379H和37AH。其中378H和37AH可读可写,而379H为只读端口
计算机25针打印口各引脚定义如下图所示。
此主题相关图片如下:^^^^^^^^^^^^^^^(丢了!)
与使用其他I/O卡一样,在运行DEBUG环境下,对打印口的各位进行检测如下。
378H作数据输出口。键入指令 –O 378 00(01,02,04,08,10,20,40,80,FF),同时用万用表分别检测2~9脚的电压(25脚接万用表“地”),可分别测到对应位与所输入的数据相符合(”1” 对应5V,”0”对应0V)。说明此地址的8位可作为8个输出线。
379H作输入端口。为了给各脚提供输入电平,我们先引入一个外部5V电源。电源地线接打印口的25脚,而后分别在10,11,12,13,15脚接入5V、0V,同时在DEBUG环境下执行 -I 379指令,读入此端口的数据。读到的各数据应与输入信号相符合。
37AH口只能作输出口。检测方法与378H 相同。
检测结果为:
378各位输出电平和指令信号一致,D0~D8位都可以做端口输出位;
37A各位输出电平和指令信号相反,D0~D3位都可以做端口输出位;
379各位悬空状态下:11脚为“0”,10,12,13,15为“1”,故使用D3~D6做端口输入位。
综上,通常使用打印口做I/O端口的共有12个输出位和4个输入位。
六、Windows 2000/XP/NT下I/O端口操作
Windows 2000/XP/NT对硬件实现了屏蔽,对I/O端口进行了严格的控制,许多在Windows 9x下正常运行的用户应用程序,在Windows 2000/XP/NT中直接访问硬件会引起系统异常,因此不能在Windows 2000/XP/NT下直接访问I/O端口。
通常有两种方法解决Windows 2000/XP/NT下I/O端口操作问题,一是编写一个运行在RING0级(设备驱动驱动程序级)的虚拟设备驱动程序(Virtual X Device,VSD),它可以不受限制地访问硬件设备、捕获I/O端口操作和内存访问等,甚至可以截获硬件中断,这样就可以在USER方式下实现Windows 2000/XP/NT下I/O端口的访问操作。另一种方法就是修改I/O允许位图设置,允许一个特定的任务存取特定的I/O端口。 这允许USER方式的程序在RING3级(应用程序级)按照I/O允许位图设置, 不受限制地访问I/O端口。
接下来本文介绍两种在Windows 2000/XP/NT下实现I/O端口操作的方法,WinIO和PortTalk。
WinIO程序库通过使用一种内核模式的设备驱动器和其它几种底层编程技巧,绕过了Windows系统的保护机制,从而允许在Windows 2000/XP/NT下应用程序直接对I/O端口和物理内存进行操作。需要注意的是,在Windows 2000/XP/NT下,WinIO函数库只允许被具有管理员权限的应用程序调用。WinIO程序库含有相应驱动程序的源代码和Visual BASIC例程,下载地址为:
http://www.internals.com/utilities/winio.zip。PortTalk使用的是上述的第二种方法,它够让你现有的程序运行在windows 2000/XP/NT下, 但是需要注意的是,因为必须在RING0和RING3下来回切换,所以使用PortTalk会降低程序的运行效率。PortTalk设备驱动程序也提供了全部源代码,下载地址为:
http://www.beyondlogic.org/porttalk/porttalk.zip。