QT 5.7串口读取速度很慢
QT 5.7 Serial Port reads very slow
我是编程新手,正在自学。我编写了一个应用程序来轮询来自控制单元的多个请求。我基本上不断地向控制单元发送各种读取命令并读回响应。我的程序运行正常,我成功发送命令并收到答案。但是读取速度很慢(我的代码中有 100 毫秒的超时以确保我得到完整的答复)
我有一个由专业编码员用 C++ 编写的用于同一控制单元的程序,在他的程序中,他每 30 毫秒轮询一次,我总是在那个时间范围内收到完整的答案。我有相同的设置 57K baud 8 bits 1 stop bit and no parity。但是我的 QT 代码需要将近 100 毫秒才能收到答案。
在我的代码中,我读取了前 2 个字节(第一个字节是消息标识符,第二个字节是消息长度的剩余部分)然后我循环读取直到总消息长度等于消息长度字节 +1(+ 1 包含第一个字节)。当我知道 QT 知道硬件是限制因素时,我不知道为什么我的代码在 QT 中如此缓慢。请求总是 3 个字节,回复从 3 到 61 个字节不等。请帮我指出我的错误。如果我删除超时我总是有短读。到目前为止,我也尝试过 read(all) 但结果相同。
以下是我阅读响应的代码摘录。完整代码位于 https://github.com/MarkusIppy/PowerTune
//Error handling
QTime startTime = QTime::currentTime();
int timeOut = 100; // timeout in milisec.
QByteArray recvData = m_serialport->read(2); // reading first two bytes of received message to determine lenght of ecpected message
int msgLen = recvData[1]; //Total message Lenght excluding the first byte
while ( recvData.size() <= (msgLen+1) )
{
if ( startTime.msecsTo(QTime::currentTime()) > timeOut ) break;
recvData += m_serialport->read(msgLen+1-recvData.size());
}
if (msgLen +1 == recvData.length()) //if the received data lenght equals the message lenght from lenght byte + identifier byte (correct message lenght received )
{
qDebug() << "Received data OK"<<msgLen +1;
if(requestIndex <= 61){requestIndex++;}
else{requestIndex = 58;}
readData(recvData);
}
else //if the lenght of the received message does not correspond with the expected lenght repeat the request
{
qDebug() << "Received data lenght NIO";
readData(recvData);
qDebug() << "Request Message again"<< requestIndex;
}
很抱歉,我没有足够的时间来完成您的项目,而且根据您提供的代码,我不能 100% 确定原因是什么。不过,我最好的猜测是,这种情况下的问题是您明确等待接收数据,而事件处理以某种方式延迟或根本没有发生。
无论如何,这里有一些建议:
- 使用 QTimer 代替 QTime.
- 了解 Qt5's signals and slots 并使用它们从串行端口异步读取。
我使用 QSerialPort 通过将它的 bytesWritten(qint64 bytes)
和 readyRead()
信号连接到我程序的插槽,比方说 on_bytesWritten(qint64 bytes)
和 on_readyRead()
。然后我向目标设备发送请求,并在 on_readyRead()
槽中处理结果。对于每个发送命令,我都会启动一个 QTimer,其 timeout()
信号连接到我的应用程序的 on_timeout()
插槽。这样我就可以监控设备是否及时响应,以及数据一来就得到。您也可以使用QSerialPort的errorOccurred(QSerialPort::SerialPortError error)
信号来检查传输是否有问题。
这是我目前所拥有的(仅发布我的 cpp 文件的重要部分)
此代码现在几乎可以完美地与我的消息模拟器一起使用。它现在按预期进行轮询,但超时总是在 5 秒后触发(我需要将其更改为仅在没有消息到来时触发)。我只能在下周末的实际硬件上对其进行测试。
这是我目前所拥有的:
void Serial::initSerialPort()
{
if (m_serialport)
delete m_serialport;
m_serialport = new SerialPort(this);
connect(this->m_serialport,SIGNAL(readyRead()),this,SLOT(readyToRead()));
connect(m_serialport, static_cast<void (QSerialPort::*) (QSerialPort::SerialPortError)>(&QSerialPort::error),
this, &Serial::handleError);
connect(&m_timer, &QTimer::timeout, this, &Serial::handleTimeout);
m_timer.start(5000);
}
void Serial::readyToRead()
{
if(ecu == 0)
{
m_readData.append(m_serialport->readAll());
Bytesexpected = m_readData[1]+1;
if (Bytesexpected == m_readData.size())
{
if(requestIndex <= 62){requestIndex++;}
else{requestIndex = 59;}
readData(m_readData); // message for processing
Serial::clear();
m_readData.clear();
}
//Timeout
if (!m_timer.isActive())
m_timer.start(5000);
}
}
void Serial::handleTimeout()
{
qDebug() << "Timeout";
//request Data Again
QString fileName = "Errors.txt";
QFile mFile(fileName);
if(!mFile.open(QFile::Append | QFile::Text)){
qDebug() << "Could not open file for writing";
}
QTextStream out(&mFile);
out << "Timeout Request Index " << int(requestIndex)<< " lenght received "<< int(m_readData.length())<< " Bytes "<< " Expected Bytes "<< int(Bytesexpected)<< " bytes " <<" Message "<< QByteArray(m_readData.toHex()) <<endl;
mFile.close();
Serial::clear();
m_readData.clear();
Serial::sendRequest(requestIndex);
}
void Serial::handleError(QSerialPort::SerialPortError serialPortError)
{
if (serialPortError == QSerialPort::ReadError) {
QString fileName = "Errors.txt";
QFile mFile(fileName);
if(!mFile.open(QFile::Append | QFile::Text)){
qDebug() << "Could not open file for writing";
}
QTextStream out(&mFile);
out << "Serial Error " << (m_serialport->errorString()) <<endl;
mFile.close();
qDebug() <<"Serialport Error" <<(m_serialport->errorString());
}
}
再次稍微更改了我的代码,现在它可以在实际硬件上完美运行
以下是我准备阅读的插槽:
void Serial::readyToRead()
{
qDebug() << "ready read";
if(ecu == 0)
{
m_readData.append(m_serialport->readAll());
Bytesexpected = m_readData[1]+1;
qDebug() << "readdata current" <<m_readData.toHex();
if (Bytesexpected == m_readData.size())
{
m_timer.stop();
if(requestIndex <= 62){requestIndex++;}
else{requestIndex = 59;}
readData(m_readData);
Serial::clear();
m_readData.clear();
Serial::sendRequest(requestIndex);
}
if (Bytesexpected != m_readData.size())
{
qDebug() << "starting timer";
m_timer.start(5000);
}
}
我是编程新手,正在自学。我编写了一个应用程序来轮询来自控制单元的多个请求。我基本上不断地向控制单元发送各种读取命令并读回响应。我的程序运行正常,我成功发送命令并收到答案。但是读取速度很慢(我的代码中有 100 毫秒的超时以确保我得到完整的答复) 我有一个由专业编码员用 C++ 编写的用于同一控制单元的程序,在他的程序中,他每 30 毫秒轮询一次,我总是在那个时间范围内收到完整的答案。我有相同的设置 57K baud 8 bits 1 stop bit and no parity。但是我的 QT 代码需要将近 100 毫秒才能收到答案。 在我的代码中,我读取了前 2 个字节(第一个字节是消息标识符,第二个字节是消息长度的剩余部分)然后我循环读取直到总消息长度等于消息长度字节 +1(+ 1 包含第一个字节)。当我知道 QT 知道硬件是限制因素时,我不知道为什么我的代码在 QT 中如此缓慢。请求总是 3 个字节,回复从 3 到 61 个字节不等。请帮我指出我的错误。如果我删除超时我总是有短读。到目前为止,我也尝试过 read(all) 但结果相同。 以下是我阅读响应的代码摘录。完整代码位于 https://github.com/MarkusIppy/PowerTune
//Error handling
QTime startTime = QTime::currentTime();
int timeOut = 100; // timeout in milisec.
QByteArray recvData = m_serialport->read(2); // reading first two bytes of received message to determine lenght of ecpected message
int msgLen = recvData[1]; //Total message Lenght excluding the first byte
while ( recvData.size() <= (msgLen+1) )
{
if ( startTime.msecsTo(QTime::currentTime()) > timeOut ) break;
recvData += m_serialport->read(msgLen+1-recvData.size());
}
if (msgLen +1 == recvData.length()) //if the received data lenght equals the message lenght from lenght byte + identifier byte (correct message lenght received )
{
qDebug() << "Received data OK"<<msgLen +1;
if(requestIndex <= 61){requestIndex++;}
else{requestIndex = 58;}
readData(recvData);
}
else //if the lenght of the received message does not correspond with the expected lenght repeat the request
{
qDebug() << "Received data lenght NIO";
readData(recvData);
qDebug() << "Request Message again"<< requestIndex;
}
很抱歉,我没有足够的时间来完成您的项目,而且根据您提供的代码,我不能 100% 确定原因是什么。不过,我最好的猜测是,这种情况下的问题是您明确等待接收数据,而事件处理以某种方式延迟或根本没有发生。
无论如何,这里有一些建议:
- 使用 QTimer 代替 QTime.
- 了解 Qt5's signals and slots 并使用它们从串行端口异步读取。
我使用 QSerialPort 通过将它的 bytesWritten(qint64 bytes)
和 readyRead()
信号连接到我程序的插槽,比方说 on_bytesWritten(qint64 bytes)
和 on_readyRead()
。然后我向目标设备发送请求,并在 on_readyRead()
槽中处理结果。对于每个发送命令,我都会启动一个 QTimer,其 timeout()
信号连接到我的应用程序的 on_timeout()
插槽。这样我就可以监控设备是否及时响应,以及数据一来就得到。您也可以使用QSerialPort的errorOccurred(QSerialPort::SerialPortError error)
信号来检查传输是否有问题。
这是我目前所拥有的(仅发布我的 cpp 文件的重要部分) 此代码现在几乎可以完美地与我的消息模拟器一起使用。它现在按预期进行轮询,但超时总是在 5 秒后触发(我需要将其更改为仅在没有消息到来时触发)。我只能在下周末的实际硬件上对其进行测试。 这是我目前所拥有的:
void Serial::initSerialPort()
{
if (m_serialport)
delete m_serialport;
m_serialport = new SerialPort(this);
connect(this->m_serialport,SIGNAL(readyRead()),this,SLOT(readyToRead()));
connect(m_serialport, static_cast<void (QSerialPort::*) (QSerialPort::SerialPortError)>(&QSerialPort::error),
this, &Serial::handleError);
connect(&m_timer, &QTimer::timeout, this, &Serial::handleTimeout);
m_timer.start(5000);
}
void Serial::readyToRead()
{
if(ecu == 0)
{
m_readData.append(m_serialport->readAll());
Bytesexpected = m_readData[1]+1;
if (Bytesexpected == m_readData.size())
{
if(requestIndex <= 62){requestIndex++;}
else{requestIndex = 59;}
readData(m_readData); // message for processing
Serial::clear();
m_readData.clear();
}
//Timeout
if (!m_timer.isActive())
m_timer.start(5000);
}
}
void Serial::handleTimeout()
{
qDebug() << "Timeout";
//request Data Again
QString fileName = "Errors.txt";
QFile mFile(fileName);
if(!mFile.open(QFile::Append | QFile::Text)){
qDebug() << "Could not open file for writing";
}
QTextStream out(&mFile);
out << "Timeout Request Index " << int(requestIndex)<< " lenght received "<< int(m_readData.length())<< " Bytes "<< " Expected Bytes "<< int(Bytesexpected)<< " bytes " <<" Message "<< QByteArray(m_readData.toHex()) <<endl;
mFile.close();
Serial::clear();
m_readData.clear();
Serial::sendRequest(requestIndex);
}
void Serial::handleError(QSerialPort::SerialPortError serialPortError)
{
if (serialPortError == QSerialPort::ReadError) {
QString fileName = "Errors.txt";
QFile mFile(fileName);
if(!mFile.open(QFile::Append | QFile::Text)){
qDebug() << "Could not open file for writing";
}
QTextStream out(&mFile);
out << "Serial Error " << (m_serialport->errorString()) <<endl;
mFile.close();
qDebug() <<"Serialport Error" <<(m_serialport->errorString());
}
}
再次稍微更改了我的代码,现在它可以在实际硬件上完美运行 以下是我准备阅读的插槽:
void Serial::readyToRead()
{
qDebug() << "ready read";
if(ecu == 0)
{
m_readData.append(m_serialport->readAll());
Bytesexpected = m_readData[1]+1;
qDebug() << "readdata current" <<m_readData.toHex();
if (Bytesexpected == m_readData.size())
{
m_timer.stop();
if(requestIndex <= 62){requestIndex++;}
else{requestIndex = 59;}
readData(m_readData);
Serial::clear();
m_readData.clear();
Serial::sendRequest(requestIndex);
}
if (Bytesexpected != m_readData.size())
{
qDebug() << "starting timer";
m_timer.start(5000);
}
}