Win CE下串口接收数据不完整???
大家好,我在WinCE下采样已封装类进行串口数据收发,串口接收数据是新建一个监视线程,主要参数设置为:串口间隔超时为MAXDWORD,读系数与读常量为0;数据收发缓冲区分配32KB大小,先用SetCommMask指定接收事件。
监视线程主要部分代码如下:
while (TRUE)
{
//如果收到读线程退出信号,则退出线程
if (WaitForSingleObject(ceSeries->m_hReadCloseEvent,500) == WAIT_OBJECT_0)
break;
if (WaitCommEvent(ceSeries->m_hComm,&evtMask,NULL))
{
SetCommMask (ceSeries->m_hComm, EV_RXCHAR | EV_CTS | EV_DSR );
//表示串口收到字符
if (evtMask & EV_RXCHAR)
{
ClearCommError(ceSeries->m_hComm,&dwReadErrors,&cmState);
willReadLen = cmState.cbInQue ;//要读取的字节数
if (willReadLen <= 0)
{
continue;
}
//分配内存
readBuf = new BYTE[willReadLen];
ZeroMemory(readBuf,willReadLen);//接收得数据初始化为0
//读取串口数据
ReadFile(ceSeries->m_hComm, readBuf, willReadLen, &actualReadLen,0);
//如果读取的数据大于0,
if (actualReadLen>0)
{
//触发读取回调函数
if (ceSeries->m_OnSeriesRead)
{
ceSeries->m_OnSeriesRead(ceSeries->m_pOwner,readBuf,actualReadLen);
}
}
//释放内存
delete[] readBuf;
readBuf = NULL;
}
}
ceSeries为封装类对象,m_OnSeriesRead为回调函数。现在的问题是,我发送一个18字节的数据段,结果在ReadFile设置断点,一般willReadLen为8,有时候也为18,因为我后面要严重数据包的格式,所以如果不是一次性读入18个字节则无法通过验证。
我想请问,为什么它不能一次性接收18个数据段呢???请大家帮忙看一下,谢谢!!!
[解决办法]
提高波特率可以显著减少数据截断的情况。或者在read之前给一个人为的延时也可以
当然最好是自己做数据拼接
给一段我拼接数据的代码参考
作用:
执行GetAnswer后最长5秒(10*500)延时,如果没收到数据则返回;
一旦收到数据,则200ms后再次ReadCom,如果收到则做数据拼接,继续延时200ms再ReadCom,如果未收到,退出。
int GetAnswer(unsigned char * pData, UINT16 MaxLen){ int result = 0; int datalen = 0; unsigned char * pDataSource = pData; for (int i=0;i<10;i++) { result = ReadCom(pData,MaxLen-datalen); if (result<0) return result; else if (result==0) { if (datalen) break; Sleep(500); } else { datalen += result; pData += result; i--; Sleep(200); } } if (DebugFunc) DebugFunc(pDataSource,datalen,1); return datalen;}int ReadCom(unsigned char * pData, UINT16 MaxLen)//从端口读取数据//pData:数据存放首地址//MaxLen:最大读取长度//返回:正常返回读取到的数据长度 否则返回错误列表//非导出函数{ if (!CheckCom()) return ER_COMINVALID; DWORD dwEvent = 0; DWORD ReceiveLength = 0; static COMSTAT comstat; static BOOL bSendData = FALSE; ZeroMemory(&comstat, sizeof(COMSTAT)); ClearCommError(hCom, &dwEvent, &comstat); if (!ReadFile(hCom, pData, MaxLen, &ReceiveLength, NULL)) { if (GetLastError() != ERROR_IO_PENDING) { return ER_COMREADFAIL; } } else { return ReceiveLength; } PurgeComm(hCom,PURGE_RXCLEAR); return (ReceiveLength);}
[解决办法]
我代码里面移动readBuf是因为readBuf是个局部变量,函数内部移动不会影响外部
你要是直接把我的代码插入你的某个函数,而你又用到了readBuf,自然就不能移动了啊。
方法也简单,要么你在移动之前记录readBuf的初值,拼接完后再恢复。要么你重新弄个指针,把readBuf赋给它,你再移那个指针不就可以了