当前位置: 首页 > news >正文

Qt下使用modbus-c库实现PLC线圈/保持寄存器的读写

系列文章目录

提示:这里是该系列文章的所有文章的目录
第一章:Qt下使用ModbusTcp通信协议进行PLC线圈/保持寄存器的读写(32位有符号数)
第二章:Qt下使用modbus-c库实现PLC线圈/保持寄存器的读写


文章目录

  • 系列文章目录
  • 前言
  • 一、下载modbus-c库
  • 二、实现ModbusLib类
  • 三、使用ModbusLib类
  • 四、下载链接
  • 总结


前言

在上一篇文章中提到了使用Qt下的Modbus模块来进行ModbusTcp的通信,采用QModbusTcpClient类作为Modbus客户端(主站)与PLC读写,正常情况下是可以满足读写需求的,但是使用过程中发现读写频率较高时会出现写入延迟等问题,后面发现使用这个C语言写的第三方Modbus库来与PLC通信会更加稳定,性能更优越,这里将结合相应的示例进行讲解,以便大家学习,如有错误之处,欢迎大家批评指正。

项目效果
请添加图片描述


提示:以下是本篇文章正文内容,下面案例可供参考

一、下载modbus-c库

通过参考博客中的下载链接到官网下载:https://sourceforge.net/projects/libmodbus/(似乎失效了,下载不了),或者通过下文中我的百度网盘链接下载压缩包,文件内容如下,其中包含相关源码和ws2_32.dll(在lib中,依赖该动态库)
请添加图片描述

二、实现ModbusLib类

这里我实现了自己的ModbusLib类的封装,使用了pri子模块的方式,也是方便日后进行此模块的复用
这里我使用的是tcp的方式来通信,pri内容如下:
ModbusLib.pri

HEADERS += \$$PWD/modbus.h \$$PWD/modbus-private.h \#$$PWD/modbus-rtu.h \#$$PWD/modbus-rtu-private.h \$$PWD/modbus-tcp.h \$$PWD/modbus-tcp-private.h \$$PWD/mymodbuslib.hSOURCES += \$$PWD/modbus.c \$$PWD/modbus-data.c \#$$PWD/modbus-rtu.c \$$PWD/modbus-tcp.c \$$PWD/mymodbuslib.cppLIBS += -L$$PWD/lib/ -lws2_32

这里会看到将modbus-c库的源码加入到工程中,所以添加好相关的头文件就可以调用库函数了,这里相关函数的使用见下文代码:
1.mymodbusLib.h

#ifndef MYMODBUSLIB_H
#define MYMODBUSLIB_H#include <QObject>
#include <QDateTime>
#include <QTimer>
#include <QThread>
#include <QEventLoop>
#include <QCoreApplication>
#include <QDebug>
#include "modbus.h"
#include "modbus-private.h"
#include "modbus-tcp.h"
#include "modbus-tcp-private.h"#define LOGDEBUG qDebug()<<QTime::currentTime().toString("[hh:mm:ss:zzz]")class MyModbusLib : public QObject
{Q_OBJECTpublic:explicit MyModbusLib(QObject *parent = nullptr);~MyModbusLib();bool initConnect(QString tcpIP,int tcpPort);bool readCoil(int readAdd);void writeCoil(int writeAdd,int writeNum);int readRegister(int writeAdd);void writeRegister32(int writeAdd,int writeNum);private:modbus_t *m_modbus;
};#endif // MYMODBUSLIB_H

2.mymodbusLib.cpp

#include "mymodbuslib.h"MyModbusLib::MyModbusLib(QObject *parent) : QObject(parent)
{}MyModbusLib::~MyModbusLib()
{modbus_close(m_modbus);modbus_free(m_modbus);
}//初始化
bool MyModbusLib::initConnect(QString tcpIP,int tcpPort)
{m_modbus = modbus_new_tcp(tcpIP.toLatin1().data(),tcpPort);modbus_set_slave(m_modbus,1);if(modbus_connect(m_modbus) == -1){return false;}//设置modbus超时时间为1000毫秒struct timeval t;t.tv_sec = 0;t.tv_usec = 1000000;modbus_set_response_timeout(m_modbus,t.tv_sec,t.tv_usec);return true;
}bool MyModbusLib::readCoil(int readAdd)
{uint8_t bitsr[1]={0};int rNum = modbus_read_bits(m_modbus,readAdd,1,bitsr);if(rNum  == -1){LOGDEBUG<<"读取线圈"<<readAdd<<"失败!";return false;}else{//LOGDEBUG<<"读取线圈"<<readAdd<<"成功!";if(bitsr[0] == 1){return true;}}return false;
}void MyModbusLib::writeCoil(int writeAdd,int writeNum)
{uint8_t bitsw[1]={0};bitsw[0] = writeNum;int rNum = modbus_write_bits(m_modbus,writeAdd,1,bitsw);if(rNum == -1){LOGDEBUG<<"线圈"<<writeAdd<<"写入"<<writeNum<<"失败!";}else{LOGDEBUG<<"线圈"<<writeAdd<<"写入"<<writeNum<<"成功!";}
}int MyModbusLib::readRegister(int readAdd)
{uint16_t regsr[2]={0};int rNum = modbus_read_registers(m_modbus,readAdd,2,regsr);if(rNum == -1){LOGDEBUG<<"读取寄存器"<<readAdd<<"失败!";}else{//LOGDEBUG<<"读取寄存器"<<readAdd<<"成功!";int readNum = regsr[0] | (regsr[1] << 16);return readNum;}return 0;
}void MyModbusLib::writeRegister32(int writeAdd,int writeNum)
{uint16_t regsw[2]={0};regsw[0] = writeNum & 0xffff;regsw[1] = (writeNum >> 16) & 0xffff;int rNum = modbus_write_registers(m_modbus,writeAdd,2,regsw);if(rNum  == -1){LOGDEBUG<<"寄存器"<<writeAdd<<"写入"<<writeNum<<"失败!";}else{LOGDEBUG<<"寄存器"<<writeAdd<<"写入"<<writeNum<<"成功!";}
}

三、使用ModbusLib类

工程结构如图,下面可以直接在主界面使用封装好的ModbusLib类,详细内容见代码:
请添加图片描述

1.ModbusTest.pro

QT       += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11DEFINES += QT_DEPRECATED_WARNINGS#设置字符
contains( CONFIG,"msvc" ):QMAKE_CXXFLAGS += /source-charset:utf-8 /execution-charset:utf-8
contains( CONFIG,"msvc" ):QMAKE_CFLAGS +=/source-charset:utf-8 /execution-charset:utf-8#包含子模块
include (./ModbusLib/ModbusLib.pri)   #libmodbus库SOURCES += \main.cpp \mainwindow.cppHEADERS += \mainwindow.hFORMS += \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

2.mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QTime>
#include <QDebug>
#include "ModbusLib/mymodbuslib.h"QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();void initWidget();private slots:void on_pb_connect_clicked();void on_pb_readC_clicked();void on_pb_writeC_clicked();void on_pb_readH_clicked();void on_pb_writeH_clicked();private:Ui::MainWindow *ui;MyModbusLib *m_myModbus;};
#endif // MAINWINDOW_H

3.mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);this->initWidget();
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::initWidget()
{//使能按钮ui->pb_readC->setEnabled(false);ui->pb_writeC->setEnabled(false);ui->pb_readH->setEnabled(false);ui->pb_writeH->setEnabled(false);//创建modbus对象m_myModbus = new MyModbusLib();
}void MainWindow::on_pb_connect_clicked()
{QString tcpIP = ui->le_ip->text();int tcpPort = ui->le_port->text().toInt();if(m_myModbus->initConnect(tcpIP,tcpPort)){ui->lb_state->setText("连接成功");LOGDEBUG<<"ModbusTCP连接成功!";//使能按钮ui->pb_readC->setEnabled(true);ui->pb_writeC->setEnabled(true);ui->pb_readH->setEnabled(true);ui->pb_writeH->setEnabled(true);}else{ui->lb_state->setText("连接失败");LOGDEBUG<<"ModbusTCP连接失败!";}
}void MainWindow::on_pb_readC_clicked()
{int readAdd = ui->le_addC->text().toInt();ui->lb_numC->setText(QString::number(m_myModbus->readCoil(readAdd)));
}void MainWindow::on_pb_writeC_clicked()
{int writeAdd = ui->le_addC->text().toInt();int writeNum = ui->le_writeNumC->text().toInt();m_myModbus->writeCoil(writeAdd,writeNum);
}void MainWindow::on_pb_readH_clicked()
{int readAdd = ui->le_addH->text().toInt();ui->lb_numH->setText(QString::number(m_myModbus->readRegister(readAdd)));
}void MainWindow::on_pb_writeH_clicked()
{int writeAdd = ui->le_addH->text().toInt();int writeNum = ui->le_writeNumH->text().toInt();m_myModbus->writeRegister32(writeAdd,writeNum);
}

4.mainwindow.ui
请添加图片描述

四、下载链接

modbus-c库下载链接:https://pan.baidu.com/s/1rBQzOhwPIrRxL_f2CofJxQ
提取码:xxcj


总结

后续在使用modbus-c库的测试中,发现读写的效率是比Qt自带的modbus模块要高并且稳定的,建议在需要与PLC进行tcp通信时使用这种方式。这里我的ModbusLib类封装在一个文件夹内,要调用直接在工程pro中添加pri子模块就可以使用,比较方便。


hello:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。

参考博客:QT 使用第三方C库实现Modbus通讯

相关文章:

Qt下使用modbus-c库实现PLC线圈/保持寄存器的读写

系列文章目录 提示&#xff1a;这里是该系列文章的所有文章的目录 第一章&#xff1a;Qt下使用ModbusTcp通信协议进行PLC线圈/保持寄存器的读写&#xff08;32位有符号数&#xff09; 第二章&#xff1a;Qt下使用modbus-c库实现PLC线圈/保持寄存器的读写 文章目录 系列文章目录…...

C++ 滑动窗口

例1 209. 长度最小的子数组 ①窗口大小不固定 ②求最小长度 -> ret INT_MAX ③数组内的值都大于0&#xff0c; 符合单调性&#xff08;sum nums[right] -> sum增大&#xff09; while里面符合条件&#xff0c;在里面更改ret 参考代码 class Solution { public:i…...

【深度学习】TensorFlow基础介绍

TensorFlow 模型 张量、变量共同点&#xff1a;具有形状、类型、值等3个属性。 不同点&#xff1a;变量可被TensorFlow的自动求导机制求导&#xff0c;常被用于机器学习模型的参数。 tfrecord tensorflow定义的数据格式&#xff0c;一种二进制文件格式&#xff0c;用于保存…...

springcloud:3.3测试重试机制

服务提供者【test-provider8001】 Openfeign远程调用服务提供者搭建 文章地址http://t.csdnimg.cn/06iz8 相关接口 测试远程调用&#xff1a;http://localhost:8001/payment/index 服务消费者【test-consumer-resilience4j8004】 Openfeign远程调用消费者搭建 文章地址http:/…...

【笔记】【电子科大 离散数学】 3.谓词逻辑

谓词引入 因为含变量的语句&#xff08;例如x > 3&#xff09;不是命题&#xff0c;无法进行逻辑推理。 为了研究简单命题句子内部的逻辑关系&#xff0c;我们需要对简单命题进行分解&#xff0c;利用个体词&#xff0c;谓词和量词来描述它们&#xff0c;并研究个体与总体…...

倍增算法C++

倍增 倍增算法是一种优化算法&#xff0c;通常用于某些需要高效计算指数幂的场景。它基于分治的思想&#xff0c;通过反复求平方来实现快速计算指数幂的目的。在实际应用中&#xff0c;倍增算法经常用于解决最近公共祖先问题、二分查找等。 1、快速幂详解 ksm核心代码 倍增就是…...

uniapp制作--进步器的选择

介绍&#xff1a; 进步器的选择,一般用于商城购物选择物品数量的场景 注意&#xff1a;该输入框只能输入大于或等于0的整数 效果展示&#xff1a; 代码展示&#xff1a; 以下是一个简单的购物车页面示例&#xff0c;包括选择商品和显示数量的功能&#xff1a; 在这个示例中…...

前端高频面试--查缺补漏篇

什么是进程和线程&#xff0c;有什么区别 进程&#xff1a;进程是程序的一次执行过程&#xff0c;是动态的过程&#xff0c;有自身产生、存在、消亡的过程。 线程&#xff1a;线程由进程创建&#xff0c;是进程的一个实体。一个进程可以拥有多个线程。 举个例子&#xff1a;…...

【计算机学习】-- 网页视频加速

系列文章目录 文章目录 系列文章目录前言一、开发者选项二、定义和用法1.基础语法&#xff1a;2.什么是uncaught TypeError:Cannot read properties of null? 二、开发者工具面板&#xff1a;1.Elements面板&#xff1a;2.Console面板&#xff1a; 总结 前言 一、开发者选项 …...

系统运维-Linux配置C、C++、Go语言编译环境

C yum install gcc -y #安装gcc编译器 gcc --version #验证环境gcc (GCC) 11.3.1 20221121 (Red Hat 11.3.1-4) Copyright (C) 2021 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even f…...

【设计模式】(二)设计模式六大设计原则

一、 设计原则概述 设计模式中主要有六大设计原则&#xff0c;简称为SOLID &#xff0c;是由于各个原则的首字母简称合并的来(两个L算一个,solid 稳定的)&#xff0c;六大设计原则分别如下&#xff1a; ​ 1、单一职责原则&#xff08;Single Responsibitity Principle&#…...

go-zero官网

go-zero 是一个集成了各种工程实践的 web 和 rpc 框架。通过弹性设计保障了大并发服务端的稳定性&#xff0c;经受了充分的实战检验。 go-zero官网&#xff1a;go-zero 缩短从需求到上线的距离...

Redis的应用场景以及常见问题(持续更新)

一、使用场景 1&#xff0c;在大型的秒杀库存扣减&#xff0c;app首页流量高峰&#xff0c;很容易将传统的关系型数据库&#xff08;mysql,oracle等&#xff09;给压垮 2&#xff0c;还有很多没必要持久化的数据&#xff0c;比如说短信验证码&#xff0c;点赞数等 3&#xff0c…...

前端添加压缩包内文件名称校验

1. tar包内文件名称校验 1. 读取tar包内所有的文件名称 export class TarReader {fileInfo: any[]buffer: string | ArrayBufferconstructor() {this.fileInfo []}readFile(file) {return new Promise(resolve > {const reader new FileReader()reader.onload event &g…...

redis02 安装

官网下载 传送门https://redis.io/download/#redis-downloads 安装Redis mac m1安装 下载你需要版本的软件包放到指定的目录下进行解压 cd 到解压好的redis目录 运行下面的命令进行编译测试 sudo make test 中途可能会提示你安装make工具&#xff0c;按提示安装即可&…...

#QT(QT时钟)

1.IDE&#xff1a;QTCreator 2.实验 3.记录 qtime&#xff08;qt的时间类&#xff09; qtimer&#xff08;qt的定时类&#xff09; 4.代码 widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTime> // #include <QTimer&g…...

T-RAG:结合实体检测的增强检索生成模型

内容摘要&#xff1a; T-RAG是一种新的大型语言模型&#xff08;LLM&#xff09;应用框架&#xff0c;在保证数据隐私的同时&#xff0c;提高了对私有企业文档的问答系统性能。T-RAG通过结合已有的增强检索生成&#xff08;RAG&#xff09;框架、自定义的开源语言模型以及一个实…...

u-boot: NAND 驱动简介

文章目录 1. 前言2. NAND 初始化3. 访问 NAND 设备3.1 查看 NAND 设备信息3.1.1 查看 NAND 设备基本信息3.1.2 查看 NAND 设备 MTD 分区3.1.3 查看 NAND 设备坏块 3.2 NAND 擦除操作3.3 NAND 写操作3.4 NAND 读操作3.5 其它 NAND 操作 1. 前言 限于作者能力水平&#xff0c;本…...

史上最全的大数据开发八股文【自己的吐血总结】

自我介绍 我本硕都是双非计算机专业&#xff0c;从研一下开始学习大数据开发的相关知识&#xff0c;从找实习到秋招&#xff0c;我投递过100公司&#xff0c;拿到过10的offer&#xff0c;包括滴滴、字节、蚂蚁、携程、蔚来、去哪儿等大厂&#xff08;岗位都是大数据开发&#…...

数据库学习案例20240304-mysql数据库案例总结(碎片,统计信息)

1 表中的碎片 在InnoDB中删除行的时候&#xff0c;这些行只是被标记为“已删除”&#xff0c;而不是真正从物理存储上进行了删除&#xff0c;因而存储空间也没有真正被释放回收。InnoDB的Purge线程会异步地来清理这些没用的索引键和行。但是依然没有把这些释放出来的空间还给操…...

别再瞎找了!2026年不容错过的专业AI论文软件

2026年AI论文写作工具已从“基础生成”升级为智能协同研究系统&#xff0c;核心评价维度包括文献真实性、格式合规性、长文本逻辑、查重降重、AIGC合规与多语言支持。本次测评覆盖6款主流工具&#xff0c;涵盖中文与英文场景、全流程与专项功能、免费与付费版本&#xff0c;让你…...

C++Stack栈类模版实例详解

栈的实现方式分为3种基于静态数组实现,内部预设一个很大的数组对象, 实现简单&#xff0c;缺点是空间受限。基于动态数组实现,内部预设一个容量值,然后分配一段内存空间数组,如果入栈大于默认容量值时,则再次扩大分配新的内存数组,并将旧数组拷贝至新数组及释放旧数组.基于双向…...

Windows HEIC缩略图预览:告别iPhone照片在Windows的“盲盒“时代

Windows HEIC缩略图预览&#xff1a;告别iPhone照片在Windows的"盲盒"时代 【免费下载链接】windows-heic-thumbnails Enable Windows Explorer to display thumbnails for HEIC/HEIF files 项目地址: https://gitcode.com/gh_mirrors/wi/windows-heic-thumbnails …...

OBS背景移除插件:零绿幕实现专业直播效果的完整指南

OBS背景移除插件&#xff1a;零绿幕实现专业直播效果的完整指南 【免费下载链接】obs-backgroundremoval An OBS plugin for removing background in portrait images (video), making it easy to replace the background when recording or streaming. 项目地址: https://gi…...

告别C盘爆满!VSCode插件和用户数据迁移到D盘的保姆级教程(附注册表修改)

告别C盘爆满&#xff01;VSCode插件和用户数据迁移到D盘的保姆级教程 每次打开VSCode都看到C盘空间告急的红色警告&#xff1f;作为开发者&#xff0c;我们往往会在不知不觉中安装几十个甚至上百个插件&#xff0c;这些插件和用户数据默认都存储在C盘&#xff0c;日积月累就会…...

告别手动写Testbench!用Quartus II + ModelSim自动生成仿真模板的保姆级教程

Quartus II ModelSim自动化测试框架实战&#xff1a;从零构建高效数字电路验证流程 在数字电路设计领域&#xff0c;验证工作往往消耗工程师60%以上的开发时间。传统手动编写Testbench的方式不仅效率低下&#xff0c;还容易引入人为错误。Altera Quartus II内置的Test Bench T…...

罗技鼠标宏:绝地求生后坐力控制全攻略

罗技鼠标宏&#xff1a;绝地求生后坐力控制全攻略 【免费下载链接】logitech-pubg PUBG no recoil script for Logitech gaming mouse / 绝地求生 罗技 鼠标宏 项目地址: https://gitcode.com/gh_mirrors/lo/logitech-pubg 想要在《绝地求生》中实现精准压枪&#xff0c…...

Zabbix 7.0 在 Ubuntu 上启用中文界面语言(zh_CN)

Zabbix 7.0 配置中文选项&#xff08;zh_CN&#xff09; 适用于 Zabbix 7.0 系统默认情况下语言文件不包含中文的情况。环境说明 Zabbix 版本&#xff1a;7.0.15&#xff08;LTS&#xff09;问题现象 Language 下拉框中 Chinese (zh_CN) 是灰色不可选&#xff1b;原因是系统未安…...

Dubbo学习笔记(快速入门)

一、分布式基础1.1 软件架构四大演变演变顺序&#xff1a;单体 → 垂直 → 分布式 → 微服务解释&#xff1a;架构进化本质&#xff1a;为了解决流量变大、代码变多、维护困难。1&#xff09;单体架构所有模块一个工程&#xff0c;一个jar包&#xff0c;全部本地调用&#xff1…...

从‘打包’到‘压缩’:一文理清Linux tar命令的-z、-j、-J参数该怎么选(附性能对比)

从‘打包’到‘压缩’&#xff1a;一文理清Linux tar命令的-z、-j、-J参数该怎么选&#xff08;附性能对比&#xff09; 在Linux系统管理中&#xff0c;文件归档与压缩是每位开发者绕不开的基础操作。当你面对几十GB的日志文件需要备份&#xff0c;或是需要将数百张高分辨率图片…...