C/C++串口通信(2)-重叠操作

转自:王柏元的博客http://wangbaiyuan.cn/c-serial-communication-write-reading.html

重叠操作时,操作还未完成函数就返回。
重叠I/O非常灵活,它也可以实现阻塞。有两种方法可以等待操作完成:
一种方法是用WaitForSingleObject这样的等待函数来等待OVERLAPPED结构的hEvent成员;
另一种方法是调用GetOverlappedResult函数等待。

//OVERLAPPED结构
typedef struct _OVERLAPPED { // o
DWORD Internal;
DWORD InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
HANDLE hEvent;//读写事件。
} OVERLAPPED;

在使用ReadFile和WriteFile重叠操作时,线程需要创建OVERLAPPED结构以供这两个函数使用。
线程通过OVERLAPPED结构获得当前的操作状态,该结构最重要的成员是hEvent。

当串口使用异步通讯时,函数返回时操作可能还没有完成,程序可以通过检查该事件得知是否读写完毕。
当调用ReadFile, WriteFile 函数的时候,该成员会自动被置为无信号状态;当重叠操作完成后,该成员变量会自动被置为有信号状态。

//GetOverlappedResult函数
BOOL GetOverlappedResult( HANDLE hFile, // 串口的句柄 ,指向重叠操作开始时指定的OVERLAPPED结构 
LPOVERLAPPED lpOverlapped, // 指向一个32位变量,该变量的值返回实际读写操作传输的字节数。
LPDWORD lpNumberOfBytesTransferred, // 该参数用于指定函数是否一直等到重叠操作结束。
//如果该参数为TRUE,函数直到操作结束才返回。
//如果该参数为FALSE,函数直接返回,
//这时如果操作没有完成,通过调用GetLastError()函数会返回ERROR_IO_INCOMPLETE。 
 BOOL bWait );

该函数返回重叠操作的结果,用来判断异步操作是否完成,它是通过判断OVERLAPPED结构中的hEvent是否被置位来实现的。

异步读串口的示例代码(1):
用WaitForSingleObject函数来等待OVERLAPPED结构的hEvent成员:

char lpInBuffer[1024];
DWORD dwBytesRead=1024;
COMSTAT ComStat;
DWORD dwErrorFlags;
OVERLAPPED m_osRead;
memset(&m_osRead,0,sizeof(OVERLAPPED));
m_osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
ClearCommError(hCom,&dwErrorFlags,&ComStat);
dwBytesRead=min(dwBytesRead,(DWORD)ComStat.cbInQue);
if(!dwBytesRead) return FALSE;
BOOL bReadStatus;
bReadStatus=ReadFile(hCom,lpInBuffer, dwBytesRead,&dwBytesRead,&m_osRead);
if(!bReadStatus)
//如果ReadFile函数返回FALSE
{
    if(GetLastError()==ERROR_IO_PENDING)
    //GetLastError()函数返回ERROR_IO_PENDING,表明串口正在进行读操作
    {
        WaitForSingleObject(m_osRead.hEvent,2000);
        //使用WaitForSingleObject函数等待,直到读操作完成或延时已达到2秒钟
        //当串口读操作进行完毕后,m_osRead的hEvent事件会变为有信号
        PurgeComm(hCom, PURGE_TXABORT| PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
        return dwBytesRead;
    }
return 0;
}
PurgeComm(hCom, PURGE_TXABORT| PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); 
return dwBytesRead;

简要说明:
在使用ReadFile 函数进行读操作前,应先使用ClearCommError函数清除错误。
ClearCommError函数的原型如下:

BOOL ClearCommError( HANDLE hFile,// 串口句柄
 LPDWORD lpErrors, // 指向接收错误码的变量
 LPCOMSTAT lpStat // 指向通讯状态缓冲区 );

该函数获得通信错误并报告串口的当前状态,同时,该函数清除串口的错误标志以便继续输入、输出操作。
参数lpStat指向一个COMSTAT结构,该结构返回串口状态信息。
COMSTAT结构 COMSTAT结构包含串口的信息,结构定义如下:

typedef struct _COMSTAT { 
// cst 
DWORD fCtsHold : 1; // Tx waiting for CTS signal 
DWORD fDsrHold : 1; // Tx waiting for DSR signal 
DWORD fRlsdHold : 1; // Tx waiting for RLSD signal 
DWORD fXoffHold : 1; // Tx waiting, XOFF char rec''d 
DWORD fXoffSent : 1; // Tx waiting, XOFF char sent 
DWORD fEof : 1; // EOF character sent 
DWORD fTxim : 1; // character waiting for Tx 
DWORD fReserved : 25; // reserved 
DWORD cbInQue; // bytes in input buffer 
DWORD cbOutQue; // bytes in output buffer
 } COMSTAT, *LPCOMSTAT;

本文只用到了cbInQue成员变量,该成员变量的值代表输入缓冲区的字节数。
最后用PurgeComm函数清空串口的输入输出缓冲区。

异步读串口示例代码(2):
调用GetOverlappedResult函数等待

char lpInBuffer[1024];
DWORD dwBytesRead=1024;
BOOL bReadStatus;
DWORD dwErrorFlags;
COMSTAT ComStat;
OVERLAPPED m_osRead;
ClearCommError(hCom,&dwErrorFlags,&ComStat);
if(!ComStat.cbInQue) return 0;
dwBytesRead=min(dwBytesRead,(DWORD)ComStat.cbInQue);
bReadStatus=ReadFile(hCom, lpInBuffer,dwBytesRead, &dwBytesRead,&m_osRead);
if(!bReadStatus) //如果ReadFile函数返回FALSE
{ 
    if(GetLastError()==ERROR_IO_PENDING)
    {
         GetOverlappedResult(hCom, &m_osRead,&dwBytesRead,TRUE);
        // GetOverlappedResult函数的最后一个参数设为TRUE,
        //函数会一直等待,直到读操作完成或由于错误而返回。
        return dwBytesRead; 
    }
    return 0; 
}
return dwBytesRead;

异步写串口的示例代码:

char buffer[1024];
DWORD dwBytesWritten=1024;
DWORD dwErrorFlags;
COMSTAT ComStat;
OVERLAPPED m_osWrite;
BOOL bWriteStat;
bWriteStat=WriteFile(hCom,buffer,dwBytesWritten, &dwBytesWritten,&m_OsWrite);
if(!bWriteStat)
{ 
    if(GetLastError()==ERROR_IO_PENDING)
    { 
        WaitForSingleObject(m_osWrite.hEvent,1000);
        return dwBytesWritten;
    }
    return 0; 
}
return dwBytesWritten;

关闭串口

BOOL CloseHandle(
HANDLE hObject; //handle to object to close
);
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值