一种基于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区
4.2.服务端模块
开通4个数据储存区分别对应服务端01、02、03、04功能码,对应客户端线圈、离散输入、保持寄存器、输入寄存器,每个数据储存区分配500个数据长度
4.3.SCL赋值
“离散输入10001”.“100”[01] := (状态地址);
“输入继存器30001”.“300”[01] := (状态参数地址);
(功能线圈地址) := “线圈00001”.“000”[01] ;
(功能参数地址):= “保持继存器40001”.“400”[01];文章来源:https://www.toymoban.com/news/detail-479865.html
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模板网!