Qt 使用modbus协议
Qt 框架下 使用modbus协议
一,使用Qt原生的 QModbusClient ,比如QModbusTcpClient
1,因为modbus的读写 需要在同一个线程中,所以需要在主线程中利用moveToThread的方式,将业务逻辑封装到 子线程中。
2,modbus封装
#pragma once
#include <QObject>
#include <QModbusTcpClient>
#include <QCoreApplication>
#include <qdebug.h>namespace Device {class Modbus:public QObject{Q_OBJECTpublic:Modbus(QObject*parent): QObject(parent){}protected:bool modbusRead(QModbusTcpClient * modbusMaster,int serverAddress, QModbusDataUnit::RegisterType type, int newStartAddress, quint16 newValueCount, QList<quint16> &array, bool warning){QModbusDataUnit readUnit(type, newStartAddress, newValueCount);QModbusReply *reply = modbusMaster->sendReadRequest(readUnit, serverAddress);if(reply == nullptr){qDebug()<<QStringLiteral("modbusRead 无效请求");return false;}while (!reply->isFinished()){QCoreApplication::processEvents();}if (reply->error() == QModbusDevice::NoError){QModbusDataUnit resultUnit = reply->result();for (int i = 0; i < static_cast<int>(resultUnit.valueCount()); ++i) {array.append(resultUnit.value(i));}return true;}else{qDebug()<<QStringLiteral("modbusRead reply %1").arg(reply->errorString());return false;}}bool modbusWrite(QModbusTcpClient * modbusMaster,int serverAddress, QModbusDataUnit::RegisterType type, int newStartAddress, quint16 newValueCount, QList<quint16> array, bool warning){QModbusDataUnit writeUnit(type, newStartAddress, newValueCount);for(int i = 0; i < newValueCount; i++)writeUnit.setValue(i, array.value(i));QModbusReply *reply = modbusMaster->sendWriteRequest(writeUnit, serverAddress);if(reply == nullptr){qDebug()<<QStringLiteral("modbusWrite 无效请求");return false;}while (!reply->isFinished()){QCoreApplication::processEvents();}if (reply->error() == QModbusDevice::NoError){return true;}else{qDebug()<<QStringLiteral("modbusWrite reply %1").arg(reply->errorString());return false;}}};
}
3,继承上述类,封装业务逻辑,以压力传感器为例。将功能放到槽函数中。
class ModbusWorkerPressure:public Modbus{ Q_OBJECT public:explicit ModbusWorkerPressure(Modbus*parent= nullptr);~ModbusWorkerPressure() override;public slots:void open();void close();void zero();signals:void siStatus(int type,int result);private:QModbusTcpClient *modbusClient{nullptr};bool bOpened{false};bool bExit{false}; };
ModbusWorkerPressure::ModbusWorkerPressure(Modbus *parent): Modbus(parent) {}ModbusWorkerPressure::~ModbusWorkerPressure() {}void ModbusWorkerPressure::close() {bExit = true;DELAY(500);if (bOpened) {modbusClient->disconnectDevice();}if (modbusClient != nullptr) {modbusClient->deleteLater();} }void ModbusWorkerPressure::open() {modbusClient = new QModbusTcpClient(this);modbusClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, "10.10.10.2");modbusClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, 502);modbusClient->setTimeout(500);if (modbusClient->connectDevice()) {DELAY(500);while (!bExit) {QList<quint16> list;int32_t pressure=0;if(modbusRead(modbusClient,1,QModbusDataUnit::HoldingRegisters,0x0000,0x0002,list,false)){int result = 0;result =static_cast<int32_t>(list[1])<<16|list[0];pressure = result;//单位gDataManager::Instance().setCurPressure(pressure);//能读出数据 认为连接成功static bool execute = false;if (!execute) {bOpened = true;emit siStatus(0, 0);execute = true;}}DELAY(5);}} else {emit siStatus(0, -1);bOpened = false;} }void ModbusWorkerPressure::zero() {QList<quint16> list{0x0001};if (!modbusWrite(modbusClient,1, QModbusDataUnit::HoldingRegisters, 0x0002, 0x0001, list, false)) {LOGE(u8"压力传感器 清零失败!");} }
4, 主线程 使用moveToThread 将上述业务线程进行封装,然后主线程中 用信号,进行触发
bool PressureSensor::open(){workerThread = new QThread();modbusWorker = new ModbusWorkerPressure();modbusWorker->moveToThread(workerThread);QObject::connect(workerThread, &QThread::started, modbusWorker, &ModbusWorkerPressure::open);QObject::connect(this, &PressureSensor::siClose, modbusWorker, &ModbusWorkerPressure::close);QObject::connect(this, &PressureSensor::siZero, modbusWorker, &ModbusWorkerPressure::zero);QObject::connect(modbusWorker, &ModbusWorkerPressure::siStatus, [&](int type, int result) {if (type == 0) {if (result == 0) {bOpened = true;} else {bOpened = false;}}});workerThread->start();return true;}bool PressureSensor::zero() {if(!bOpened)return false;emit siZero();return true;}
5,此种方式 优点就是Qt原生框架,但是缺点是 这种方式是异步的方式,想要做到同步调用,比如轴系运动中,需要自己去同步,试过 QEventLoop的方式,但是不行,会丢失事件。
二,第三方库 libmodbus
1,编译及下载
Libmodbus在win11下的编译与VS2019下的运行_libmodbus vs2019-CSDN博客
2,写bool
auto home = [&](bool flag){const int read_regAddress = 55;const int numBits = 1;uint16_t coilStatus[numBits];int rc;{QMutexLocker locker(&mutex);rc = modbus_read_registers(modbusContext,read_regAddress,numBits,coilStatus);}if (rc == -1) {LOGE(QString("goHome Failed to read Modbus coils %1").arg(modbus_strerror(errno)).toUtf8());}else {uint16_t value = coilStatus[0];if(flag){value|=0x80;}else{value&=0xFF7F;}{QMutexLocker locker(&mutex);rc = modbus_write_register(modbusContext, read_regAddress, value);}if (rc == -1) {LOGE(QString("goHome Failed to write Modbus coil %1").arg(modbus_strerror(errno)).toUtf8());}}};home(false);DELAY(100);home(true);
3,读取double
while (!bExit){const int read_regAddress = 1104;const int numBits = 4;uint16_t coilStatus[numBits];int rc;{QMutexLocker locker(&mutex);rc = modbus_read_registers(modbusContext,read_regAddress,numBits,coilStatus);}if (rc == -1) {LOGE(QString("getPos Failed to read Modbus coils %1").arg(modbus_strerror(errno)).toUtf8());}else {::uint64_t combined = static_cast<uint64_t>(coilStatus[3]) << 48 |static_cast<uint64_t>(coilStatus[2]) << 32|static_cast<uint64_t>(coilStatus[1]) << 16| coilStatus[0];double realValue;std::memcpy(&realValue, &combined, sizeof(realValue));DataManager::Instance().setCurZ(realValue*1000);}DELAY(5);}
4,写double
//位置const int write_regAddress_pos = 1150;const int numReg = 4;::uint64_t rawPos = *reinterpret_cast<::uint64_t*>(&ptpPos);::uint16_t listPos[4]{static_cast<uint16_t>(rawPos&0xFFFF),static_cast<uint16_t>((rawPos>>16)&0xFFFF),static_cast<uint16_t>((rawPos>>32)&0xFFFF),static_cast<uint16_t>((rawPos>>48)&0xFFFF)};int rc;{QMutexLocker locker(&mutex);rc = modbus_write_registers(modbusContext, write_regAddress_pos,numReg, listPos);}if (rc == -1) {LOGE(QString("setPos Failed to write Modbus coil %1").arg(modbus_strerror(errno)).toUtf8());}
5,注意
modbus_t 并不是线程安全的,因此在使用的地方 需要加锁。亲测这个 比Qt原生的好用
相关文章:
Qt 使用modbus协议
Qt 框架下 使用modbus协议 一,使用Qt原生的 QModbusClient ,比如QModbusTcpClient 1,因为modbus的读写 需要在同一个线程中,所以需要在主线程中利用moveToThread的方式,将业务逻辑封装到 子线程中。 2,m…...
pip离线安装一个github仓库
要使用pip安装一个本地Git仓库,你可以按照以下步骤操作: 确保你已经克隆了Git仓库到本地。 进入仓库所在的目录。 使用pip安装。 以下是具体的命令: 克隆Git仓库到本地(替换下面的URL为你的仓库URL) git clone https…...
【ETCD】【源码阅读】深入分析 storeTxnWrite.Put方法源码
该方法是 storeTxnWrite 类型中的核心方法,负责将键值对存储到数据库,同时处理键的元数据(如版本、修订号、租约)并管理租约关联。 目录 一、完整代码二、方法详解方法签名1. 计算修订号并初始化变量2. 检查键是否已存在3. 生成索…...
桥接模式的理解和实践
桥接模式(Bridge Pattern),又称桥梁模式,是一种结构型设计模式。它的核心思想是将抽象部分与实现部分分离,使它们可以独立地进行变化,从而提高系统的灵活性和可扩展性。本文将详细介绍桥接模式的概念、原理…...
【Rust自学】3.2. 数据类型:标量类型
3.2.0. 写在正文之前 欢迎来到Rust自学的第三章,一共有6个小节,分别是: 变量与可变性数据类型:标量类型(本文)数据类型:复合类型函数和注释控制流:if else控制流:循环 通过第二章…...
【Leetcode Top 100】199. 二叉树的右视图
问题背景 给定一个二叉树的 根节点 r o o t root root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。 数据约束 二叉树的节点个数的范围是 [ 0 , 100 ] [0,100] [0,100] − 100 ≤ N o d e . v a l ≤ 100…...
Java并发编程框架之其他并发工具
选错了就选错了,不要一遍一遍的后悔,总是一遍遍的想,当时怎么样就好了,不要欺负当时的自己,当时你一个人站在迷雾中,也很迷茫,就算重新来一遍,以你当时的阅历和心智,还是…...
MinerU:PDF文档提取工具
目录 docker一键启动本地配置下载模型权重文件demo.py使用命令行启动GPU使用情况 wget https://github.com/opendatalab/MinerU/raw/master/Dockerfile docker build -t mineru:latest .docker一键启动 有点问题,晚点更新 本地配置 就是在Python环境中配置依赖和…...
Unity性能优化---使用SpriteAtlas创建图集进行批次优化
在日常游戏开发中,UI是不可缺少的模块,而在UI中又使用着大量的图片,特别是2D游戏还有很多精灵图片存在,如果不加以处理,会导致很高的Batches,影响性能。 比如如下的例子: Batches是9࿰…...
wazuh-modules-sca-scan
sca模块主函数wm_sca_main -> wm_sca_start 检查policy文件中的每一个项目wm_sca_check_policy static int wm_sca_check_policy(const cJSON * const policy, const cJSON * const checks, OSHash *global_check_list) {if(!policy) {return 1;}const cJSON * const id c…...
力扣-图论-15【算法学习day.65】
前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向和记录学习过程(例如想要掌握基础用法,该刷哪些题?)我的解析也不会做的非常详细,只会提供思路和一些关键点,力扣上的大佬们的题解质量是非…...
JS萤石云录像回放拖动进度条无法正常播放
问题描述: 本项目版本:vue2.6.12,webpack3.6.0,ezuikit-js0.7.2 在使用萤石云的JavaScript SDK做监控的直播、录像回放时,遇到部分设备的录像回放,无法根据控制面板的拖动进度条查看某时间段的录像。 官方…...
Spring Boot 启动时间优化全攻略
引言 随着 Spring Boot 的广泛应用,开发者享受到了快速开发和自动化配置的便利。然而,随着项目复杂度的增加,Spring Boot 项目启动时间也变得越来越长,这在开发、调试和部署阶段可能会成为效率瓶颈。如何优化 Spring Boot 的启动…...
ubuntu服务器木马类挖矿程序排查、及安全管理总结
版本 24.04 由于GPU多卡服务器多人使用,需要链接隧道ssh等,容易中招挖矿脚本。 总的思路是,顺着进程的PID回溯最终的程序运行起点,这里可以先看一下日志: journalctl -u PID 通过 PID 精确定位进程的信息,…...
redis 使用Lettuce 当redis挂掉重启之后 网络是怎么重新连接
Lettuce是一个高性能的Java Redis客户端,支持同步、异步和反应式编程模式 Lettuce的核心功能包括: 高性能:通过使用Netty作为底层网络通信框架,实现了非阻塞IO,提高了性能。丰富的API:提供了丰富…...
【PyTorch】实现在训练过程中自定义动态调整学习率
问题描述: 在使用 PyTorch 训练自定义神经网络时,我们希望能够动态地调整学习率,以便在训练过程中逐渐优化模型,避免过拟合并加速收敛。那么,如何在 PyTorch 中实现这一功能呢? 解决方案: 在训…...
【Flink-scala】DataStream编程模型总结
系列文章目录 1.【Flink-Scala】DataStream编程模型之数据源、数据转换、数据输出 2.【Flink-scala】DataStream编程模型之 窗口的划分-时间概念-窗口计算程序 3.【Flink-scala】DataStream编程模型之窗口计算-触发器-驱逐器 4.【Flink-scala】DataStream编程模型之水位线 5.【…...
语音芯片赋能可穿戴设备:开启个性化音频新体验
在科技日新月异的今天,语音芯片与可穿戴设备的携手合作,正引领我们步入一个前所未有的个性化音频时代。这一创新融合,用户可以享受到更加个性化、沉浸式的音频体验。下面将详细介绍语音芯片与可穿戴设备合作的优点和具体应用。 1. 定制化音效…...
JavaFX使用jfoenix的UI控件
jfoenix还是一个不错的样式,推荐使用,而且也可以支持scene builder中的拖拖拽拽 需要注意的是过高的javafx版本可能会使得某些样式或控件无法使用 比如alert控件,亲测javaFX 19版本可以正常使用 1.在pom.xml中引入依赖 GitHub地址https://gi…...
SpringBoot集成ENC对配置文件进行加密
在线MD5生成工具 配置文件加密,集成ENC 引入POM依赖 <!-- ENC配置文件加密 --><dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><version>2.1.2</ver…...
基于AI对话生成剧情AVG游戏
游戏开发这个领域,一直有较高的学习门槛。作为一个非专业的游戏爱好者,如果想要开发游戏,往往受制于游戏引擎的专业程度,难以完成复杂的游戏项目。 AI IDE的诞生,提供了另外的一种思路,即通过AI 生成项目及…...
MAVEN--Maven的生命周期,pom.xml详解,Maven的高级特性(模块化、聚合、依赖管理)
目录 (一)Maven的生命周期 1.Maven的三套生命周期 2.Maven常用命令 (二)pom.xml详解 (三)Maven的高级特性(模块化、聚合、依赖管理) 1.Maven的依赖范围 2.版本维护 3.依赖传…...
SpringBoot的事务钩子函数
如果需要在A方法执行完成之后做一个不影响主方法运行的动作B,我们需要判断这个A方法是否存在事务,并且使用异步执行动作B; import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transa…...
uniapp滚动消息列表
两个相同的循环列表,循环滚动 <view class"winners_list uni-flex uni-column" :animation"animationData"><view v-for"(item, index) in winnersList" :key"index" class"li uni-flex uni-column"&g…...
基于python对pdf文件进行加密等操作
利用python对pdf文件进行操作 读取pdf-源码 import PyPDF2 # 读取pdf格式的文件 reader PyPDF2.PdfFileReader(示例文件/aaa.pdf) print(reader)# 读取指定页面的文件 page reader.getPage(0) # 输出当前页面的文本数据 print(page.extractText())读取pdf-源码解析 这段代…...
Three.js材质纹理扩散过渡
Three.js材质纹理扩散过渡 import * as THREE from "three"; import { ThreeHelper } from "/src/ThreeHelper"; import { LoadGLTF, MethodBaseSceneSet } from "/src/ThreeHelper/decorators"; import { MainScreen } from "/src/compone…...
【Leetcode 每日一题 - 扩展】45. 跳跃游戏 II
问题背景 给定一个长度为 n n n 的 0 0 0 索引 整数数组 n u m s nums nums。初始位置为 n u m s [ 0 ] nums[0] nums[0]。 每个元素 n u m s [ i ] nums[i] nums[i] 表示从索引 i i i 向前跳转的最大长度。换句话说,如果你在 n u m s [ i ] nums[i] nums[i…...
被裁20240927 --- YOLO 算法
背景 在云端部署ViSP,ViSP实现视觉伺服、yolo实现视觉跟踪。 开源的2d视觉跟踪算法有哪些? 开源的2D视觉跟踪算法有很多呢,这里给你推荐一些比较知名和常用的吧。 ByteTrackV2:这是一个通用2D跟踪算法,提出了分层的…...
AI技术架构:从基础设施到应用
人工智能(AI)的发展,正以前所未有的速度重塑我们的世界。了解AI技术架构,不仅能帮助我们看懂 AI 的底层逻辑,还能掌握其对各行业变革的潜力与方向。 一、基础设施层:AI 技术的坚实地基 基础设施层是 AI 技…...
植物大战僵尸辅助【控制台版本】
前面介绍了使用CE和OD的简单使用:CE和OD介绍和使用CE查找阳光的教学:阳光基地址和偏移地址,下面先使用最简单的控制台程序来实现修改阳光的功能。 项目地址 1.分析程序 我们的控制台程序想要修改植物大战僵尸游戏内的数据,它们…...
css中样式前加 css样式前面加个圆点
创建CSS样式,样式名称的前面需要加什么 1、我们只知道符号代表的意思是at,其翻译是 在... 例如media就是 在媒介上。没人规定本身具有什么意义,或者说就算规定了我们也改变不了,只需要知道其规定属性的用法即可。 2、px;}然后根据你自己索要…...
算法刷题Day18: BM41 输出二叉树的右视图
题目链接 描述 思路: 递归构造二叉树在Day15有讲到。复习一下,就是使用递归构建左右子树。将中序和前序一分为二。 接下来是找出每一层的最右边的节点,可以利用队列层次遍历。 利用队列长度记录当前层有多少个节点,每次从队列里…...
如何实现规范化LabVIEW编程
规范编写LabVIEW程序的目的是提高代码的可读性、可维护性、可扩展性,并确保团队成员能够高效地理解和修改代码。以下是一些关键建议,帮助您编写更专业的LabVIEW代码,并确保它易于后续的升级和维护: 1. 合理的项目结构 目录结构…...
TQ15EG开发板教程:使用SSH登录petalinux
本例程在上一章“创建运行petalinux2019.1”基础上进行,本例程将实现使用SSH登录petalinux。 将上一章生成的BOOT.BIN与imag.ub文件放入到SD卡中启动。给开发板插入电源与串口,注意串口插入后会识别出两个串口号,都需要打开,查看串…...
Springboot+vue实现大文件上传
背景:为了实现大文件上传的功能 1新建数据表sql file_chunk CREATE TABLE file_chunk (id bigint UNSIGNED NOT NULL AUTO_INCREMENT,file_name varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci NULL DEFAULT NULL COMMENT 文件名,chunk_nu…...
Linux笔记
常用的基本命令 查询某个安装包有没有安装某个软件 使用的命令是rpm -qa |grep 软件名字 卸载软件 rpm -e --nodeps 软件名称 查看已经启动的服务 netstat -tunlp 一般我们在Linux系统中上传文件一般上传到 /usr/local/src的目录下 查看防火墙的命令 firewall-cmd --sta…...
相机(Camera)成像原理详解
简介:个人学习分享,如有错误,欢迎批评指正。 成像流程 1、光学相机的定义 顾名思义,光学相机就是利用光学原理进行成像的相机,而且市面上的相机几乎都是光学相机,只不过随着时代的发展,胶卷式…...
计算机网络知识点全梳理(一.TCP/IP网络模型)
目录 TCP/IP网络模型概述 应用层 什么是应用层 应用层功能 应用层协议 传输层 什么是传输层 传输层功能 传输层协议 网络层 什么是网络层 网络层功能 网络层协议 数据链路层 什么是数据链路层 数据链路层功能 物理层 物理层的概念和功能 写在前面 本系列文…...
后端接受前端传递数组进行批量删除
问题描述:当我们需要做批量删除功能的时候,我们循环单次删除的接口也能进行批量删除,但要删除100条数据就要调用100次接口,或者执行100次sql,这样系统开销是比较大的,那么我们直接采用接收的数组格式数据sq…...
理解数据结构 hashtable的简易理解思路
结构图 为了方便演示,下图中分区算法为下标取模 private int hashFun(int id) {//使用 hash并取模return id % size;}Hashtable的结构如图所示:是一个数组(元素为各个链表的表头) 多个链表组成,也就是说 hashtable 结…...
大数据面试题--企业面试真题
大数据面试题--企业面试真题 PlanHub 点击访问获取: 大数据面试体系专栏_酷兜科技www.kudoumh.top/hlwai/85.html 点击访问获取: 大数据面试体系专栏_酷兜科技www.kudoumh.top/hlwai/85.html 大数据面试题汇总 HDFS 1、 HDFS 读写流程。 2、HDF…...
数据结构(C语言版)-6.查找
1. 查找的基本概念 2. 静态查找 2.1 顺序查找 typedef int KeyType; typedef int InfoType; typedef struct {KeyType key;InfoType otherdata; }SeqList; // 顺序表类型 // 顺序查找int SeqSearch(SeqList R[], int n, int k) {int i n;R[0].key k; // R[0].key为查找不成…...
RabbitMQ消息队列的笔记
Rabbit与Java相结合 引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </dependency> 在配置文件中编写关于rabbitmq的配置 rabbitmq:host: 192.168.190.132 /…...
linux不同发行版中的主要差异
一、初始化系统 Linux不同发行版中的系统初始化系统(如 System V init、Upstart 或 systemd) System V init: 历史:System V init 是最传统的 Linux 系统初始化系统,起源于 Unix System V 操作系统。运行级别ÿ…...
Elasticsearch+Kibana分布式存储引擎
1.ElaticSearch介绍 ElaticSearch ,简称为 ES , ES 是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检 索数据;本身扩展性很好,可以扩展到上百台服务器,处理 PB 级别的数据。 ES 也使用 …...
spark 分布式 原理
Apache Spark 是一个快速且通用的大数据处理引擎,它支持分布式计算。Spark 的设计旨在通过高效的内存内计算和对多种数据源的支持来简化大规模数据集的处理。以下是关于 Spark 分布式原理的详细介绍: 1. 架构概述 Driver Program(驱动程序&…...
Hadoop学习笔记(包括hadoop3.4.0集群安装)(黑马)
Hadoop学习笔记 0-前置章节-环境准备 0.1 环境介绍 配置环境:hadoop-3.4.0,jdk-8u171-linux-x64 0.2 VMware准备Linux虚拟机 0.2.1主机名、IP、SSH免密登录 1.配置固定IP地址(root权限) 开启master,修改主机名为…...
thinkphp:try-catch捕获异常
使用简单的例子,实现了一个简单的try-catch捕获异常的实例 //开始事务Db::startTrans(); try{ //有异常抛出异常 if(存在错误){ throw new \Exception("异常信息"); } // 提交事务 Db::commit(); // 返回成功信息 ... } catch (\…...
如何使用 uni-app 构建直播应用程序?
使用uni-app构建直播应用程序涉及前端和后端的开发,以及音视频处理技术的选择。下面我将概述一个典型的直播应用架构,并详细说明如何在uni-app中实现关键功能。 直播应用架构 前端(uni-app):负责用户界面展示、互动逻…...
正则表达式入门教程
正则表达式入门教程 1. 引言 正则表达式(Regular Expression,简称Regex)是一种用于处理字符串的强大工具,它允许用户通过特定的模式(pattern)来搜索、匹配、查找和替换文本中的数据。正则表达式在文本处理、数据验证、数据提取等领域有着广泛的应用。本教程将带你了解正…...