commit d63d454cc5df99b31b1543fb08821d074a1e30f4 Author: tianzhendong <1203886034@qq.com> Date: Wed Mar 23 16:16:47 2022 +0800 first 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