最近项目遇到一个问题:从串口读数据时,如果使用 USB-Serial Adapter,那么每次读取只能读到1字节,循环读取效率特别低下。而如果是接 RS232 则不会产生这个问题。
推测这个问题产生的原因,是Win32下不同驱动程序产生 COMM 事件的时机不同。RS232是在受信缓冲区中产生一定量的数据之后,才会令API产生 EV_RXCHAR,而USB转串口的驱动,一收到数据就直接发生 EV_RXCHAR 了。
基于这个推论,再找解决办法。只要“等”一小会儿就可以了。那么等多久合适呢?
实验发现,受信缓冲区中数据的大小,其实存在ClearCommError()函数的输出参数的 COMSTAT 结构体中。
COMSTAT 的文档中说得很明确:
cbInQue
The number of bytes received by the serial provider but not yet read by a ReadFile operation.
这就好办了,只要等到这个值不发生变化,那就是收完了。
下面是代码示例,只是示意,不要照抄,编不过的。其精华就在于while。
bool MassRead(HANDLE hFile, UINT8* pBuff, UINT* pLen) { UINT8 tmpBuf[1024] = {0}; DWORD dwRead(0); DOWRD dwIn(0); DWORD Err(0); COMSTAT cs; ClearCommError(h_drv, &Err, &cs); while(dwIn < cs.cbInQue && cs.cbInQue < 500)//一般串口的受信buff大小是512,避免缓冲区溢出。 { dwIn = cs.cbInQue; ::Sleep(10); ClearCommError(h_drv, &Err, &cs); } bool fResult = ReadFile (hFile, tmpBuf, sizeof(tmpBuf), &dwRead, 0); if (fResult&&dwRead) { memcpy_s(pBuff, dwRead, tmpBuf, dwRead); *pLen = dwRead; } return fResult; } DWORD dwCommModemStatus(0); SetCommMask (h_drv, EV_RXCHAR | EV_ERR); WaitCommEvent (h_drv, &dwCommModemStatus, 0); if (dwCommModemStatus&EV_RXCHAR) MassRead (h_drv, read_buf, sizeof(read_buf), &len);
我怎么感觉你之前写过类似的.
话说这个又该怎么理解?是目前的USB-RS232通用驱动有问题?
不能算驱动有问题。驱动可以有不同的理解。写代码的时候把现象统一了就行。
我们这也是在连USB这头的时候收长数据出现了超时才发现的。
之前写过一个基板上的USB切断未识别的问题,那个驱动完全是自己写的。
这个封了好几层了,是WindowAPI的调用。
跟 USB-RS232 这玩意打交道的经历我大概能写出相当长一篇文章出来。有一段时间完全想自己买一根拿来用,但是真的当我可以买的时候,使用场景已经完全不存在了。
调基板的时候使用串口的场景还挺多的。PC跟PC间确实很少用了。
最初摸RS232是2003年前后吧,当时的文曲星只能靠串口传数据。
第二次摸是2011年,在电信,接交换机要用串口。
后来是到北京,网康的设备装系统需要用串口。
再后来遇到的几个公司就都很傻逼,买的硬件虽然都带串口,但是员工装系统都要抱着显示器才能装,有时还要拆机箱插显卡。多数员工还不会在命令行下配IP,所以还要装图形界面。
等到我真正回归到正常公司时,IPMI 已经面世了,甭说RS232,连USB口都可以不用就能搞定一切。
学习了,感谢