首页 > 其他分享 >QT实现Modbus

QT实现Modbus

时间:2022-12-04 21:00:12浏览次数:55  
标签:modbusDevice QT 实现 comboBox Modbus ui connect reply MainWindow

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "settingsdialog.h"
#include "writeregistermodel.h"
#include <QModbusTcpClient>
//Modbus TCP下的客户端类
#include <QModbusRtuSerialMaster>
//Modbus串口通信下的客户端类 主
#include <QStandardItemModel>
#include <QStatusBar>
#include <QUrl>

//定义枚举类型:两种传输模式:串行链路和以太网TCP/IP
enum ModbusConnection{
Serial,
Tcp
};

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_settingsDialog = new SettingsDialog(this);
initActions();
modbusDevice = NULL;
//先设置一个初始值,让其指向空,不然变成野指针,会出现段错误
m_settingsDialog = new SettingsDialog(this);
// QStringList str;
// str << "语文" <<"数学" <<"英语";
// ui->comboBox_content->addItems(str);
//四种通信内容:线圈(Coil)、离散量输入(Discrete Inputs)、输入寄存器 (Input Registers)、 保持寄存器(Holding Registers)、
ui->comboBox_content->addItem(tr("Coils"), QModbusDataUnit::Coils);
ui->comboBox_content->addItem(tr("Discrete Inputs"), QModbusDataUnit::DiscreteInputs);
ui->comboBox_content->addItem(tr("Input Registers"), QModbusDataUnit::InputRegisters);
ui->comboBox_content->addItem(tr("Holding Registers"), QModbusDataUnit::HoldingRegisters);

//下拉框设置1-10的数字表示大小
auto model = new QStandardItemModel(10, 1, this);
for (int i = 0; i < 10; ++i)
model->setItem(i, new QStandardItem(QStringLiteral("%1").arg(i + 1)));
ui->comboBox_writesize->setModel(model);
ui->comboBox_writesize->setCurrentText("10");
connect(ui->comboBox_writesize,&QComboBox::currentTextChanged, writeModel,
&WriteRegisterModel::setNumberOfValues);

auto valueChanged = static_cast<void (QSpinBox::*)(int)> (&QSpinBox::valueChanged);
connect(ui->spinBox_write_start_address, valueChanged, writeModel, &WriteRegisterModel::setStartAddress);
connect(ui->spinBox_write_start_address, valueChanged, this, [this, model](int i) {
int lastPossibleIndex = 0;
const int currentIndex = ui->comboBox_writesize->currentIndex();
for (int ii = 0; ii < 10; ++ii) {
if (ii < (10 - i)) {
lastPossibleIndex = ii;
model->item(ii)->setEnabled(true);
} else {
model->item(ii)->setEnabled(false);
}
}
if (currentIndex > lastPossibleIndex)
ui->comboBox_writesize->setCurrentIndex(lastPossibleIndex);
});

writeModel = new WriteRegisterModel(this);
writeModel->setStartAddress(ui->spinBox_write_start_address->value());
writeModel->setNumberOfValues(ui->comboBox_writesize->currentText());
ui->treeView->setModel(writeModel);
ui->treeView->hideColumn(2);
connect(writeModel, &WriteRegisterModel::updateViewport, ui->treeView->viewport(),
static_cast<void (QWidget::*)()>(&QWidget::update));

//设置目前的定位点
ui->comboBox_conn_type->setCurrentIndex(0);
on_comboBox_conn_type_currentIndexChanged(0);
//设置值的范围
ui->spinBox_server_address->setRange(0,5);
//设置服务器地址的初始值
ui->spinBox_server_address->setValue(1);
}

MainWindow::~MainWindow()
{
if (modbusDevice)
modbusDevice->disconnectDevice();
//如果Modbus设备是链接的,断开链接
delete modbusDevice;
//删除设备
delete ui;
}

//链接方式的选择 Modbus TCP Modbus RTU
void MainWindow::on_comboBox_conn_type_currentIndexChanged(int index)
{
if (modbusDevice) {
modbusDevice->disconnectDevice();
delete modbusDevice;
modbusDevice = nullptr;
}

//auto实现类型引导 static_cast实现将 index转成ModbusConnection
//判断链接方式:串口或者tcp
auto type = static_cast<ModbusConnection> (index);
if (type == Serial) {
modbusDevice = new QModbusRtuSerialMaster(this);
} else if (type == Tcp) {
modbusDevice = new QModbusTcpClient(this);
if (ui->lineEdit_port->text().isEmpty())
ui->lineEdit_port->setText(QLatin1Literal("127.0.0.1:502"));
}

connect(modbusDevice, &QModbusClient::errorOccurred, [this](QModbusDevice::Error) {
statusBar()->showMessage(modbusDevice->errorString(), 5000);
});

if (!modbusDevice) {
ui->pushButton_connect->setDisabled(true);
if (type == Serial)
statusBar()->showMessage(tr("Could not create Modbus master."), 5000);
else
statusBar()->showMessage(tr("Could not create Modbus client."), 5000);
} else {
connect(modbusDevice, &QModbusClient::stateChanged,
this, &MainWindow::onStateChanged);
}

}

//状态发生改变时 链接还是断开
void MainWindow::onStateChanged(int state)
{
bool connected = (state != QModbusDevice::UnconnectedState);
ui->action_Connect->setEnabled(!connected);
ui->action_Disconnect->setEnabled(connected);

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


//链接按钮
void MainWindow::on_pushButton_connect_clicked()
{
if (!modbusDevice)
return;

statusBar()->clearMessage();
//查看modbusDevice的连接状态:是否已经连接到modbus网络
if (modbusDevice->state() != QModbusDevice::ConnectedState) {
if (static_cast<ModbusConnection> (ui->comboBox_conn_type->currentIndex()) == Serial) {
modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter,
ui->lineEdit_port->text());
//setConnectionParameter将参数的值设为值
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->lineEdit_port->text());
modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, url.port());
modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, url.host());
}

modbusDevice->setTimeout(m_settingsDialog->settings().responseTime);
modbusDevice->setNumberOfRetries(m_settingsDialog->settings().numberOfRetries);
if (!modbusDevice->connectDevice()) {
statusBar()->showMessage(tr("Connect failed: ") + modbusDevice->errorString(), 5000);
} else {
ui->action_Connect->setEnabled(false);
ui->action_Disconnect->setEnabled(true);
}
} else {
modbusDevice->disconnectDevice();
ui->action_Connect->setEnabled(true);
ui->action_Disconnect->setEnabled(false);
}
}

//初始化
void MainWindow::initActions()
{
ui->action_Connect->setEnabled(true);
ui->action_Disconnect->setEnabled(false);
//ui->actionExit->setEnabled(true);
ui->actionOptions->setEnabled(true);

connect(ui->action_Connect, &QAction::triggered,
this, &MainWindow::on_pushButton_connect_clicked);
connect(ui->action_Disconnect, &QAction::triggered,
this, &MainWindow::on_pushButton_connect_clicked);

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

//读服务器内容的值
void MainWindow::on_pushButton_read_clicked()
{
if (!modbusDevice)
return;
ui->listWidget_read_list->clear();
//先将listWidget(读文本框中的内容清空)
statusBar()->clearMessage();
//清空最下面的状态栏
if (auto *reply = modbusDevice->sendReadRequest(readRequest(), ui->spinBox_server_address->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);
}
}

void MainWindow::readReady()
{
//auto 实现类型引导
//得到到底是谁触发了signal
auto reply = qobject_cast<QModbusReply *>(sender());
if (!reply)
return;
//没有错误
if (reply->error() == QModbusDevice::NoError) {
const QModbusDataUnit unit = reply->result();
for (uint i = 0; i < unit.valueCount(); i++) {
const QString entry = tr("Address: %1, Value: %2").arg(unit.startAddress() + i)
.arg(QString::number(unit.value(i),
unit.registerType() <= QModbusDataUnit::Coils ? 10 : 16));
ui->listWidget_read_list->addItem(entry);
}
} else if (reply->error() == QModbusDevice::ProtocolError) {
//协议错误
statusBar()->showMessage(tr("Read response error: %1 (Mobus exception: 0x%2)").
arg(reply->errorString()).
arg(reply->rawResult().exceptionCode(), -1, 16), 5000);
} else {
//其他错误
statusBar()->showMessage(tr("Read response error: %1 (code: 0x%2)").
arg(reply->errorString()).
arg(reply->error(), -1, 16), 5000);
}

reply->deleteLater();
}

QModbusDataUnit MainWindow::readRequest() const
{
const auto table =
static_cast<QModbusDataUnit::RegisterType> (ui->comboBox_content->currentData().toInt());
//QModusDataUnit是一个容器类 可用于读取和写入操作
//RegisterType 确定哪一个寄存器用于操作
int startAddress = ui->spinBox_read_start_address->value();
Q_ASSERT(startAddress >= 0 && startAddress < 10);
//程序运行时执行表达式内的值,假的话报错,真的话继续向后执行
// do not go beyond 10 entries
int numberOfEntries = qMin(ui->comboBox_readsize->currentText().toInt(), 10 - startAddress);
return QModbusDataUnit(table, startAddress, numberOfEntries);
}

QModbusDataUnit MainWindow::writeRequest() const
{
const auto table =
static_cast<QModbusDataUnit::RegisterType> (ui->comboBox_content->currentData().toInt());
//寄存器的类型 DiscreteInputs Coils InputRegisters HoldingRegisters
int startAddress = ui->spinBox_write_start_address->value();
Q_ASSERT(startAddress >= 0 && startAddress < 10);

// do not go beyond 10 entries
int numberOfEntries = qMin(ui->comboBox_writesize->currentText().toInt(), 10 - startAddress);
return QModbusDataUnit(table, startAddress, numberOfEntries);
}

//void MainWindow::on_writeTable_currentIndexChanged(int index)
//{
// const bool coilsOrHolding = index == 0 || index == 3;
// if (coilsOrHolding) {
// ui->treeView->setColumnHidden(1, index != 0);
// ui->treeView->setColumnHidden(2, index != 3);
// ui->treeView->resizeColumnToContents(0);
// }

// ui->pushButton_read_write->setEnabled(index == 3);
// ui->pushButton_read->setEnabled(coilsOrHolding);
// ui->groupBox_2->setEnabled(coilsOrHolding);
//}


//写操作
void MainWindow::on_pushButton_write_clicked()
{
if (!modbusDevice)
return;
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->sendWriteRequest(writeUnit, ui->spinBox_server_address->value())) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, this, [this, reply]() {
if (reply->error() == QModbusDevice::ProtocolError) {
statusBar()->showMessage(tr("Write response error: %1 (Mobus exception: 0x%2)")
.arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 16),
5000);
} else if (reply->error() != QModbusDevice::NoError) {
statusBar()->showMessage(tr("Write response error: %1 (code: 0x%2)").
arg(reply->errorString()).arg(reply->error(), -1, 16), 5000);
}
reply->deleteLater();
});
} else {
// broadcast replies return immediately
reply->deleteLater();
}
} else {
statusBar()->showMessage(tr("Write error: ") + modbusDevice->errorString(), 5000);
}
}



//读和写
void MainWindow::on_pushButton_read_write_clicked()
{
if (!modbusDevice)
return;
ui->listWidget_read_list->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->spinBox_server_address->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);
}
}



//根据选择 coils 或者 holdingregisters 时才能写,在treeview中显示表格,其他不能写
void MainWindow::on_comboBox_content_currentIndexChanged(int index)
{
const bool coilsOrHolding = index == 0 || index == 3;
if (coilsOrHolding) {
ui->treeView->setColumnHidden(1, index != 0);
ui->treeView->setColumnHidden(2, index != 3);
ui->treeView->resizeColumnToContents(0);
}

ui->pushButton_read_write->setEnabled(index == 3);
ui->pushButton_write->setEnabled(coilsOrHolding);
ui->groupBox_2->setEnabled(coilsOrHolding);


}

QT实现Modbus_Modbus

标签:modbusDevice,QT,实现,comboBox,Modbus,ui,connect,reply,MainWindow
From: https://blog.51cto.com/u_15515702/5910060

相关文章

  • 工程坐标转换方法C#代码实现
    目录1.前言2.计算总体框架3.C#代码实现3.1整体类的构建3.2椭球参数赋值3.3转换1、3(大地经纬度坐标与地心地固坐标的转换)3.4投影转换3.5转换2的实现(三参数、七参数)3......
  • 页式存储管理--两种置换算法的实现
    一.实验目的1.了解虚拟存储技术,通过编写和调试存储管理的模拟程序以加深对存储管理方案的理解。2.掌握FIFO和LRU等置换算法,加强对地址转换过程的了解。二.实验内容......
  • Python——pygam库实现弹跳小球
    代码实现:importsys#导入sys模块importpygame#导入pygame模块pygame.init()#初始化pygamesize=width,height=700,500#设置窗口screen......
  • 11.C++日期类的实现
    日期类的实现在前面学过默认成员函数后,我们就可以写一个简单的日期类了。如何写呢?我们可以先分析分析。日期类的成员变量都是int类型,那么构造函数是要显式定义的,成员变......
  • 详解用BitBlt实现透明贴图
    效果:代码:structBitmapInDC{HDCm_hdc;HBITMAPm_hbmp;HGDIOBJm_hbmpOld;BitmapInDC(HDChdc,HBITMAPbmp){m_hdc=CreateCompatibleDC(hdc);......
  • 决策树实现
    importmatplotlib.pyplotaspltimportnumpyasnpimportpandasaspdimporttorchimporttorch.fftasfftdf=pd.read_csv('train.csv')df=df.drop(['ID'],ax......
  • 如何用JDK优雅的实现几个算法
    今天给大家介绍下八股文中的两个重要成员,LinkedHashMap和TreeMap。 这两者都实现了Map接口,也经常会在面试中被拿来与HashMap比较。 到底它们能使用哪些魔法呢,接下来......
  • Node.js实现国密算法
    一、node.js环境安装1去官网下载压缩包,并放置到/usr/local/bin文件夹下2进行环境变量配置vim/etc/profile在环境变量文件的末尾添加exportNODEJS=/usr/local/b......
  • 11.C语言实现【N子棋】
    C语言实现一个大家小时候都玩过的小游戏的进阶版本,不止是三子棋,可以根据玩家需要设定棋盘大小。的可读性,我将源码分为了三个部分,分别是源文件test.c、game.c、game.h。tes......
  • 19.C语言实现【通讯录】
    简单功能展示增加联系人功能。按照姓名排序功能。保存文件,重新启动重新加载功能。头文件contact.h//文件保存版#include<stdio.h>#include<string.h>#include<s......