ile()和WriteFile()进行数据的读写,用WaitCommEvent()监视通信事件。CloseHandle()用于关闭串口。
在ReadFile()和WriteFile()读写串口时,可以采取同步执行方式,也可以采取重叠I/O方式。同步执行时,函数直到执行完毕才返回,因而同步执行的其他线程会被阻塞,效率下降;而在重叠方式下,调用的读写函数会立即返回,I/O操作在后台进行,这样线程就可以处理其他事务。这样,线程可以在同一串口句柄上实现读写操作,实现"重叠"。
使用重叠I/O方式时,线程要创建OVERLAPPED结构供读写函数使用,该结构最重要的成员是hEvent事件句柄。它将作为线程的同步对象使用,读写函数完成时hEvent处于有信号状态,表示可进行读写操作;读写函数未完成时,hEvent被置为无信号。
4
程序关键代码的实现
程序专门建立了一个串口通信类,下面给出关键成员函数的核心代码。
BOOL InitComm file://串口初始化,这里只给出关键步骤的代码,下同
{
HANDLE m_hComm;
COMMTIMEOUTS m_CommTimeouts;
m_hComm = CreateFile("COM1", file://在这里只使用串口1
GENERIC_READ | GENERIC_WRITE, file://打开类型为可读写
0, file://以独占模式打开串口
NULL, file://不设置安全属性
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, file://重叠I/O方式
0);
if (m_hComm == INVALID_HANDLE_VALUE) file://打开不成功
{return FALSE;}
m_CommTimeouts.ReadIntervalTimeout = 1000;
file://进行超时设置,读者应根据自己的实际需要设置
m_CommTimeouts.ReadTotalTimeoutMultiplier = 500;
m_CommTimeouts.ReadTotalTimeoutConstant = 5000;
m_CommTimeouts.WriteTotalTimeoutMultiplier = 500;
m_CommTimeouts.WriteTotalTimeoutConstant = 5000;
if (!SetCommTimeouts(m_hComm, &m_CommTimeouts))
{CloseHandle(m_hComm);
return FALSE;}
PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); file://清缓冲
return TRUE;
}
以上是专门针对COM1的初始化,如果要利用同一函数对不同串口初始化,则要在初始化前先进入代码临界区,以保证在某一时刻只进行一个串口的初始化。
在串口初始化成功后,就可以建立监控线程处理串口通信事件。下面是该线程的关键代码。
UINT CommThread(LPVOID pParam) file://用于监控串口的工作者线程
{
BOOL bResult = FALSE;
if (m_hComm) file://查看端口是否打开,这里m_hComm同上,作者在这里做了简化
PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
for (;;) file://只要线程运行,就处于监视端口行为的无限循环
{
bResult = WaitCommEvent(m_hComm, &Event, &m_ov);
file://m_ov是OVERLAPPED类型的成员变量
if (!bResult)
{ file://进行出错处理}
else
{
Event = WaitForMultipleObjects(4, m_hEvent, FALSE, INFINITE);
file://无限等待设定的事件发生,数组m_hEvent根据需要定义了须响应的接收,发送,关闭端口事件和OVERLAPPED类型的hEvent事件
switch (Event)
{ file://读写事件的响应处理过程,在此略}
}
return 0;
}
这样监控主
程序就可以使用AfxBeginThread()函数来产生CommThread串口监控线程。如果要实现对所有端口的同时监控,可以分别对端口建立监控线程。
5 小结
作为一个机房监控系统的组成部分,本串口通信
程序在VC++6.0下编译通过,在使用windows 98/NT的局域网里运行良好。