基于QtModbus模块实现 用于读取modbusrtu 协议的硬件485保持寄存器数据
问题相关代码 运行时主要调用work 进行作业,几个方法都存于子线程中
QModbusResponse MyThread::send(const QModbusRequest &request){
qDebug() << this << "send:" << "threadId:" << QThread::currentThreadId();
QModbusResponse response;
if(!this->m_comConnected || request.data().size() < 2){
emit m_modbus_fail(errorFail.value("ConnectionClosed"));
return response;
}
if(m_functionCode == QModbusRequest::WriteSingleRegister){
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents,30);
QThread::msleep(30);
}
if(!request.isValid()){
emit m_modbus_fail("发送数据发生错误:" + QString::number(request.exceptionCode()));
qDebug() << this << "requestFail:" << request.data();
return response;
}
m_functionCode = request.functionCode();
int optionCode = request.data().left(2).toHex().toInt(0,16);
qDebug() << this << "optionCode:" << m_optionCode;
m_optionCode = optionCode;
QModbusReply* reply = modbusUtil->sendSyncModbusRawRequest(request,m_channelAddr);
return converReply(reply);
}
QModbusResponse MyThread::converReply(QModbusReply *reply){
QModbusResponse response;
if(reply){
qDebug() << this << "waitStartTime" << getNowDataFormat("yyyyMMddhhmmss.zzz");
if (!reply->isFinished()) {
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents,30);
QEventLoop eventLoop;
connect(reply, &QModbusReply::finished,&eventLoop,&QEventLoop::quit);
eventLoop.exec();
// eventLoop.deleteLater();
}
if(reply->error() == QModbusDevice::NoError){
qDebug() << this << "afterTime" << getNowDataFormat("yyyyMMddhhmmss.zzz");
response = reply->rawResult();
qDebug() << this << "hex:" << response.data().toHex(' ');
m_modbusResponse = response;
if(m_functionCode == QModbusRequest::ReadHoldingRegisters){
emit m_modbus_finished(m_optionCode,response.data());
}
}else if(reply->error() == QModbusDevice::ProtocolError){
emit m_modbus_fail(errorFail.value("SendMessageCodeFail") + reply->errorString());
}else if(reply->error() == QModbusDevice::TimeoutError){
emit m_modbus_fail(errorFail.value("SendMessageTimeout"));
qDebug() << this << "errorMessage:" << reply->errorString();
}else{
emit m_modbus_fail(errorFail.value("SendMessageFail"));
qDebug() << this << "fail";
}
reply->deleteLater(); delete reply; reply = Q_NULLPTR;
}
return response;
}
void MyThread::work(){
// QModbusDataUnit read(QModbusDataUnit::HoldingRegisters,0,quint16(0x0002));
QModbusRequest read(QModbusRequest::ReadHoldingRegisters,quint16(0x0000),quint16(0x0002));
m_frequency_time_text = getNowDataFormat("yyyyMMddhhmmss");
m_second_frequency_num = 0;
while(m_is_start){
qDebug() << "------start-------" << getNowDataFormat("yyyyMMddhhmmss.zzz");
QModbusResponse response = send(read);
m_post_num++;
if(response.isValid() && m_optionCode == 0){
m_get_num ++;
// 计算频率
if(m_frequency_time_text == getNowDataFormat("yyyyMMddhhmmss")){
m_second_frequency_num ++;
}else{
emit m_second_frequency_call(m_second_frequency_num);
m_second_frequency_num = 1;
m_frequency_time_text = getNowDataFormat("yyyyMMddhhmmss");
}
// 计算重量值
m_real_val = formatWeight(response.data(),false);
m_real_data_str = getNowDataFormat("yyyy年MM月dd日hh时mm分ss秒zzz毫秒");
if(m_max_val < m_real_val){
m_max_val = m_real_val;
}
if(m_min_val > m_real_val){
m_min_val = m_real_val;
}
qDebug() << "m_frequency_time:" << m_frequency_time;
emit m_work_success(getNowDataFormat("yyyy年MM月dd日hh时mm分ss秒zzz毫秒"),0,response.data());
}
if(m_frequency_time > 0){
QThread::msleep(m_frequency_time);
}
qDebug() << "------end-------" << getNowDataFormat("yyyyMMddhhmmss.zzz");
}
}
运行结果及报错内容
// 正常情况返回
------start------- "20211127111941.271"
MyThread(0x1eba45f8) send: threadId: 0x1df8
MyThread(0x1eba45f8) optionCode: 0
ModbusUtil(0x1ec907d8) instance: threadId: 0x1df8
ModbusUtil(0x1ec907d8) sendSyncModbusRawRequest: threadId: 0x1df8
MyThread(0x1eba45f8) waitStartTime "20211127111941.272"
MyThread(0x1eba45f8) send: threadId: 0x1df8
MyThread(0x1eba45f8) optionCode: 0
ModbusUtil(0x1ec907d8) instance: threadId: 0x1df8
ModbusUtil(0x1ec907d8) sendSyncModbusRawRequest: threadId: 0x1df8
MyThread(0x1eba45f8) waitStartTime "20211127111941.274"
// 异常情况返回
------start------- "20211127111941.275"
MyThread(0x1eba45f8) send: threadId: 0x1df8
MyThread(0x1eba45f8) optionCode: 17
ModbusUtil(0x1ec907d8) instance: threadId: 0x1df8
ModbusUtil(0x1ec907d8) sendSyncModbusRawRequest: threadId: 0x1df8
MyThread(0x1eba45f8) waitStartTime "20211127111941.307"
ModbusUtil(0x1ec907d8) instance: threadId: 0x1df8
commit Success 60
MyThread(0x1eba45f8) errorMessage: "Request timeout."
commit Success 0
------end------- "20211127111941.459"
我的解答思路和尝试过的方法
目前无法判断时哪个流程出问题了,最主要是这个问题时偶现,如果是硬件不回复的话应该是 response timeout吧
我想要达到的结果
能够知道是什么问题导致 request timeout 这个看起来很像服务端电脑出现的问题因为他立马就返回了这个错误
自问自答吧,经过阅读qt源码发现此问题是因为QSerialPort 抛出 Resource error异常导致,而此异常是因为 QIODevice 抛出了io异常。
由此最主要的原因是串口连接异常导致,也就是说串口连接出问题了而此时QModbusRtuSerialMaster的状态并没有更新为关闭,所以如果继续调用QModbusRtuSerialMaster::sendSyncModbusRawRequest 等就会 抛出 Request timeout.