本文介绍了在Windows平台下串口开发的方法,并给出一个使用Delphi设计的远程数据采集的实例。
1 引言
在工业生产实践中,使用PC机对Inprise公司推出的Delphi是一种功能强大的高级编程语言,其具有可视化面向对象的特征,特别适合Windows平台下的图形界面和用户程序的编制。本文就介绍在Windows平台下用Delphi开发串口的方法和使用Delphi设计的一个实现远程串行数据采集的实例。
2 串口工作原理及软件实现方法
串口进行通信的方式有两种:同步通信方式和异步通信方式。同步通信方式要求通信双方以相同的时钟频率进行,而且准确协调,通过共享一个单个时钟或定时脉冲源保证发送方和接收方的准确同步,效率较高;异步通信方式不要求双方同步,收发方可采用各自的时钟源,双方遵循异步的通信协议,以字符为数据传输单位,发送方传送字符的时间间隔不确定,发送效率比同步传送效率低。
在Windows平台下,Win32 API支持同步和异步两种I/O操作。同步操作的方式的程序设计相对比较简单,但是I/O操作函数在I/O操作结束前不能返回,这将挂起调用线程,直到I/O操作结束;异步操作方式要相对复杂一些,但是可以让I/O操作在后台运行,而不会挂起调用线程,这在大数据量通信情况下对改善调用线程的响应速度是相当有效的。同时由于Win9x和WinNT下对串行通信的处理不同,这就导致了在Win9x下开发的同步方式串行通信程序在NT下会发生工作线程之间的协作阻塞,即当读线程在等待WaitCommEvent的时候,写线程不能正常工作,停在那里,整个程序处于瘫痪状态。这个问题是Windows的API函数处理串行通信的一个BUG,所以对于适应性强的程序都是选择异步方式。下面,本文对在Windows平台下对串口进行开发的方法进行介绍:
1. 汇编程序直接读写串口
汇编语言的编译效率和执行效率都很高,使用汇编语言直接对串口进行操作可以部分弥补串行通信速度较慢的缺陷,具体做法是:用汇编语言编写读、写串口的函数,在通信程序中直接调用,或者在Delphi中直接内嵌汇编程序进行对端口的读写。
例如:
asm
mov dx,0001h
mov ax,005eh
int 14h
end;
这样可以达到直接读到端口的效果。但是在WinNT和Win2000下,系统使用了保护机制,不允许用户态的程序直接读取端口,所以在WinNT和Win2000下,这种方法不能被允许执行。Ring3的用户态的程序要进入Ring0去读写端口必须先提供一个驱动(sys)程序,然后通过DLL导出函数供用户程序调用,显然,这种方法比较不容易实现。
2. 使用API函数进行串口编程
Windows系统通信一般都以WOSA(Windows Open Service Architecture,即Windows开放式服务体系)模型为基础,在此模型中位于上层的应用程序通过调用各种通信API(Application Programming Interfaces,即应用程序接口)与位于下层的设备驱动程序进行数据交换。
在Windows平台下,Windows将设备看作是文件进行管理,对设备的操作也可以看作是对文件的操作。Win32 API提供了CreateFile(),WriteFile(),ReadFile(),WaitForSingleObject(),WaitForMultipleObjects(),CreateEvent(),CreateMutex(),CreateSemaphore(),CreateThread()等函数,其基本步骤如下:
(1) 利用CreateFile()函数打开串口。该函数有七个参数,其中dwCreationDistribution参数取OPEN_EXISTING,表明打开的串口对应于实际的物理串口;lpFileName参数是要打开的串口名称,如"COM1";DwFlagsAndAttributes参数决定对串口的操作是同步操作还是异步操作;DwDesiredAccess参数是访问方式,可取GENERIC_READ或GENERIC_WRITE;DwShareMode参数是共享模式,对串口物理设备必须取0;LpSecurityAttributes参数是安全属性,取值为NULL;DwFlagsAndAttributes是文件属性和标识,一般取值为FILE_ATTRIBUTE_NORMAL。该函数返回串口操作的句柄。
(2) 对该串口句柄对应的设备进行配置,如波特率、数据位、停止位、是否奇偶校验等。这部分首先使用GetCommState()函数得到当前的串口配置信息,将这些信息存放在一个DCB结构中,然后对该DCB结构里面的内容进行重新按要求设置,最后调用SetCommState()函数使修改的设置生效。
(3) 配置串口事件。SetCommMask()函数可以设置多个串口信息事件,其串口的信息事件可以是以下任意的组合:
EV_BREAK:在输入时Windows检测到中断;
EV_CTS :CTS信号改变状态;
EV_DSR :DSR信号改变状态;
EV_ERR :发生线状态错误;
EV_RING :检测到振铃指示;
EV_RLSD :接收线信号探测状态发生改变;
EV_RXCHAR:接收缓冲区里收到字符;EV_RXFLAG:收到事件字符,并放入接收缓冲区;
EV_TXEMPTY:输出缓冲区空。