使用vs2013+qt5.5.0使用QSerialPort时,因qt-add插件中没有QSerialPort模块,但qt安装目录中有QSerialPort类,故将qt安装目录下的QSerialPort头文件、库文件、dll动态库拷贝出来,使用
vs2013包含进头文件和库文件路径中,当成普通的库来使用。

近日在使用QSerialPort发送接收串口命令时,发送给串口的命令都正常,串口都有回复,但每次接收的串口数据都只能接收到最开始的起始符一个字节,试过readAll(),readLine(),read()都是只能
读到起始的第一个字节,但实际上是有一串命令数据的。使用bytesAvailable()获取适合的数据,也是返回1。接收数据代码如下:read()函数始终只返回1个字节,下一次再读就返回0没有数据了。

int SerialPort::RecvData(unsigned char* data, int size, int timeoutMs)
{
if (!m_bOpen)
{
WLog(LOG_ERR, "serial is not open succ");
return -1;
}


if(data == NULL)
{
WLog(LOG_ERR, "write data == NULL");
return -1;
}


bool bsucc = m_serialPort.waitForReadyRead(timeoutMs);
if(!bsucc)
{
WLog(LOG_ERR, "waitForReadyRead timeout");
return -1;
}


int len = 0;
while(len < size)
{
int n = m_serialPort.read((char*)data+len,size-len);
if(n==-1 || n==0)
{
if(n!=0) WLog(LOG_ERR, "read data err[%s],n[%d]", m_serialPort.errorString().toLocal8Bit().data(), n);
break;
}


len += n;
}


std::string str;
for (int i = 0; i<len; i++)
{
char buf[8] = { 0 };
sprintf(buf, "%02X ", data[i]);
str += std::string(buf);
}
WLog(LOG_DEBUG, "recv data[%s]",str.c_str());


return len;
}

后来想是不是串口发送其他数据时与第一个字符会有小段时间的延时,这样就造成每次只有第一个字节数据,后面的数据后面才来到。因此代码修改为读取一次,就进入while循环,然后等待数据
到达,waitForReadyRead()里面的超时时间设置为10ms,这样不会等待太久影响接收数据的时间,如果在该时间内有数据到达就接收,否则如果超时就当成数据已经接收完成。换了此种方法后,
串口发送的数据才全部接收到。使用普通的串口工具助手能够一次接收到所有的数据,使用QSerialPort类接收会有这样的问题,也不知道是串口工具助手做了处理还是QSerialPort类的接收数据方面有些小bug。

int SerialPort::RecvData(unsigned char* data, int size, int timeoutMs)
{
if (!m_bOpen)
{
WLog(LOG_ERR, "serial is not open succ");
return -1;
}


if(data == NULL)
{
WLog(LOG_ERR, "write data == NULL");
return -1;
}


bool bsucc = m_serialPort.waitForReadyRead(timeoutMs);
if(!bsucc)
{
WLog(LOG_ERR, "waitForReadyRead timeout");
return -1;
}


int n = m_serialPort.bytesAvailable();
QString readData = m_serialPort.readAll(); //很奇怪的情况,一次只能读到开始的:,其他数据读取不了,只能用下列方式来读取
while (1)
{
bsucc = m_serialPort.waitForReadyRead(10);
if (!bsucc)
{
break;
}


n += m_serialPort.bytesAvailable();
readData += m_serialPort.readAll();
}
int len = readData.size();
memcpy(data, readData.toLocal8Bit().data(), len);

/*int len = 0;
while(len < size)
{
int n = m_serialPort.read((char*)data+len,size-len);
if(n==-1 || n==0)
{
if(n!=0) WLog(LOG_ERR, "read data err[%s],n[%d]", m_serialPort.errorString().toLocal8Bit().data(), n);
break;
}
len += n;
}*/


std::string str;
for (int i = 0; i<len; i++)
{
char buf[8] = { 0 };
sprintf(buf, "%02X ", data[i]);
str += std::string(buf);
}
WLog(LOG_DEBUG, "recv data[%s]",str.c_str());


return len;
}

以下网友提供的同步解决方式:

//今天就遇到这个问题, 我说说同步的方式解决:  
serial.write(data);
if(serial.waitForBytesWritten(-1))
{
if(serial.waitForReadyRead(-1))
{
QByteArray readDate = serial.readAll();
}
}

//这样下来基本可以解决读取不完整的问题