modbus TCP协议

简介

Modbus是一种通信协议,用于在自动化设备之间进行数据传输。它是一个开放的通信协议,被广泛应用于工业自动化领域。

Modbus协议定义了一个主从结构,其中一个设备充当主设备发送请求消息,而其他设备则充当从设备响应请求。Modbus支持不同的物理层传输,如串行通信(RS-232、RS-485)和以太网通信。常见的Modbus变体包括Modbus RTU(基于二进制数据传输)和Modbus TCP(在以太网上运行)。

使用Modbus协议,主设备可以向从设备发送读取或写入寄存器的请求,以获取或修改设备的状态和数据。Modbus协议支持多种数据类型,如位(布尔)、16位整数、32位整数、浮点数等。
在这里插入图片描述

相关配置

在pro文件中添加:

QT += modbus

常用类

  • QModbusTcpClient:Modbus TCP客户端类,用于与Modbus TCP从机建立连接并进行通信。

  • QModbusTcpServer:Modbus TCP服务器类,用于创建一个Modbus TCP主机,接收来自Modbus TCP客户端的请求并提供响应。

  • QModbusDataUnit:Modbus数据单元类,用于表示Modbus协议中的数据单元,包括读取和写入操作的起始地址、数据类型和值等信息。

  • QModbusReply:Modbus请求回复类,用于表示Modbus请求的响应,包含了响应的状态、结果数据等信息。

QModbusTcpServer常用函数:

QModbusTcpServer(QObject *parent = nullptr);:创建一个Modbus/TCP服务器对象。

bool setConnectionParameter(QModbusDevice::ConnectionParameter parameter, const QVariant &value);:设置连接参数。

bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 502):开始监听指定地址和端口号的连接请求。

void close():关闭Modbus/TCP服务器。

QModbusDataUnit registerData(QModbusDataUnit::RegisterType table, int address, quint16 size):注册一个数据单元。

QModbusDataUnitMap data():返回当前已经注册的所有数据单元。

void setData(QModbusDataUnitMap &data):设置数据单元。

  • 参数data是一个QModbusDataUnitMap类型的值,表示要设置的数据单元。

bool processRequest(QModbusRequest &request, QModbusResponse &response):处理Modbus请求。

  • 参数request是一个QModbusRequest类型的值,表示要处理的Modbus请求。
  • 参数response是一个QModbusResponse类型的值,表示要返回的Modbus响应。
  • 返回值为true表示处理成功,false表示处理失败。

bool setValue(QModbusDataUnit::RegisterType table, int address, const QVector<quint16> &values):设置寄存器的值。

QVector<quint16> value(QModbusDataUnit::RegisterType table, int address, quint16 size) const:获取寄存器的值。

QModbusTcpClient常用函数:

connectDevice():建立与Modbus TCP服务器的连接。
disconnectDevice():断开与Modbus TCP服务器的连接。

setConnectionParameter:用于设置Modbus设备的连接参数。它接受两个参数:参数类型和参数值。

  • QModbusDevice::NetworkAddressParameter:IP地址类型
  • QModbusDevice::NetworkPortParameter:端口号类型

state():获取当前连接状态。
errorString():获取最近一次错误信息。

readRequest():发送读取请求,如读取线圈、离散输入等。
writeRequest():发送写入请求,如写入线圈、寄存器等。

sendRawRequest():发送自定义的原始请求。
processReply():处理响应数据,获取读取数据或处理错误信息。

QModbusDataUnit常用函数

setData():设置要发送的数据,可以是一个字节数组或一个QVector。
data():获取接收到的数据。

functionCode():获取数据单元的功能码。
startAddress():获取数据单元的起始地址。

valueCount():获取数据单元中的值的数量
setValueCount():设置数据单元中的值的数量。

values():获取数据单元中的值,以QVector的形式返回。
setValue():设置数据单元中指定索引位置的值。
value():获取数据单元中指定索引位置的值。

toByteArray():将数据单元转换为字节数组,用于在Modbus通信中进行传输。

QModbusReply常用函数

isValid():检查回复是否有效。

error():获取错误码,如果没有错误则返回QModbusDevice::NoError。
errorString():获取错误信息的字符串表示。

result():如果响应是成功的,获取操作的结果。
rawResult():获取原始的操作结果数据。

serverAddress():获取Modbus服务器的地址。
functionCode():获取Modbus功能码。

data():获取回复的数据,以字节数组的形式返回。
registerType():获取寄存器类型。
value():获取回复中特定位置的值。
values():获取回复中所有值,以QVector的形式返回。

参数说明:

slave ID:从站地址,在Modbus协议中,每个从设备(即Modbus从机)都有一个唯一的地址,用于与主设备(即Modbus主机)通信。

Holding Registers:保持寄存器,是Modbus协议中的一种寄存器类型,用于存储从机设备的数据。它们被用于读取和写入操作,通常用于存储配置参数、状态信息和实时数据等。

numRegisters:是指需要读取或写入的寄存器数量,它通常与起始地址一起用来指定操作的寄存器范围

QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, 0, 2);
writeUnit.setValue(0, 123);
writeUnit.setValue(1, 456);

在Modbus通信中,写入Holding Registers的操作需要提供要写入的数据。setValue()函数就是用于设置要写入的值。
它接受两个参数:

  • 第一个参数是寄存器的偏移地址(也就是寄存器在数据单元中的索引)
  • 第二个参数是要写入的数值。

QModbusDataUnit对象的构造函数的第一个参数指定了数据单元类型,这里是Holding Registers。第二个参数是起始地址,这里是0,表示从第一个寄存器开始写入。第三个参数是寄存器数量,这里是2,表示要写入两个寄存器。

然后,使用setValue()函数分别设置第一个和第二个寄存器的值。最后,通过sendWriteRequest()函数发送写入请求,并通过信号槽机制处理响应。

代码实现:

//1.创建Modbus TCP客户端对象
QModbusTcpClient *modbusClient = new QModbusTcpClient(this);

//2.连接到Modbus从机
modbusClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, "192.168.1.100");
modbusClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, 502);

if (!modbusClient->connectDevice()) {
    qDebug() << "无法连接到Modbus从机:" << modbusClient->errorString();
}

//3.执行读取或写入操作

//创建一个QModbusDataUnit对象用于读取操作,指定寄存器类型、起始地址和寄存器数量。
QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters, address, numRegisters);

//执行读取请求
if (auto *reply = modbusClient->sendReadRequest(readUnit, slaveId)) {
    if (!reply->isFinished())
        connect(reply, &QModbusReply::finished, this, &MyClass::readReady);
    else
        delete reply;
} else {
    qDebug() << "读取操作失败:" << modbusClient->errorString();
}

//读取数据槽函数:
void MyClass::readReady()
{
    //获取发送信号的对象,并将其转换为QModbusReply类型
	/*
	在Modbus通信中,当我们发送请求(如读取或写入数据)时,modbusDevice->sendReadRequest()和modbusDevice->sendWriteRequest()函数会返回一个QModbusReply对象,该对象表示与Modbus设备的通信会话。
	如果通信成功,QModbusReply对象会发出一个finished()信号,表示Modbus设备已经响应了我们的请求。
	*/
    auto reply = qobject_cast<QModbusReply *>(sender());
    if (!reply)
        return;

    if (reply->error() == QModbusDevice::NoError) {
        const QModbusDataUnit unit = reply->result();
        for (int i = 0; i < unit.valueCount(); i++) {
            qDebug() << "读取到的值:" << unit.value(i);
        }
    } else if (reply->error() == QModbusDevice::ProtocolError) {
        qDebug() << "Modbus协议错误:" << reply->errorString();
    } else {
        qDebug() << "读取错误:" << reply->errorString();
    }

    reply->deleteLater();
}

//执行写入请求
QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, 0, 2);
writeUnit.setValue(0, 123);
writeUnit.setValue(1, 456);

if (auto *reply = modbusClient->sendWriteRequest(writeUnit, slaveId)) {
    if (!reply->isFinished())
        connect(reply, &QModbusReply::finished, this, &MyClass::writeReady);
    else
        delete reply;
} else {
    qDebug() << "写入操作失败:" << modbusClient->errorString();
}

//写入数据槽函数:
void MyClass::writeReady()
{
    auto reply = qobject_cast<QModbusReply *>(sender());
    if (!reply)
        return;

    if (reply->error() == QModbusDevice::NoError) {
        // 写入成功
    } else if (reply->error() == QModbusDevice::ProtocolError) {
        qDebug() << "Modbus协议错误:" << reply->errorString();
    } else {
        qDebug() << "写入错误:" << reply->errorString();
    }

    reply->deleteLater();
}


//断开连接和释放资源
modbusClient->disconnectDevice();
delete modbusClient;


  • 40
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值