利用Qt5已有QModbus相关类实现ModbusTcpServer总结


文章目录


在疫情环境下催生出了很多的无人或者减少人员接触的项目,比如无人智慧餐厅项目中的无人送餐项目,主要是由送餐小车和一个中控屏和部分协助发餐的设备组成,由于餐厅一般的范围不会很大,考虑到Wi-Fi通信可能比较麻烦,我们前期组网协议使用的是

​zigbee​​,这样的话小车可以无网络运行且待电能力较高,zigbee无线通信方案也比较较成熟,有一些现成的zigbee串口通信芯片,硬件和软件实现都方便一些。随着版本的迭代,有一些新的需求,我们需要接入一些第三方的设备,这些设备可能是

​PLC​​设备,而和这些设备通信的时候可能需要用到

​Modbus​​协议,而中控屏恰好是使用Qt开发的,因此我们借助于Qt5自带的一些功能来实现Modbus-TCP服务端和客户端做一下实验。

1、Modbus/TCP协议简单了解

可以查看这篇文章

2、Qt5 Modbus客户机(master主)服务器(slave从)实现示例分析学习

(1)、搜索Modbus

打开Qt creator后在示例中搜索Modbus,可以看到Modbus主/从的两个示例。

利用Qt5已有QModbus相关类实现ModbusTcpServer总结_搜索

(2)、运行后结果

我们将master和slave都运行起来,可以看到Modbus\TCP协议的Port是502,本地使用的127.0.0.1的IP地址,然后我们点击connect开始server,下面的勾选是输入和接收输出的回调,右侧客户端的Holding Registers输入要发送的值,左侧服务端我们将各个字节勾选上,然后左侧Input Registers的各个字节输入要发送的内容,之后点击客户端的Read-Write进行读写测试即可:

利用Qt5已有QModbus相关类实现ModbusTcpServer总结_ModbusTcpServer_02

(3)、slave代码分析

我们通过tree /f查看文件树:

C:\Qt\Qt5.9.1\Examples\Qt-5.9.1\serialbus\modbus\slave>tree /f
文件夹 PATH 列表
卷序列号为 00000087 0856:6C30
C:.
│ main.cpp
│ mainwindow.cpp
│ mainwindow.h
│ mainwindow.ui
│ settingsdialog.cpp
│ settingsdialog.h
│ settingsdialog.ui
│ slave.pro
│ slave.pro.user
│ slave.qrc

├─doc
│ ├─images
│ │ modbusserver.png
│ │
│ └─src
│ modbusslave.qdoc

└─images
application-exit.png
connect.png
disconnect.png
settings.png

可以看出来基本就是main、mainwindow、settingsdialog(settingdialog是对串口属性的设置,所以这里也不用看了)相关的内容,所以我们只需要看两个cpp文件就差不多可以掌握Qt5关于Modbus/TCP的接口使用了,此外可能就是检查一下.pro里面如何添加modbus相关的模块到我们的项目中。

main.cpp(注意一下如何获取modbus的日志即可,其它的没有啥特别的):

#include "mainwindow.h"

#include <QApplication>
#include <QLoggingCategory>

int main(int argc, char *argv[])
{
// TODO uncomment this line before release
// right now we always need it
QLoggingCategory::setFilterRules(QStringLiteral("qt.modbus* = true"));
QApplication a(argc, argv);
MainWindow w;
w.show();

return a.exec();
}

mainwindow.cpp:

初始化->建立连接:通看的话基本上就是initActions->on_connectButton_clicked来确认进行modbus类型选择以及判断是否已连接,如果是modbus/tcp的话则设置端口和url即可,一般来说端口就是502,url则需要根据我们局域网配置的url来定。

读写:setRegister、updateWidgets两个槽函数中有读写的接口,在on_connectType_currentIndexChanged方法中我们点击connect建立连接后就可以对server设置读取的信号槽连接。

#include "mainwindow.h"
#include "settingsdialog.h"
#include "ui_mainwindow.h"

#include <QModbusRtuSerialSlave>
#include <QModbusTcpServer>
#include <QRegularExpression>
#include <QStatusBar>
#include <QUrl>

enum ModbusConnection {
Serial,
Tcp
};

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, modbusDevice(nullptr)
{
ui->setupUi(this);
setupWidgetContainers();

ui->connectType->setCurrentIndex(0);
on_connectType_currentIndexChanged(0);

m_settingsDialog = new SettingsDialog(this);
initActions();
}

MainWindow::~MainWindow()
{
if (modbusDevice)
modbusDevice->disconnectDevice();
delete modbusDevice;

delete ui;
}

void MainWindow::initActions()
{
ui->actionConnect->setEnabled(true);
ui->actionDisconnect->setEnabled(false);
ui->actionExit->setEnabled(true);
ui->actionOptions->setEnabled(true);

connect(ui->actionConnect, &QAction::triggered,
this, &MainWindow::on_connectButton_clicked);
connect(ui->actionDisconnect, &QAction::triggered,
this, &MainWindow::on_connectButton_clicked);

connect(ui->actionExit, &QAction::triggered, this, &QMainWindow::close);
connect(ui->actionOptions, &QAction::triggered, m_settingsDialog, &QDialog::show);
}

void MainWindow::on_connectType_currentIndexChanged(int index)
{
if (modbusDevice) {
modbusDevice->disconnect();
delete modbusDevice;
modbusDevice = nullptr;
}

ModbusConnection type = static_cast<ModbusConnection> (index);
if (type == Serial) {
modbusDevice = new QModbusRtuSerialSlave(this);
} else if (type == Tcp) {
modbusDevice = new QModbusTcpServer(this);
if (ui->portEdit->text().isEmpty())
ui->portEdit->setText(QLatin1Literal("127.0.0.1:502"));
}
ui->listenOnlyBox->setEnabled(type == Serial);

if (!modbusDevice) {
ui->connectButton->setDisabled(true);
if (type == Serial)
statusBar()->showMessage(tr("Could not create Modbus slave."), 5000);
else
statusBar()->showMessage(tr("Could not create Modbus server."), 5000);
} else {
QModbusDataUnitMap reg;
reg.insert(QModbusDataUnit::Coils, { QModbusDataUnit::Coils, 0, 10 });
reg.insert(QModbusDataUnit::DiscreteInputs, { QModbusDataUnit::DiscreteInputs, 0, 10 });
reg.insert(QModbusDataUnit::InputRegisters, { QModbusDataUnit::InputRegisters, 0, 10 });
reg.insert(QModbusDataUnit::HoldingRegisters, { QModbusDataUnit::HoldingRegisters, 0, 10 });

modbusDevice->setMap(reg);

connect(modbusDevice, &QModbusServer::dataWritten,
this, &MainWindow::updateWidgets);
connect(modbusDevice, &QModbusServer::stateChanged,
this, &MainWindow::onStateChanged);
connect(modbusDevice, &QModbusServer::errorOccurred,
this, &MainWindow::handleDeviceError);

connect(ui->listenOnlyBox, &QCheckBox::toggled, this, [this](bool toggled) {
if (modbusDevice)
modbusDevice->setValue(QModbusServer::ListenOnlyMode, toggled);
});
emit ui->listenOnlyBox->toggled(ui->listenOnlyBox->isChecked());
connect(ui->setBusyBox, &QCheckBox::toggled, this, [this](bool toggled) {
if (modbusDevice)
modbusDevice->setValue(QModbusServer::DeviceBusy, toggled ? 0xffff : 0x0000);
});
emit ui->setBusyBox->toggled(ui->setBusyBox->isChecked());

setupDeviceData();
}
}

void MainWindow::handleDeviceError(QModbusDevice::Error newError)
{
if (newError == QModbusDevice::NoError || !modbusDevice)
return;

statusBar()->showMessage(modbusDevice->errorString(), 5000);
}

void MainWindow::on_connectButton_clicked()
{
bool intendToConnect = (modbusDevice->state() == QModbusDevice::UnconnectedState);

statusBar()->clearMessage();

if (intendToConnect) {
if (static_cast<ModbusConnection> (ui->connectType->currentIndex()) == Serial) {
modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter,
ui->portEdit->text());
modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter,
m_settingsDialog->settings().parity);
modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,
m_settingsDialog->settings().baud);
modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,
m_settingsDialog->settings().dataBits);
modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,
m_settingsDialog->settings().stopBits);
} else {
const QUrl url = QUrl::fromUserInput(ui->portEdit->text());
modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, url.port());
modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, url.host());
}
modbusDevice->setServerAddress(ui->serverEdit->text().toInt());
if (!modbusDevice->connectDevice()) {
statusBar()->showMessage(tr("Connect failed: ") + modbusDevice->errorString(), 5000);
} else {
ui->actionConnect->setEnabled(false);
ui->actionDisconnect->setEnabled(true);
}
} else {
modbusDevice->disconnectDevice();
ui->actionConnect->setEnabled(true);
ui->actionDisconnect->setEnabled(false);
}
}

void MainWindow::onStateChanged(int state)
{
bool connected = (state != QModbusDevice::UnconnectedState);
ui->actionConnect->setEnabled(!connected);
ui->actionDisconnect->setEnabled(connected);

if (state == QModbusDevice::UnconnectedState)
ui->connectButton->setText(tr("Connect"));
else if (state == QModbusDevice::ConnectedState)
ui->connectButton->setText(tr("Disconnect"));
}

void MainWindow::coilChanged(int id)
{
QAbstractButton *button = coilButtons.button(id);
bitChanged(id, QModbusDataUnit::Coils, button->isChecked());
}

void MainWindow::discreteInputChanged(int id)
{
QAbstractButton *button = discreteButtons.button(id);
bitChanged(id, QModbusDataUnit::DiscreteInputs, button->isChecked());
}

void MainWindow::bitChanged(int id, QModbusDataUnit::RegisterType table, bool value)
{
if (!modbusDevice)
return;

if (!modbusDevice->setData(table, id, value))
statusBar()->showMessage(tr("Could not set data: ") + modbusDevice->errorString(), 5000);
}

void MainWindow::setRegister(const QString &value)
{
if (!modbusDevice)
return;

const QString objectName = QObject::sender()->objectName();
if (registers.contains(objectName)) {
bool ok = true;
const int id = QObject::sender()->property("ID").toInt();
if (objectName.startsWith(QStringLiteral("inReg")))
ok = modbusDevice->setData(QModbusDataUnit::InputRegisters, id, value.toInt(&ok, 16));
else if (objectName.startsWith(QStringLiteral("holdReg")))
ok = modbusDevice->setData(QModbusDataUnit::HoldingRegisters, id, value.toInt(&ok, 16));

if (!ok)
statusBar()->showMessage(tr("Could not set register: ") + modbusDevice->errorString(),
5000);
}
}

void MainWindow::updateWidgets(QModbusDataUnit::RegisterType table, int address, int size)
{
for (int i = 0; i < size; ++i) {
quint16 value;
QString text;
switch (table) {
case QModbusDataUnit::Coils:
modbusDevice->data(QModbusDataUnit::Coils, address + i, &value);
coilButtons.button(address + i)->setChecked(value);
break;
case QModbusDataUnit::HoldingRegisters:
modbusDevice->data(QModbusDataUnit::HoldingRegisters, address + i, &value);
registers.value(QStringLiteral("holdReg_%1").arg(address + i))->setText(text
.setNum(value, 16));
break;
default:
break;
}
}
}

// -- private

void MainWindow::setupDeviceData()
{
if (!modbusDevice)
return;

for (int i = 0; i < coilButtons.buttons().count(); ++i)
modbusDevice->setData(QModbusDataUnit::Coils, i, coilButtons.button(i)->isChecked());

for (int i = 0; i < discreteButtons.buttons().count(); ++i) {
modbusDevice->setData(QModbusDataUnit::DiscreteInputs, i,
discreteButtons.button(i)->isChecked());
}

bool ok;
for (QLineEdit *widget : qAsConst(registers)) {
if (widget->objectName().startsWith(QStringLiteral("inReg"))) {
modbusDevice->setData(QModbusDataUnit::InputRegisters, widget->property("ID").toInt(),
widget->text().toInt(&ok, 16));
} else if (widget->objectName().startsWith(QStringLiteral("holdReg"))) {
modbusDevice->setData(QModbusDataUnit::HoldingRegisters, widget->property("ID").toInt(),
widget->text().toInt(&ok, 16));
}
}
}

void MainWindow::setupWidgetContainers()
{
coilButtons.setExclusive(false);
discreteButtons.setExclusive(false);

QRegularExpression regexp(QStringLiteral("coils_(?<ID>\\d+)"));
const QList<QCheckBox *> coils = findChildren<QCheckBox *>(regexp);
for (QCheckBox *cbx : coils)
coilButtons.addButton(cbx, regexp.match(cbx->objectName()).captured("ID").toInt());
connect(&coilButtons, SIGNAL(buttonClicked(int)), this, SLOT(coilChanged(int)));

regexp.setPattern(QStringLiteral("disc_(?<ID>\\d+)"));
const QList<QCheckBox *> discs = findChildren<QCheckBox *>(regexp);
for (QCheckBox *cbx : discs)
discreteButtons.addButton(cbx, regexp.match(cbx->objectName()).captured("ID").toInt());
connect(&discreteButtons, SIGNAL(buttonClicked(int)), this, SLOT(discreteInputChanged(int)));

regexp.setPattern(QLatin1String("(in|hold)Reg_(?<ID>\\d+)"));
const QList<QLineEdit *> qle = findChildren<QLineEdit *>(regexp);
for (QLineEdit *lineEdit : qle) {
registers.insert(lineEdit->objectName(), lineEdit);
lineEdit->setProperty("ID", regexp.match(lineEdit->objectName()).captured("ID").toInt());
lineEdit->setValidator(new QRegExpValidator(QRegExp(QStringLiteral("[0-9a-f]{0,4}"),
Qt::CaseInsensitive), this));
connect(lineEdit, &QLineEdit::textChanged, this, &MainWindow::setRegister);
}
}

(4)、master代码分析

同样我们先查看文件树:

C:\Qt\Qt5.9.1\Examples\Qt-5.9.1\serialbus\modbus\master>tree /f
文件夹 PATH 列表
卷序列号为 000000E4 0856:6C30
C:.
│ main.cpp
│ mainwindow.cpp
│ mainwindow.h
│ mainwindow.ui
│ master.pro
│ master.pro.user
│ master.qrc
│ settingsdialog.cpp
│ settingsdialog.h
│ settingsdialog.ui
│ writeregistermodel.cpp
│ writeregistermodel.h

├─doc
│ ├─images
│ │ modbusmaster.png
│ │
│ └─src
│ modbusmaster.qdoc

└─images
application-exit.png
connect.png
disconnect.png
settings.png

基本和slave的接口类似,主要modbus\tcp相关的操作都是在mainwindow下,settingsdialog还是对串口的设置,writeregistermodel是对QAbstractTableModel的继承和部分接口重写,完成双击输入内容的功能。

建立连接:

modbusDevice = new QModbusTcpClient(this);
if (ui->portEdit->text().isEmpty())
ui->portEdit->setText(QLatin1Literal("127.0.0.1:502"));

modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, url.port());
modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, url.host());

void MainWindow::on_readWriteButton_clicked()
{
if (!modbusDevice)
return;
ui->readValue->clear();
statusBar()->clearMessage();

QModbusDataUnit writeUnit = writeRequest();
QModbusDataUnit::RegisterType table = writeUnit.registerType();
for (uint i = 0; i < writeUnit.valueCount(); i++) {
if (table == QModbusDataUnit::Coils)
writeUnit.setValue(i, writeModel->m_coils[i + writeUnit.startAddress()]);
else
writeUnit.setValue(i, writeModel->m_holdingRegisters[i + writeUnit.startAddress()]);
}

if (auto *reply = modbusDevice->sendReadWriteRequest(readRequest(), writeUnit,
ui->serverEdit->value())) {
if (!reply->isFinished())
connect(reply, &QModbusReply::finished, this, &MainWindow::readReady);
else
delete reply; // broadcast replies return immediately
} else {
statusBar()->showMessage(tr("Read error: ") + modbusDevice->errorString(), 5000);
}
}

if (modbusDevice)
modbusDevice->disconnectDevice();
delete modbusDevice;

(5)、QModbusServer和QModbusClient类了解

打开Assistant,搜索QModbusTcp来查看QModbusTcpClient和QModbusTcpServer相关的内容(首先可以确定的是从Qt 5.8开始支持的):

利用Qt5已有QModbus相关类实现ModbusTcpServer总结_ModbusTcpServer_03

下面是所有的实现的方法:

This is the complete list of members for QModbusTcpServer, including inherited members.

enum ConnectionParameter
enum Error
enum Option
enum State
QModbusTcpServer(QObject *)
~QModbusTcpServer()
blockSignals(bool )
childEvent(QChildEvent *)
children() const
close()
close()
connect(const QObject *, const char *, const QObject *, const char *, Qt::ConnectionType )
connect(const QObject *, const QMetaMethod &, const QObject *, const QMetaMethod &, Qt::ConnectionType )
connect(const QObject *, const char *, const char *, Qt::ConnectionType ) const
connect(const QObject *, PointerToMemberFunction , const QObject *, PointerToMemberFunction , Qt::ConnectionType )
connect(const QObject *, PointerToMemberFunction , Functor )
connect(const QObject *, PointerToMemberFunction , const QObject *, Functor , Qt::ConnectionType )
connectDevice() : bool
connectNotify(const QMetaMethod &)
connectionParameter(int ) const : QVariant
customEvent(QEvent *)
d_ptr :
data(QModbusDataUnit *) const : bool
data(QModbusDataUnit::RegisterType , quint16 , quint16 *) const : bool
dataWritten(QModbusDataUnit::RegisterType , int , int )
deleteLater()
destroyed(QObject *)
disconnect(const QObject *, const char *, const QObject *, const char *)
disconnect(const QObject *, const QMetaMethod &, const QObject *, const QMetaMethod &)
disconnect(const QMetaObject::Connection &)
disconnect(const char *, const QObject *, const char *) const
disconnect(const QObject *, const char *) const
disconnect(const QObject *, PointerToMemberFunction , const QObject *, PointerToMemberFunction )
disconnectDevice()
disconnectNotify(const QMetaMethod &)
dumpObjectInfo() const
dumpObjectTree() const
dynamicPropertyNames() const
error() const : Error
errorOccurred(QModbusDevice::Error )
errorString() const : QString
event(QEvent *)
eventFilter(QObject *, QEvent *)
findChild(const QString &, Qt::FindChildOptions ) const
findChildren(const QString &, Qt::FindChildOptions ) const
findChildren(const QRegExp &, Qt::FindChildOptions ) const
findChildren(const QRegularExpression &, Qt::FindChildOptions ) const
inherits(const char *) const
installEventFilter(QObject *)
isSignalConnected(const QMetaMethod &) const
isWidgetType() const
isWindowType() const
killTimer(int )
metaObject() const
moveToThread(QThread *)
objectName() const
objectNameChanged(const QString &)
open() : bool
open() : bool
parent() const
processPrivateRequest(const QModbusPdu &) : QModbusResponse
processRequest(const QModbusPdu &) : QModbusResponse
processRequest(const QModbusPdu &) : QModbusResponse
processesBroadcast() const : bool
property(const char *) const
readData(QModbusDataUnit *) const : bool
receivers(const char *) const
removeEventFilter(QObject *)
sender() const
senderSignalIndex() const
serverAddress() const : int
setConnectionParameter(int , const QVariant &)
setData(const QModbusDataUnit &) : bool
setData(QModbusDataUnit::RegisterType , quint16 , quint16 ) : bool
setError(const QString &, QModbusDevice::Error )
setMap(const QModbusDataUnitMap &) : bool
setObjectName(const QString &)
setParent(QObject *)
setProperty(const char *, const QVariant &)
setServerAddress(int )
setState(QModbusDevice::State )
setValue(int , const QVariant &) : bool
signalsBlocked() const
startTimer(int , Qt::TimerType )
startTimer(std::chrono::milliseconds , Qt::TimerType )
state() const : State
stateChanged(QModbusDevice::State )
staticMetaObject :
staticQtMetaObject :
thread() const
timerEvent(QTimerEvent *)
tr(const char *, const char *, int )
value(int ) const : QVariant
writeData(const QModbusDataUnit &) : bool

可以针对性的了解一些方法。

3、实现一个modbus/tcp服务进行测试

基本上对于上位机来说作为modbus/tcp服务器的情况比较多。

.pro中添加:

QT       += core gui sql serialport serialbus

主要创建内容和读写操作(结合example和​​这里的例子​​):

#ifndef
#define

#include <QObject>
#include <QModbusServer>
#include <QModbusRtuSerialSlave>
#include <QModbusTcpServer>
#include <QSerialPort>

/*
*
*
* modbus slave 从站
*
* modbusSlove_* m_slave = new modbusSlove_(this);
*
* initModbusSerialSlove()
*
* connectDevice()
*
* //寄存器值发生改变,连接这个信号
void registerData_signal(int address,int value);
*
*/
class ModbusServer : public QObject
{
Q_OBJECT
public:
explicit ModbusServer(QObject *parent = nullptr);

/**
* @projectName testMyClass
* @brief 初始化串口modbusSlave
* 其他参数 波特率 数据位 校验位 停止位
* @author SMY
* @date 2019-03-27
*/
bool initModbusSerialServer(QString portName, qint32 baudRate, QSerialPort::DataBits dataBits,
QSerialPort::Parity parity, QSerialPort::StopBits stopBits);
/**
* @projectName testMyClass
* @brief 初始化网口modbusSlave
* ip地址,端口号
* @author SMY
* @date 2019-03-27
*/
bool initModbusNetworkServer(QString address,int port);

/**
* @projectName testMyClass
* @brief 连接设备
* @author SMY
* @date 2019-03-27
*/
bool connectDevice();
/**
* @projectName testMyClass
* @brief 网口还是串口连接
* @author SMY
* @date 2019-03-26
*/
enum modbusConnection
{
Serial,
Tcp
};

signals:
//寄存器值发生改变
void registerData_signal(int address,int value);
//发生错误
void error_signal(QString errorString);
/*state :1 connect ,0:unconnect
*状态发生改变
*/
void stateChanged_signal(int state);
public slots:
private slots:
/**
* @projectName testMyClass
* @brief 更新寄存器数据
* @author SMY
* @date 2019-03-26
*/
void updateData(QModbusDataUnit::RegisterType table, int address, int size);
/**
* @projectName testMyClass
* @brief device error
* @author SMY
* @date 2019-03-27
*/
void handleDeviceError(QModbusDevice::Error newError);
/**
* @projectName testMyClass
* @brief 连接状态改变
* @author SMY
* @date 2019-03-27
*/
void onStateChanged(int state);
private:
modbusConnection m_mode;
QModbusServer* modbusServer;
};

#endif// MODBUSSERVER__H
#include "modbusserver.h"
#include <QDebug>

ModbusServer::ModbusServer(QObject *parent) : QObject(parent)
{

}

bool ModbusServer::initModbusSerialServer(QString portName, qint32 baudRate, QSerialPort::DataBits dataBits,
QSerialPort::Parity parity,
QSerialPort::StopBits stopBits)
{
//串口

modbusServer = new QModbusRtuSerialSlave(this);

m_mode = Serial;

if(!modbusServer)
{
qDebug()<<"could not create modbus slave";
return 0;
}

QModbusDataUnitMap reg;
reg.insert(QModbusDataUnit::Coils, { QModbusDataUnit::Coils, 0, 10 });
reg.insert(QModbusDataUnit::DiscreteInputs, { QModbusDataUnit::DiscreteInputs, 0, 10 });
reg.insert(QModbusDataUnit::InputRegisters, { QModbusDataUnit::InputRegisters, 0, 10 });
reg.insert(QModbusDataUnit::HoldingRegisters, { QModbusDataUnit::HoldingRegisters, 0, 10 });

modbusServer->setMap(reg);

modbusServer->setConnectionParameter(QModbusDevice::SerialPortNameParameter,
portName);
modbusServer->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,
baudRate);
modbusServer->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,
dataBits);
modbusServer->setConnectionParameter(QModbusDevice::SerialParityParameter,
parity);
modbusServer->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,
stopBits);


//更新寄存器值
connect(modbusServer,&QModbusServer::dataWritten,this,
&ModbusServer::updateData);
//更新连接状态
connect(modbusServer, &QModbusServer::stateChanged,
this, &ModbusServer::onStateChanged);
//错误发生
connect(modbusServer, &QModbusServer::errorOccurred,
this, &ModbusServer::handleDeviceError);
return 1;

}

bool ModbusServer::initModbusNetworkServer(QString address, int port)
{
// if(modbusServer)
// {
// modbusServer->disconnect();
// delete modbusServer;
// modbusServer = nullptr;
// }

//网口
modbusServer = new QModbusTcpServer(this);

m_mode = Tcp;

if(!modbusServer)
{
qDebug()<<"could not create modbus slave";
return false;
}

QModbusDataUnitMap reg;
reg.insert(QModbusDataUnit::Coils, { QModbusDataUnit::Coils, 0, 10 });
reg.insert(QModbusDataUnit::DiscreteInputs, { QModbusDataUnit::DiscreteInputs, 0, 10 });
reg.insert(QModbusDataUnit::InputRegisters, { QModbusDataUnit::InputRegisters, 0, 10 });
reg.insert(QModbusDataUnit::HoldingRegisters, { QModbusDataUnit::HoldingRegisters, 0, 10 });

modbusServer->setMap(reg);

modbusServer->setConnectionParameter(QModbusDevice::NetworkAddressParameter,address);
modbusServer->setConnectionParameter(QModbusDevice::NetworkPortParameter,port);

//更新寄存器值
connect(modbusServer,&QModbusServer::dataWritten,this,
&ModbusServer::updateData);
//更新连接状态
connect(modbusServer, &QModbusServer::stateChanged,
this, &ModbusServer::onStateChanged);
//错误发生
connect(modbusServer, &QModbusServer::errorOccurred,
this, &ModbusServer::handleDeviceError);

return true;
}

bool ModbusServer::connectDevice()
{
//设置modbusServer的modbus地址固定为1
modbusServer->setServerAddress(1);
return modbusServer->connectDevice();
}

void ModbusServer::updateData(QModbusDataUnit::RegisterType table, int address, int size)
{
for (int i = 0; i < size; ++i) {
quint16 value;
QString text;
switch (table) {
case QModbusDataUnit::Coils:
modbusServer->data(QModbusDataUnit::Coils, address + i, &value);

break;
case QModbusDataUnit::HoldingRegisters:
modbusServer->data(QModbusDataUnit::HoldingRegisters, address + i, &value);

break;
default:
break;
}

emit registerData_signal(address+i,value);

}
}

void ModbusServer::handleDeviceError(QModbusDevice::Error newError)
{
if(newError == QModbusDevice::NoError || !modbusServer)
return;
emit error_signal(modbusServer->errorString());
}

void ModbusServer::onStateChanged(int state)
{
if(state == QModbusDevice::UnconnectedState)
emit stateChanged_signal(0);
else if(state == QModbusDevice::ConnectedState)
emit stateChanged_signal(1);
}

main.cpp中添加modbus协议调试(参考示例):

QLoggingCategory::setFilterRules(QStringLiteral("qt.modbus* = true"));

调用我们封装的modbusServer类:

ModbusServer *modbusServer = new ModbusServer(this);

modbusServer->initModbusNetworkServer("127.0.0.1", 502);
modbusServer->connectDevice();

其实还应该添加析构方法断开连接释放资源,自己加一下哦~

接收成功了,我们可以根据需求再进行一些修改:

利用Qt5已有QModbus相关类实现ModbusTcpServer总结_搜索_04