Qt下使用ModbusTcp通信协议进行PLC线圈/保持寄存器的读写(32位有符号数)
系列文章目录
提示:这里是该系列文章的所有文章的目录
第一章:Qt下使用ModbusTcp通信协议进行PLC线圈/保持寄存器的读写(32位有符号数)
第二章:Qt下使用modbus-c库实现PLC线圈/保持寄存器的读写
文章目录
- 系列文章目录
- 前言
- 一、引入Modbus模块
- 二、Modbus设备的连接
- 三、各寄存器数据的读取
- 四、各寄存器数据的写入
- 五、示例完整代码
- 总结
前言
本文主要讲述了使用Qt的Modbus模块来进行ModbusTcp的通信,实现对PLC的线圈寄存器和保持寄存器的读写,基于TCP/IP的Modbus协议的内容我就不做过多解释了,详见参考文章。在本文示例中采用QModbusTcpClient类作为Modbus客户端(主站),PLC作为从站,封装了一个自己的MyModbus类,希望可以帮助到大家,如有错误之处,欢迎大家批评指正。
项目效果
提示:以下是本篇文章正文内容,下面案例可供参考
一、引入Modbus模块
1.这里我实现了自己的MyModbus类的封装,使用了pri子模块的方式,也是方便日后进行此模块的复用
pri中引入Modbus模块:
MyModbus.pri
QT += serialbus serialport
MyModbus类中添加相关头文件
#include #include
二、Modbus设备的连接
1.ModbusTcp的连接只需要配置好连接参数IP+Port
//判断当前连接状态是否为断开状态 if(myClient->state() != QModbusDevice::ConnectedState) { //配置ModbusTcp的连接参数IP+Port myClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter,ip); myClient->setConnectionParameter(QModbusDevice::NetworkPortParameter,port); myClient->connectDevice(); }三、各寄存器数据的读取
1.Modbus中有4种操作对象,这4种都能进行读取操作:线圈、离散输入、保持寄存器、输入寄存器
//读取modbus设备各寄存器数据 //typeNum:1_线圈 2_离散输入 3_保持 4_输入 bool MyModbus::readModbusData(int typeNum,int startAdd,quint16 numbers) { if(myClient->state() != QModbusDevice::ConnectedState) { return false; } //确定寄存器类型 QModbusDataUnit ReadUnit; if(typeNum == 1) { ReadUnit = QModbusDataUnit(QModbusDataUnit::Coils,startAdd,numbers); } else if(typeNum == 2) { ReadUnit = QModbusDataUnit(QModbusDataUnit::DiscreteInputs,startAdd,numbers); } else if(typeNum == 3) { ReadUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters,startAdd,numbers); } else if(typeNum == 4) { ReadUnit = QModbusDataUnit(QModbusDataUnit::InputRegisters,startAdd,numbers); } else { LOGDEBUG if(!reply-isFinished()) { if((typeNum == 1) || (typeNum == 2)) { QObject::connect(reply,&QModbusReply::finished,this,&MyModbus::slot_readReadyCoils); //读取线圈 } if((typeNum == 3) || (typeNum == 4)) { QObject::connect(reply,&QModbusReply::finished,this,&MyModbus::slot_readReadyRegisters); //读取寄存器 } //reply-deleteLater(); return true; } else { reply-deleteLater(); return false; } } else { LOGDEBUG if(myClient-state() != QModbusDevice::ConnectedState) { return false; } //确定寄存器类型 QModbusDataUnit writeUnit; if(typeNum == 1) { writeUnit = QModbusDataUnit(QModbusDataUnit::Coils,startAdd,1); //写入一个数据 writeUnit.setValue(0,writeNum); //单写 //bool ok; //quint16 hexData = writeData.toInt(&ok,16); //转16进制 } else if(typeNum == 2) { writeUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters,startAdd,2); //写入两个数据 quint16 uData16[2] = {0}; uData16[0] = writeNum & 0xffff; uData16[1] = (writeNum 16) & 0xffff; writeUnit.setValue(0,uData16[0]); writeUnit.setValue(1,uData16[1]); //LOGDEBUG LOGDEBUG if(!reply-isFinished()) { connect(reply,&QModbusReply::finished,this,[reply]() { if(reply-error() == QModbusDevice::NoError) { reply-deleteLater(); return true; } else { LOGDEBUG reply-deleteLater(); return false; } } else { LOGDEBUGTARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target Q_OBJECT public: explicit MyModbus(QObject *parent = nullptr); ~MyModbus(); void initModbus(); void connectToModbus(QString ip,int port); bool readModbusData(int typeNum,int startAdd,quint16 numbers); bool writeModbusData(int typeNum,int startAdd,int writeNum); signals: void signal_stateChanged(bool flag); void signal_readCoils(QVector this-initModbus(); } MyModbus::~MyModbus() { } //初始化 void MyModbus::initModbus() { myClient = new QModbusTcpClient(); //connect(myClient,SIGNAL(stateChanged()),this,SLOT(slot_stateChanged())); connect(myClient,&QModbusClient::stateChanged,this,&MyModbus::slot_stateChanged); } //连接到modbus设备 void MyModbus::connectToModbus(QString ip,int port) { if(!myClient) { return; } //判断当前连接状态是否为断开状态 if(myClient-state() != QModbusDevice::ConnectedState) { //配置ModbusTcp的连接参数IP+Port myClient-setConnectionParameter(QModbusDevice::NetworkAddressParameter,ip); myClient-setConnectionParameter(QModbusDevice::NetworkPortParameter,port); myClient-connectDevice(); } //else //{ // myClient-disconnectDevice(); //} } //读取modbus设备各寄存器数据 //typeNum:1_线圈 2_离散输入 3_保持 4_输入 bool MyModbus::readModbusData(int typeNum,int startAdd,quint16 numbers) { if(myClient-state() != QModbusDevice::ConnectedState) { return false; } //确定寄存器类型 QModbusDataUnit ReadUnit; if(typeNum == 1) { ReadUnit = QModbusDataUnit(QModbusDataUnit::Coils,startAdd,numbers); } else if(typeNum == 2) { ReadUnit = QModbusDataUnit(QModbusDataUnit::DiscreteInputs,startAdd,numbers); } else if(typeNum == 3) { ReadUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters,startAdd,numbers); } else if(typeNum == 4) { ReadUnit = QModbusDataUnit(QModbusDataUnit::InputRegisters,startAdd,numbers); } else { LOGDEBUG if(!reply-isFinished()) { if((typeNum == 1) || (typeNum == 2)) { QObject::connect(reply,&QModbusReply::finished,this,&MyModbus::slot_readReadyCoils); //读取线圈 } if((typeNum == 3) || (typeNum == 4)) { QObject::connect(reply,&QModbusReply::finished,this,&MyModbus::slot_readReadyRegisters); //读取寄存器 } //reply-deleteLater(); return true; } else { reply-deleteLater(); return false; } } else { LOGDEBUG if(myClient-state() != QModbusDevice::ConnectedState) { return false; } //确定寄存器类型 QModbusDataUnit writeUnit; if(typeNum == 1) { writeUnit = QModbusDataUnit(QModbusDataUnit::Coils,startAdd,1); //写入一个数据 writeUnit.setValue(0,writeNum); //单写 //bool ok; //quint16 hexData = writeData.toInt(&ok,16); //转16进制 } else if(typeNum == 2) { writeUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters,startAdd,2); //写入两个数据 quint16 uData16[2] = {0}; uData16[0] = writeNum & 0xffff; uData16[1] = (writeNum 16) & 0xffff; writeUnit.setValue(0,uData16[0]); writeUnit.setValue(1,uData16[1]); //LOGDEBUG LOGDEBUG if(!reply-isFinished()) { connect(reply,&QModbusReply::finished,this,[reply]() { if(reply-error() == QModbusDevice::NoError) { reply-deleteLater(); return true; } else { LOGDEBUG reply-deleteLater(); return false; } } else { LOGDEBUG LOGDEBUG emit signal_stateChanged(true); } else if(myClient-state() == QModbusDevice::UnconnectedState) { emit signal_stateChanged(false); } } //接收到读取线圈/离散输入寄存器请求后执行的槽函数 void MyModbus::slot_readReadyCoils() { QVector LOGDEBUG const QModbusDataUnit unit = reply-result(); vAllData = unit.values(); emit signal_readCoils(vAllData); } else { LOGDEBUG QModbusReply *reply = qobject_cast LOGDEBUG const QModbusDataUnit unit = reply-result(); auto valueList = unit.values(); int nSize = valueList.size(); if(nSize == 2) { quint16 uData16[2] = {0}; uData16[0] = valueList[0]; uData16[1] = valueList[1]; int resultNum = uData16[0] | (uData16[1] LOGDEBUG LOGDEBUG class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); void initWidget(); private slots: void slot_stateChanged(bool flag); void slot_readCoils(QVector ui-setupUi(this); this-initWidget(); } Widget::~Widget() { delete ui; } void Widget::initWidget() { //初始化MyModbus对象 m_myModsbus = new MyModbus(); connect(m_myModsbus,SIGNAL(signal_stateChanged(bool)),this,SLOT(slot_stateChanged(bool))); connect(m_myModsbus,SIGNAL(signal_readCoils(QVector if(flag) { ui-lb_state-setText("连接成功"); ui-te_show-appendPlainText(QTime::currentTime().toString("hh:mm:ss: ") + "连接成功"); QMessageBox::warning(this,"警告","连接成功!"); } else { ui-lb_state-setText("连接断开"); ui-te_show-appendPlainText(QTime::currentTime().toString("hh:mm:ss: ") + "连接断开"); QMessageBox::warning(this,"警告","连接断开!"); } } void Widget::slot_readCoils(QVector LOGDEBUG LOGDEBUG LOGDEBUG QString ip = ui-le_ip-text(); int port = ui-le_port-text().toInt(); LOGDEBUG int startAdd = ui-le_addressM-text().toInt(); LOGDEBUG QMessageBox::warning(this,"警告","M区数据读取失败!"); } } void Widget::on_pb_writeM_clicked() { int startAdd = ui-le_addressM-text().toInt(); int writeNum = ui-le_dataM-text().toInt(); LOGDEBUG QMessageBox::warning(this,"警告","M区数据写入失败!"); } } void Widget::on_pb_readD_clicked() { int startAdd = ui-le_addressD-text().toInt(); LOGDEBUG QMessageBox::warning(this,"警告","D区数据读取失败!"); } } void Widget::on_pb_writeD_clicked() { int startAdd = ui-le_addressD-text().toInt(); int writeNum = ui-le_dataD-text().toInt();; LOGDEBUG QMessageBox::warning(this,"警告","D区数据写入失败!"); } } static QMutex mutex; mutex.lock(); //初始化log文件夹 QString logFilePath = QCoreApplication::applicationDirPath() + "/LogFile/"; QDir dstDir(logFilePath); if(!dstDir.exists()) { if(!dstDir.mkpath(logFilePath)) { LOGDEBUG LOGDEBUG QString debugDateTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"); debugMsg = QString("%1\n%2%3").arg(debugDateTime).arg(msg).arg(context.function); } //保存文件 QString curDate = QDate::currentDate().toString("yyyyMMdd"); QString logFile = logFilePath + "log_" + curDate + ".txt"; QFile file(logFile); file.open(QIODevice::WriteOnly | QIODevice::Append); QTextStream textStream(&file); textStream QApplication a(argc, argv); qInstallMessageHandler(outputMessage); Widget w; w.show(); return a.exec(); }
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

