Qt Modbus 报文即QModbusRequest与sendRawRequest的使用

Modbus 报文

  • 序言
  • 环境
  • 理论解释,以RTU模式为例
    • 写单个保持寄存器——查询报文
    • 写单个保持寄存器——响应报文
    • 报文字节类型要求
    • 报文大小端要求

序言

记录下学习Modbus时,研究代码,思考验证了一下午后,终于豁然开朗。

环境

Qt5.12

:建议不要使用这个版本去学习或者使用Modbus,除非你不是用Qt的Modbus库,原因点这了解Qt 难找的崩溃原因或错误原因

理论解释,以RTU模式为例

写单个保持寄存器——查询报文

以写单个保持寄存器为例,下图就是查询报文的组成。
Qt Modbus 报文即QModbusRequest与sendRawRequest的使用_第1张图片
而如何编写该报文呢?

我们主要用到这么两个:QModbusRequest类与sendRawRequest函数。

QModbusRequest用以构成报文中间的功能码及以下到差错校验之前的所有数据。

就比如上图的中间报文:0x06 0x00 0x95 0x04 0xB0

换成QModbusRequest就是利用其构造函数:功能码+对应的字节指令,功能码在QModbusRequest有对应枚举

int Addr = 3;
QModbusRequest message( QModbusRequest::WriteSingleRegister, quint16( 0x0095 ), quint16( 0x04B0 ) );
或
QModbusRequest message( QModbusRequest::WriteSingleRegister, QByteArray::fromHex( "009504B0" ) );

modbusRtuSerialMaster.sendRawRequest( message, Addr )

QModbusRtuSerialMaster中保存着波特率、数据位、停止位、奇偶校验、端口号等数据,并且内含RTU的CRC校验函数,会在sendRawRequest中自行校验,其它继承了QModbusClient的一样有效,只不过由于多态效果,含有的也有可能是LRC校验,只看使用类。

sendRawRequest将实参与QModbusRtuSerialMaster中的RTU数据与方法合成的报文发送到了对应设备上。

简单来说,就是QModbusRequest保存功能码及以下到差错校验之前的所有数据,sendRawRequest里会自行添加帧头与差错校验,并加上实参的从机地址,就发送了完整的报文。
.

写单个保持寄存器——响应报文

至于反馈的响应报文
Qt Modbus 报文即QModbusRequest与sendRawRequest的使用_第2张图片
Qt Modbus 报文即QModbusRequest与sendRawRequest的使用_第3张图片
sendRawRequest返回的QModbusReply中的rawResult()返回的QModbusResponse,这报文数据就储存在这里,使用modbusResponse.data().toHex()即可得到起始地址与变更数据。

报文字节类型要求

相信大家对字节命令有所疑惑,那我简单讲解下。

QModbusRequest中,其构造函数如下

QModbusRequest::QModbusRequest(const QModbusPdu &pdu)
QModbusRequest::QModbusRequest(QModbusPdu::FunctionCode code, const QByteArray &data = ...)
QModbusRequest::QModbusRequest(QModbusPdu::FunctionCode code, Args... data)

第一个重载没什么好说的,就是把一个写好的中间报文,到处可传,重复利用。

第二个重载,其以QByteArray作为字节指令存储的载体,QByteArray都知道,是以字节形式存储的,所以使用QByteArray也再好不过,例子如下。

QModbusRequest message( QModbusRequest::WriteSingleRegister, QByteArray::fromHex( "009504B0" ) );

其是以报文顺序存储的字节顺序,00是起始地址(高位),95是起始地址(低位),04是变更数据(高位),B0是变更数据(低位)。

第三个重载,其并没有注明类型是什么,这是因为可以让我们以普通类型存储,比如说unsigned char或unsigned short,举例如下。

QModbusRequest message( QModbusRequest::WriteSingleRegister, quint16( 0x0095 ), quint16( 0x04B0 ) );
或
QModbusRequest message( QModbusRequest::WriteSingleRegister, quint8( 0x00 ), quint8( 0x95 ), quint8( 0x04 ), quint8( 0xB0 ) );

报文要求的是以字节,而quint16实际为unsigned short,其为两个字节,无符号,因为字节指令基本都是以无符号存储,除了quint16,还可以使用quint8单字节无符号即unsigned char,但是除了这两个类型,其他都不能用。

官方原文:
Note: Usage is limited quint8 and quint16 only. This is because QDataStream stream operators will not only append raw data, but also e.g. size, count, etc. for complex types.

有道翻译:
注:仅限使用quint8和quint16。 这是因为QDataStream流操作符不仅会追加原始数据,还会追加复杂类型的大小、计数等。
.

报文大小端要求

Modbus作为一个行业标准,自然标定了固定的存储方式,那就是大端存储,从报文顺序就可见一二。

设备读取报文,从帧头读到帧尾,字节存储是以低地址连续存到高地址。

那么读完功能码之后,首先读到的就是高位起始地址,便是以低位内存地址存储高位有效字节,以高位内存地址存储低位有效字节,这很明显是大端模式。

所以如果你不是使用Qt,而是使用其他的平台,切记要记得这种报文的顺序。

过些时候我再写个Qt Modbus RTU的用法
Qt Modbus 报文即QModbusRequest与sendRawRequest的使用_第4张图片

你可能感兴趣的:(#,Qt功能模块,qt,开发语言)