一.问题与解决
1.问题:
在做串口发送固件升级数据的时候,总是莫名提示错误:
QObject::startTimer: Timers cannot be started from another thread
QObject::startTimer: Timers cannot be started from another thread
QObject::startTimer: Timers cannot be started from another thread
用多线程也没有用,后来发现程序写的不够严谨,导致发送和接收出现了一些不太常见的问题,分享如下。
问题程序示例:
void MainWindow::startTransfer()
{
localFile = new QFile(fileName);
if (!localFile->open(QFile::ReadOnly)) {
qDebug() << "client: open file error!";
return;
}
payloadSize = 1024;
bytesWritten = 0;
bytesToWrite = 0;
totalBytes = localFile->size();
outBlock = localFile->read(totalBytes);
while((totalBytes-bytesWritten) >= payloadSize)
{
serial.write(outBlock.mid(bytesWritten,payloadSize));
bytesWritten = bytesWritten +payloadSize;
}
if((totalBytes-bytesWritten) > 0)
{
serial.write(outBlock.mid(bytesWritten,(totalBytes-bytesWritten)));
}
localFile->close();
}
2.解决
发送完成后加入代码:serial.waitForBytesWritten(),修改为:
void MainWindow::startTransfer()
{
localFile = new QFile(fileName);
if (!localFile->open(QFile::ReadOnly)) {
qDebug() << "client: open file error!";
return;
}
payloadSize = 1024;
bytesWritten = 0;
bytesToWrite = 0;
totalBytes = localFile->size();
outBlock = localFile->read(totalBytes);
while((totalBytes-bytesWritten) >= payloadSize)
{
serial.write(outBlock.mid(bytesWritten,payloadSize));
if(!serial.waitForBytesWritten())
{
qDebug()<<"serial write error";
}
bytesWritten = bytesWritten +payloadSize;
}
if((totalBytes-bytesWritten) > 0)
{
serial.write(outBlock.mid(bytesWritten,(totalBytes-bytesWritten)));
if(!serial.waitForBytesWritten())
{
qDebug()<<"serial write error";
}
}
localFile->close();
}
二.原理分析
1.在Qt中,进行串口通信时,QSerialPort 类是一个非常重要的类,它封装了与串口通信相关的功能。当你通过串口发送数据时,数据并不是立即被发送到物理设备上的,而是先被放入到QSerialPort的内部缓冲区中,然后由Qt的底层机制(可能是依赖于操作系统的串口驱动)负责将缓冲区中的数据发送给目标设备。
2.serial.waitForBytesWritten(int msecs = 30000) 函数的作用就是等待直到所有待发送的字节都被写入到底层的串口硬件,或者直到指定的毫秒数(msecs)过去。这个函数对于确保数据的完整发送非常重要,尤其是在需要连续发送多条消息或者发送后需要立即读取响应的场合。
参数说明:
msecs:这是一个可选参数,表示等待的最大时间(以毫秒为单位)。如果在这段时间内,所有的字节都被成功写入到底层串口硬件,函数将返回true。如果超时(即指定的时间过去了,但仍有数据未被写入),函数将返回false。如果msecs被设置为-1,则函数将无限期地等待,直到所有字节都被写入。
使用场景:
确保数据完整性:在发送重要数据后,你可能需要确保这些数据已经完全被发送出去,此时就可以调用waitForBytesWritten()函数来等待发送完成。
同步通信:在进行同步通信时,你可能需要发送一条命令后,立即读取命令的响应。在这种情况下,使用waitForBytesWritten()可以确保命令已经完全发送,然后再读取响应。
性能优化:在一些性能敏感的场合,你可能需要减少不必要的等待时间。通过调整waitForBytesWritten()的等待时间,可以在确保数据完整性的同时,尽量减少等待时间,从而提高程序的性能。
需要注意的是,虽然waitForBytesWritten()函数非常有用,但在一些情况下(如非阻塞通信模式),你可能不需要显式地等待所有字节都被写入。此外,如果串口通信出现问题(如设备断开连接),该函数可能会无限期地等待(如果msecs被设置为-1),因此在使用时需要注意处理这种情况。