From d63d454cc5df99b31b1543fb08821d074a1e30f4 Mon Sep 17 00:00:00 2001 From: tianzhendong <1203886034@qq.com> Date: Wed, 23 Mar 2022 16:16:47 +0800 Subject: [PATCH] first --- .gitignore | 73 +++++++++++ MyModbusTcp.pro | 33 +++++ main.cpp | 11 ++ mainwindow.cpp | 65 ++++++++++ mainwindow.h | 50 ++++++++ mainwindow.ui | 192 ++++++++++++++++++++++++++++ mymodbustcp.cpp | 325 ++++++++++++++++++++++++++++++++++++++++++++++++ mymodbustcp.h | 111 +++++++++++++++++ 8 files changed, 860 insertions(+) create mode 100644 .gitignore create mode 100644 MyModbusTcp.pro create mode 100644 main.cpp create mode 100644 mainwindow.cpp create mode 100644 mainwindow.h create mode 100644 mainwindow.ui create mode 100644 mymodbustcp.cpp create mode 100644 mymodbustcp.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fab7372 --- /dev/null +++ b/.gitignore @@ -0,0 +1,73 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + diff --git a/MyModbusTcp.pro b/MyModbusTcp.pro new file mode 100644 index 0000000..ce462d6 --- /dev/null +++ b/MyModbusTcp.pro @@ -0,0 +1,33 @@ +QT += core gui serialbus + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + mainwindow.cpp \ + mymodbustcp.cpp + +HEADERS += \ + mainwindow.h \ + mymodbustcp.h + +FORMS += \ + mainwindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..fd3e533 --- /dev/null +++ b/main.cpp @@ -0,0 +1,11 @@ +#include "mainwindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..645c5f7 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,65 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); + modbusTcpClient = new MyModbusTcp(); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + + +void MainWindow::on_connectBTN_clicked() +{ + modbusTcpClient->connectModbusTcp(); +} + +void MainWindow::on_disconnectBTN_clicked() +{ + modbusTcpClient->disconnectModbusTcp(); +} + +void MainWindow::on_ontimeBTN_clicked() +{ +// modbusTcpClient->onTimeReadHR(); + + timer1 = new QTimer(this); //启动定时器,100ms + connect(timer1, SIGNAL(timeout()), this, SLOT(ontimeRead())); + timer1->start(100); // 每隔1000ms +// modbusTcpClient->readMultipleHR(0,20,1); + +} + +void MainWindow::ontimeRead(){ + modbusTcpClient->readMultipleHR(0, 20, 1); + QString buf; +// int len = sizeof(modbusTcpClient->dataRCV)/sizeof(modbusTcpClient->dataRCV[0]); + for(int i= 0; i<30; i++){ + buf.append(QString::number(modbusTcpClient->dataRCV[i])); + buf.append(" "); + } + ui->textEdit->setText(buf); +} + +void MainWindow::on_stopOntimeBTN_clicked() +{ + timer1->stop(); + timer1->deleteLater(); +} + +void MainWindow::on_pushButton_clicked() +{ + modbusTcpClient->writeSingleFloat(0, -3.14f, 1); +} + +void MainWindow::on_pushButton_2_clicked() +{ + float dataSend[3] = {0.0f, 1.1f, -2.3f}; + modbusTcpClient->writeMultipleHR(0, 6, dataSend, 1); +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..6f53023 --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,50 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include "mymodbustcp.h" + +QT_BEGIN_NAMESPACE +namespace Ui { class MainWindow; } +QT_END_NAMESPACE + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + QTimer *timer1; + MyModbusTcp *modbusTcpClient = nullptr; + +private slots: + /** + * @brief on_connectBTN_clicked 连接 + */ + void on_connectBTN_clicked(); + /** + * @brief on_disconnectBTN_clicked 断开连接 + */ + void on_disconnectBTN_clicked(); + /** + * @brief on_ontimeBTN_clicked 持续读 + */ + void on_ontimeBTN_clicked(); + /** + * @brief on_stopOntimeBTN_clicked 停止读 + */ + void on_stopOntimeBTN_clicked(); + /** + * @brief ontimeRead 持续都写 + */ + void ontimeRead(); + + void on_pushButton_clicked(); + + void on_pushButton_2_clicked(); + +private: + Ui::MainWindow *ui; +}; +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..54b6e9f --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,192 @@ + + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + MainWindow + + + + + + + + 300 + 100 + + + + + + + + + + + 150 + 50 + + + + + 300 + 50 + + + + + 14 + + + + 连接 + + + + + + + + 150 + 50 + + + + + 300 + 50 + + + + + 14 + + + + 断开连接 + + + + + + + + 150 + 50 + + + + + 300 + 50 + + + + + 14 + + + + 持续读 + + + + + + + + 150 + 50 + + + + + 300 + 50 + + + + + 14 + + + + 停止持续读 + + + + + + + + 150 + 50 + + + + + 300 + 50 + + + + + 14 + + + + 写单个f + + + + + + + + 150 + 50 + + + + + 300 + 50 + + + + + 14 + + + + 写多个 + + + + + + + + + + + 0 + 0 + 800 + 21 + + + + + + + + diff --git a/mymodbustcp.cpp b/mymodbustcp.cpp new file mode 100644 index 0000000..711ce2d --- /dev/null +++ b/mymodbustcp.cpp @@ -0,0 +1,325 @@ +#include "mymodbustcp.h" + +MyModbusTcp::MyModbusTcp() +{ + modbusDevice = new QModbusTcpClient(); + //有错误发生时,发出提示 + connect(modbusDevice, &QModbusClient::errorOccurred, this, &MyModbusTcp::errorOccurred_Slot); + //状态改变 + if(modbusDevice == nullptr){ + qDebug()<<"cannot create modbus client"; + } + else{ + connect(modbusDevice, &QModbusClient::stateChanged, this, &MyModbusTcp::stateChanged_SLot); + } +} +/** + * @brief MyModbusTcp::timeGoBy 等待tms + * @param time + * @param t + */ +void MyModbusTcp::timeGoBy(QTime time, int t){ + time.start(); //设定time为当前时间 + while(time.elapsed() < t){ //等待时间流逝500ms + QCoreApplication::processEvents(); //处理事件 + } +} +//===================================数据类型转换=============================== +/** + * @brief MyModbusTcp::float2Word 将浮点数f转化为2个8位数据存放在word数组中 + * @param f 待转换的浮点数 + * @param word 转换后的word数组 + */ +void MyModbusTcp::float2Word(float f, unsigned int *word) +{ + unsigned long longdata = 0; + longdata = *(unsigned long*)&f; //注意,会丢失精度 + word[0] = (longdata & 0xFFFF0000) >> 16; + word[1] = (longdata & 0x0000FFFF); +} + +/** + * @brief MyModbusTcp::word2Float 将2个word数据转化为浮点数 + * @param p 指向word数组的指针 + * @param dataTransformed 转化后的浮点数 + */ +void MyModbusTcp:: word2Float(unsigned int *p, float dataTransformed) +{ + dataTransformed=0; + unsigned long longdata = 0; + longdata = (*p<< 16) + (*(p+1) << 0); + dataTransformed = *(float*)&longdata; +} + +//==========================================modbustcp==================== +/** + * @brief MyModbusTcp::errorOccurred_Slot 有错误发生 + */ +void MyModbusTcp::errorOccurred_Slot(){ + qDebug()<<"new error"<errorString(); +} + +/** + * @brief MyModbusTcp::stateChanged_SLot 状态改变 + */ +void MyModbusTcp::stateChanged_SLot(){ + if(modbusDevice->state() == QModbusDevice::UnconnectedState){ + qDebug()<<"Tcp Client未连接到server"; + } + else if(modbusDevice->state() == QModbusDevice::ConnectingState){ + qDebug()<<"正在连接"; + } + else if(modbusDevice->state() == QModbusDevice::ConnectedState){ + qDebug()<<"已连接"; + } + else if(modbusDevice->state() == QModbusDevice::ClosingState){ + qDebug()<<"已关闭"; + } +} + +/** + * @brief MyModbusTcp::connectModbusTcp 连接ModbusTcp + */ +void MyModbusTcp::connectModbusTcp() +{ + if(!modbusDevice){ + return; + } + if(modbusDevice->state() != QModbusDevice::ConnectedState){ + modbusDevice->setConnectionParameter(QModbusClient::NetworkAddressParameter,"192.168.9.71"); + modbusDevice->setConnectionParameter(QModbusClient::NetworkPortParameter,502); + modbusDevice->setTimeout(2000); //设置超时 + modbusDevice->setNumberOfRetries(3); //重试 + if(!modbusDevice->connectDevice()){ + qDebug()<<"连接失败"; + } + else { + qDebug()<<"连接成功"; + } + }else{ +// QMessageBox::information(this, "提示", "ModBusTcp已经连接"); + return; + } +} + +/** + * @brief MyModbusTcp::disconnectModbusTcp 断开连接 + */ +void MyModbusTcp::disconnectModbusTcp() +{ + if(modbusDevice->state() != QModbusDevice::ConnectedState){ +// QMessageBox::critical(this, "错误", "MosBusTcp未连接"); + return; + } + modbusDevice->disconnectDevice(); + qDebug()<<"ModBusTCP断开连接"; +// ui->stageShwoPlain->appendPlainText("与下位机断开连接成功!"); +} + +//===========================================数据发送、接收====================== +/** + * @brief MyModbusTcp::writeSingleFloat 将单个float写入保持性寄存器 + * @param address 写入的保持性寄存器地址 + * @param dataSend 写入的数据 + * @param serverID id + */ +void MyModbusTcp::writeSingleFloat(int address, float dataSend, int serverID = 1){ + if(modbusDevice->state() != QModbusDevice::ConnectedState){ +// QMessageBox::critical(this, "错误", "MosBusTcp未连接"); + return; + } + QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters,address,2); + unsigned int word[2]; + float2Word(dataSend, word); + writeUnit.setValue(0, word[0]); + writeUnit.setValue(1, word[1]); + if (auto *reply = modbusDevice->sendWriteRequest(writeUnit, serverID)) {// ui->spinBox_SerAddress->value()是server address sendWriteRequest是向服务器写数据 + if (!reply->isFinished()) { //reply Returns true when the reply has finished or was aborted. + //接收响应信息 + connect(reply, &QModbusReply::finished, this, [this, reply]() { + if (reply->error() == QModbusDevice::ProtocolError) { //接收到的响应信息是协议错误 + qDebug() << "写入数据错误:" << reply->errorString(); + } else if (reply->error() != QModbusDevice::NoError) { //接收到的响应消息是其它错误 + qDebug() << "写入数据错误: " << reply->errorString(); + }else { //接收到的消息没有错误 一般没有必要解析响应消息 + const QModbusDataUnit data = reply->result(); +// qDebug() << "消息数据个数:" << data.valueCount() << " :" << data.values(); + } + reply->deleteLater(); + }); + } else { // broadcast replies return immediately + reply->deleteLater(); + } + } else { + qDebug() << "sendWriteRequest Error: " << reply->errorString(); + } +} + +/** + * @brief MyModbusTcp::writeSingleWord 写入单个word(int) + * @param i 地址 + * @param w 写入的数据 + */ +void MyModbusTcp::writeSingleWord(int i, int w){ + QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters,i,1); + writeUnit.setValue(0, w); + if (auto *reply = modbusDevice->sendWriteRequest(writeUnit, 1)) {// ui->spinBox_SerAddress->value()是server address sendWriteRequest是向服务器写数据 + if (!reply->isFinished()) { //reply Returns true when the reply has finished or was aborted. + //接收响应信息 + connect(reply, &QModbusReply::finished, this, [this, reply]() { + if (reply->error() == QModbusDevice::ProtocolError) { //接收到的响应信息是协议错误 + qDebug() << "写入数据错误:" << reply->errorString(); + } else if (reply->error() != QModbusDevice::NoError) { //接收到的响应消息是其它错误 + qDebug() << "写入数据错误: " << reply->errorString(); + }else { //接收到的消息没有错误 一般没有必要解析响应消息 + const QModbusDataUnit data = reply->result(); +// qDebug() << "消息数据个数:" << data.valueCount() << " :" << data.values(); + } + reply->deleteLater(); + }); + } else { // broadcast replies return immediately + reply->deleteLater(); + } + } else { + qDebug() << "sendWriteRequest Error: " << reply->errorString(); + } +} + +/** + * @brief MyModbusTcp::writeMultipleHR 写多个保持性寄存器HR + * @param address 起始地址 + * @param num 数量 + * @param dataSend 写入的数组 + * @param serverID id + */ +void MyModbusTcp::writeMultipleHR(int address, int num, float *dataSend, int serverID = 1) +{ + if(modbusDevice->state() != QModbusDevice::ConnectedState){ +// QMessageBox::critical(this, "错误", "MosBusTcp未连接"); + return; + } + //发送数据 + qDebug() << "开始发送"; + QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, address, num); + unsigned int word[2]; //转换后存放的数组 + for(int i=0;i<6;i++){ + float2Word(dataSend[i], word); + qDebug() << dataSend[i]; +// qDebug() <<*word; +// qDebug() <<*(word+1); + writeUnit.setValue(2*i,word[0]); + writeUnit.setValue(2*i+1,word[1]); + } + + if (auto *reply = modbusDevice->sendWriteRequest(writeUnit, serverID)) {// ui->spinBox_SerAddress->value()是server address sendWriteRequest是向服务器写数据 + if (!reply->isFinished()) { //reply Returns true when the reply has finished or was aborted. + //接收响应信息 + connect(reply, &QModbusReply::finished, this, [this, reply]() { + if (reply->error() == QModbusDevice::ProtocolError) { //接收到的响应信息是协议错误 + qDebug() << "写入数据错误:" << reply->errorString(); + } else if (reply->error() != QModbusDevice::NoError) { //接收到的响应消息是其它错误 + qDebug() << "写入数据错误: " << reply->errorString(); + }else { //接收到的消息没有错误 一般没有必要解析响应消息 + const QModbusDataUnit data = reply->result(); +// qDebug() << "消息数据个数:" << data.valueCount() << " :" << data.values(); + } + reply->deleteLater(); + }); + } else { // broadcast replies return immediately + reply->deleteLater(); + } + } else { + qDebug() << "sendWriteRequest Error: " ; + } +} + +/** + * @brief MyModbusTcp::readMultipleHR 读取数据并放到wordRCV数组中 + * @param startAddress 起始地址 + * @param num 数量 + * @param serverID id + */ +void MyModbusTcp::readMultipleHR(int startAddress, int num, int serverID = 1){ + if(modbusDevice->state() != QModbusDevice::ConnectedState){ +// QMessageBox::critical(this, "错误", "MosBusTcp未连接"); + return; + } + QModbusDataUnit data(QModbusDataUnit::HoldingRegisters, startAddress, num); //地址 + if(auto *reply = modbusDevice->sendReadRequest(data, serverID)){ //发送请求 + if(!reply->isFinished()){ + connect(reply,&QModbusReply::finished, this, &MyModbusTcp::onReadReadyHR_Slot); + } + else{ + delete reply; + } + } +} + +/** + * @brief MyModbusTcp::onReadReadyHR_Slot 读取保持性寄存器数据并放到dataRCV数组中 + */ +void MyModbusTcp:: onReadReadyHR_Slot(){ + if(modbusDevice->state() != QModbusDevice::ConnectedState){ +// QMessageBox::critical(this, "错误", "MosBusTcp未连接"); + return; + } + QModbusReply *reply = qobject_cast(sender()); + if(!reply) return; + if(reply->error() == QModbusDevice::NoError){ + const QModbusDataUnit responseData = reply->result(); //接收的数据 + for(uint i = 0;ierror() == QModbusDevice::ProtocolError) { + qDebug()<<"协议错误"; + qDebug()<<"protocol error:"<errorString(); + } + else{ + qDebug()<<"回复错误"; + qDebug()<<"error:"<errorString(); + } + reply->deleteLater(); +} + +//=======================定时获取数据============================== +/** + * @brief MyModbusTcp::onTimeReadHR 定时读HR,并保存到dataRCV数组中 + */ +//void MyModbusTcp::onTimeReadHR() +//{ +// qDebug()<<"开始持续获取plc数据"; +// timer = new QTimer(this); //启动定时器,100ms +// connect(timer, SIGNAL(timeout()), this, SLOT(readMultipleHR())); +// timer->start(1000); // 每隔1000ms +//} + +///** +// * @brief MyModbusTcp::stopOnTimeReadHR 停止获取数据 +// */ +//void MyModbusTcp::stopOnTimeReadHR() +//{ +// qDebug()<<"停止获取plc数据"; +// timer->stop(); +// timer->deleteLater(); +//} + +//================================等待时间========================= +///** +// * @brief MyModbusTcp::waitTime 等待tms +// * @param time +// * @param t +// */ +//void MyModbusTcp::waitTime(QTime time, int t){ +// time.start(); //设定time为当前时间 +// while(time.elapsed() < t){ //等待时间流逝500ms +// QCoreApplication::processEvents(); //处理事件 +// } +//} diff --git a/mymodbustcp.h b/mymodbustcp.h new file mode 100644 index 0000000..83bb4bd --- /dev/null +++ b/mymodbustcp.h @@ -0,0 +1,111 @@ +#ifndef MYMODBUSTCP_H +#define MYMODBUSTCP_H + +#include +#include +#include +#include +#include +#include + + +class MyModbusTcp : public QObject +{ +public: + MyModbusTcp(); + //声明modbusDevice + QModbusClient *modbusDevice; + //modbustcp接收的原始数据,以word为单位 + unsigned int wordRCV[40]; + //用于存放读取的数据的数组,float类型 + float dataRCV[30]; +// QTimer *timer = nullptr; + + /** + * @brief timeGoBy 等待t毫秒 + * @param time + * @param t + */ + void timeGoBy(QTime time, int t); + /** + * @brief connectModbusTcp 连接modbustcp + */ + void connectModbusTcp(); + + /** + * @brief disconnectModbusTcp 断开连接 + */ + void disconnectModbusTcp(); + + /** + * @brief writeSingleHR 将单个float写入保持性寄存器 + * @param address 写入的保持性寄存器地址 + * @param dataSend 写入的数据 + * @param serverID id + */ + void writeSingleFloat(int address, float dataSend, int serverID); + /** + * @brief writeSingleWord 写入单个word(int) + * @param i 地址 + * @param w 写入的数据 + */ + void writeSingleWord(int i, int w); + /** + * @brief writeMultipleHR 写多个保持性寄存器HR + * @param address 起始地址 + * @param num 数量 + * @param dataSend 写入的数组 + * @param serverID id + */ + void writeMultipleHR(int address, int num, float *dataSend, int serverID); + + /** + * @brief readMultipleHR 读多个保持性寄存器,并保存到dataRCV数组中 + * @param startAddress 起始地址 + * @param num 数量 + * @param serverID id + */ + void readMultipleHR(int startAddress, int num, int serverID); + +// /** +// * @brief onTimeReadHR 定时读HR +// */ +// void onTimeReadHR(); + +// /** +// * @brief stopOnTimeReadHR 停止定时获取数据 +// */ +// void stopOnTimeReadHR(); + +private: + + /** + * @brief float2Word 将浮点数f转化为2个8位数据存放在word数组中 + * @param f 待转换的浮点数 + * @param word 转换后的word数组 + */ + void float2Word(float f, unsigned int *word); + /** + * @brief word2Float 将2个word数据转化为浮点数 + * @param p 指向word数组的指针 + * @param dataTransformed 转化后的浮点数 + */ + void word2Float(unsigned int *p, float dataTransformed); + + /** + * @brief errorOccurred_Slot 错误发生 + */ + void errorOccurred_Slot(); + + /** + * @brief stateChanged_SLot 状态改变 + */ + void stateChanged_SLot(); + + /** + * @brief onReadReadyHR_Slot HR读取准备就绪 + */ + void onReadReadyHR_Slot(); +}; + +#endif // MYMODBUSTCP_H