QModbus例程分析

news2024/9/23 12:27:22

由于有一个Modebus上位机的需要,分析一下QModbus Slave的源代码,方便后面的开发。

什么是Modbus

Modbus是一种常用的串行通信协议,被广泛应用于工业自动化领域。它最初由Modicon(目前属于施耐德电气公司)于1979年开发,旨在实现PLC(可编程逻辑控制器)和外部设备之间的数据交换。以下是对Modbus的详细解析:

一、Modbus协议的特点

  1. 免费使用:Modbus协议是免费开放的,用户可以自由使用,无需支付任何版权费用。
  2. 多种电气接口和传输介质:Modbus支持多种电气接口,如RS-232、RS-485等,以及多种传输介质,如双绞线、光纤、无线等,使得数据传输更加灵活。
  3. 帧格式简单:Modbus的帧格式简单易懂,方便开发人员快速上手和使用。
  4. 可靠性好:Modbus协议对数据进行了严格的校验,确保数据传输的可靠性。同时,它还支持主从方式定时收发数据,能够及时检测和恢复通信故障。

二、Modbus的传输方式与格式

Modbus协议可以使用串口和网线(含光纤)等方式进行传输,根据常用传输介质,它主要支持以下三种传输模式:

  1. ASCII模式:将数据以ASCII码形式进行传输,适用于低速率的串行通信。
  2. RTU模式:使用二进制格式传输数据,相比ASCII模式,在同样的波特率下可以传输更多的数据,适用于中高速率的串行通信。
  3. TCP/IP模式:利用TCP/IP协议进行网络通信,称为Modbus TCP/IP,适用于需要远程通信的场合。

三、Modbus协议的应用领域

Modbus协议广泛应用于工业自动化领域,包括但不限于以下几个方面:

  1. 工业自动化控制:连接PLC、传感器、执行器等设备,实现监控和控制功能。
  2. 智能家居:连接各种传感器和执行器,实现远程控制和监测。
  3. 能源监控:连接电表、燃气表、水表等设备,实现能源数据的采集和分析。
  4. 环境监测:连接各种传感器和仪器,监测环境参数如温度、湿度、气压等。
  5. 智能交通:连接交通控制设备、车辆检测器等,实现交通信号的控制和管理。

四、Modbus协议的工作原理

Modbus协议是一种使用主从关系实现的请求-响应协议。在主从关系中,通信总是成对发生——一个设备(主设备)发起请求,然后等待另一个设备(从设备)的响应。主站通常是人机界面(HMI)或监控和数据采集(SCADA)系统,从站则是传感器、PLC或可编程自动化控制器(PAC)等。

Modbus协议定义了一系列功能码,用于指定设备执行不同的操作。例如,读取线圈状态(Read Coil Status)功能码用于读取设备中的开关量输出状态;写单个寄存器(Write Single Register)功能码用于写入设备中的单个寄存器数据。在进行数据交换时,主设备会向从设备发送包含功能码和地址等信息的请求帧,从设备则根据请求帧中的信息执行相应的操作,并将结果以响应帧的形式返回给主设备。

五、总结

Modbus协议以其简单性、可靠性和广泛的兼容性,成为了工业自动化领域中最流行的通信协议之一。它支持多种电气接口和传输介质,适用于各种设备和系统之间的数据交换。同时,Modbus协议还具有良好的可扩展性和灵活性,能够满足不同应用场景的需求。

SettingDialog

SettingDialog中,是串口的参数配置,从上到下依次是:校验,波特率,数据位,停止位。

源代码

  • 头文件
#ifndef SETTINGSDIALOG_H
#define SETTINGSDIALOG_H

#include <QtSerialBus/qtserialbusglobal.h>
#include <QDialog>
#if QT_CONFIG(modbus_serialport)
#include <QSerialPort>
#endif

QT_BEGIN_NAMESPACE

namespace Ui {
class SettingsDialog;
}

QT_END_NAMESPACE

class SettingsDialog : public QDialog
{
    Q_OBJECT

public:

    // 串口配置数据结构
    struct Settings {
#if QT_CONFIG(modbus_serialport)
        int parity = QSerialPort::EvenParity; // 校验位初始化为偶校验
        int baud = QSerialPort::Baud19200; // 波特率初始化为19200
        int dataBits = QSerialPort::Data8; // 数据位初始化为8位
        int stopBits = QSerialPort::OneStop; // 停止位初始化为1位
#endif
    };

    explicit SettingsDialog(QWidget *parent = nullptr);
    ~SettingsDialog();

    Settings settings() const;

private:
    Settings m_settings;
    Ui::SettingsDialog *ui;
};

#endif // SETTINGSDIALOG_H

  • 源文件
#include "settingsdialog.h"
#include "ui_settingsdialog.h"

SettingsDialog::SettingsDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::SettingsDialog)
{
    ui->setupUi(this);

    ui->parityCombo->setCurrentIndex(1);
#if QT_CONFIG(modbus_serialport)

    // 从下拉框获取配置
    ui->baudCombo->setCurrentText(QString::number(m_settings.baud));
    ui->dataBitsCombo->setCurrentText(QString::number(m_settings.dataBits));
    ui->stopBitsCombo->setCurrentText(QString::number(m_settings.stopBits));
#endif

    /*
    信号和槽绑定,按下确认时修改默认参数,然后隐藏窗口。
    */
    connect(ui->applyButton, &QPushButton::clicked, [this]() {
#if QT_CONFIG(modbus_serialport)
        m_settings.parity = ui->parityCombo->currentIndex();
        if (m_settings.parity > 0)
            m_settings.parity++;
        m_settings.baud = ui->baudCombo->currentText().toInt();
        m_settings.dataBits = ui->dataBitsCombo->currentText().toInt();
        m_settings.stopBits = ui->stopBitsCombo->currentText().toInt();
#endif
        hide();
    });
}

SettingsDialog::~SettingsDialog()
{
    delete ui;
}

// 获取配置结果
SettingsDialog::Settings SettingsDialog::settings() const
{
    return m_settings;
}

MainWindow

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

    connect(ui->connectButton, &QPushButton::clicked,
            this, &MainWindow::onConnectButtonClicked);
    connect(ui->actionConnect, &QAction::triggered,
            this, &MainWindow::onConnectButtonClicked);
    connect(ui->actionDisconnect, &QAction::triggered,
            this, &MainWindow::onConnectButtonClicked);
    connect(ui->connectType, QOverload<int>::of(&QComboBox::currentIndexChanged),
            this, &MainWindow::onCurrentConnectTypeChanged);

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

连接函数

void MainWindow::onConnectButtonClicked()
{
    // 判断是否连接
    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());
#if QT_CONFIG(modbus_serialport)
            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);
#endif
        } 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);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1989860.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AXS4054:单节锂电池充电管理芯片特性与应用推荐

AXS4054是一款单节锂离子电池恒流/恒压线性充电器&#xff0c;芯片集成功率晶体管&#xff0c;充电电流可以用外部电阻设定&#xff0c;蕞大持续充电电流可达600mA,非常适合便携式设备应用&#xff0c;适合USB电源和适配器电源工作&#xff0c;内部采用防倒充电路&#xff0c;不…

关于暨南大学电子信息复试机试篇

书接上回&#xff0c;上一篇文章为关于暨南大学智科院电子信息复试笔试篇&#xff0c;由于我误信了卖复试辅导书的店家说今年改机试&#xff0c;所以在复试方案出来之前&#xff0c;我一直都在准备机试&#xff0c;暨南大学的机试历年来一直都是四道编程题&#xff0c;可以使用…

【C++】C++11中的包装器和绑定器

目录 一、function包装器 1.1 可调用对象 1.2 概念 1.3 应用场景 二、bind绑定器 一、function包装器 1.1 可调用对象 我们平时使用的普通函数、函数指针、仿函数和Lambda表达式都是可调用对象&#xff0c;它们不仅可以作为其他函数的参数传入&#xff0c;还可以作为其他…

逻辑回归模型构建+PDP(部分依赖图)解析——Python代码及运行结果分析

一、逻辑回归模型简介 逻辑回归是一种广泛用于二分类问题的统计模型。它通过使用逻辑函数将预测结果映射到0到1之间&#xff0c;从而可以用于概率预测。模型的训练过程通常包括以下几个步骤&#xff1a; 数据预处理&#xff1a;处理缺失值、编码分类变量、标准化数值变量。特…

Python代码之特征工程基础

1. 什么是特征工程 特征工程是指从原始数据中提取、转换和创建适合于模型训练的数据特征的过程。它是机器学习和深度学习中非常重要的一步&#xff0c;因为好的特征工程可以显著提高模型的性能。特征工程涉及从数据中提取有意义的信息&#xff0c;并将其转换为模型可以理解和使…

[CP_AUTOSAR]_通信服务_DCM模块(二)_通用设计元素

目录 1、通用设计元素1.1、子模块1.2、NRC&#xff08;Negative Response Code&#xff09;1.3、Non-volatile 信息1.4、Types1.4.1、Atomic types overview1.4.2、Data array types overview1.4.3、Nested Data types overview1.4.4、Data types constraints1.4.5、Dcm_OpStat…

第一周、、

7-1 入度与出度 分数 10 全屏浏览 切换布局 作者 黄龙军 单位 绍兴文理学院 求有向图G中各顶点的入度与出度。建议分别采用邻接矩阵和邻接表这两种不同的存储结构完成。 输入格式: 首先输入一个正整数T&#xff0c;表示测试数据的组数&#xff0c;然后是T组测试数据。每组…

2024年,这4款思维导图在线工具帮你高效作图

思维导图是一种强大的思维工具&#xff0c;它能够帮助我们更好地处理信息、解决问题。很多人都不知道要怎么制作&#xff0c;我整理的这4款工具是目前很受欢迎的思维导图工具&#xff0c;使用起来也很简单。 1、福昕导图软件 传送门&#xff1a;pdf365.cn/naotu 这是一款制作…

kubernetes 集群组件介绍

kubernetes 集群组件介绍 Kubernetes 架构 在Kubernetes&#xff08;k8s&#xff09;集群中&#xff0c;主节点&#xff08;Master Node&#xff09;和工作节点&#xff08;Worker Node&#xff09;都运行特定的软件组件&#xff0c;它们共同管理和运行容器化的应用程序。以下…

SD卡参数错误:深度解析与数之寻软件恢复实战

一、SD卡参数错误&#xff1a;数据与设备的隐形杀手 在数字化时代&#xff0c;SD卡作为便携存储设备&#xff0c;广泛应用于相机、手机、无人机及各类电子设备中&#xff0c;承载着人们珍贵的照片、视频、文档等重要数据。然而&#xff0c;SD卡在使用过程中&#xff0c;有时会…

天津有哪些SOLIDWORKS代理商?

随着数字化转型的步伐加快&#xff0c;越来越多的企业开始寻求高效的三维设计解决方案来提高生产力和创新力。在天津&#xff0c;亿达四方作为SOLIDWORKS官方授权的代理商&#xff0c;正成为众多企业的首选合作伙伴。本文将详细介绍亿达四方提供的服务和优势&#xff0c;帮助您…

CTFHUB-web-RCE-过滤运算符

开启题目 查看源码发现管道符被过滤&#xff0c;使用分号&#xff1b;拼接注入&#xff0c;发现了 flag 的可疑文件 127.0.0.1;ls 使用 cat 查看 flag 文件&#xff0c;右键查看页面源代码发现了 flag 127.0.0.1;cat flag_229701159030749.php

IP地址申请SSL证书,实现https访问

一般情况下&#xff0c;SSL证书都是通过域名来申请的&#xff0c;但是很多单位没有域名或者不方便提供域名&#xff0c;只能提供IP地址&#xff0c;那么如果想实现IP地址的https访问&#xff0c;就得申请IP地址专用SSL证书&#xff0c;市面上专供IP地址使用的SSL证书服务商比较…

数字孪生平台:构建智慧未来,重塑空间智能生态的钥匙

数字孪生平台这一创新概念的勃然兴起&#xff0c;不仅是技术的飞跃&#xff0c;更是对空间信息处理与决策智慧化、生态构建的一次世代跃迁跃进。本文旨在深度剖析数字孪生平台的内核、运作机制、应用前景及其对智慧生态的深远影响。 数字孪生平台&#xff1a;定义与构想 数字…

【Python基础】Python六种标准数据类型中哪些是可变数据,哪些是不可变数据

文章目录 1.基本介绍可变数据类型不可变数据类型2.可变和不可变到底指的是什么?可变(Mutable)不可变(Immutable)总结1.基本介绍 Python 中的六种标准数据类型分为可变数据类型和不可变数据类型。以下是这些数据类型的分类: 可变数据类型 列表(List) 列表是一种有序集…

分类预测 | Matlab实现PSO-XGBoost粒子群算法优化XGBoost的多特征分类预测

分类预测 | Matlab实现PSO-XGBoost粒子群算法优化XGBoost的多特征分类预测 目录 分类预测 | Matlab实现PSO-XGBoost粒子群算法优化XGBoost的多特征分类预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现PSO-XGBoost粒子群算法优化XGBoost的多特征分类预测&a…

【Python】一文向您详细介绍 *(星号)和 **(双星号)

&#x1f680;【Python】一文向您详细介绍 *&#xff08;星号&#xff09;和 **&#xff08;双星号&#xff09; 下滑即可查看博客内容 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地&#xff01;&#x1f387;…

什么是网格策略?高抛低吸神奇—网格交易

网格交易主要是根据行情的波动&#xff0c;自动进行短线的高抛低吸操作&#xff0c;从而达到止损 止盈或者降低持仓成本的目的。 网格策略&#xff0c;是一种利用‘交易档位’模式对标的进行机械式买入卖出操作的量化 策略&#xff0c;是一个适用于震荡行情的经典策略。 适合做…

防火墙标签解决轮询错误

接上文&#xff08;LVS实验——部署DR模式集群&#xff09;&#xff0c;以http和https为例&#xff0c;当在RS中同时开放80和443端口&#xff0c;那么默认控制是分开轮询的&#xff0c;这样就出现了一个轮询错乱的问题 当第一次访问80被轮询到RS2后下次访问443仍然可能会被轮询…

一键翻译 | 分享一个更高级、更AI的翻译插件

最近AutoGPT不是更新了嘛 我也打算搭建一个来玩玩。 不过呢&#xff0c;官方文档都是英文&#xff0c;阅读起来还是比较费劲的 之前用的翻译插件实在难用&#xff0c;即卡而且翻译不准 在网上找了一个新的AI翻译插件&#xff0c;发现贼好用&#xff0c;速度上很快&#xff…