ModbusTCP的数据帧可分为两部分:
MBAP+PDU
MBAP
MBAP为报文头,长度为7字节,组成如下:
事务处理标识 协议标识 长度 单元标识符
2字节 2字节 2字节 1字节
内容 | 解释 |
事务处理标识 | 可以理解为报文的序列号,一般每次通信之后就要加1以区别不同的通信数据报文。 |
协议标识符 | 00 00表示ModbusTCP协议。 |
长度 | 表示接下来的数据长度,单位为字节。 |
单元标识符 | 可以理解为设备地址。 |
PDU
PDU由功能码+数据组成:
功能码 | 含义 |
---|---|
0x01 | 读线圈 |
0x05 | 写单个线圈 |
0x0F | 写多个线圈 |
0x02 | 读离散量输入 |
0x04 | 读输入寄存器 |
0x03 | 读保持寄存器 |
0x06 | 写单个保持寄存器 |
0x10 | 写多个保持寄存器 |
数据长度不定,一般是由读取信息长度和内容组成。
示例
Coil:
读取一个线圈:
request: 00 03 00 00 00 06 FF 01 00 64 00 01 读取100地址
responses: 00 03 00 00 00 04 FF 01 01 00 值为0
*****************************************************************
request请求解析:
事务处理标识 | 协议标识 | 长度 | 单元标识符 |
---|---|---|---|
00 03 | 00 00 | 00 06 | FF |
功能码 | 起始地址 | 长度 |
---|---|---|
01 | 00 64 | 00 01 |
解析:功能码是01,则这是要读取线圈 ,接着就是请求地址的起始地址:
这里00 64 的计算为 6*16+4 = 100。
最后则是长度。
responses反馈解析:
事务处理标识 | 协议标识 | 长度 | 单元标识符 |
---|---|---|---|
00 03 | 00 00 | 00 04 | FF |
功能码 | 长度 | 数据 |
---|---|---|
01 | 01 | 00 |
这里反馈的功能码是相同的,接着就是长度,然后跟着反馈的数据。
同理,大家可以自行分析一下的报文:
读取两个线圈:
request: 00 02 00 00 00 06 FF 01 00 64 00 02 读取100,101两个地址
responses: 00 02 00 00 00 04 FF 01 01 02 值为 0,1
这里需要注意的是反馈的数据是02,为什么是解释为0,1呢?
二进制是这样的:0000 0010
写一个线圈:
request: 00 04 00 00 00 08 FF 0F 00 64 00 01 01 01 写100地址 写入1
responses: 00 04 00 00 00 06 FF 0F 00 64 00 01
写两个线圈
request: 00 09 00 00 00 08 FF 0F 00 64 00 02 01 03 写100,101 : 1 1
responses: 00 09 00 00 00 06 FF 0F 00 64 00 02
request: 00 09 00 00 00 08 FF 0F 00 64 00 02 01 01 写100,101 : 1 0
responses: 00 09 00 00 00 06 FF 0F 00 64 00 02
Register:
读int16
request: 00 5B 00 00 00 06 FF 03 00 C8 00 01 读取200地址单个寄存器
responses: 00 5B 00 00 00 05 FF 03 02 00 12 十进制为18
写int16
request: 00 5D 00 00 00 09 FF 10 00 C8 00 01 02 30 39 写值到200地址,十进制值为12345
responses: 00 5D 00 00 00 06 FF 10 00 C8 00 01
读int32
request: 00 61 00 00 00 06 FF 03 00 D0 00 02 读取起始地址为208的连续两个地址
responses: 00 61 00 00 00 07 FF 03 04 04 6A 00 01 读值为十进制66666
写int32
request: 00 62 00 00 00 0B FF 10 00 D0 00 02 04 90 38 00 0D 写值888888到起始地址为208的int32数据
responses: 00 62 00 00 00 06 FF 10 00 D0 00 02
读float
request: 00 63 00 00 00 06 FF 03 00 02 00 02 读取起始地址为2的浮点型数据
responses: 00 63 00 00 00 07 FF 03 04 66 66 40 96 读取值为4.69999980927
写float
request: 00 64 00 00 00 0B FF 10 00 02 00 02 04 33 33 42 02 写值32.55到起始地址为2的浮点型数据 42023333
responses: 00 64 00 00 00 06 FF 10 00 02 00 02
读double
request: 00 65 00 00 00 06 01 03 00 CC 00 04 读取起始地址为204的64位浮点型数据
responses: 00 65 00 00 00 0B 01 03 08 53 F8 A5 E3 44 9B 40 12 值为4.567
写double
request: 00 66 00 00 00 0F 01 10 00 CC 00 04 08 58 10 B4 39 D6 C8 40 46 写值45.678到起始地址为204的64位浮点型数据 4046 D6C8 B439 5810
responses: 00 66 00 00 00 06 01 10 00 CC 00 04
报错报文:
读取单个输入寄存器(这里服务器并没有开启输入寄存器地址空间):
request: 00 02 00 00 00 06 01 04 00 00 00 01
responses: 00 02 00 00 00 03 01 84 02
读取11600地址的寄存器:
request: 00 07 00 00 00 06 01 03 2D 4F 00 01
responses: 00 07 00 00 00 03 01 83 02
写入11600地址的寄存器:
request: 00 07 00 00 00 06 01 06 2D 4F 00 00
responses: 00 07 00 00 00 03 01 86 02
解析:
84 02 与 83 02的反馈:
8表示最高位为1,代表异常,3或者4是各自请求的功能码,02为错误代码,错误码表如下:
代码 | 名称 | 含义 |
---|---|---|
01 | 非法功能 | 对于服务器(或从站)来说,询问中接收到的功能码是不可允许的操作,可能是因为功能码仅适用于新设备而被选单元中不可实现同时,还指出服务器(或从站)在错误状态中处理这种请求,例如:它是未配置的,且要求返回寄存器值。 |
02 | 非法数据地址 | 对于服务器(或从站)来说,询问中接收的数据地址是不可允许的地址,特别是参考号和传输长度的组合是无效的。对于带有100个寄存器的控制器来说,偏移量96和长度4的请求会成功,而偏移量96和长度5的请求将产生异常码02。 |
03 | 非法数据值 | 对于服务器(或从站)来说,询问中包括的值是不可允许的值。该值指示了组合请求剩余结构中的故障。例如:隐含长度是不正确的。modbus协议不知道任何特殊寄存器的任何特殊值的重要意义,寄存器中被提交存储的数据项有一个应用程序期望之外的值。 |
04 | 从站设备故障 | 当服务器(或从站)正在设法执行请求的操作时,产生不可重新获得的差错。 |
05 | 确认 | 与编程命令一起使用,服务器(或从站)已经接受请求,并且正在处理这个请求,但是需要长持续时间进行这些操作,返回这个响应防止在客户机(或主站)中发生超时错误,客户机(或主机)可以继续发送轮询程序完成报文来确认是否完成处理。 |
07 | 从属设备忙 | 与编程命令一起使用,服务器(或从站)正在处理长持续时间的程序命令,当服务器(或从站)空闲时,客户机(或主站)应该稍后重新传输报文。 |
08 | 存储奇偶性差错 | 与功能码20和21以及参考类型6一起使用,指示扩展文件区不能通过一致性校验。服务器(或从站)设备读取记录文件,但在存储器中发现一个奇偶校验错误。客户机(或主机)可重新发送请求,但可以在服务器(或从站)设备上要求服务。 |
0A | 不可用网关路径 | 与网关一起使用,指示网关不能为处理请求分配输入端口值输出端口的内部通信路径,通常意味着网关是错误配置的或过载的。 |
0B | 网关目标设备响应失败 | 与网关一起使用,指示没有从目标设备中获得响应,通常意味着设备未在网络中。 |