1. 测试界面
2.工程文件
#-------------------------------------------------
#
# Project created by QtCreator 2023-04-02T22:39:29
#
#-------------------------------------------------
QT += core gui serialbus
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = ModbusTcp
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as 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 you use 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
CONFIG += c++11
SOURCES += \
cmodbustcp.cpp \
main.cpp \
mainwindow.cpp
HEADERS += \
cmodbustcp.h \
mainwindow.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
3.ModbusTcp类的设计与实现
1)cmodbustcp.h
#ifndef CMODBUSTCP_H
#define CMODBUSTCP_H
#include <QObject>
#include <QModbusTcpClient>
class QModbusClient;
class QModbusReply;
class CModbusTcp : public QObject
{
Q_OBJECT
public:
public:
explicit CModbusTcp(QObject *parent = nullptr);
~CModbusTcp();
QString m_strReceived;
QModbusClient *m_pmodbusDevice = nullptr;
public:
signals:
void signalStateChanged(bool bConnected);
void signalDataReceived(QString strDataReceived);
public slots:
void onReadReady();
void onModbusStateChanged(QModbusDevice::State state);
void coilRead(int nStartAddress,uint16_t numbers,int ServerID);
void coilWrite(int nStartAddress,QString strCoilToWrite,int ServerID);
void discreteInputRead();
void inputRegisterRead();
void holdingRegsiterRead();
void holdingRegisterWrite(QString strHoldingRegisterToWrite);
bool connect2Server(QString strIP = "127.0.0.1", QString strPort = "502");
void disconnectFromServer();
};
#endif // CMODBUSTCP_H
2)cmodbustcp.cpp
#include "cmodbustcp.h"
#include <QThread>
#include <QDebug>
#define DELETE_AND_SET_NULL(pointer) if(pointer != nullptr) { delete pointer; pointer = nullptr;};
#define DELETE_AND_SET_NULL_ARRAY(pointer) if(pointer != nullptr) { delete[] pointer; pointer = nullptr;};
CModbusTcp::CModbusTcp(QObject *parent) :
QObject(parent)
{
m_pmodbusDevice = new QModbusTcpClient(this);
connect(m_pmodbusDevice, &QModbusClient::stateChanged,this, &CModbusTcp::onModbusStateChanged);
}
CModbusTcp::~CModbusTcp()
{
DELETE_AND_SET_NULL(m_pmodbusDevice);
}
bool CModbusTcp::connect2Server(QString strIP, QString strPort)
{
bool bRet= false;
m_pmodbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, strIP);
m_pmodbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, strPort.toInt());
m_pmodbusDevice->setTimeout(1000);
m_pmodbusDevice->setNumberOfRetries(3);
bRet = m_pmodbusDevice->connectDevice();
if(bRet)
{
qDebug()<< "connect to PLC OK";
} else {
qDebug()<< "connect to PLC Fail";
}
return bRet;
}
void CModbusTcp::disconnectFromServer()
{
if(m_pmodbusDevice) m_pmodbusDevice->disconnectDevice();
}
void CModbusTcp::coilRead(int nStartAddress,uint16_t numbers,int ServerID)
{
if(m_pmodbusDevice)
{
QModbusDataUnit data(QModbusDataUnit::Coils, nStartAddress, numbers);
auto reply = m_pmodbusDevice->sendReadRequest(data, ServerID);
if(nullptr == reply)
{
qDebug() << "faile to send request data: " << m_pmodbusDevice->errorString();
} else {
if (!reply->isFinished())
{
connect(reply, &QModbusReply::finished, this, &CModbusTcp::onReadReady);
}
else
{
delete reply;
}
}
}
}
void CModbusTcp::coilWrite(int nStartAddress,QString strCoilToWrite,int ServerID)
{
if(m_pmodbusDevice)
{
int nstrLength = strCoilToWrite.length();
if(nstrLength == 0)
{
qDebug() << "Warnning:Coil String to send is Null!";
return;
}
QModbusDataUnit writeData(QModbusDataUnit::Coils, nStartAddress, (nstrLength >> 1) + (nstrLength & 1));
for (uint i = 0; i < writeData.valueCount(); i++)
{
writeData.setValue(i, strCoilToWrite.at(2*i).unicode() - '0');
}
qDebug() << "data sent is: " << writeData.values();
QModbusReply* reply = m_pmodbusDevice->sendWriteRequest(writeData, ServerID);
if (reply)
{
if (!reply->isFinished())
{
connect(reply, &QModbusReply::finished, this, [this, reply](){
if (reply->error() == QModbusDevice::ProtocolError)
{
qDebug() << "data written error: " << reply->errorString();
}
else if (reply->error() != QModbusDevice::NoError)
{
qDebug() << "data written error: " << reply->errorString();
}
else
{
const QModbusDataUnit data = reply->result();
qDebug() << "data written: " << data.values();
m_strReceived = "";
for(auto value: data.values())
{
m_strReceived += tr("%1 ").arg(value);
}
emit signalDataReceived(m_strReceived);
}
reply->deleteLater();
});
}
else
{
reply->deleteLater();
}
}
else
{
qDebug() << "sendWriteRequest Error: " << reply->errorString();
}
}
}
void CModbusTcp::discreteInputRead()
{
if(m_pmodbusDevice)
{
QModbusDataUnit data(QModbusDataUnit::DiscreteInputs, 0, 10);
auto reply = m_pmodbusDevice->sendReadRequest(data, 0x1);
if (nullptr == reply)
{
qDebug() << "fail to send data: " << m_pmodbusDevice->errorString();
}
else
{
if (!reply->isFinished())
{
connect(reply, &QModbusReply::finished, this, &CModbusTcp::onReadReady);
}
else
{
delete reply;
}
}
}
}
void CModbusTcp::inputRegisterRead()
{
qDebug() << "enter input register Read";
qDebug() << "CPLCCommunicationAgent:" <<QThread::currentThreadId() << QThread::currentThread();
if(m_pmodbusDevice)
{
QModbusDataUnit data(QModbusDataUnit::InputRegisters, 201, 1);
QModbusReply* reply = m_pmodbusDevice->sendReadRequest(data, 0x1);
if (nullptr == reply)
{
qDebug() << "failed to send data: " << m_pmodbusDevice->errorString();
}
else
{
qDebug() << "input register Read command have sent";
if (!reply->isFinished())
{
qDebug() << "input register Read command is running";
connect(reply, &QModbusReply::finished, this, &CModbusTcp::onReadReady);
}
else
{
qDebug() << "input register Read command immediately reply";
delete reply;
}
}
}
}
void CModbusTcp::holdingRegsiterRead()
{
if(m_pmodbusDevice)
{
QModbusDataUnit data(QModbusDataUnit::HoldingRegisters, 0, 10);
auto reply = m_pmodbusDevice->sendReadRequest(data, 0x1);
if (nullptr == reply)
{
qDebug() << "failed to send request data: " << m_pmodbusDevice->errorString();
}
else
{
if (!reply->isFinished())
{
connect(reply, &QModbusReply::finished, this, &CModbusTcp::onReadReady);
}
else
{
delete reply;
}
}
}
}
void CModbusTcp::holdingRegisterWrite(QString strHoldingRegisterToWrite)
{
if(m_pmodbusDevice)
{
QModbusDataUnit writeData(QModbusDataUnit::HoldingRegisters, 210, 10);
for (uint i = 0; i < writeData.valueCount(); i++)
qDebug() << "data sent: " << writeData.values();
QModbusReply* reply = m_pmodbusDevice->sendWriteRequest(writeData, 1);
if (reply)
{
if (!reply->isFinished())
{
connect(reply, &QModbusReply::finished, this, [this, reply](){
if (reply->error() == QModbusDevice::ProtocolError)
{
qDebug() << "data written error: " << reply->errorString();
}
else if (reply->error() != QModbusDevice::NoError)
{
qDebug() << "data written error: " << reply->errorString();
}
else
{
const QModbusDataUnit data = reply->result();
qDebug() << "data written: " << data.values();
m_strReceived = "";
for(auto value: data.values())
{
m_strReceived += tr("%1 ").arg(value);
}
emit signalDataReceived(m_strReceived);
}
reply->deleteLater();
});
}
else
{
reply->deleteLater();
}
}
else
{
qDebug() << "sendWriteRequest Error: " << reply->errorString();
}
}
}
void CModbusTcp::onReadReady()
{
auto reply = qobject_cast<QModbusReply*>(sender());
if (nullptr == reply)
{
return;
}
if (reply->error() == QModbusDevice::NoError)
{
const QModbusDataUnit responseData = reply->result();
qDebug() << "data receive: " << responseData.values();
m_strReceived = "";
for(auto value: responseData.values())
{
m_strReceived += tr("%1 ").arg(value);
}
emit signalDataReceived(m_strReceived);
}
else if (reply->error() == QModbusDevice::ProtocolError)
{
qDebug() << "Read response Protocol error: " << reply->errorString();
}
else
{
qDebug() << "Read response Error: " << reply->errorString();
}
reply->deleteLater();
}
void CModbusTcp::onModbusStateChanged(QModbusDevice::State state)
{
bool bConnected=false;
if(state == QModbusDevice::ConnectedState)
{
bConnected=true;
}
else
{
bConnected=false;
}
emit signalStateChanged(bConnected);
}
4.主窗口程序
1)windows.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "cmodbustcp.h"
#include <QTextEdit>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButtonConnect_clicked();
void on_pushButtonDisconnect_clicked();
void on_pushButtonCoilRead_clicked();
void on_pushButtonCoilWrite_clicked();
void on_pushButtonHoldingRegiserRead_clicked();
void on_pushButtonHoldingRegisterWrite_clicked();
void on_pushButtondiscreteInputRead_clicked();
void on_pushButtoninputRegisterRead_clicked();
void slotDataReceived(QString strData);
private:
Ui::MainWindow *ui;
CModbusTcp *m_pModbusTcp;
QString m_strDataReceived;
QTextEdit *m_currentTextEdit;
};
#endif // MAINWINDOW_H
2)windows.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#define DELETE_AND_SET_NULL(pointer) if(pointer != nullptr) { delete pointer; pointer = nullptr;};
#define DELETE_AND_SET_NULL_ARRAY(pointer) if(pointer != nullptr) { delete[] pointer; pointer = nullptr;};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_currentTextEdit = nullptr;
m_pModbusTcp = new CModbusTcp();
connect(m_pModbusTcp,SIGNAL(signalDataReceived(QString)), this, SLOT(slotDataReceived(QString)));
}
MainWindow::~MainWindow()
{
delete ui;
if (m_pModbusTcp) {
m_pModbusTcp->disconnectFromServer();
delete m_pModbusTcp;
m_pModbusTcp = nullptr;
}
}
void MainWindow::slotDataReceived(QString strData)
{
m_strDataReceived = strData;
qDebug() << "slot received string data:" << strData;
if(m_currentTextEdit != nullptr)
{
m_currentTextEdit->clear();
m_currentTextEdit->append(m_strDataReceived);
}
}
void MainWindow::on_pushButtonConnect_clicked()
{
if(m_pModbusTcp != nullptr)
{
bool bres = m_pModbusTcp->connect2Server(ui->lineEditIP->text(),ui->lineEditPort->text());
if(bres)
{
ui->textEditConnectStatus->append("PLC connect OK");
} else {
ui->textEditConnectStatus->append("PLC connect Fail");
}
}
}
void MainWindow::on_pushButtonDisconnect_clicked()
{
if(m_pModbusTcp != nullptr)
{
m_pModbusTcp->disconnectFromServer();
ui->textEditConnectStatus->append("Disconnect from PLC");
}
}
void MainWindow::on_pushButtonCoilRead_clicked()
{
if(m_pModbusTcp != nullptr)
{
QString strAddr = ui->lineEditCoilReadAddr->text();
QString strNum = ui->lineEditCoilReadNum->text();
QString strServerID = ui->lineEditServerID->text();
m_pModbusTcp->coilRead(strAddr.toInt(),strNum.toInt(),strServerID.toInt());
m_currentTextEdit = ui->textEditCoilRead;
}
}
void MainWindow::on_pushButtonCoilWrite_clicked()
{
if(m_pModbusTcp != nullptr)
{
QString strAddr = ui->lineEditCoilWriteAddr->text();
QString strSentData = ui->lineEditCoilWriteData->text();
QString strServerID = ui->lineEditServerID2->text();
m_pModbusTcp->coilWrite(strAddr.toInt(),strSentData,strServerID.toInt());
m_currentTextEdit = ui->textEditCoilWrite;
}
}
void MainWindow::on_pushButtonHoldingRegiserRead_clicked()
{
}
void MainWindow::on_pushButtonHoldingRegisterWrite_clicked()
{
}
void MainWindow::on_pushButtondiscreteInputRead_clicked()
{
}
void MainWindow::on_pushButtoninputRegisterRead_clicked()
{
}
5. 主程序
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}