13.5.3 读写串口(2)
(2)同步写串口示例代码如下:
- 01 bool WriteCom(char *str, int len)
- 02 {
- 03 DWORD dwBytesWriten = 0; //写入的字节数
- 04 COMSTAT ComStat;
- 05 DWORD dwErrorFlags;
- 06 BOOL bWriteStat;
- 07 ClearCommError( hCom, &dwErrorFlags, &ComStat);
- 08 bWriteStat=WriteFile( hCom, str, len, &dwBytesWriten, NULL);
- 09 if( !bWriteStat )
- 10 { //写串口失败
- 11 AfxMessageBox( "写串口失败! ");
- 12 return false;
- 13 }
- 14 PurgeComm( hCom,
- 15 PURGE_TXABORT| PURGE_RXABORT| PURGE_TXCLEAR|
- 16 PURGE_RXCLEAR); //清空读写缓冲区
- 17 }
异步读写串口的实现就比较灵活了,既可以实现非阻塞读写,也可以实现阻塞读写。有两种方法可以等待操作完成而实现阻塞读写。
用像WaitForSingleObject()等待函数一样来等待OVERLAPPED结构的hEvent成员。
调用GetOverlappedResult()函数等待,后面将演示说明。
在OVERLAPPED结构中包含了重叠I/O的一些信息,定义如下:
- typedef struct _OVERLAPPED
- {
- DWORD Internal; //操作系统保留,指出一个和系统相关的状态
- DWORD InternalHigh; //指出发送或接收的数据长度
- DWORD Offset; //文件传送的开始位置
- DWORD OffsetHigh; //文件传送的字节偏移量的高位字
- HANDLE hEvent; //指定一个I/O操作完成后触发的事件
- }OVERLAPPED;
在使用ReadFile()或WriteFile()函数进行异步重叠操作时,线程需要创建OVERLAPPED结构以供这两个函数使用。线程通过OVERLAPPED结构获得当前的操作状态,该结构最重要的成员是hEvent。hEvent是读写事件。当串口使用异步通信时,函数返回时操作可能还没有完成,程序可以通过检查该事件得知是否读写完毕。当调用ReadFile()或WriteFile()函数的时候,该成员会自动被置为无信号状态;当重叠操作完成后,该成员变量会自动被置为有信号状态。
GetOverlappedResult()函数返回重叠操作的结果,通过判断OVERLAPPED结构中的hEvent是否被置位,来判断异步操作是否完成,函数原型如下:
- BOOL GetOverlappedResult(
- HANDLE hFile, //串口的句柄
- LPOVERLAPPED lpOverlapped, //重叠操作开始时指定的OVERLAPPED结构
- LPDWORD lpNumberOfBytesTransferred,//实际读写操作传输的字节数
- BOOL bWait //用于指定函数是否一直等到重叠操作结束
- );
在异步操作前应先使用ClearCommError()函数获取尚未读取的字节数,函数的原型如下:- BOOL ClearCommError(
- HANDLE hFile, //串口句柄
- LPDWORD lpErrors, //指向接收错误码的变量
- LPCOMSTAT lpStat //指向通信状态缓冲区
- );
根据以上信息给出异步读串口的示例代码如下:- 01 bool ReadCom(char * str, DWORD *len)
- 02 {
- 03 COMSTAT ComStat;
- 04 DWORD dwErrorFlags;
- 05 OVERLAPPED m_osRead;
- 06 memset(&m_osRead,0,sizeof(OVERLAPPED));
- 07 m_osRead.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); //创建事件
- 08 ClearCommError(hCom,&dwErrorFlags,&ComStat);
- 09 dwBytesRead=min(len,(DWORD)ComStat.cbInQue); //获取尚未读取的字节数
- 10 if(!dwBytesRead)
- 11 return FALSE;
- 12 BOOL bReadStatus;
- 13 bReadStatus=ReadFile(hCom,str,len,&len,&m_osRead);
- 14 if(!bReadStatus) //读取失败
- 15 {
- 16 if(GetLastError()==ERROR_IO_PENDING)
- 17 { //串口正在进行读操作
- 18 //等到读操作完成或延时已达到2秒钟
- 19 WaitForSingleObject(m_osRead.hEvent,2000);
- 20 PurgeComm(hCom, PURGE_TXABORT|
- 21 PURGE_RXABORT|PURGE_TXCLEAR|
- 22 PURGE_RXCLEAR); //清空串口缓冲
- 23 }
- 24 return false;
- 25 }
- 26 PurgeComm(hCom, PURGE_TXABORT|PURGE_RXABORT|
- 27 PURGE_TXCLEAR|PURGE_RXCLEAR); //清空串口缓冲
- 28 return true;
- 29 }
【代码解析】
第9行获取将要读取的字节数。第13行读取数据。第14行判断读取是否成功,如不成功则在第13~26行进行错误处理。最后在第26、27行清空串口缓冲区。