一种基于QT5.12+VS2015的ModbusTcp客户端轮询方法

这篇具有很好参考价值的文章主要介绍了一种基于QT5.12+VS2015的ModbusTcp客户端轮询方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一种基于QT5.12+VS2015的ModbusTcp客户端轮询方法

服务端:西门子PLC-1200
客户端:Win10+QT5.12.1+VS2015

1.ModbusTcp寄存器规划

(1)客户端00000(线圈:可读可写) -> 服务端10000(离散输入)
(2)客户端10000(离散输入:只读) -> 服务端00000(线圈)
(3)客户端30000(输入寄存器:只读) -> 服务端40000(保持寄存器)
(4)客户端40000(保持寄存器:可读可写) -> 服务端30000(输入寄存器)

2.控制规则

(1)点控:客户端写线圈(00001置1) -> 客户端读线圈(直到00001为1) -> 客户端写线圈(00001置0)
(2)开关:客户端写线圈(00001置1)/ 客户端写线圈(00001置0)
(3)闭环:客户端写线圈(00001置1) -> 客户端读线圈 ->(服务端执行功能中) -> 客户端读离散输入(直到10001为1)-> 客户端写线圈(00001置0)
(4)监控状态:客户端读离散输入
(5)写入参数:客户端写保持寄存器(40001) -> 客户端读保持寄存器(40001)
(6)状态参数:客户端读输入寄存器(30001)

3.Modbus数据长度

ModBus只能有一个主机(TCP客户端),可以有多个从机(TCP服务端)。

3.1.报文请求格式如下:

ModbusRTU:ADU(8字节)=设备地址(1字节)+PDU(5字节)+校验(2字节)
ModbusTCP:ADU(12字节)=MBAP(7字节)+PDU(5字节)

        MBAP(7字节)=事务标(2字节)+协议(2字节)+长度(2字节)+单元(1字节)
        PDU(5字节)=功能码(1字节)+起始地址(2字节)+数据长度(2字节)

3.2.报文响应格式如下:

ModbusRTU:ADU(256字节)=地址(1字节)+PDU(253字节)+校验(2字节)
ModbusTCP:ADU(260字节)=MBAP(7字节)+PDU(253字节)

        MBAP(7字节)=事务标(2字节)+协议(2字节)+长度(2字节)+单元(1字节)
        PDU(253字节)=功能码(1字节)+数据(252字节)
        数据(252字节)=数据长度(1字节)+数据储存区(251字节)

3.3.Modbus TCP和Modbus RTU的通信格式:

差别一是:ModbusRTU最后带两个字节的CRC校验,而ModbusTCP没有;
差别二是:ModbusTCP增加一个7个字节的MBAP的报文头

3.4.存储区数据结构如下:

线圈:1位 = 1/8字节
寄存器:16位 = 2字节

3.5.根据西门子说明可知一次读取数据最大个数如下:

线圈:2000个
离散寄存器:2000个
保持寄存器:125个
输入寄存器:125个

4.服务端配置

4.1.设置DB区

一种基于QT5.12+VS2015的ModbusTcp客户端轮询方法
一种基于QT5.12+VS2015的ModbusTcp客户端轮询方法

4.2.服务端模块

一种基于QT5.12+VS2015的ModbusTcp客户端轮询方法
一种基于QT5.12+VS2015的ModbusTcp客户端轮询方法开通4个数据储存区分别对应服务端01、02、03、04功能码,对应客户端线圈、离散输入、保持寄存器、输入寄存器,每个数据储存区分配500个数据长度

4.3.SCL赋值

“离散输入10001”.“100”[01] := (状态地址);
“输入继存器30001”.“300”[01] := (状态参数地址);
(功能线圈地址) := “线圈00001”.“000”[01] ;
(功能参数地址):= “保持继存器40001”.“400”[01];

4.4.其他设置

IP、Port、设备号、设备标识文章来源地址https://www.toymoban.com/news/detail-479865.html

5.基于QT的ModbusTCP

5.1.模块设计

/*************************************************************************************************************************************************
**Copyright(C), 2020-2025, bjtds.
**Version:2.0
**Author: dz
**Date:2021.12.27
**Description:
**Others:                          "CModbusTcpClient"
                              ____________________________
              Connect_Device->|REQ          |        DONE|->Done
           Disconnect_Device->|DISCONNECT   |       ERROR|->Error
                  Read/Write->|MB_MODE      |      STATUS|->status
                        addr->|MB_DATA_ADDR |            |
                        size->|MB_DATA_LEN  |            |
                      value ->|MB_DATA_PTR  |            |
                  ip,port,id->|CONNECT      |            |
                              ----------------------------
*************************************************************************************************************************************************/

5.2.Public_Header.h

#pragma once
/*************************************************************************************************************************************************
**Function:RGV功能映射
*************************************************************************************************************************************************/
#define RGV_Fuction_0      0//通信控制(线圈)                (离散:为1时远程控制,PLC端无控制))
#define RGV_Fuction_7      7//主动力位置清零(线圈,工控机立即复位)(离散)
#define RGV_Fuction_8      8//主动力故障复位(线圈,工控机立即复位)(离散)
#define RGV_Fuction_9      9//主动力手动左行(线圈,点控)          (离散:为1运行中)
#define RGV_Fuction_10     10//主动力手动右行(线圈,点控)         (离散:为1运行中)
#define RGV_Fuction_11     11//正向连续运行(线圈,工控机立即复位) (离散:为1运行中)
#define RGV_Fuction_12     12//返向连续运行(线圈,工控机立即复位) (离散:为1运行中)
#define RGV_Fuction_13     13//返向连续运行再启动(线圈,工控机立即复位)(离散:为1运行中)
#define RGV_Fuction_14     14//急停(线圈,工控机立即复位)(离散)
#define RGV_Fuction_15     15//左机器人开机(线圈,工控机立即复位)(离散:为1完成开机)
#define RGV_Fuction_16     16//左机器人关机(线圈,工控机立即复位)(离散:为1完成关机)
#define RGV_Fuction_17     17//右机器人开机(线圈,工控机立即复位)(离散:为1完成开机)
#define RGV_Fuction_18     18//右机器人关机(线圈,工控机立即复位)(离散:为1完成关机)
#define RGV_Fuction_19     19//上电(线圈,工控机立即复位)        (离散:为1所有设备上电处于待机状态)
#define RGV_Fuction_20     20//充电回原点(线圈,工控机立即复位)  
#define RGV_Fuction_21     21//风刀(线圈,工控机立即复位)  
#define RGV_Fuction_22     22//清扫电机(线圈,工控机立即复位)  
#define RGV_Fuction_24     24//轴1移动(线圈,工控机立即复位)(离散:为为1移动中)
#define RGV_Fuction_25     25//轴2移动(线圈,工控机立即复位)(离散:为1移动中)
#define RGV_Fuction_26     26//开始充电(线圈,工控机立即复位)(离散:为1时远程控制,PLC端无控制)
#define RGV_Fuction_27     27//结束充电(线圈,工控机立即复位)(离散:为1时远程控制,PLC端无控制)
#define RGV_Date_0     0//左升降台速度
#define RGV_Date_1     2//左升降台位置
#define RGV_Date_2     4//右升降台速度
#define RGV_Date_3     6//右升降台位置
#define RGV_Date_4     8//轴1移动距离
#define RGV_Date_5     9//轴2移动距离
***************************************************************
**Function:包含目录
*************************************************************************************************************************************************/
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <SDKDDKVer.h>
#include <Windows.h>
using namespace std;

#include <QMap>
#include <QDir>
#include <QFile>
#include <Qbrush>
#include <QDebug>
#include <QTimer>
#include <QWidget>
#include <QObject>
#include <QThread>
#include <QVector>
#include <Qpainter>
#include <QtCharts>
#include <QVariant>
#include <QDateTime>
#include <QKeyEvent>
#include <QJsonValue>
#include <QByteArray>
#include <QJsonArray>
#include <QEventLoop>
#include <QTcpServer>
#include <QTcpSocket>
#include <QUdpSocket>
#include <QMainWindow>
#include <QJsonObject>
#include <QPolarChart>
#include <QMessageBox>
#include <QPainterPath>
#include <QHostAddress>
#include <QApplication>
#include <QJsonDocument>
#include <QstackedWidget>
#include <QScatterSeries>
#include <QAbstractSocket>
#include <QModbusDataUnit>
#include <QConicalGradient>
#include <QModbusTcpClient>

5.3.RGV_Client.h

在这里插入代码片
#include "Variable.h"
#include "Public_Header.h"

class c_RGV_Client : public QObject
{
    Q_OBJECT
public:
    explicit c_RGV_Client(QObject *parent = nullptr);
	virtual ~c_RGV_Client();

signals:
    void Connect_Done();//连接到服务器
    void Disconnect_Done();//断开连接
    void Read_Coils_Done(QJsonObject value);//读线圈完成
    void Read_DiscreteInputs_Done(QJsonObject value);//读离散输入完成
    void Read_InputRegisters_Done(QJsonObject value);//读输入寄存器完成
    void Read_HoldingRegisters_Done(QJsonObject value);//读保持寄存器完成
    void Write_Coils_Done(); //写线圈完成
    void Write_HoldingRegisters_Done();//写保持寄存器完成
    void Read_Coils_Error();//读线圈错误
    void Read_DiscreteInputs_Error();//读离散输入错误
    void Read_InputRegisters_Error();//读输入寄存器错误
    void Read_HoldingRegisters_Error();//读保持寄存器错误
    void Write_Coils_Error(); //写线圈完成
    void Write_HoldingRegisters_Error();//写保持寄存器错误
    void Status(int state);//通讯状态

public slots:
    void Init();//子线程初始化
    void Connect_Device(QString ip, int port);//连接到服务器
    void Disconnect_Device();//断开连接
    void Read_Coils(int addr, int size);//读线圈
    void Read_DiscreteInputs(int addr, int size);//读离散输入
    void Read_InputRegisters(int addr, int size);//读输入寄存器
    void Read_HoldingRegisters(int addr, int size);//读保持寄存器
    void Write_Coils(int addr, QJsonObject value, int size); //写线圈
    void Write_HoldingRegisters(int addr, QJsonObject value, int size);//写保持寄存器

private slots:
    void State_Changed();//状态改变
    void Read_Ready_Coils();//准备读线圈
    void Read_Ready_DiscreteInputs();//准备散输入完成
    void Read_Ready_InputRegisters();//准备输入寄存器错误
    void Read_Ready_HoldingRegisters();//准备寄存器错误

private:
    QModbusTcpClient *m_ModbusDevice;
	QJsonObject m_Coils;//数据缓存区间
	QJsonObject m_DiscreteInputs;//数据缓存区间
	QJsonObject m_InputRegisters;//数据缓存区间
	QJsonObject m_HoldingRegisters;//数据缓存区间
};

5.4.RGV_Client.cpp

#pragma execution_character_set("utf-8")
#include "RGV_Client.h"
/*************************************************************************************************************************************************
**Function:    构造函数
**Description: 初始化成员变量
**Input:       无输入
**Output:      无输出
**Return:      无返回
**Others:      构造函数初始化在主线程实例化中完成,故在子线程中运行时,成员函数的初始化不能在构造函数中完成
*************************************************************************************************************************************************/
c_RGV_Client::c_RGV_Client(QObject *parent) : QObject(parent)
{

}
/*************************************************************************************************************************************************
**Function:    析构函数
**Description: 析构成员变量
**Input:       无输入
**Output:      无输出
**Return:      无返回
**Others:      析构成员变量后,再次操作时需要重新实例化
*************************************************************************************************************************************************/
c_RGV_Client::~c_RGV_Client()
{
	m_ModbusDevice->deleteLater();
}
/*************************************************************************************************************************************************
**Function:    初始化函数
**Description: 线程的构造函数
**Input:       无输入
**Output:      无输出
**Return:      无返回
**Others:
*************************************************************************************************************************************************/
void c_RGV_Client::Init()
{
    //对象实列化
    m_ModbusDevice = new QModbusTcpClient;
    //状态改变
    QObject::connect(m_ModbusDevice, &QModbusTcpClient::stateChanged, this, &c_RGV_Client::State_Changed);
    //错误诊断
    QObject::connect(m_ModbusDevice, &QModbusTcpClient::errorOccurred, this, &c_RGV_Client::Status);
}
/*************************************************************************************************************************************************
**Function:    Connect_Device()
**Description: 连接modbustcp服务器
**Input:       -> ip
               -> port
**Output:      onStateChanged -> connectDone    连接成功
                              -> disconnectDone 断开成功
               status -> 0 已连接
                      -> 1 读取操作期间发生错误。
                      -> 2 写入操作期间发生错误。
                      -> 3 尝试打开后端时出错。
                      -> 4 尝试设置配置参数时出错。
                      -> 5 I/O期间发生超时。I/O操作未在给定的时间范围内完成。
                      -> 6 发生Modbus特定协议错误。
                      -> 7 由于设备断开连接,回复被中止。
                      -> 8 发生未知错误
                      -> 9 设备已断开连接。
                      ->10 正在连接设备。
                      ->11 设备正在关闭
**Return:      无返回
**Others:      二次调用时,如果已连接,则会先断开原来的连接
*************************************************************************************************************************************************/
void c_RGV_Client::Connect_Device(QString ip, int port)
{
    //如果已连接,则返回
    if (m_ModbusDevice->state() == QModbusDevice::ConnectedState)
    {
        return;
    }
    //配置modbus tcp的连接参数 IP + Port
    m_ModbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, ip);
    m_ModbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, port);
    //再设置从机无响应时的动作
    m_ModbusDevice->setTimeout(1000);//从设备回复信息的超时时间
    m_ModbusDevice->setNumberOfRetries(2);//重复发送次数
    m_ModbusDevice->connectDevice();
}
/*************************************************************************************************************************************************
**Function:    Disconnect_Device()
**Description: 断开modbustcp服务器
**Input:       无输入
**Output:      onStateChanged、status
**Return:      无返回
**Others:      如果未连接,则会直接返回
*************************************************************************************************************************************************/
void c_RGV_Client::Disconnect_Device()
{
    if ((!m_ModbusDevice) || (m_ModbusDevice->state() != QModbusDevice::ConnectedState))
    {
        return;//如果RGV没有连接则提前退出
    }
    m_ModbusDevice->disconnectDevice();
}
/*************************************************************************************************************************************************
**Function:    readCoils(ModbusTcpDataBlock dataBlock)
**Description: 读线圈寄存器(读写,一般为继电器的控制)
**Input:       QJsonObject dataBlock -> readCoilsAddr
                                     -> readCoilsSize
                                     -> id
**Output:      status、readCoilsError、readReadyCoils
**Return:      无返回
**Others:      采用的是基于ModbusReply的Finished信号,做异步处理
*************************************************************************************************************************************************/
void c_RGV_Client::Read_Coils(int addr, int size)
{
    if ((!m_ModbusDevice) || (m_ModbusDevice->state() != QModbusDevice::ConnectedState))
    {
        return;//如果RGV没有连接则提前退出
    }
    if(size == 0)
    {
        emit Read_Coils_Error();
        return;
    }
    QModbusDataUnit ReadUnit(QModbusDataUnit::Coils, addr, size);
    auto *reply = m_ModbusDevice->sendReadRequest(ReadUnit, 1);
    if(reply)
    {
        if (!reply->isFinished())
        {
          QObject::connect(reply, &QModbusReply::finished, this, &c_RGV_Client::Read_Ready_Coils);
        }
        else
        {
            reply->deleteLater();
            emit Read_Coils_Error();
            return;
        }
    }
    else
    {
        reply->deleteLater();
        emit Read_Coils_Error();;
        return;
    }
}
/*************************************************************************************************************************************************
**Function:    readDiscreteInputs(QJsonObject dataBlock)
**Description: 读离散输入寄存器(只读,通常为开关量输入)
**Input:       QJsonObject dataBlock -> readDiscreteInputsAddr
                                     -> readDiscreteInputsSize
                                     -> id
**Output:      status、readDiscreteInputsError、readReadyDiscreteInputs
**Return:      无返回
**Others:      采用的是基于ModbusReply的Finished信号,做异步处理
*************************************************************************************************************************************************/
void c_RGV_Client::Read_DiscreteInputs(int addr, int size)
{
    if ((!m_ModbusDevice) || (m_ModbusDevice->state() != QModbusDevice::ConnectedState))
    {
        return;//如果RGV没有连接则提前退出
    }
    if(size == 0)
    {
        emit Read_DiscreteInputs_Error();
        return;
    }
    QModbusDataUnit ReadUnit(QModbusDataUnit::DiscreteInputs, addr, size);
    auto *reply = m_ModbusDevice->sendReadRequest(ReadUnit, 1);
    if(reply)
    {
        if (!reply->isFinished())
        {
          QObject::connect(reply, &QModbusReply::finished, this, &c_RGV_Client::Read_Ready_DiscreteInputs);
        }
        else
        {
            reply->deleteLater();
            emit Read_DiscreteInputs_Error();
            return;
        }
    }
    else
    {
        reply->deleteLater();
        emit Read_DiscreteInputs_Error();
        return;
    }
}
/*************************************************************************************************************************************************
**Function:    readInputRegisters(ModbusTcpDataBlock dataBlock)
**Description: 读输入寄存器(只读,一般为模拟量输入)
**Input:       QJsonObject dataBlock -> readInputRegistersAddr
                                     -> readInputRegistersSize
                                     -> id
**Output:      status、readInputRegistersError、readReadyInputRegisters
**Return:      无返回
**Others:      采用的是基于ModbusReply的Finished信号,做异步处理
*************************************************************************************************************************************************/
void c_RGV_Client::Read_InputRegisters(int addr, int size)
{
    if ((!m_ModbusDevice) || (m_ModbusDevice->state() != QModbusDevice::ConnectedState))
    {
        return;//如果RGV没有连接则提前退出
    }
    if(size == 0)
    {
        emit Read_InputRegisters_Error();
        return;
    }
    QModbusDataUnit ReadUnit(QModbusDataUnit::InputRegisters, addr, size);
    auto *reply = m_ModbusDevice->sendReadRequest(ReadUnit, 1);
    if(reply)
    {
        if (!reply->isFinished())
        {
          QObject::connect(reply, &QModbusReply::finished, this, &c_RGV_Client::Read_Ready_InputRegisters);
        }
        else
        {
            reply->deleteLater();
            emit Read_InputRegisters_Error();
            return;
        }
    }
    else
    {
        reply->deleteLater();
        emit Read_InputRegisters_Error();
        return;
    }
}
/*************************************************************************************************************************************************
**Function:    readHoldingRegisters(ModbusTcpDataBlock dataBlock)
**Description: 读保持寄存器(读写,一般状态参数控制)
**Input:       QJsonObject dataBlock -> readHoldingRegistersAddr
                                     -> readHoldingRegistersSize
                                     -> id
**Output:      status、readHoldingRegistersError、readReadyHoldingRegisters
**Return:      无返回
**Others:      采用的是基于ModbusReply的Finished信号,做异步处理
*************************************************************************************************************************************************/
void c_RGV_Client::Read_HoldingRegisters(int addr, int size)
{
    if ((!m_ModbusDevice) || (m_ModbusDevice->state() != QModbusDevice::ConnectedState))
    {
        return;//如果RGV没有连接则提前退出
    }
    if(size == 0)
    {
        emit Read_HoldingRegisters_Error();
        return;
    }
    QModbusDataUnit ReadUnit(QModbusDataUnit::HoldingRegisters, addr, size);
    auto *reply = m_ModbusDevice->sendReadRequest(ReadUnit, 1);
    if(reply)
    {
        if (!reply->isFinished())
        {
          QObject::connect(reply, &QModbusReply::finished, this, &c_RGV_Client::Read_Ready_HoldingRegisters);
        }
        else
        {
            reply->deleteLater();
            emit Read_HoldingRegisters_Error();
            return;
        }
    }
    else
    {
        reply->deleteLater();
        emit Read_HoldingRegisters_Error();
        return;
    }
}
/*************************************************************************************************************************************************
**Function:    writeCoils(int addr, QJsonObject value, quint16 size)
**Description: 写线圈寄存器(读写,一般为继电器的控制)
**Input:       ->addr 地址
               ->value 值
               ->size 个数
**Output:      status、writeCoilsError、writeCoilsDone
**Return:      无返回
**Others:      采用的是基于ModbusReply的Finished信号,做异步处理
*************************************************************************************************************************************************/
void c_RGV_Client::Write_Coils(int addr, QJsonObject value, int size)
{
    if ((!m_ModbusDevice) || (m_ModbusDevice->state() != QModbusDevice::ConnectedState))
    {
        return;//如果RGV没有连接则提前退出
    }
    if(size <= 0)
    {
        emit Write_HoldingRegisters_Error();
        return;
    }
    //写,地址,写多少位
    QModbusDataUnit writeUnit(QModbusDataUnit::Coils, addr, size);
    //该位置,数据
    for(int i=0; i<size; i++)
    {
        QString address = QString::number(addr + i);//当前数据地址
        quint16 data = quint16(value.value(address).toInt());
        writeUnit.setValue(i, data);
    }
    //发送校验 1 代表设备地址
    if(auto *reply = m_ModbusDevice->sendWriteRequest(writeUnit, 1))
    {
        if (!reply->isFinished())
        {
            //如果接收到响应信息
            QObject::connect(reply, &QModbusReply::finished, this, [&, reply]()
            {
                if (reply->error() == QModbusDevice::NoError)
                {
                    //接收到的响应信无错误,发送完成信号
                    emit Write_Coils_Done();
                }
                else
                {
                    reply->deleteLater();
                    emit Write_Coils_Error();
                    return;
                }
                reply->deleteLater();
            });
        }
        else
        {
            reply->deleteLater();
            emit Write_Coils_Error();
            return;
        }
    }
}
/*************************************************************************************************************************************************
**Function:    writeHoldingRegisters(int addr, QJsonObject value, quint16 size)
**Description: 写保持寄存器(读写,一般状态参数控制)
**Input:       ->addr 地址
               ->value 值
               ->size 个数
**Output:      status、writeHoldingRegistersError、writeHoldingRegistersDone
**Return:      无返回
**Others:      采用的是基于ModbusReply的Finished信号,做异步处理
*************************************************************************************************************************************************/
void c_RGV_Client::Write_HoldingRegisters(int addr, QJsonObject value, int size)
{
    if ((!m_ModbusDevice) || (m_ModbusDevice->state() != QModbusDevice::ConnectedState))
    {
        return;//如果RGV没有连接则提前退出
    }
    if(size <= 0)
    {
        emit Write_HoldingRegisters_Error();
        return;
    }

    //写,地址,写多少位
    QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, addr, size);
    //该位置,数据
    for(int i=0; i<size; i++)
    {
        QString address = QString::number(addr + i);//当前数据地址
        quint16 data = quint16(value.value(address).toInt());
        writeUnit.setValue(i, data);
    }
    //发送校验 1 代表设备地址
    if(auto *reply = m_ModbusDevice->sendWriteRequest(writeUnit, 1))
    {
        if (!reply->isFinished())
        {
            //如果接收到响应信息
            QObject::connect(reply, &QModbusReply::finished, this, [&, reply]()
            {
                if (reply->error() == QModbusDevice::NoError)
                {
                    //接收到的响应信无错误,发送完成信号
                    emit Write_HoldingRegisters_Done();
                }
                else
                {
                    reply->deleteLater();
                    emit Write_HoldingRegisters_Error();
                    return;
                }
                reply->deleteLater();
            });
        }
        else
        {
            reply->deleteLater();
            emit Write_HoldingRegisters_Error();
            return;
        }
    }
}
/*************************************************************************************************************************************************
**Function:    onStateChanged()
**Description: modbustcp连接状态改变
**Input:       无输入
**Output:      connectDone、disconnectDone、status
**Return:      无返回
**Others:      已连接、连接中、已断开、断开中
*************************************************************************************************************************************************/
void c_RGV_Client::State_Changed()
{
    if(m_ModbusDevice->state() == QModbusDevice::ConnectedState)
    {
        emit Status(0);
        emit Connect_Done();
    }
    if(m_ModbusDevice->state() == QModbusDevice::UnconnectedState)
    {
        emit Status(9);
        emit Disconnect_Done();
    }
    if(m_ModbusDevice->state() == QModbusDevice::ConnectingState)
    {
        emit Status(10);
    }
    if(m_ModbusDevice->state() == QModbusDevice::ClosingState)
    {
        emit Status(11);
    }
}
/*************************************************************************************************************************************************
**Function:    readReadyCoils()
**Description: 读线圈寄存器(读写,一般为继电器的控制)
**Input:       readCoils
**Output:      QJsonObject value -> {"地址":值}
               status、readCoilsError、readCoilsDone
**Return:      无返回
**Others:      采用的是基于ModbusReply的Finished信号,做异步处理
*************************************************************************************************************************************************/
void c_RGV_Client::Read_Ready_Coils()
{
    if ((!m_ModbusDevice) || (m_ModbusDevice->state() != QModbusDevice::ConnectedState))
    {
        return;//如果RGV没有连接则提前退出
    }
    auto *reply = qobject_cast<QModbusReply *>(sender());
    if (!reply)
    {
        reply->deleteLater();
        emit Read_Coils_Error();
        return;
    }
    //如果校验无误
    if (reply->error() == QModbusDevice::NoError)
    {
        const QModbusDataUnit writeUnit = reply->result();//获取结果
        int size = int(writeUnit.valueCount());//数据长度
        int addr = writeUnit.startAddress();//数据起始地址
        for(int i=0; i<size; i++)
        {
            QString add = QString::number(addr + i);//当前数据地址
            int data = int(writeUnit.value(i));//当前数据值
            m_Coils.insert(add, data);//记录数据
        }
    }
    //如果校验有误
    else
    {
        reply->deleteLater();
        emit Read_Coils_Error();
        return;
    }
    reply->deleteLater(); //删除答复
    //发送信号
    emit Read_Coils_Done(m_Coils);//输出数据
}
/*************************************************************************************************************************************************
**Function:    readReadyDiscreteInputs()
**Description: 读离散输入寄存器(只读,通常为开关量输入)
**Input:       readDiscreteInputs
**Output:      QJsonObject value -> {"地址":值}
               status、readDiscreteInputsError、readDiscreteInputsDone
**Return:      无返回
**Others:      采用的是基于ModbusReply的Finished信号,做异步处理
*************************************************************************************************************************************************/
void c_RGV_Client::Read_Ready_DiscreteInputs()
{
    if ((!m_ModbusDevice) || (m_ModbusDevice->state() != QModbusDevice::ConnectedState))
    {
        return;//如果RGV没有连接则提前退出
    }
    auto *reply = qobject_cast<QModbusReply *>(sender());
    if (!reply)
    {
        reply->deleteLater();
        emit Read_DiscreteInputs_Error();
        return;
    }
    //如果校验无误
    if (reply->error() == QModbusDevice::NoError)
    {
        const QModbusDataUnit readUnit = reply->result();//获取结果
        int size = readUnit.valueCount();//数据长度
        int addr = readUnit.startAddress();//数据起始地址
        for(int i=0; i<size; i++)
        {
            QString add = QString::number(addr + i);//当前数据地址
            int data = int(readUnit.value(i));//当前数据值
            m_DiscreteInputs.insert(add, data);//记录数据
        }
    }
    //如果校验有误
    else
    {
        reply->deleteLater();
        emit Read_DiscreteInputs_Error();
        return;
    }
    reply->deleteLater(); //删除答复
    //发送信号
    emit Read_DiscreteInputs_Done(m_DiscreteInputs);//输出数据
}
/*************************************************************************************************************************************************
**Function:    readReadyInputRegisters()
**Description: 读输入寄存器(只读,一般为模拟量输入)
**Input:       readInputRegisters
**Output:      QJsonObject value -> {"地址":值}
               status、readInputRegistersError、readInputRegistersDone
**Return:      无返回
**Others:      采用的是基于ModbusReply的Finished信号,做异步处理
*************************************************************************************************************************************************/
void c_RGV_Client::Read_Ready_InputRegisters()
{
    if ((!m_ModbusDevice) || (m_ModbusDevice->state() != QModbusDevice::ConnectedState))
    {
        return;//如果RGV没有连接则提前退出
    }
    auto *reply = qobject_cast<QModbusReply *>(sender());
    if (!reply)
    {
        reply->deleteLater();
        emit Read_InputRegisters_Error();
        return;
    }
    //如果校验无误
    if (reply->error() == QModbusDevice::NoError)
    {
        const QModbusDataUnit readUnit = reply->result();//获取结果
        int size = readUnit.valueCount();//数据长度
        int addr = readUnit.startAddress();//数据起始地址
        for(int i=0; i<size; i++)
        {
            QString add = QString::number(addr + i);//当前数据地址
            int data = int(readUnit.value(i));//当前数据值
            m_InputRegisters.insert(add, data);//记录数据
        }
    }
    //如果校验有误
    else
    {
        reply->deleteLater();
        emit Read_InputRegisters_Error();
        return;
    }
    reply->deleteLater(); //删除答复
    //发送信号
    emit Read_InputRegisters_Done(m_InputRegisters);//输出数据
}
/*************************************************************************************************************************************************
**Function:    readReadyHoldingRegisters()
**Description: 读保持寄存器(读写,一般状态参数控制)
**Input:       readHoldingRegisters
**Output:      QJsonObject value -> {"地址":值}
               status、readHoldingRegistersError、readHoldingRegistersDone
**Return:      无返回
**Others:      采用的是基于ModbusReply的Finished信号,做异步处理
*************************************************************************************************************************************************/
void c_RGV_Client::Read_Ready_HoldingRegisters()
{
    if ((!m_ModbusDevice) || (m_ModbusDevice->state() != QModbusDevice::ConnectedState))
    {
        return;//如果RGV没有连接则提前退出
    }
    auto *reply = qobject_cast<QModbusReply *>(sender());
    if (!reply)
    {
        reply->deleteLater();
        emit Read_HoldingRegisters_Error();
        return;
    }
    //如果校验无误
    if (reply->error() == QModbusDevice::NoError)
    {
        const QModbusDataUnit readUnit = reply->result();//获取结果
        int size = readUnit.valueCount();//数据长度
        int addr = readUnit.startAddress();//数据起始地址
        for(int i=0; i<size; i++)
        {
            QString add = QString::number(addr + i);//当前数据地址
            int data = int(readUnit.value(i));//当前数据值
            m_HoldingRegisters.insert(add, data);//记录数据
        }
    }
    //如果校验有误
    else
    {
        reply->deleteLater();
        emit Read_HoldingRegisters_Error();
        return;
    }
    reply->deleteLater(); //删除答复
    //发送信号
    emit Read_HoldingRegisters_Done(m_HoldingRegisters);//输出数据
}

5.5.在线程中实现轮询RGV_Remote.h

#pragma once
#include "RGV_Client.h"

class c_RGV_Remote : public QObject
{
	Q_OBJECT
public:
	explicit c_RGV_Remote(QObject *parent = nullptr);
	virtual ~c_RGV_Remote();
	QThread *m_RGV_Remote_Thread;
	c_RGV_Client *m_RGV_Remote;

	public slots:
	void Init();
	void Connect();
	void Fuction_0_Set();//通信控制(线圈)
	void Fuction_0_Reset();//通信控制(线圈)
	void Fuction_7();//主动力位置清零(线圈,工控机立即复位)
	void Fuction_8();//主动力故障复位(线圈,工控机立即复位)
	void Fuction_9_Set();//主动力手动左行(线圈,点控)
	void Fuction_9_Reset();//主动力手动左行(线圈,点控)
	void Fuction_10_Set();//主动力手动右行(线圈,点控) 
	void Fuction_10_Reset();//主动力手动右行(线圈,点控) 
	void Fuction_11();//正向连续运行(线圈,工控机立即复位)
	void Fuction_12();//返向连续运行(线圈,工控机立即复位)
	void Fuction_13();//返向连续运行再启动(线圈,工控机立即复位)
	void Fuction_14();//急停(线圈,工控机立即复位)(离散)
	void Fuction_15();//左机器人开机(线圈,工控机立即复位)
	void Fuction_16();//左机器人关机(线圈,工控机立即复位)
	void Fuction_17();//右机器人开机(线圈,工控机立即复位)
	void Fuction_18();//右机器人关机(线圈,工控机立即复位)
	void Fuction_19_Set();//上电(线圈,点控)
	void Fuction_19_Reset();//上电(线圈,点控)
	void Fuction_20();//充电回原点(线圈,工控机立即复位)
	void Fuction_21_Set();//风刀电机开
	void Fuction_21_Reset();//风刀电机关
	void Fuction_22_Set();//清扫电机开
	void Fuction_22_Reset();//清扫电机关
	void Fuction_24();//轴1移动(线圈,工控机立即复位)
	void Fuction_25();//轴2移动(线圈,工控机立即复位)
	void Fuction_26();//开始充电(线圈,工控机立即复位)
	void Fuction_27();//结束充电(线圈,工控机立即复位)
	void Date_0();//左升降台速度
	void Date_1();//左升降台位置
	void Date_2();//右升降台速度
	void Date_3();//右升降台位置
	void Date_4();//轴1移动距离
	void Date_5();//轴2移动距离

signals:
	void Connect_Device(QString ip, int port);//连接到服务器
	void Disconnect_Device();//断开连接
	void Write_RGV_Remote_State(QJsonObject db);//写状态
	void RGV_Remote_Read_Ready();//写入缓存区
	void Set_Working();//工作状态
	void Set_Default();//非工作状态
	void setEnabled(bool ready);//写消息状态
	void Status(QString status);//监视器状态
	void Write_Coils(int addr, QJsonObject value, int size);//写线圈
	void Write_HoldingRegisters(int addr, QJsonObject value, int size);//写输入寄存器
	void Read_Coils(int addr, int size);//读线圈
	void Read_HoldingRegisters(int addr, int size);//读输入寄存器
	void Read_DiscreteInputs(int addr, int size); //读离散输入
	void Read_InputRegisters(int addr, int size);//读输入寄存器

private:
	QJsonObject m_RGV_Remote_DB;
	QJsonObject m_RGV_Remote_State;
	QJsonObject m_Coils;
	QJsonObject m_DiscreteInputs;
	QJsonObject m_InputRegisters;
	QJsonObject m_HoldingRegisters;

	bool m_RGV_Fuction_0_Set = false;//通信控制(线圈)
	bool m_RGV_Fuction_0_Reset = false;//通信控制(线圈)
	bool m_RGV_Fuction_7 = false;//主动力位置清零(线圈,工控机立即复位)
	bool m_RGV_Fuction_8 = false;//主动力故障复位(线圈,工控机立即复位)
	bool m_RGV_Fuction_9_Set = false;//主动力手动左行(线圈,点控)
	bool m_RGV_Fuction_9_Reset = false;//主动力手动左行(线圈,点控)
	bool m_RGV_Fuction_10_Set = false;//主动力手动右行(线圈,点控)
	bool m_RGV_Fuction_10_Reset = false;//主动力手动右行(线圈,点控)
	bool m_RGV_Fuction_11 = false;//正向连续运行(线圈,工控机立即复位)
	bool m_RGV_Fuction_12 = false;//返向连续运行(线圈,工控机立即复位)
	bool m_RGV_Fuction_13 = false;//返向连续运行再启动(线圈,工控机立即复位)
	bool m_RGV_Fuction_14 = false;//急停(线圈,工控机立即复位)
	bool m_RGV_Fuction_15 = false;//左机器人开机(线圈,工控机立即复位)
	bool m_RGV_Fuction_16 = false;//左机器人关机(线圈,工控机立即复位)
	bool m_RGV_Fuction_17 = false;//右机器人开机(线圈,工控机立即复位)
	bool m_RGV_Fuction_18 = false;//右机器人关机(线圈,工控机立即复位)
	bool m_RGV_Fuction_19_Set = false;//上电(线圈,点控)
	bool m_RGV_Fuction_19_Reset = false;//上电(线圈,点控)
	bool m_RGV_Fuction_20 = false;//充电回原点(线圈,工控机立即复位)
	bool m_RGV_Fuction_21_Set = false;//风刀电机开
	bool m_RGV_Fuction_21_Reset = false;//风刀电机关
	bool m_RGV_Fuction_22_Set = false;//清扫电机开
	bool m_RGV_Fuction_22_Reset = false;//清扫电机关
	bool m_RGV_Fuction_24 = false;//轴1移动(线圈,工控机立即复位)
	bool m_RGV_Fuction_25 = false;//轴2移动(线圈,工控机立即复位)
	bool m_RGV_Fuction_26 = false;//开始充电(线圈,工控机立即复位)
	bool m_RGV_Fuction_27 = false;//结束充电(线圈,工控机立即复位)
	bool m_RGV_Date_0 = false;//左升降台速度
	bool m_RGV_Date_1 = false;//左升降台位置
	bool m_RGV_Date_2 = false;//右升降台速度
	bool m_RGV_Date_3 = false;//右升降台位置
	bool m_RGV_Date_4 = false;//轴1移动距离
	bool m_RGV_Date_5 = false;//轴2移动距离
	int m_DiscreteInputs_Addr;//离散起始地址
	int m_DiscreteInputs_Size;//离散数据长度
	int m_Coils_Addr;//线圈起始地址
	int m_Coils_Size;//线圈数据长度
	int m_InputRegisters_Addr;//输入起始地址
	int m_InputRegisters_Size;//输入数据长度
	int m_HoldingRegisters_Addr;//保持起始地址
	int m_HoldingRegisters_Size;//保持数据长度
	int m_Read_Coils_Count;//读线圈长度
	int m_Read_DiscreteInputs_Count;//读离散次数
	int m_Read_HoldingRegisters_Count;//读保持次数
	int m_Read_InputRegisters_Count;//读输入次数
	int m_Carbox_Number;//车厢号
	int m_Bogie_Number;//转向架号
	int m_Axis_Number;//轮轴号

	private slots:
	void Connect_Done();
	void Disconnect_Done();
	void Write_Coils_Done();//读线圈
	void Write_HoldingRegisters_Done();//读保持寄存器
	void Read_Coils_Done(QJsonObject value);//读线圈
	void Read_HoldingRegisters_Done(QJsonObject value);//读输入寄存器
	void Read_DiscreteInputs_Done(QJsonObject value);//读离散输入
	void Read_InputRegisters_Done(QJsonObject value);//读输入寄存器
	void Write_RGV_State();
	bool Set_Coils(int addr);
	bool Reset_Coils(int addr);
	bool Set_HoldingRegisters_16(int addr, int value);
	bool Set_HoldingRegisters_32(int addr, int low, int high);
	bool If_Write_Coils();
	bool If_Write_HoldingRegisters();
	bool If_Coils_Set();
};

5.6.RGV_Remote.cpp

#pragma execution_character_set("utf-8")
#include "RGV_Remote.h"
/*************************************************************************************************************************************************
**Function:构造函数
*************************************************************************************************************************************************/
c_RGV_Remote::c_RGV_Remote(QObject *parent) : QObject(parent)
{

}
/*************************************************************************************************************************************************
**Function:析构函数
*************************************************************************************************************************************************/
c_RGV_Remote::~c_RGV_Remote()
{
	//线程中断
	m_RGV_Remote_Thread->requestInterruption();
	//线程退出
	m_RGV_Remote_Thread->quit();
	//线程等待
	m_RGV_Remote_Thread->wait();
}
/*************************************************************************************************************************************************
**Function:初始化函数
*************************************************************************************************************************************************/
void c_RGV_Remote::Init()
{
	//实例化
	m_RGV_Remote = new c_RGV_Client;
	m_RGV_Remote_Thread = new QThread;
	m_RGV_Remote->moveToThread(m_RGV_Remote_Thread);
	//初始化数据交换层
	QObject::connect(m_RGV_Remote_Thread, &QThread::started, m_RGV_Remote, &c_RGV_Client::Init);
	QObject::connect(m_RGV_Remote_Thread, &QThread::finished, m_RGV_Remote, &c_RGV_Client::deleteLater);
	//连接设备
	QObject::connect(this, &c_RGV_Remote::Connect_Device, m_RGV_Remote, &c_RGV_Client::Connect_Device);
	QObject::connect(this, &c_RGV_Remote::Disconnect_Device, m_RGV_Remote, &c_RGV_Client::Disconnect_Device);
	//读数据
	QObject::connect(this, &c_RGV_Remote::Read_Coils, m_RGV_Remote, &c_RGV_Client::Read_Coils);
	QObject::connect(this, &c_RGV_Remote::Read_HoldingRegisters, m_RGV_Remote, &c_RGV_Client::Read_HoldingRegisters);
	QObject::connect(this, &c_RGV_Remote::Read_DiscreteInputs, m_RGV_Remote, &c_RGV_Client::Read_DiscreteInputs);
	QObject::connect(this, &c_RGV_Remote::Read_InputRegisters, m_RGV_Remote, &c_RGV_Client::Read_InputRegisters);
	//写数据
	QObject::connect(this, &c_RGV_Remote::Write_Coils, m_RGV_Remote, &c_RGV_Client::Write_Coils);
	QObject::connect(this, &c_RGV_Remote::Write_HoldingRegisters, m_RGV_Remote, &c_RGV_Client::Write_HoldingRegisters);
	//设备状态改变
	QObject::connect(m_RGV_Remote, &c_RGV_Client::Connect_Done, this, &c_RGV_Remote::Set_Working);
	QObject::connect(m_RGV_Remote, &c_RGV_Client::Disconnect_Done, this, &c_RGV_Remote::Set_Default);
	//键盘按键改变
	QObject::connect(this, &c_RGV_Remote::Set_Working, this, [=] {emit setEnabled(true); });
	QObject::connect(this, &c_RGV_Remote::Set_Default, this, [=] {emit setEnabled(false); });
	//读到消息
	QObject::connect(m_RGV_Remote, &c_RGV_Client::Write_Coils_Done, this, &c_RGV_Remote::Write_Coils_Done);
	QObject::connect(m_RGV_Remote, &c_RGV_Client::Write_HoldingRegisters_Done, this, &c_RGV_Remote::Write_HoldingRegisters_Done);
	QObject::connect(m_RGV_Remote, &c_RGV_Client::Read_Coils_Done, this, &c_RGV_Remote::Read_Coils_Done);
	QObject::connect(m_RGV_Remote, &c_RGV_Client::Read_HoldingRegisters_Done, this, &c_RGV_Remote::Read_HoldingRegisters_Done);
	QObject::connect(m_RGV_Remote, &c_RGV_Client::Read_DiscreteInputs_Done, this, &c_RGV_Remote::Read_DiscreteInputs_Done);
	QObject::connect(m_RGV_Remote, &c_RGV_Client::Read_InputRegisters_Done, this, &c_RGV_Remote::Read_InputRegisters_Done);
	//向状态服务写入状态
	QObject::connect(m_RGV_Remote, &c_RGV_Client::Connect_Done, this, &c_RGV_Remote::Connect_Done);
	QObject::connect(m_RGV_Remote, &c_RGV_Client::Disconnect_Done, this, &c_RGV_Remote::Disconnect_Done);
	//提示信息
	QObject::connect(m_RGV_Remote, &c_RGV_Client::Status, this, [=](int state) {emit Status(c_Variable::Modbus_Status(state)); });
	//启动线程
	m_RGV_Remote_Thread->start();
	emit setEnabled(false);
}
/*************************************************************************************************************************************************
**Function:连接设备
*************************************************************************************************************************************************/
void c_RGV_Remote::Connect()
{
	if (m_RGV_Remote_State.value("Connected").toBool()) { return; }
	QString ip = c_Variable::g_Communicate_DB.value("RGV_Ip").toString();
	int port = c_Variable::g_Communicate_DB.value("RGV_Port").toInt();
	emit Connect_Device(ip, port);
}
/*************************************************************************************************************************************************
**断开连接
************************************************************************************************************************************************/
void c_RGV_Remote::Disconnect_Done()
{
	m_RGV_Remote_State.insert("Connected", false);
	Write_RGV_State();
}
/*************************************************************************************************************************************************
**置位复位赋值
************************************************************************************************************************************************/
bool c_RGV_Remote::Set_Coils(int addr)
{
	m_Coils.insert(QString::number(addr), 1);
	emit Write_Coils(addr, m_Coils, 1);
	return false;
}
bool c_RGV_Remote::Reset_Coils(int addr)
{
	m_Coils.insert(QString::number(addr), 0);
	emit Write_Coils(addr, m_Coils, 1);
	return false;
}
bool c_RGV_Remote::Set_HoldingRegisters_16(int addr, int value)
{
	m_HoldingRegisters.insert(QString::number(addr), value);
	emit Write_HoldingRegisters(addr, m_HoldingRegisters, 1);
	return false;
}
bool c_RGV_Remote::Set_HoldingRegisters_32(int addr, int low, int high)
{
	m_HoldingRegisters.insert(QString::number(addr), low);
	m_HoldingRegisters.insert(QString::number(addr + 1), high);
	emit Write_HoldingRegisters(addr, m_HoldingRegisters, 2);
	return false;
}
void c_RGV_Remote::Write_RGV_State()
{
	QEventLoop *loop = new QEventLoop;
	QObject::connect(this, &c_RGV_Remote::RGV_Remote_Read_Ready, loop, &QEventLoop::quit);
	emit Write_RGV_Remote_State(m_RGV_Remote_State);//发送到缓存区
	loop->exec();
}
/*************************************************************************************************************************************************
**轮询操作
************************************************************************************************************************************************/
//完成连接->读线圈
void c_RGV_Remote::Connect_Done()
{
	m_RGV_Remote_State.insert("Connected", true);
	Write_RGV_State();
	//更新轮询参数
	m_Coils_Addr = c_Variable::g_Communicate_DB.value("Write_Coils_Addr").toInt();
	m_Coils_Size = c_Variable::g_Communicate_DB.value("Write_Coils_Size").toInt();
	m_Read_Coils_Count = 1;
	if (m_Coils_Size > 1000) {
		emit Read_Coils(m_DiscreteInputs_Addr, 1000);
		return;
	}
	emit Read_Coils(m_Coils_Addr, m_Coils_Size);
}
//读线圈完成->写线圈复位
//直到线圈全部复位->读保持存器
void c_RGV_Remote::Read_Coils_Done(QJsonObject value)
{
	m_Coils = value;
	m_RGV_Remote_DB.insert("Coils", value);//保存离散数据
	m_RGV_Remote_State.insert("DB", m_RGV_Remote_DB);//编入通讯协议
	Write_RGV_State();//发送到缓存区
	
	//当前需要读取的线圈起始地址 = 读取次数 * 每次读取长度 (0~999=1000)
	int Read_Coils_Addr = m_Read_Coils_Count * 1000;
	//当前需要读取的线圈数据长度 = 总数据长度(1000) - 当前起始地址(0)
	int Read_Coils_Size = m_Coils_Size - Read_Coils_Addr;
	//如果当前地址 < 总长度 且 还需读取长度大于124 则 从当前地址开始再读124个长度 计数加1 并返回
	if (Read_Coils_Addr < m_Coils_Size && Read_Coils_Size > 1000) {
		emit Read_Coils(Read_Coils_Addr, 1000);
		m_Read_Coils_Count += 1;
		return;
	}
	//如果当前地址 < 总长度 且 还需读取长度小于124 则 从当前地址开始读完剩余数据 并返回
	if (Read_Coils_Addr < m_Coils_Size && Read_Coils_Size < 1000) {
		emit Read_Coils(Read_Coils_Addr, Read_Coils_Size);
		m_Read_Coils_Count += 1;
		return;
	}
	//如果读到需要复位的线圈,进行复位,并返回写线圈完成
	if (If_Coils_Set()) { return; }
	//更新轮询参数
	m_HoldingRegisters_Addr = c_Variable::g_Communicate_DB.value("Write_HoldingRegisters_Addr").toInt();
	m_HoldingRegisters_Size = c_Variable::g_Communicate_DB.value("Write_HoldingRegisters_Size").toInt();
	m_Read_HoldingRegisters_Count = 1;
	if (m_HoldingRegisters_Size > 124) {
		emit Read_HoldingRegisters(m_HoldingRegisters_Addr, 124);
		return;
	}
	emit Read_HoldingRegisters(m_HoldingRegisters_Addr, m_HoldingRegisters_Size);
}
//写线圈完成->读线圈是否写完
void c_RGV_Remote::Write_Coils_Done()
{
	c_Variable::msleep(2);
	//更新轮询参数
	m_Coils_Addr = c_Variable::g_Communicate_DB.value("Write_Coils_Addr").toInt();
	m_Coils_Size = c_Variable::g_Communicate_DB.value("Write_Coils_Size").toInt();
	m_Read_Coils_Count = 1;
	if (m_Coils_Size > 1000) {
		emit Read_Coils(m_DiscreteInputs_Addr, 1000);
		return;
	}
	emit Read_Coils(m_Coils_Addr, m_Coils_Size);
}
//读保持寄存器完成->读离散输入
void c_RGV_Remote::Read_HoldingRegisters_Done(QJsonObject value)
{
	m_HoldingRegisters = value;
	m_RGV_Remote_DB.insert("HoldingRegisters", value);//保存保持数据
	m_RGV_Remote_State.insert("DB", m_RGV_Remote_DB);//编入通讯协议
	Write_RGV_State();//发送到缓存区
	
	//当前需要读取的保持寄存器起始地址 = 读取次数 * 每次读取长度 (0~123=124)
	int Read_HoldingRegisters_Addr = m_Read_HoldingRegisters_Count * 124;
	//当前需要读取的保持寄存器数据长度 = 总数据长度(250) - 当前起始地址(124)
	int Read_HoldingRegisters_Size = m_HoldingRegisters_Size - Read_HoldingRegisters_Addr;
	//如果当前地址 < 总长度 且 还需读取长度大于124 则 从当前地址开始再读124个长度 计数加1 并返回
	if (Read_HoldingRegisters_Addr < m_HoldingRegisters_Size && Read_HoldingRegisters_Size > 124) {
		emit Read_HoldingRegisters(Read_HoldingRegisters_Addr, 124);
		m_Read_HoldingRegisters_Count += 1;
		return;
	}
	//如果当前地址 < 总长度 且 还需读取长度小于124 则 从当前地址开始读完剩余数据 并返回
	if (Read_HoldingRegisters_Addr < m_HoldingRegisters_Size && Read_HoldingRegisters_Size < 124) {
		emit Read_HoldingRegisters(Read_HoldingRegisters_Addr, Read_HoldingRegisters_Size);
		m_Read_HoldingRegisters_Count += 1;
		return;
	}
	//读离散输入更新轮询参数
	m_DiscreteInputs_Addr = c_Variable::g_Communicate_DB.value("Read_DiscreteInputs_Addr").toInt();
	m_DiscreteInputs_Size = c_Variable::g_Communicate_DB.value("Read_DiscreteInputs_Size").toInt();
	m_Read_DiscreteInputs_Count = 1;
	if (m_DiscreteInputs_Size > 1000) {
		emit Read_DiscreteInputs(m_DiscreteInputs_Addr, 1000);
		return;
	}
	emit Read_DiscreteInputs(m_DiscreteInputs_Addr, m_DiscreteInputs_Size);
}
//需要写线圈时:读离散输入完成->写线圈
//不需要写线圈时:读离散输入完成->读输入存器
void c_RGV_Remote::Read_DiscreteInputs_Done(QJsonObject value)
{
	m_DiscreteInputs = value;
	m_RGV_Remote_DB.insert("DiscreteInputs", value);//保存离散数据
	m_RGV_Remote_State.insert("DB", m_RGV_Remote_DB);//编入通讯协议
	Write_RGV_State();//发送到缓存区
	
	//当前需要读取的离散起始地址 = 读取次数 * 每次读取长度 (0~999=1000)
	int Read_DiscreteInputs_Addr = m_Read_DiscreteInputs_Count * 1000;
	//当前需要读取的离散数据长度 = 总数据长度(1000) - 当前起始地址(0)
	int Read_DiscreteInputs_Size = m_DiscreteInputs_Size - Read_DiscreteInputs_Addr;
	//如果当前地址 < 总长度 且 还需读取长度大于124 则 从当前地址开始再读124个长度 计数加1 并返回
	if (Read_DiscreteInputs_Addr < m_DiscreteInputs_Size && Read_DiscreteInputs_Size > 1000) {
		emit Read_DiscreteInputs(Read_DiscreteInputs_Addr, 1000);
		m_Read_DiscreteInputs_Count += 1;
		return;
	}
	//如果当前地址 < 总长度 且 还需读取长度小于124 则 从当前地址开始读完剩余数据 并返回
	if (Read_DiscreteInputs_Addr < m_DiscreteInputs_Size && Read_DiscreteInputs_Size < 1000) {
		emit Read_DiscreteInputs(Read_DiscreteInputs_Addr, Read_DiscreteInputs_Size);
		m_Read_DiscreteInputs_Count += 1;
		return;
	}
	//如果线圈改变则等待线圈写完成后,读线圈
	if (If_Write_Coils()) { return; }
	//如果线圈不改变则不读线圈,直接读输入寄存器,更新轮询参数
	m_InputRegisters_Addr = c_Variable::g_Communicate_DB.value("Read_InputRegisters_Addr").toInt();
	m_InputRegisters_Size = c_Variable::g_Communicate_DB.value("Read_InputRegisters_Size").toInt();
	//如果读取的数据长度大于124则读124个数据,并初始化计数
	m_Read_InputRegisters_Count = 1;
	if (m_InputRegisters_Size > 124) {
		emit Read_InputRegisters(m_InputRegisters_Addr, 124);
		return;
	}
	emit Read_InputRegisters(m_InputRegisters_Addr, m_InputRegisters_Size);
}
//需写保持寄存器:读输入寄存器完成—>写保持寄存器
//无需写保持寄存器:读输入寄存器完成->读离散
void c_RGV_Remote::Read_InputRegisters_Done(QJsonObject value)
{
	m_InputRegisters = value;
	m_RGV_Remote_DB.insert("InputRegisters", value);//保存输入数据
	m_RGV_Remote_State.insert("DB", m_RGV_Remote_DB);//编入通讯协议
	Write_RGV_State();//发送到缓存区
	
	//当前需要读取的输入寄存器起始地址 = 读取次数 * 每次读取长度 (0~123=124)
	int Read_InputRegisters_Addr = m_Read_InputRegisters_Count * 124;
	//当前需要读取的输入寄存器数据长度 = 总数据长度(250) - 当前起始地址(124)
	int Read_InputRegisters_Size = m_InputRegisters_Size - Read_InputRegisters_Addr;
	//如果当前地址 < 总长度 且 还需读取长度大于124 则 从当前地址开始再读124个长度 计数加1 并返回
	if (Read_InputRegisters_Addr < m_InputRegisters_Size && Read_InputRegisters_Size > 124) {
		emit Read_InputRegisters(Read_InputRegisters_Addr, 124);
		m_Read_InputRegisters_Count += 1;
		return;
	}
	//如果当前地址 < 总长度 且 还需读取长度小于124 则 从当前地址开始读完剩余数据 并返回
	if (Read_InputRegisters_Addr < m_InputRegisters_Size && Read_InputRegisters_Size < 124) {
		emit Read_InputRegisters(Read_InputRegisters_Addr, Read_InputRegisters_Size);
		m_Read_InputRegisters_Count += 1;
		return;
	}
	//完成所有输入数据读取后,继续执行如下程序
	//如果保持寄存器改变则等待保持寄存器写完成后,读保持寄存器
	if (If_Write_HoldingRegisters()) { return; }
	//如果保持寄存器没有改变,则直接读离散输入
	//更新轮询参数
	m_DiscreteInputs_Addr = c_Variable::g_Communicate_DB.value("Read_DiscreteInputs_Addr").toInt();
	m_DiscreteInputs_Size = c_Variable::g_Communicate_DB.value("Read_DiscreteInputs_Size").toInt();
	m_Read_DiscreteInputs_Count = 1;
	if (m_DiscreteInputs_Size > 1000) {
		emit Read_DiscreteInputs(m_DiscreteInputs_Addr, 1000);
		return;
	}
	emit Read_DiscreteInputs(m_DiscreteInputs_Addr, m_DiscreteInputs_Size);
}
//写保持寄存器完成->读保持寄存器
void c_RGV_Remote::Write_HoldingRegisters_Done()
{
	c_Variable::msleep(2);
	//更新轮询参数
	m_HoldingRegisters_Addr = c_Variable::g_Communicate_DB.value("Write_HoldingRegisters_Addr").toInt();
	m_HoldingRegisters_Size = c_Variable::g_Communicate_DB.value("Write_HoldingRegisters_Size").toInt();
	m_Read_HoldingRegisters_Count = 1;
	if (m_HoldingRegisters_Size > 124) {
		emit Read_HoldingRegisters(m_HoldingRegisters_Addr, 124);
		return;
	}
	emit Read_HoldingRegisters(m_HoldingRegisters_Addr, m_HoldingRegisters_Size);
}
/*************************************************************************************************************************************************
**线圈操作
************************************************************************************************************************************************/
//通信控制(线圈)(离散:为1时远程控制,PLC端无控制)
void c_RGV_Remote::Fuction_0_Set()
{
	m_RGV_Fuction_0_Set = true;
}
void c_RGV_Remote::Fuction_0_Reset()
{
	m_RGV_Fuction_0_Reset = true;
}
//主动力位置清零(线圈,工控机立即复位)(离散)
void c_RGV_Remote::Fuction_7()
{
	m_RGV_Fuction_7 = true;
}
//主动力故障复位(线圈,工控机立即复位)(离散)
void c_RGV_Remote::Fuction_8()
{
	m_RGV_Fuction_8 = true;
}
//主动力手动左行(线圈,点控)(离散:为1运行中)
void c_RGV_Remote::Fuction_9_Set()
{
	m_RGV_Fuction_9_Set = true;
}
//主动力手动左行(线圈,点控)(离散:为1运行中)
void c_RGV_Remote::Fuction_9_Reset()
{
	m_RGV_Fuction_9_Reset = true;
}
//主动力手动右行(线圈,点控)(离散:为1运行中)
void c_RGV_Remote::Fuction_10_Set()
{
	m_RGV_Fuction_10_Set = true;
}
//主动力手动右行(线圈,点控)(离散:为1运行中)
void c_RGV_Remote::Fuction_10_Reset()
{
	m_RGV_Fuction_10_Reset = true;
}
//正向连续运行(线圈,工控机立即复位)(离散:为1运行中)
void c_RGV_Remote::Fuction_11()
{
	m_RGV_Fuction_11 = true;
}
//返向连续运行(线圈,工控机立即复位)(离散:为1运行中)
void c_RGV_Remote::Fuction_12()
{
	m_RGV_Fuction_12 = true;
}
//返向连续运行再启动(线圈,工控机立即复位)(离散:为1运行中)
void c_RGV_Remote::Fuction_13()
{
	m_RGV_Fuction_13 = true;
}//
 //急停(线圈,工控机立即复位)(离散)
void c_RGV_Remote::Fuction_14()
{
	m_RGV_Fuction_14 = true;
}
//左机器人开机(线圈,工控机立即复位)(离散:为1完成开机)
void c_RGV_Remote::Fuction_15()
{
	m_RGV_Fuction_15 = true;
}
//左机器人关机(线圈,工控机立即复位)(离散:为1完成关机)
void c_RGV_Remote::Fuction_16()
{
	m_RGV_Fuction_16 = true;
}
//右机器人开机(线圈,工控机立即复位)(离散:为1完成开机)
void c_RGV_Remote::Fuction_17()
{
	m_RGV_Fuction_17 = true;
}
//右机器人关机(线圈,工控机立即复位)(离散:为1完成关机)
void c_RGV_Remote::Fuction_18()
{
	m_RGV_Fuction_18 = true;
}
//上电(线圈,点控)(离散:为1所有设备上电处于待机状态)
void c_RGV_Remote::Fuction_19_Set()
{
	m_RGV_Fuction_19_Set = true;
}
//上电(线圈,点控)(离散:为1所有设备上电处于待机状态)
void c_RGV_Remote::Fuction_19_Reset()
{
	m_RGV_Fuction_19_Reset = true;
}
//充电回原点(线圈,工控机立即复位)
void c_RGV_Remote::Fuction_20()
{
	m_RGV_Fuction_20 = true;
}
//风刀电机开
void c_RGV_Remote::Fuction_21_Set()
{
	m_RGV_Fuction_21_Set = true;
}
//风刀电机关
void c_RGV_Remote::Fuction_21_Reset()
{
	m_RGV_Fuction_21_Reset = true;
}
//清扫电机开
void c_RGV_Remote::Fuction_22_Set()
{
	m_RGV_Fuction_22_Set = true;
}
//清扫电机关
void c_RGV_Remote::Fuction_22_Reset()
{
	m_RGV_Fuction_22_Reset = true;
}
//轴1移动(线圈,工控机立即复位)(离散:为为1移动中)
void c_RGV_Remote::Fuction_24()
{
	m_RGV_Fuction_24 = true;
}
//轴2移动(线圈,工控机立即复位)(离散:为1移动中)
void c_RGV_Remote::Fuction_25()
{
	m_RGV_Fuction_25 = true;
}
//开始充电(线圈,工控机立即复位)(离散:为1时远程控制,PLC端无控制)
void c_RGV_Remote::Fuction_26()
{
	m_RGV_Fuction_26 = true;
}
//结束充电(线圈,工控机立即复位)(离散:为1时远程控制,PLC端无控制)
void c_RGV_Remote::Fuction_27()
{
	m_RGV_Fuction_27 = true;
}
/*************************************************************************************************************************************************
**保持寄存器操作
************************************************************************************************************************************************/
//左升降台速度
void c_RGV_Remote::Date_0()
{
	m_RGV_Date_0 = true;
}
//左升降台位置
void c_RGV_Remote::Date_1()
{
	m_RGV_Date_1 = true;
}
//右升降台速度
void c_RGV_Remote::Date_2()
{
	m_RGV_Date_2 = true;
}
//右升降台位置
void c_RGV_Remote::Date_3()
{
	m_RGV_Date_3 = true;
}
//轴1移动距离
void c_RGV_Remote::Date_4()
{
	m_RGV_Date_4 = true;
}
//轴2移动距离
void c_RGV_Remote::Date_5()
{
	m_RGV_Date_5 = true;
}
/*************************************************************************************************************************************************
**判断是否写线圈
************************************************************************************************************************************************/
bool c_RGV_Remote::If_Write_Coils()
{
	if (m_RGV_Fuction_0_Set) {
		m_RGV_Fuction_0_Set = Set_Coils(RGV_Fuction_0);
		return true;
	}
	if (m_RGV_Fuction_0_Reset) {
		m_RGV_Fuction_0_Reset = Reset_Coils(RGV_Fuction_0);
		return true;
	}
	if (m_RGV_Fuction_7) {
		m_RGV_Fuction_7 = Set_Coils(RGV_Fuction_7);
		return true;
	}
	if (m_RGV_Fuction_8) {
		m_RGV_Fuction_8 = Set_Coils(RGV_Fuction_8);
		return true;
	}
	if (m_RGV_Fuction_9_Set) {
		m_RGV_Fuction_9_Set = Set_Coils(RGV_Fuction_9);
		return true;
	}
	if (m_RGV_Fuction_9_Reset) {
		m_RGV_Fuction_9_Reset = Reset_Coils(RGV_Fuction_9);
		return true;
	}
	if (m_RGV_Fuction_10_Set) {
		m_RGV_Fuction_10_Set = Set_Coils(RGV_Fuction_10);
		return true;
	}
	if (m_RGV_Fuction_10_Reset) {
		m_RGV_Fuction_10_Reset = Reset_Coils(RGV_Fuction_10);
		return true;
	}
	if (m_RGV_Fuction_11) {
		m_RGV_Fuction_11 = Set_Coils(RGV_Fuction_11);
		return true;
	}
	if (m_RGV_Fuction_12) {
		m_RGV_Fuction_12 = Set_Coils(RGV_Fuction_12);
		return true;
	}
	if (m_RGV_Fuction_13) {
		m_RGV_Fuction_13 = Set_Coils(RGV_Fuction_13);
		return true;
	}
	if (m_RGV_Fuction_14) {
		m_RGV_Fuction_14 = Set_Coils(RGV_Fuction_14);
		return true;
	}
	if (m_RGV_Fuction_15) {
		m_RGV_Fuction_15 = Set_Coils(RGV_Fuction_15);
		return true;
	}
	if (m_RGV_Fuction_16) {
		m_RGV_Fuction_16 = Set_Coils(RGV_Fuction_16);
		return true;
	}
	if (m_RGV_Fuction_17) {
		m_RGV_Fuction_17 = Set_Coils(RGV_Fuction_17);
		return true;
	}
	if (m_RGV_Fuction_18) {
		m_RGV_Fuction_18 = Set_Coils(RGV_Fuction_18);
		return true;
	}
	if (m_RGV_Fuction_19_Set) {
		m_RGV_Fuction_19_Set = Set_Coils(RGV_Fuction_19);
		return true;
	}
	if (m_RGV_Fuction_19_Reset) {
		m_RGV_Fuction_19_Reset = Reset_Coils(RGV_Fuction_19);
		return true;
	}
	if (m_RGV_Fuction_20) {
		m_RGV_Fuction_20 = Set_Coils(RGV_Fuction_20);
		return true;
	}
	if (m_RGV_Fuction_21_Set) {
		m_RGV_Fuction_21_Set = Set_Coils(RGV_Fuction_21);
		return true;
	}
	if (m_RGV_Fuction_21_Reset) {
		m_RGV_Fuction_21_Reset = Reset_Coils(RGV_Fuction_21);
		return true;
	}
	if (m_RGV_Fuction_22_Set) {
		m_RGV_Fuction_22_Set = Set_Coils(RGV_Fuction_22);
		return true;
	}
	if (m_RGV_Fuction_22_Reset) {
		m_RGV_Fuction_22_Reset = Reset_Coils(RGV_Fuction_22);
		return true;
	}
	if (m_RGV_Fuction_24) {
		m_RGV_Fuction_24 = Set_Coils(RGV_Fuction_24);
		return true;
	}
	if (m_RGV_Fuction_25) {
		m_RGV_Fuction_25 = Set_Coils(RGV_Fuction_25);
		return true;
	}
	if (m_RGV_Fuction_26) {
		m_RGV_Fuction_26 = Set_Coils(RGV_Fuction_26);
		return true;
	}
	if (m_RGV_Fuction_27) {
		m_RGV_Fuction_27 = Set_Coils(RGV_Fuction_27);
		return true;
	}
	else {
		return false;
	}
}
/*************************************************************************************************************************************************
**判断是否写保持寄存器
************************************************************************************************************************************************/
bool c_RGV_Remote::If_Write_HoldingRegisters()
{
	//左升降台速度
	if (m_RGV_Date_0) {
		int Date = c_Variable::g_Communicate_DB.value("RGV_Date_0").toInt();
		int high = Date / 65536;
		int low = Date % 65536;
		m_RGV_Date_0 = Set_HoldingRegisters_32(RGV_Date_0, low, high);
		return true;
	}
	//左升降台位置
	if (m_RGV_Date_1) {
		int Date = c_Variable::g_Communicate_DB.value("RGV_Date_1").toInt();
		int high = Date / 65536;
		int low = Date % 65536;
		m_RGV_Date_1 = Set_HoldingRegisters_32(RGV_Date_1, low, high);
		return true;
	}
	//右升降台速度
	if (m_RGV_Date_2) {
		int Date = c_Variable::g_Communicate_DB.value("RGV_Date_2").toInt();
		int high = Date / 65536;
		int low = Date % 65536;
		m_RGV_Date_2 = Set_HoldingRegisters_32(RGV_Date_2, low, high);
		return true;
	}
	//右升降台位置
	if (m_RGV_Date_3) {
		int Date = c_Variable::g_Communicate_DB.value("RGV_Date_3").toInt();
		int high = Date / 65536;
		int low = Date % 65536;
		m_RGV_Date_3 = Set_HoldingRegisters_32(RGV_Date_3, low, high);
		return true;
	}
	//轴1移动距离
	if (m_RGV_Date_4) {
		int Date = c_Variable::g_Communicate_DB.value("RGV_Date_4").toInt();
		m_RGV_Date_4 = Set_HoldingRegisters_16(RGV_Date_4, Date);
		return true;
	}
	//轴2移动距离
	if (m_RGV_Date_5) {
		int Date = c_Variable::g_Communicate_DB.value("RGV_Date_5").toInt();
		m_RGV_Date_5 = Set_HoldingRegisters_16(RGV_Date_5, Date);
		return true;
	}
	//否则返回false
	else {
		return false;
	}
}
/*************************************************************************************************************************************************
**判断线圈是否置位(点控)
************************************************************************************************************************************************/
bool c_RGV_Remote::If_Coils_Set()
{
	//主动力位置清零
	if (m_Coils.value(QString::number(RGV_Fuction_7)).toInt() == 1 ) {
		Reset_Coils(RGV_Fuction_7);
		return true;
	}
	//主动力故障复位
	if (m_Coils.value(QString::number(RGV_Fuction_8)).toInt() == 1 ) {
		Reset_Coils(RGV_Fuction_8);
		return true;
	}
	//正向连续运行
	if (m_Coils.value(QString::number(RGV_Fuction_11)).toInt() == 1) {
		Reset_Coils(RGV_Fuction_11);
		return true;
	}
	//返向连续运行
	if (m_Coils.value(QString::number(RGV_Fuction_12)).toInt() == 1 ) {
		Reset_Coils(RGV_Fuction_12);
		return true;
	}
	//返向连续运行再启动
	if (m_Coils.value(QString::number(RGV_Fuction_13)).toInt() == 1) {
		Reset_Coils(RGV_Fuction_13);
		return true;
	}
	//急停
	if (m_Coils.value(QString::number(RGV_Fuction_14)).toInt() == 1) {
		Reset_Coils(RGV_Fuction_14);
		return true;
	}
	//左机器人开机
	if (m_Coils.value(QString::number(RGV_Fuction_15)).toInt() == 1) {
		Reset_Coils(RGV_Fuction_15);
		return true;
	}
	//左机器人关机
	if (m_Coils.value(QString::number(RGV_Fuction_16)).toInt() == 1) {
		Reset_Coils(RGV_Fuction_16);
		return true;
	}
	//右机器人开机
	if (m_Coils.value(QString::number(RGV_Fuction_17)).toInt() == 1) {
		Reset_Coils(RGV_Fuction_17);
		return true;
	}
	//右机器人关机
	if (m_Coils.value(QString::number(RGV_Fuction_18)).toInt() == 1) {
		Reset_Coils(RGV_Fuction_18);
		return true;
	}
	//充电回原点(线圈,工控机立即复位)
	if (m_Coils.value(QString::number(RGV_Fuction_20)).toInt() == 1) {
		Reset_Coils(RGV_Fuction_20);
		return true;
	}
	//轴1移动
	if (m_Coils.value(QString::number(RGV_Fuction_24)).toInt() == 1) {
		Reset_Coils(RGV_Fuction_24);
		return true;
	}
	//轴2移动
	if (m_Coils.value(QString::number(RGV_Fuction_25)).toInt() == 1) {
		Reset_Coils(RGV_Fuction_25);
		return true;
	}
	//开始充电(线圈,工控机立即复位)
	if (m_Coils.value(QString::number(RGV_Fuction_26)).toInt() == 1) {
		Reset_Coils(RGV_Fuction_26);
		return true;
	}
	//结束充电(线圈,工控机立即复位)
	if (m_Coils.value(QString::number(RGV_Fuction_27)).toInt() == 1) {
		Reset_Coils(RGV_Fuction_27);
		return true;
	}
	//否则返回false
	else {
		return false;
	}
}

5.7.在UI中实例化,并绑定控件

到了这里,关于一种基于QT5.12+VS2015的ModbusTcp客户端轮询方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • QT5 creator创建项目移植VS2015时一些问题的解决方案(MSB307错误、.ui无法编译)

    将QT5项目移植VS2015工程的方案中,我目前体验过的最便捷的一条路线是: 1.利用QT5 Creator创建项目(不需要进行界面设计),得到XXX.h /XXX.cpp /XXX.ui (暂时不需要编译自动生成的ui_XXX.h); 2.复制以上文件到VS工程源码目录下,.ui与头文件目录相同,并进行CMAKE编译、项目生成(

    2024年02月15日
    浏览(36)
  • VS2019+QT5.12.9环境下,调试QString无显示解决

    1、搜索 qt5.natvis.xml 文件,路径一般为C:UsersieskongAppDataLocalMicrosoftVisualStudio16.0_cb8bc8a7Extensionsoih0nd55.5jrqt5.natvis.xml,【建议使用Everything这个工具搜索] 2、复制到C:Program Files (x86)Microsoft Visual Studio2019EnterpriseCommon7PackagesDebuggerVisualizers目录下并重命名为qt5.natvis即可(如果

    2024年02月09日
    浏览(29)
  • Win10平台VS2017+OpenCV3.4.0+Qt5.12配置教程

    本文专为图像处理开发项目人员准备,涉及多个软件和库的安装、配置教程,亲测可行。 1、 VS 是美国微软公司(Microsoft)开发的 集成开发环境 “Visual Studio” 的简称,是Windows平台最流行的应用程序集成开发环境。 注意区分:MSVC(Microsoft Visual C++ Compiler)是指微软的VC编译

    2024年02月05日
    浏览(42)
  • 【工控通信】ModbusTCP通讯之ModbusPoll客户端工具配置

    1.安装Modbus Poll客户端工具 2.Modbus Poll客户端工具安装好以后的界面 Modbus Poll uses a multiple windows user interface. That means you can open several windows showing different data areas or data from different slave ID’s at the same time. You can write any text in the Alias cells. In any dialog box you can press the F1 key for more he

    2024年02月13日
    浏览(26)
  • C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端

    客户端可以是一个程序或一个设备,这里我以C#WINFORM程序来实现客户机与PLC的Modbustcp服务器通信,开发环境是VS2019,.NET Framework版本是4.7.2  创建类库   编写C#各种类的转换库,该库由我提供,不用操心,文章最后提供。 项目引入这个类库  找到项目,找到引用,右键“管理

    2024年02月11日
    浏览(27)
  • S7-1200PLC 作为MODBUSTCP服务器通信(多客户端访问)

    S7-1200PLC作为MODBUSTCP服务器端通信编程应用,详细内容请查看下面文章链接: ModbusTcp通信(S7-1200PLC作为服务器端)-CSDN博客 文章浏览阅读239次。S7-200Smart plc作为ModbusTcp服务器端的通信S7-200SMART PLC ModbusTCP通信(ModbusTcp服务器)_s7-200 modbustcp-CSDN博客文章浏览阅读2.3k次。 https://rxxw-con

    2024年02月01日
    浏览(34)
  • Qt5.9.6+MSVC2015安装配置(附带全部安装包)

    一、安装VS2015 安装MSVC2015有两种办法,一种笨方法是安装visual studio2015,这也是最有效的办法,第二种是单独安装C++库,这个有问题,暂时未成功,以下介绍第一种安装方法。 DVD驱动器装载en_visual_studio_community_2015_with_update_3_x86_x64_dvd_8923300.iso(或者解压ISO文件),然后双击

    2024年02月05日
    浏览(33)
  • 【Qt5.12】Qt5.12安装教程[通俗易懂]

    Qt5.12下载网址: Index of /archive/qt/5.12/5.12.2 选择Windows平台, Linux和Mac平台类似 下载好之后的安装包: Step1: 双击安装包, 稍等片刻, 然后点击next Step2: 如果没有账号, 则选择skip Step3: Qt设置欢迎界面, 选择下一步 Step4: 选择安装路径 Step5: 选择组件, 然后选择下一步 Step6: 同意许可协议

    2024年02月13日
    浏览(31)
  • vs2015调试时无法显示QT变量值

    问题描述:         vs2015调试时无法显示 QT变量值,只能显示地址,导致想要查看变量值的时候,只能想办法打印出来,非常麻烦。如下图:   问题解决:         调试 - 选项 - 调试 - 常规 - 去掉 使用本机兼容性模式,默认是勾选的         亲测可用    

    2024年02月12日
    浏览(24)
  • 【Qt】Qt5.12.12安装教程详解

    Qt(官方发音 [kju:t],音同 cute)是一个跨平台的 C++ 开发库,主要用来开发图形用户界面(Graphical User Interface,GUI)程序,当然也可以开发不带界面的命令行(Command User Interface,CUI)程序。 Qt 是纯 C++ 开发的,所以学好 C++ 非常有必要,对于不了解 C++ 的读者,我建议先阅读《

    2024年02月13日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包