现在各种QT python ide用起来很方便,但生成的程序太大不方便,个人平时还是喜欢用c++builder写一些小测试程序,程序可以做到很小巧。
TYbCommDevice 是c++ builder的很方便的一个串口收发控件,目前最新版是1.5.0.6,在官网看到是2017年后就没有更新。
最新利用TYbCommDevice写了一个测试程序接收并解释由MCU发上来的持续数据,波特率是115200bps,使用USB转口模块转发数据。
测试过程发现在接收大量,及持续数据时,经常会出现读线程阻塞,导致系统卡住的问题。
1. 分析初步原因是ReadFile及GetOverlappedResult函数读取失败,导致变量BytesRemain没有自减至0而导致while(BytesRemain>0)无法退出
2. 估计的实质原因是ReadFile及是GetOverlappedResult函数调用过快引起IO申请过于频繁引起的系统异常,报ERROR_IO_INCOMPLETE错误
注:ERROR_I0_PENDING表示读取IO操作是异步的并且尚未完成, ERROR_IO_INCOMPLETE表示I/O操作仍在进行中尚未完成,
其实ReadFile函数在非串口数据读取的其它场合,调用过快引起IO申请太频繁也会引发ERROR_I0_PENDING/ERROR_IO_INCOMPLETE错误导致意想不到的异常,尤其在CPU运行速度越来越快的情况下,所以需要合理使用此函数,比如使用定时器(降实时性换稳定性),或者当查询到的数据量大于一定值再调用ReadFile(一个字节调用一次就有点频繁了)
解决方案:
如出现上述两种情况,尝试使用CancelIo函数取消当前的IO申请并休眠1ms,经长时间测试仍稳定接收,未测出异常(原测试不超过10分钟就挂掉)
如有需要可以下载我编译好控件及库(有源码):
VictorComm1506-VCL-CB6-FIX(20230917)串口控件库及源码(修复串口持续接收高波特率数据异常问题)资源-CSDN文库
if(dwEvtMask & EV_RXCHAR)
{
ClearCommError(Comm->Handle, &dwErrorFlag, &ComStat);
BytesRemain = ComStat.cbInQue;
while(BytesRemain>0)
{
BytesToRead = BytesRemain<RecvBufSize?BytesRemain:RecvBufSize;
if(ReadFile(Comm->Handle, RecvBuf, BytesToRead, &dwBytes, &Comm->_ReadOS))
{
Comm->_InQueue->In(RecvBuf, dwBytes);
BytesRemain-=dwBytes;
}
else
{
DWORD dwError = GetLastError();
if(dwError==ERROR_IO_PENDING)
{
if(GetOverlappedResult(Comm->Handle, &Comm->_ReadOS, &dwBytes, false))
{
Comm->_InQueue->In(RecvBuf, dwBytes);
BytesRemain-=dwBytes;
retry = 0;
}
else
{
dwError = GetLastError();
/* 测试过程中,在高波特率,接收大量,及持续数据时,经常会出现读线程阻塞,系统卡住的问题
1. 分析初步原因是ReadFile及GetOverlappedResult函数读取失败,导致变量BytesRemain没有自减至0而导致while(BytesRemain>0)无法退出
2. 估计的实质原因是ReadFile及是GetOverlappedResult函数调用过快引起IO申请过于频繁引起的系统异常,报ERROR_IO_INCOMPLETE错误
ERROR_I0_PENDING表示读取IO操作是异步的并且尚未完成, ERROR_IO_INCOMPLETE表示I/O操作仍在进行中尚未完成
修改方案:
如出现上述两种情况,尝试使用CancelIo函数取消当前的IO申请并休眠1ms,经长时间测试仍稳定接收,未测出异常(原测试不超过10分钟就挂掉)
*/
if((dwError==ERROR_IO_INCOMPLETE)||(dwError==ERROR_IO_PENDING))
{
CancelIo(Comm->Handle);
Sleep(1);
}
// retry 500ms
if(retry++>500)
{
CancelIo(Comm->Handle);
BytesRemain = 0; // error, give up retry!
}
}
}
}
}
}