基于Windows API函数的串口通讯程序设计

2015-03-27 12:11安徽博微长安电子有限公司丁旭玲
电子世界 2015年19期
关键词:主程序调用线程

安徽博微长安电子有限公司 龙 灏 丁旭玲

1 引言

随着监控系统的发展,监控系统与各个外围设备数据传输量巨大,通讯方式越来越多样,CPU处理任务越来越繁重。串口通讯的数据收发处理是监控程序的重要一部分,串口通信中如何结合异步通信、多线程等技术,编写出高质量、高效率的串口通信程序,具有一定的现实意义。

2 Windows API串口编程概述

在Windows平台下,串口被视为一种特殊的文件,串口的操作可以被视为一种文件操作。在实际的编程中,可以使用文件相关的API函数,例如CreateFile()、ReadFile()以及WriteFile()等对串口进行关联或者操作。

串口的操作模式分为同步模式和异步模式,同步模式是指程序中的代码按顺序执行,只有前面的程序执行完毕并返回,才能继续执行后面的程序,该模式容易造成程序的假死。异步模式下,调用的函数会立即返回,不会造成线程的阻塞,线程可以在不同的句柄上同时执行I/O操作,甚至可以在同一句柄上同时进行读写操作,效率更高。

3 串口类的设计

程序将串口操作函数及相应的变量封装为串口类,方便主程序调用。主程序可定义串口类的对象调用各种函数,同时对多串口进行监听及读写操作。串口类中的重要函数如表1所示:

表1 串口类包含的函数及功能实现

为了提高程序的效率,串口类中由事件驱动数据发送、接收和线程的退出。类中定义了3个事件:

m_hShutDownEvent(串口关闭事件)、m_hWriteEvent(数据发送事件)、Overlapped结构的m_ov(数据接收事件)。配合线程中的WaitForMultipleObjects()函数,实现线程的调度。为了实现对不同串口初始化,需要使用临界区对象,以保证在某一时刻只进行一个串口的初始化。部分初始化代码如下:

If(m_ov.hEvent!=NULL)//事件的建立

ResetEvent(m_ov.hEvent);

m_ov.hEvent=CreatEvent(NULL,TRUE,FALSE,NULL);//事件被定义为手动复位

……

m_h Event Array[0]=m_h Shut Dow n Ev ent;//m_hEventArray为事件数组

m_hEventArray[1]=m_ov.hEvent;

m_hEventArray[2]=m_hWriteEvent;

InitializeCriticalSection(&m_csCommunication);//初始化临界区对象

……

串口的初始化首先需要使用API函数CreateFile()打开串口并创建与该串口相关联的文件。注意将文件相关属性设置为FILE_FLAG_OVERLAPPED,才可以对串口进行异步操作。打开串口代码如下:

HANDLE hCom; //定义串口句柄

hCom=CreateFile(szPort,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,

FILE_FLAG_OVERLAPPED,NULL);//创建异步模式文件并关联串口,返回其句柄

表2 串口配置函数

在获得通讯设备句柄后,可使用句柄进行串口参数设置。在串口API函数编程时,波特率、校验方式等参数均被封装到一个结构体DCB中。在查询或配置串口的参数时,都要使用该结构体。配置串口使用的函数如表2所示。

串口初始化完成后,可在线程中等待通信事件的发生。线程函数中使用WaitForMultipleObjects()函数对m_hEventArray数组中的3个事件同时进行监测处理。当判断某个事件为有信号时,执行相应的操作。线程函数部分代码如下:

for (;;) //循环

{

……

Event = Wait For Multip leObjects(3, por t->m_hEventArray, FALSE, INFINITE);

//无限等待事件的发生

switch (Event)

{

case 0://线程关闭事件为有信号状态

{

port->m_bThreadAlive = FALSE;

AfxEndThread(0);//退出线程

}

case 1: // 读事件为有信号状态

{

GetCommMask(port->m_hComm, &CommEvent);//得到串口事件

if (CommEvent & EV_RXCHAR)//判断为接收事件

if(!port->m_bBlockRead)

ReceiveChar(port, comstat);//调用ReadFile()函数读取数据,每接收一个字节数据向主程序送WM_COMM_RXCHAR消息和接收到的数据

break;

}

case 2: // 写事件为有信号状态

{

WriteChar(port);// 调用WriteFile()发送数据

break;

}

}

4 串口类的使用

将串口类的源程序及头文件导入到主程序工程中,即可在主程序中定义该串口类的对象,通过对象引用串口初始化InitPort()、串口监视函数StartMonitoring()等函数。当需要向串口发送数据时,可调用WritePort()函数。当串口类的线程收到一个字节的数据,会向主程序发送WM_COM_RXchar消息和接收到的数据,因此在主程序中需自定义WM_COMM_RxCHAR消息,并关联消息处理函数以处理接收的数据。主程序消息处理函数部分代码如下所示:

OnRecvByte(UINT wParam,LONG lParam)

{

Unsigned char JustRecv=(unsigned char)wParam;

Int PortNum=(int)lParam;

If(PortNum==1)

{

RecvData[Cnt]=JustRecv;//将接收的字节保存

Cnt++;

}

}

上面的代码为自定义消息WM_COMM_RxCHAR的处理函数OnRecvByte(),在消息处理函数中将不同串口的数据存储到指定的数组中,供主程序使用。

5 结束语

本文介绍了基于API函数的串口类的实现,综合使用了异步模式、多线程、事件等方法,并给出VC开发环境下实现串口通信类的关键代码。在实际监控项目中,该串口类运行稳定可靠,实现多串口数据的高效率读写,具备较强的实践价值和参考意义。

[1]阚能琪.VC++串口通信中多线程技术的应用研究[J].西华大学学报,2005,24(4):84-85.

[2]梁伟,等.Visual C++网络编程案例实战[M].北京:清华大学出版社,2014,10:35-54.

[3]李琳娜,等.Visual C++编程实战宝典[M].北京:清华大学出版社,2014,9:379-388.

[4]赵永发,由大伟,杨丽,等.Visual C++开发宝典[M].北京:机械工业出版社,2012,4:510-519.

猜你喜欢
主程序调用线程
自动升级程序在船舶监测系统中的应用
基于C#线程实验探究
基于国产化环境的线程池模型研究与实现
浅谈数控铣削技术代码程序的嵌套方式研究
核电项目物项调用管理的应用研究
电控冰箱软件模块化设计
LabWindows/CVI下基于ActiveX技术的Excel调用
时光倒流 换回PotPlayer老图标
浅谈linux多线程协作
基于系统调用的恶意软件检测技术研究