明星静态网站,域名注册需要资料,南京广告公司排行榜,广告设计制作公司名字目录 问题 Modbus放在主线程#xff0c;界面事件会阻塞信号传输解决方案 将modbus放在子线程实现 问题 Modbus放在主线程#xff0c;界面事件会阻塞信号传输
在使用QT5.14.2时 使用QT自带的QModbusClient类实现对一个力传感器的数据读取。本人为了测试就将modbus读取逻辑等都… 目录 问题 Modbus放在主线程界面事件会阻塞信号传输解决方案 将modbus放在子线程实现 问题 Modbus放在主线程界面事件会阻塞信号传输
在使用QT5.14.2时 使用QT自带的QModbusClient类实现对一个力传感器的数据读取。本人为了测试就将modbus读取逻辑等都写在主线程中但是本人采用modbus异步通讯的方式给从站发一个读取数据的信号sendReadRequest然后使用信号槽等待从站回复数据readSerialForceData。这种方式的好处是不会阻塞主线程。
但是本人发现一个问题就是在我拖动主界面的时候modbus通讯就停止了当我松开鼠标的时候modbus正常通讯目前还不知道为什么会这样猜测是鼠标事件影响了modbus的信号槽机制。但是我试了一下其他的槽函数都是能正常触发的比如定时器之类。在我拖动界面的时候UI界面也可以正常的刷新。只有modbus被阻塞了。
void MainWindow::on_readRequest()
{// 读取寄存器QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters,0,1);if (auto *reply modbusDevice-sendReadRequest(readUnit, 1)){if (!reply-isFinished())connect(reply, QModbusReply::finished, this, MainWindow::readSerialForceData);elsedelete reply; // broadcast replies return immediately}else{//底部状态栏显示ui-statusBar-showMessage(tr(Read error: ) modbusDevice-errorString(), 5000);}
}void MainWindow::readSerialForceData()
{auto reply qobject_castQModbusReply *(sender());if (!reply)return;if (reply-error() QModbusDevice::NoError){const QModbusDataUnit unit reply-result();//遍历数据单元的值for (int i 0, total int(unit.valueCount()); i total; i){qint16 sValue static_castqint16(unit.value(i));forceData_Temp sValue/10.0;const QString entry tr(Address: %1, Value: %2).arg(unit.startAddress() i).arg(QString::number(sValue));ui-textBrowser_Log-append(entry);}}else if (reply-error() QModbusDevice::ProtocolError){statusBar()-showMessage(tr(Read response error: %1 (Mobus exception: 0x%2)).arg(reply-errorString()).arg(reply-rawResult().exceptionCode(), -1, 16), 5000);}else{statusBar()-showMessage(tr(Read response error: %1 (code: 0x%2)).arg(reply-errorString()).arg(reply-error(), -1, 16), 5000);}reply-deleteLater();
}解决方案 将modbus放在子线程实现
经过测试发现将modbus放在子线程中通过信号槽与主线程进行通讯将数据保存成静态变量或者全局变量即可解决问题。
这里新建一个serialThread 类用 .h文件
class serialThread : public QObject
{Q_OBJECT
public:serialThread(QObject *parent Q_NULLPTR);~serialThread();QModbusClient *modbusDevice nullptr;QDateTime startTime;QDateTime endTime;double intervalTime 0;//串口数据间隔时间double intervalTime_Last0;//数据采集定时器QTimer *pollTimer;//串口数据读取定时器signals:void sig_connectSerialFinished(bool flag);void sig_disconnectSerialFinished(bool flag);public slots:void startThread();void on_connectSerial();void on_disconnectSerial();void on_startReadData();void on_stopReadData();void on_readRequest();void on_readRequestFinished();
};#endif // SERIALTHREAD_H.cpp文件
#include serialthread.hserialThread::serialThread(QObject *parent ) : QObject(parent)
{qDebug()串口线程构造函数:QThread::currentThreadId();
}serialThread::~serialThread()
{//退出串口if (modbusDevice){modbusDevice-disconnectDevice();}delete modbusDevice;}void serialThread::startThread()
{qDebug()串口线程成员函数 startThread :QThread::currentThreadId();modbusDevice new QModbusRtuSerialMaster(this);
}void serialThread::on_connectSerial()
{qDebug()串口线程成员函数 on_connectSerial :QThread::currentThreadId();QMutexLocker locker(ForceSensorGlobal::mutex); // 锁定互斥锁//设置串口号modbusDevice-setConnectionParameter(QModbusDevice::SerialPortNameParameter,ForceSensorGlobal::SeriComName);//设置波特率modbusDevice-setConnectionParameter(QModbusDevice::SerialBaudRateParameter,ForceSensorGlobal::BaudRate);//设置数据位modbusDevice-setConnectionParameter(QModbusDevice::SerialDataBitsParameter,ForceSensorGlobal::DataBits);//设置奇偶检验switch(ForceSensorGlobal::ParityID){case 0: modbusDevice-setConnectionParameter(QModbusDevice::SerialParityParameter,QSerialPort::NoParity);break;case 1: modbusDevice-setConnectionParameter(QModbusDevice::SerialParityParameter,QSerialPort::EvenParity);break;case 2: modbusDevice-setConnectionParameter(QModbusDevice::SerialParityParameter,QSerialPort::OddParity);break;case 3: modbusDevice-setConnectionParameter(QModbusDevice::SerialParityParameter,QSerialPort::SpaceParity);break;case 4: modbusDevice-setConnectionParameter(QModbusDevice::SerialParityParameter,QSerialPort::MarkParity);break;default: break;}//设置停止位switch(ForceSensorGlobal::StopBitsID){case 0: modbusDevice-setConnectionParameter(QModbusDevice::SerialStopBitsParameter,QSerialPort::OneStop);break;case 1: modbusDevice-setConnectionParameter(QModbusDevice::SerialStopBitsParameter,QSerialPort::OneAndHalfStop);break;case 2: modbusDevice-setConnectionParameter(QModbusDevice::SerialStopBitsParameter,QSerialPort::TwoStop);break;default: break;}//设置执行请求时间modbusDevice-setTimeout(1000);//设置执行请求次数modbusDevice-setNumberOfRetries(3);//连接串口 并发送成功与否标志emit sig_connectSerialFinished(modbusDevice-connectDevice());pollTimer new QTimer;pollTimer-setTimerType(Qt::PreciseTimer);//精确定时pollTimer-setInterval(ForceSensorGlobal::IntervalTime);connect(pollTimer,QTimer::timeout, this, serialThread::on_readRequest);}void serialThread::on_disconnectSerial()
{modbusDevice-disconnectDevice();emit sig_disconnectSerialFinished(true);}void serialThread::on_startReadData()
{QMutexLocker locker(ForceSensorGlobal::mutex); // 锁定互斥锁//清空一下数据 方便再次存储ForceSensorGlobal:: recordData.clear();QVectordouble vectorTemp;for (int i 0; i 2; i){ForceSensorGlobal::recordData.append(vectorTemp);}startTime QDateTime::currentDateTime();//获取开始时间pollTimer-setInterval(ForceSensorGlobal::IntervalTime);pollTimer-start();qDebug() 子线程 on_startReadData ;
}void serialThread::on_stopReadData()
{pollTimer-stop();qDebug() 子线程 on_stopReadData ;
}void serialThread::on_readRequest()
{// 读取寄存器QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters,0,1);if (auto *reply modbusDevice-sendReadRequest(readUnit, 1)){if (!reply-isFinished())connect(reply, QModbusReply::finished, this, serialThread::on_readRequestFinished);elsereply-deleteLater(); // broadcast replies return immediately}else{//读取错误qDebug() 读取错误: modbusDevice-errorString();}
}void serialThread::on_readRequestFinished()
{auto reply qobject_castQModbusReply *(sender());if (!reply)return;QMutexLocker locker(ForceSensorGlobal::mutex); // 锁定互斥锁if (reply-error() QModbusDevice::NoError){const QModbusDataUnit unit reply-result();//遍历数据单元的值for (int i 0, total int(unit.valueCount()); i total; i){//接受信号的时间endTime QDateTime::currentDateTime();intervalTime startTime.msecsTo(endTime) / 1000.0;double now (intervalTime - intervalTime_Last)*1000.0;qDebug() now;intervalTime_Last intervalTime;//收到的数据是uint16 需转换为int16qint16 sValue static_castqint16(unit.value(i));//传感器默认有一位小数需除以10double forceData_Temp sValue/10.0;//将时间 力数据存在到全局变量中ForceSensorGlobal::recordData[0].append(intervalTime);ForceSensorGlobal::recordData[1].append(forceData_Temp);}}else if (reply-error() QModbusDevice::ProtocolError){//接收到的响应信息是协议错误qDebug() 接收到的响应信息是协议错误: modbusDevice-errorString();}else{//接收到的响应信息是其他错误qDebug() 接收到的响应信息是其他错误: modbusDevice-errorString();}reply-deleteLater();
}
在主线程中通过moveToThread将modbus放入子线程
主界面.h文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include QMainWindow
#include QSerialPort
#include QtSerialBus
#include QModbusDataUnit
#include QModbusClient
#include QSerialPortInfo
#include QMessageBox
#include QDebug
#include QSettings
#include forcesensorglobal.h
#include qcustomplot.h
#include CurvePlot.h
#include serialthread.hnamespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent nullptr);~MainWindow();/*************串口通讯线程***************///串口线程QThread * mySerialThread;//串口操作类serialThread *mySerialModbus;/***************定时器**********************/QTimer *plotTimer;////UI界面初始化void initUI();//搜索串口void SearchSerialPorts();signals:void sig_connectSerial();void sig_disconnectSerial();void sig_startReadData();void sig_stopReadData();private slots:void on_plotTimerTimeOut();void on_pBtn_connectSerial_clicked();void on_pBtn_disconnectSerial_clicked();//接受子线程 modbus串口连接完成信号void on_connectSerialFinished(bool flag);//接受子线程 modbus串口断开完成信号void on_disconnectSerialFinished(bool flag);void on_pBtn_refreshSerial_clicked();void on_pBtn_startRead_clicked();void on_pBtn_stopRead_clicked();void on_pBtn_sendData_clicked();
private:Ui::MainWindow *ui;
};#endif // MAINWINDOW_H主界面.cpp文件
#include mainwindow.h
#include ui_mainwindow.hMainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui-setupUi(this);initUI();/*创建串口线程*/mySerialModbus new serialThread();mySerialThread new QThread;mySerialModbus-moveToThread(mySerialThread);//线程开始mySerialThread-start();connect(mySerialThread, QThread::started, mySerialModbus, serialThread::startThread);connect(mySerialThread, QThread::finished, mySerialModbus, QObject::deleteLater);//终止线程时要调用deleteLater槽函数connect(mySerialThread, QThread::finished, mySerialModbus, QObject::deleteLater);/*绘图刷新定时器*/plotTimer new QTimer;plotTimer-setInterval(100);connect(plotTimer,QTimer::timeout, this, MainWindow::on_plotTimerTimeOut);/*****************信号槽*********************************///主线-子线程 串口连接信号connect(this, MainWindow::sig_connectSerial, mySerialModbus, serialThread::on_connectSerial);//主线-子线程 串口断开信号connect(this, MainWindow::sig_disconnectSerial, mySerialModbus, serialThread::on_disconnectSerial);//主线-子线程 开始采集信号connect(this, MainWindow::sig_startReadData, mySerialModbus, serialThread::on_startReadData);//主线-子线程 停止采集信号connect(this, MainWindow::sig_stopReadData, mySerialModbus, serialThread::on_stopReadData);//子线程-主线 串口连接完成信号connect(mySerialModbus, serialThread::sig_connectSerialFinished,this,MainWindow::on_connectSerialFinished);//子线程-主线 串口断开完成信号connect(mySerialModbus, serialThread::sig_disconnectSerialFinished,this,MainWindow::on_disconnectSerialFinished);void MainWindow::on_pBtn_connectSerial_clicked()
{//更新数据ForceSensorGlobal::SeriComName ui-cBox_SeriComName-currentText();ForceSensorGlobal::BaudRate ui-cBox_BaudRate-currentText().toInt();ForceSensorGlobal::DataBits ui-cBox_DataBits-currentText().toInt();ForceSensorGlobal::ParityID ui-cBox_Parity-currentIndex();ForceSensorGlobal::StopBitsID ui-cBox_StopBits-currentIndex();ForceSensorGlobal::IntervalTime ui-sBox_Interval-value();emit sig_connectSerial();qDebug()主线程 sig_connectSerial :QThread::currentThreadId();}void MainWindow::on_pBtn_disconnectSerial_clicked()
{on_pBtn_stopRead_clicked();emit sig_disconnectSerial();
}void MainWindow::on_connectSerialFinished(bool flag)
{if (flag){// 设置控件可否使用ui-pBtn_connectSerial-setEnabled(false);ui-pBtn_refreshSerial-setEnabled(false);ui-pBtn_disconnectSerial-setEnabled(true);}else //打开失败提示{QMessageBox::information(this,tr(错误),tr(连接从站失败),QMessageBox::Ok);}
}void MainWindow::on_disconnectSerialFinished(bool flag)
{if (flag){// 设置控件可否使用ui-pBtn_connectSerial-setEnabled(true);ui-pBtn_refreshSerial-setEnabled(true);ui-pBtn_disconnectSerial-setEnabled(false);}else{QMessageBox::information(this,tr(错误),tr(断开连接失败),QMessageBox::Ok);}}void MainWindow::on_pBtn_refreshSerial_clicked()
{//填充串口号组合框SearchSerialPorts();
}void MainWindow::on_pBtn_startRead_clicked()
{ForceSensorGlobal::IntervalTime ui-sBox_Interval-value();emit sig_startReadData();plotTimer-start();}void MainWindow::on_pBtn_stopRead_clicked()
{plotTimer-stop();emit sig_stopReadData();}}