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

怎么优化自己网站的关键词营销网站建设服务

怎么优化自己网站的关键词,营销网站建设服务,长沙做网站费用,wordpress模板 鸟Qt的Modbus协议-RTU从站实现 1、Modbus协议1.1 modbusRTU 协议格式1.2 读寄存器功能码0x032、Qt实现Modbus RTU协议2.1 添加相关的库2.2 添加相关的头文件2.3 设置串口参数2.4 一秒读取一次从机数据2.5 处理读取数据2.6 大小端排序 3、文件3,1 头文件3.2 cpp文件 4、总结 1、Mo…

Qt的Modbus协议-RTU从站实现

  • 1、Modbus协议
    • 1.1 modbusRTU 协议格式
    • 1.2 读寄存器功能码0x03
    • 2、Qt实现Modbus RTU协议
    • 2.1 添加相关的库
    • 2.2 添加相关的头文件
    • 2.3 设置串口参数
    • 2.4 一秒读取一次从机数据
    • 2.5 处理读取数据
    • 2.6 大小端排序
  • 3、文件
    • 3,1 头文件
    • 3.2 cpp文件
  • 4、总结

1、Modbus协议

Modbus协议是一种工业自动化领域广泛应用的串行通信协议,由Modicon公司(现施耐德电气)于1979年推出,现已成为工业设备通信的业界标准13。

1.1 modbusRTU 协议格式

设备地址:设备的通讯地址、站号。

功能码:对数据帧的功能编号。

寄存器:存放某类数据的内存区域。一个设备可能有多种寄存器,不同的寄存器存放不同类别的数据。

寄存器地址:某个数据在寄存器里的编号。不同的设备定义不同。

1.2 读寄存器功能码0x03

在这里插入图片描述

这个意思是设备地址为04,功能码是03,,寄存器起始地址为 0x80,查询数据分别为 0x1234和 0x5678;

2、Qt实现Modbus RTU协议

2.1 添加相关的库

QT       += core gui serialport serialbus

在这里插入图片描述

2.2 添加相关的头文件

#include <QSerialPort>
#include <QtSerialBus>
#include <QModbusDataUnit>
#include <QModbusClient>

在这里插入图片描述

2.3 设置串口参数

// 函数功能:初始化Modbus RTU串行通信连接
void mainInterface::setupModbusConnectxion()
{// 创建Modbus RTU主设备实例modbusDevice = new QModbusRtuSerialMaster(this);// 配置串口通信参数(标准Modbus RTU设置)modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, "COM1");  // 使用COM1端口modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, QSerialPort::Baud115200);  // 波特率115200modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, QSerialPort::Data8);  // 8位数据位modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, QSerialPort::OneStop);  // 1位停止位modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::NoParity);  // 无校验位// 连接错误信号槽(Lambda表达式处理错误)connect(modbusDevice, &QModbusDevice::errorOccurred, [](QModbusDevice::Error error) {qDebug() << "Modbus Error:" << error;  // 打印错误类型(如超时、校验错误等)});// 尝试建立物理连接if (!modbusDevice->connectDevice()) {qDebug() << "无法连接";  // 连接失败(可能端口被占用或参数错误)} else {qDebug() << "成功连接";  // 连接成功,可开始发送Modbus请求}
}

2.4 一秒读取一次从机数据

利用定时器来达到1秒钟读取一次
    //初始化定时器dataTimer = new QTimer(this);connect(dataTimer, &QTimer::timeout, this, &mainInterface::readFlowData);dataTimer->start(1000); // 每秒读取一次
读取数据
    // 创建Modbus数据读取单元// 参数说明:// 1. HoldingRegisters - 读取保持寄存器类型,对应功能码0x03// 2. 4104 - 起始寄存器地址(对应设备文档中的4104或0x1008)// 3. 2 - 读取2个寄存器(32位数据通常需要2个16位寄存器)QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters, 4104, 2);// 发送读取请求到从设备(设备地址为4)if (auto *reply = modbusDevice->sendReadRequest(readUnit, 4)) {// 检查请求是否已完成(立即完成可能表示错误)if (!reply->isFinished()) {// 连接完成信号到处理槽函数connect(reply, &QModbusReply::finished, this, &mainInterface::handleReadResult);} else {// 立即完成的异常情况,释放reply对象delete reply;}} else {// 发送请求失败,输出错误信息qDebug() << "读取错误: " << modbusDevice->errorString();}
}

2.5 处理读取数据

// 函数功能:处理Modbus读取请求的返回结果
void mainInterface::handleReadResult()
{// 获取发送信号的QModbusReply对象(即触发此槽的reply对象)auto reply = qobject_cast<QModbusReply *>(sender());if (!reply){return;  // 转换失败则直接返回}// 检查Modbus通信是否无错误if (reply->error() == QModbusDevice::NoError) {// 获取返回的寄存器数据单元const QModbusDataUnit unit = reply->result();// 准备存储转换结果的变量QString dataStr;float flowValuee = 0;// 将两个寄存器的值转换为浮点数// 参数说明:// unit.value(0) - 第一个寄存器的值(高16位)// unit.value(1) - 第二个寄存器的值(低16位)// 0 - 可能的转换选项(如字节序)flowValuee = convertToFloat(unit.value(0), unit.value(1), 0);// 在UI上显示带一位小数的流量值ui->flowlabel->setText(QString::number(flowValuee, 'f', 1));}else {// 输出错误信息到调试窗口qDebug() << "读取数据错误" << reply->errorString();}// 安全释放reply对象(Qt的内存管理机制)reply->deleteLater();
}

2.6 大小端排序

/*** @brief 将两个16位寄存器值转换为32位浮点数* @param reg1 第一个寄存器值(高/低16位,取决于字节序)* @param reg2 第二个寄存器值(高/低16位,取决于字节序)* @param isBigEndian 字节序标志:true表示大端模式,false表示小端模式* 大端模式:高字节在低地址,低字节在高地址* 小端模式:低字节在低地址,高字节在高地址* @return 转换后的32位浮点数*/
float mainInterface::convertToFloat(quint16 reg1, quint16 reg2, bool isBigEndian)
{// 使用联合体实现二进制数据到浮点数的类型转换union {quint32 i;  // 32位整型用于存储组合后的寄存器值float f;    // 32位浮点数用于最终输出} converter;// 根据字节序组合两个16位寄存器if (isBigEndian) {// 大端模式:reg1为高16位,reg2为低16位converter.i = (reg1 << 16) | reg2;} else {// 小端模式:reg2为高16位,reg1为低16位converter.i = (reg2 << 16) | reg1;}// 通过联合体直接返回浮点数表示return converter.f;
}

3、文件

3,1 头文件

#ifndef MAININTERFACE_H
#define MAININTERFACE_H#include <QWidget>
#include <QDateTime>
#include <QTimer>
#include <QSerialPort>
#include <QtSerialBus>
#include <QModbusDataUnit>
#include <QModbusClient>
#include <QProcess>
#include <windows.h>
#include <QMessageBox>namespace Ui {
class mainInterface;
}class mainInterface : public QWidget
{Q_OBJECTpublic:explicit mainInterface(QWidget *parent = nullptr);~mainInterface();typedef union /*申明一个联合体*/
{
float dataf;
uint32_t data32;
uint16_t data16[2];
uint8_t data8[4];
} data_t;private slots:void on_exitPushButton_clicked();void readFlowData();void updateDateTime();void handleReadResult();void on_keyboardPushButton_clicked();void on_historyPushButton_clicked();void on_setPushButton_clicked();void on_helpPushButton_clicked();private:Ui::mainInterface *ui;QTimer *dataTimer;QTimer *clockTimer;QModbusClient *modbusDevice;void setupModbusConnection();float parseFloatFromRegisters(const QVector<quint16> &registers);quint16 swapBytes(quint16 value);QProcess *keyboardProcess;bool keyboardVisible;float convertToFloat(quint16 reg1, quint16 reg2, bool isBigEndian);};#endif // MAININTERFACE_H

3.2 cpp文件

#include "maininterface.h"
#include "ui_maininterface.h"mainInterface::mainInterface(QWidget *parent) :QWidget(parent),ui(new Ui::mainInterface)
{ui->setupUi(this);keyboardVisible = false;this->setWindowFlag(Qt::FramelessWindowHint);           //去边框//    this->setAttribute(Qt::WA_TranslucentBackground);       //半透明背景//初始化定时器dataTimer = new QTimer(this);connect(dataTimer, &QTimer::timeout, this, &mainInterface::readFlowData);dataTimer->start(1000); // 每秒读取一次//更新时间clockTimer = new QTimer(this);connect(clockTimer, &QTimer::timeout, this, &mainInterface::updateDateTime);clockTimer->start(1000); // 每秒更新一次时间// 初始化键盘进程keyboardProcess = new QProcess(this);keyboardVisible = false;//初始化Modbus连接setupModbusConnection();//初始化时间显示updateDateTime();}mainInterface::~mainInterface()
{delete ui;
}//退出
void mainInterface::on_exitPushButton_clicked()
{QMessageBox quitMes;                        //创建退出弹窗对象quitMes.setWindowTitle("关闭界面");          //弹窗标题quitMes.setWindowIcon(QIcon(":/widdgetMainInterface/exit.png"));        //设置窗口图标quitMes.setIcon(QMessageBox::Warning);      //弹窗图片quitMes.setText("请确认是否退出");              //弹窗文本quitMes.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);      //设置Ok和Cancle两个按钮quitMes.setButtonText(QMessageBox::Ok, "确认");           //Ok改为确认quitMes.setButtonText(QMessageBox::Cancel,"取消");        //Cancle改为取消int result = quitMes.exec();       //显示信息框等待用户交互//如果用户选择了Okif(result == QMessageBox::Ok){this->close();          //关闭界面}else    //用户取消什么都不做{}this->close();
}//设置串口参数
void mainInterface::setupModbusConnection()
{modbusDevice = new QModbusRtuSerialMaster(this);// 设置Modbus RTU参数modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, "COM1");modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,QSerialPort::Baud115200);modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, QSerialPort::Data8);modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, QSerialPort::OneStop);modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::NoParity);// 连接错误信号connect(modbusDevice, &QModbusDevice::errorOccurred, [](QModbusDevice::Error error) {qDebug() << "Modbus Error:" << error;});// 尝试连接设备if (!modbusDevice->connectDevice()) {qDebug() << "无法连接";} else {qDebug() << "成功连接";}
}//读取数据
void mainInterface::readFlowData()
{if (!modbusDevice || modbusDevice->state() != QModbusDevice::ConnectedState){return;}// 读取流量寄存器 (地址4104-4105, 对应0x1008-0x1009)QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters, 4104, 2);//    QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters, 0, 2);if (auto *reply = modbusDevice->sendReadRequest(readUnit, 4)) { // 设备地址4if (!reply->isFinished()) {connect(reply, &QModbusReply::finished, this, &mainInterface::handleReadResult);} else {delete reply;}} else {qDebug() << "读取错误: " << modbusDevice->errorString();}
}//更新时间
void mainInterface::updateDateTime()
{QDateTime currentTime = QDateTime::currentDateTime();QString ymdTimeStr = currentTime.toString("yyyy年MM月dd日");QString hmsTimeStr = currentTime.toString("hh:mm:ss");ui->currentTimeymdlabel->setText(ymdTimeStr);ui->currentTimehmslabel->setText(hmsTimeStr);}//大小端排序
//大端模式:高字节在低地址,低字节在高地址
//小端模式:低字节在低地址,高字节在高地址
float mainInterface::convertToFloat(quint16 reg1, quint16 reg2, bool isBigEndian)
{union {quint32 i;float f;} converter;if (isBigEndian) {converter.i = (reg1 << 16) | reg2;} else {converter.i = (reg2 << 16) | reg1;}return converter.f;
}//处理读取数据
void mainInterface::handleReadResult()
{auto reply = qobject_cast<QModbusReply *>(sender());if (!reply){return;}if (reply->error() == QModbusDevice::NoError) {const QModbusDataUnit unit = reply->result();// 将数据值转换为字符串QString dataStr;float flowValuee = 0;flowValuee = convertToFloat(unit.value(0),unit.value(1),0);// 显示带一位小数的结果ui->flowlabel->setText(QString::number(flowValuee, 'f', 1));}else {qDebug() << "读取数据错误" << reply->errorString();}reply->deleteLater();}//高低字节交换
quint16 mainInterface::swapBytes(quint16 value)
{return ((value << 8) & 0xFF00) | ((value >> 8) & 0x00FF);}//转换数据
float mainInterface::parseFloatFromRegisters(const QVector<quint16> &registers)
{// 根据协议文档,每个寄存器内部进行字节交换quint16 low = swapBytes(registers[0]);quint16 high = swapBytes(registers[1]);//组合为32位整数//    qint32 combined = (static_cast<quint32>(high)<<16) | low;quint32 combined = (qFromBigEndian(high) << 16) | qFromBigEndian(low);// 重新解释为浮点数float result;memcpy(&result, &combined, sizeof(result));return result;}//软键盘
void mainInterface::on_keyboardPushButton_clicked()
{if (!keyboardVisible) {bool started = false;// 方法1: 使用QProcess尝试启动keyboardProcess->start("osk.exe");if (keyboardProcess->waitForStarted(1500)) {keyboardVisible = true;started = true;qDebug() << "软键盘已启动 (QProcess)";}// 方法2: 如果QProcess失败,尝试完整路径if (!started) {QString oskPath = "C:\\Windows\\System32\\osk.exe";keyboardProcess->start(oskPath);if (keyboardProcess->waitForStarted(1500)) {keyboardVisible = true;started = true;qDebug() << "软键盘已启动 (完整路径)";}}// 方法3: 如果前两种方法失败,使用Windows API绕过重定向if (!started) {qDebug() << "尝试使用Windows API启动软键盘";// 禁用文件系统重定向PVOID oldValue;Wow64DisableWow64FsRedirection(&oldValue);// 使用ShellExecute启动HINSTANCE result = ShellExecuteW(0,L"open",L"osk.exe",0,0,SW_SHOWNORMAL);// 恢复文件系统重定向Wow64RevertWow64FsRedirection(oldValue);if (reinterpret_cast<int>(result) > 32) {keyboardVisible = true;started = true;qDebug() << "软键盘已启动 (Windows API)";} else {qDebug() << "Windows API启动失败, 错误码:" << reinterpret_cast<int>(result);}}if (!started) {QMessageBox::warning(this, "错误", "无法启动软键盘。请确保系统支持屏幕键盘(osk.exe)。");}else {// 关闭软键盘if (keyboardProcess->state() == QProcess::Running) {keyboardProcess->terminate();if (keyboardProcess->waitForFinished(1000)) {keyboardVisible = false;qDebug() << "软键盘已关闭";} else {qDebug() << "无法关闭软键盘:" << keyboardProcess->errorString();}} else {keyboardVisible = false;}}}}//历史记录
void mainInterface::on_historyPushButton_clicked()
{QMessageBox::information(this,"历史记录","查看历史记录");
}//设置
void mainInterface::on_setPushButton_clicked()
{QMessageBox::information(this, "系统设置", "系统设置功能");
}//帮助
void mainInterface::on_helpPushButton_clicked()
{QMessageBox::information(this, "帮助", "流量监控系统帮助文档\n\n""1. 系统每秒自动更新流量数据\n""2. 点击键盘图标调用系统软键盘\n");
}

仓库地址

4、总结

以上就是Qt的Modbus协议-RTU从站实现的整个过程了,浏览过程中,如若发现错误,欢迎大家指正,有问题的欢迎评论区留言或者私信。最后,如果大家觉得有所帮助,可以点一下赞,谢谢大家!祝大家天天开心,顺遂无虞!
http://www.khdw.cn/news/3236.html

相关文章:

  • 宁波建工合肥正规的seo公司
  • 城乡与建设部网站济南网络推广公司
  • 做网站设计需要办理icp搜索引擎优化的主要策略
  • 做nba直播网站有哪些人百度pc网页版登录入口
  • 巢湖网站设计网站域名查询地址
  • 动态网站开发实训总结报告咸阳seo
  • 绵阳市中医医院网站建设阿里云搜索
  • 网站开发为什么需要域名如何做好互联网营销
  • 分类信息网站建设计划江苏关键词推广seo
  • 怎么在京东做网站seo网站优化推广费用
  • 菠菜网站搭建怎么做seo的中文含义是
  • 企业网站报价方案百度产品
  • 网站中的搜索功能怎么做的app下载推广平台
  • 网站推广方案的构成seo技术培训
  • 百度云建站网站建设竞价推广外包
  • 温州免费建站百度关键词屏蔽
  • 国内好的设计网站推荐seo推广优化外包价格
  • 扬州做网站的网络公司seo外链自动群发工具
  • 微机课做网站自媒体推广渠道有哪些
  • 建设一个网站步骤网址ip地址查询工具
  • 服务器托管平台seo技术培训茂名
  • 小说网站怎么做防采集seo面试常见问题及答案
  • 运动网站源码最佳磁力引擎吧
  • 怎么做网站评估今日头条seo
  • 深圳网站建设公司公司优化网站标题名词解释
  • 单页网站做cpa江苏网站开发
  • 什么网站做弹窗广告好徐州seo外包
  • 石家庄做网站的公司有哪些惠州seo报价
  • 企业网站制作收费北京关键词优化平台
  • 免费传奇网站免费传奇千网推软文推广平台