李可一,朱环娟,周凤华
1.北京林业大学工学院自动化系,北京 100083
2.河北省承德市气象局,河北承德 067000
3.华北电网有限公司承德供电公司,河北承德 067000
基于多线程技术的串口通信的设计与研究
李可一1,朱环娟2,周凤华3
1.北京林业大学工学院自动化系,北京 100083
2.河北省承德市气象局,河北承德 067000
3.华北电网有限公司承德供电公司,河北承德 067000
本文以VC++ 6.0为开发平台,讲述了如何使用32位的WindoWs API 串口通信函数,编程实现高效的多线程全双工串口通信,并在阐述中给出了相关函数或代码。实验证明,该方法有着较好的灵活性、可靠性与高效性。
VC++;串口通信;多线程;重叠I/O
串口是常用的计算机与外部设备之间的数据传输通道,由于使用其通信方便易行,且能实现数据的长远距离传输,故应用极其广泛。为此,根据不同的使用环境灵活地编写出串口通信处理程序是必要的工作。在Windows上,微软专门提供了相应的文件I/O函数和通信函数,以方便我们编写出所需的串口通信程序。目前,实现串口通信的方法有两种。第一种,使用VC++提供的串口通信控件MSComm;第二种,使用32位的API 通信函数。本文采用了第二种方法,且结合多线程技术,实现了更加灵活的串口通信程序设计。
在Windows操作系统中,串行口是被作为文件来进行处理的,而不是直接对端口进行操作,为此我们使用某一个串口进行通信时,需首先调用API函数 CreateFile(szPort,GENERIC_ READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,NULL );获取一个串口通信设备句柄hCom。其中,该函数的第一个参数szPort标识将要开启的端口号,第二个参数规定了端口读写属性,剩下的参数中较重要的是设置FILE_FLAG_OVERLAPPED标识,即开启重叠I/O的方式。在该模式下,当我们调用读写函数时,即使操作还未完成,被调用的函数也会立即返回,这样费时的I/O操作会在后台进行,使系统在这段时间可以去干别的事情,提高了系统的执行效率,且借用多线程技术还能实现读、写的同时进行。
接下来,需要根据需求,调用SetCommTimeouts(hCom, &m_ CommTimeouts);函数,设置COMMTIMEOUTS类型的结构体变量m_CommTimeouts。更改COMMTIMEOUTS结构体里面的成员变量,可以设置串口读写超时时间,以实现系统若未在指定时间内读出或写入指定数量的字符,就不再继续,立即返回执行下一次的任务。然后,还需要分别调用SetCommState和SetupComm函数,设置端口的速率、数据位、输入输出缓冲区大小等配置信息。至此,就完成了串口的初始化并开启操作。
1.2.1 多线程全双工通信
想要编写高效率的串口通信程序,除了设置重叠I/O外,再结合多线程技术,可以起到更好的效果。所谓多线程,就是指要计算机并行的处理不同的事情。在VC中线程分为用户界面线程和工作者线程,其主要区别是前者能够提供界面和用户的交互,而后者没有界面,用于处理后台任务。本文在设计通信程序时,建立了两个工作者线程,一个用于不断监视数据的接收,一个用于数据的发送。这样,使程序实现了收发同时进行的全双工工作方式,在实际应用中更有效率。
另外,值得注意的是使用重叠I/O需要创建OVERLAPPED结构以供读写函数,即ReadFile和WriteFile使用。而OVERLAPPED结构中最重要的成员是hEvent。hEvent是一个事件对象句柄,通过CreateEvent函数来创建,被用作线程的同步对象使用。如果读写函数未完成操作就返回,那么会将hEvent置为无信号状态。只有操作完成后(包括超时),hEvent才会置为有信号状态,这样我们就可以通过hEvent知晓当前通讯设备的读写状态。
实际程序运行时,若发现读、写函数的返回值为假,由于开启了重叠I/O方式,那么未必是指读写失败,此时需要通过GetLastError函数的返回值做进一步判断。若返回为ERROR_IO_ PENDING,说明当前读或写操作还未完成,这时就可以挂起读、写线程,等待操作完成。而程序设计时有两种等待方法:一种是用WaitForSingleObject等待函数来等待OVERLAPPED结构体中的成员hEvent为有信号状态;另一种办法是调用GetOverlappedResult函数等待,注意需要将该函数的bWait参数设为TRUE,那么该函数将会一直等待hEvent 事件,直到其有信号才返回。同时,利用GetOverlappedResult还可以返回一个OVERLAPPED结构体,里面包含有实际发送、接收字节等重叠操作的结果。
下面将分别给出读、写线程的关键代码,并作适当分析。
1.2.2 串口读操作
以上给出的即是接收数据线程的主要代码,由于在实际使用中,我们想实时监控端口的数据输入情况,做到输入缓冲区一有数据传来就立即执行读取操作,故在程序中要建立一个定时器,设定一个监控的时间间隔,定点不断执行以上工作者线程的代码,以实现对端口的监控。另外,我们在线程中需要使用ClearCommError函数获取输入缓冲区的数据状态,以判断是否该开始读取数据。
1.2.3 串口写操作
以上所示的数据发送线程,我们只需在想要发送数据时创建、启动线程即可。
本文描述了在VC++上如何使用Win32 API中相关的通信函数,编程实现串口通讯程序,且采用多线程的程序设计思想,在重叠I/O的方式下,不仅提高了串口通信的效率,而且还实现了收发同时进行的全双工工作方式,为计算机与外部设备通过串口通信提供了更灵活的方案。
[1]胡春燕.基于VC的串口通信的实现[J].福建电脑,2005(10).
[2]阚能琪. VC ++ 串口通信中多线程技术的应用研究[J].西华大学学报:自然科学版,2005,7.
[3]孙鑫,余安萍. VC++深入详解[M].北京:电子工业出版社,2006,6.
[4]Microsoft Corporation. Microsoft Developer NetWork Library[DB/DK].Microsoft Corporation,2001.
TP313
A
1674-6708(2010)24-0219-02