之前工作时用到并口的IO进行通讯和控制,在完全没有系统开发基础的情况下,很难找到比较全面的并口操作资源,因此特地写这篇博客记录。
因为日常编程中很少使用到并口进行开发,因此这篇并口开发编程主要适用于工业软件与机器间的信息互通,使用语言为C#,使用,包括目前网上几乎找不到的自动获取并口地址、读写高于0x7FFF地址段的并口(一般为并口扩展卡)、还有对并口操作进行一定的封装和对象化等,适用范围比较广,几乎涵盖了所有需要并口开发会遇到的困难和对应的解决措施。
在并口开发之前我们先了解一下并口:
因为并口介绍的文章太多,我就不进行详细的赘述,需要了解的童鞋可以直接翻下方参考维基百科或者一篇个人觉得介绍比较全面易懂的中文博客学习。(参考:WIKI PC并口LPT的IO操作(基于WinIo))
而在这里主要介绍抛开打印机指令直接看并口端口。
25针脚并口一般由3个字节读写引脚(Pin)信息
地址为基地址的1个字节对应Pin2-Pin9,是只写的Data Pin,但是Pin9有写操作的限制,例如写入11111111,会自动变为11110101;写入10000000,会变为10101100等特殊情况(也有可能是我电脑并口的原因,但是我对电脑的打印机并口LPT1和扩展卡并口LPT3进行写操作都出现上述情况),因此不推荐对Pin9进行写操作。而Pin4口会由于某些读口的读入,有可能自动跳变成1,这点也需要注意。
地址为基地址+1的1个字节对应Pin10、Pin11、Pin12、Pin13、Pin15,(具体字节组成请在参考文章中了解),是只读的Status Pin。这里需要注意的是Pin11电平反转,意思是当外部电平是高电平时,读取到Pin11的数据位为0,后面的电平反转意思相同。而不知道是不是由于需要针对打印机进行控制的原因,并口的Pin11口在高电平变为低电平时,电脑是无法读取到Pin11数据位变化,反而是Pin10的数据位发生了变化(另外还有一些不同的情况,需要自己进行测试)
地址为基地址+2的1个字节对应Pin1、Pin14、Pin16、Pin17,是可读可写的Control Pin。同样Pin1、Pin14、Pin17电平反转。另外有些并口是只能使用I或者O或者IO都不能使用的,因此开发控制端口的时候需要先进行测试。
在了解完并口开发之后,本篇将介绍Inpout32.dll这个并口读写库,库的源码和示例在Inpout32 & 64上可以找到,感谢作者的开发!Inpout32提供了很便捷的函数让我们直接读取和写入并口,源码由C语言编写,使用时要用DllImport如下
[DllImport("inpout32.dll")]
private static extern void Out32(ushort PortAddress, short Data);
[DllImport("inpout32.dll")]
private static extern char Inp32(ushort PortAddress);
两个核心函数分别进行字节写入和读取。
//Inpout32.h
void _stdcall Out32(short PortAddress, short data);
short _stdcall Inp32(short PortAddress);
需要十分注意的是,作者的源码中对该函数的基地址输入使用的变量类型为SHORT,想要读取高于0x7FFF地址段的并口,很明显SHORT16字节有符号数是不能读取的,但是其实进行变量类型转义后,也是可以读取的(即32768=0x8000=(short)-1,是可以传进函数使用并且读取到的也确实是0x8000地址),因此在使用的时候我直接使用Unsigned SHORT数据类型传入,这样就不会出现它源码的example里面读取不了高位地址的情况了。
因为网上找到的几乎所有的使用Inpout32开发的程序都是使用short类型作为传入地址的类型,因此完全找不到能够读取高地址段并口的文档,但是其实源码一查发现里面有实现DlPortReadPortUshort函数并且传入类型为USHORT,就可以推敲出USHORT类型是可以使用的,然后试一试就知道结果了,所以研究源码还是很关键的!
最后介绍WMI搜索并口的方法
由于.NET框架的封装,几乎是很难接触到系统底层的,而WMI是微软提供的.NET框架对系统底层资源的访问和修改的接口,甚至可以对远程计算机的系统资源进行访问和修改,通过这个接口我们可以访问到系统、设备等一系列信息,也包括我们的并口信息。
在运行里面输入“wbemtest”可以打开WMI测试工具,测试工具的使用在网上有很多教程和方法,这里不作解释。
WMI的类里面有一个“Win32_PnPEntity”的类,这是管理pnp设备实体的,每一个pnp设备都会在里面有实例,因此所有的并口(包括串口)都能在里面查询到,而这个类的关联类"Win32_PortResource"是所有端口的实例,可以在这里查找到pnp设备对应的地址和内存地址。
使用方法也很简单,WQL语句几乎和SQL语句相同,通过下面的语句就可以找到所有LPTx的设备,name可以用description代替,description是在设备管理器中的显示名字,name是打开属性后里面的显示名字,一般也都会包含LPT关键字。
SELECT * FROM Win32_PnPEntity WHERE name LIKE '%LPT[0-9]%'
其他详细的使用方法在实例代码中都会涉及,如果不想使用或下载我的实例的童鞋也可以自己寻找方式,网上的代码结合我这里提及的要点几乎就是我实例的雏形,只是我做了更为实用的封装。
最后,实例开发借用了https://www.codeproject.com/Tips/441815/Parallel-Port-Control-with-Csharp-NET-2-0的模型,在他的基础上进行了修改(不过几乎全部改完了,也就窗体是保持原样的),也很感谢这位作者的源码!
附上实例:https://download.csdn.net/download/u012557895/10632706,亲测可用!
(内容原创,可随意转载,转载请注明作者或引用)
dadi
2018/8/29