4. 协议结构
本部分阐述了通过MODBUS/TCP网络携带的MODBUS请求和或响应封装的一般格式。必须注意到请求和响应本体(从功能代码到数据部分的末尾)的结构和其它MODBUS变量具有完全相同的版面格式和含义,如:
MODBUS 串行端口 - ASCII 编码
MODBUS 串行端口 - RTU (二进制) 编码
MODBUS PLUS 网络 – 数据通道
这些其它案例仅在组帧次序,检错模式和地址描述等格式有所不同。
所有的请求通过TCP从寄存器端口502发出。 请求通常是在给定的连接以半双工的方式发送。也就是说,当单一连接被响应所占用,就不能发送其它的请求。有些装置采用多条TCP连接来维持高的传输速率。
然而一些客户端设备尝试“流水线式”的请求。允许服务器以这种方式工作的技术在附录A中阐述。
MODBUS “从站地址”字段被单字节的“单元标识符”替换,从而用于通过网桥和网关等设备的通讯,这些设备用单一IP地址来支持多个独立的终接单元。
请求和响应带有六个字节的前缀,如下:
byte 0: 事务处理标识符 –由服务器复制 –通常为 0
byte 1: 事务处理标识符 –由服务器复制 –通常为 0
byte 2: 协议标识符= 0
byte 3: 协议标识符= 0
byte 4: 长度字段 (上半部分字节) = 0 (所有的消息长度小于256)
byte 5: 长度字段 (下半部分字节) = 后面字节的数量
byte 6: 单元标识符 (原“从站地址”)
byte 7: MODBUS 功能代码
byte 8 on: 所需的数据
因而处理示例“以4的偏移从UI 9读1寄存器”返回5的值将是
请求:00 00 00 00 00 06 09 03 00 04 00 01
响应:00 00 00 00 00 05 09 03 02 00 05
一致性等级0-2的功能代码的应用的例子见后续部分
熟悉MODBUS的设计师将注意到MODBUS/TCP中不需要“CRC-16”或“LRC”检查字段。而是采用TCP/IP和链路层(以太网)校验和机制来校验分组交换的准确性。
5. 一致性等级的协议参考值
注意到在例子中,请求和响应列在功能代码字节的前面。如前所述,在MODBUS/TCP案例中有一个依赖传输的包含7个字节的前缀。
ref ref 00 00 00 len unit前面两个字节的“ref ref”在服务器中没有具体的值,只是为方便客户端而从请求和响应中逐字的复制过来。单客户机通常将该值置为0。
在这个例子中,请求和响应的格式如下(例子是“读寄存器”请求,详述见后面部分)。
03 00 00 00 01 => 03 02 12 34
这表示给前缀加上一个十六进制的串联的字节,这样,TCP连接上的整个消息将是(假设单元标识符还是09)
请求: 00 00 00 00 00 06 09 03 00 00 00 01
响应: 00 00 00 00 00 05 09 03 02 12 34
(所有的这些请求和响应通过查询Modicon Quantum PLC规范采用自动工具来进行校验。
5.1 等级0 指令详述
5.1.1 读乘法寄存器(FC 3)
请求
Byte 0: FC = 03
Byte 1-2: 参考数值
Byte 3-4: 指令数(1-125)
响应
Byte 0: FC = 03
Byte 1: 响应的字节数 (B=2 x指令数)
Byte 2-(B+1): Register values
异常
Byte 0: FC = 83 (hex)
Byte 1: 异常代码 = 01 or 02
示例:
读参考值为0 (Modicon 984中为40001)时的1寄存器得到十六进制的值1234
03 00 00 00 01 => 03 02 12 34
5.1.2 写乘法寄存器(FC 16)
请求
Byte 0: FC = 10 (hex)
Byte 1-2: 参考数值
Byte 3-4: 指令数 (1-100)
Byte 5: 字节数 (B=2 x word count)
Byte 6-(B+5): 寄存器值
响应
Byte 0: FC = 10 (hex)
Byte 1-2: 参考数值
Byte 3-4: 指令数
异常
Byte 0: FC = 90 (hex)
Byte 1: 异常代码 = 01 or 02
示例:
读参考值为0(Modicon 984中为40001)时的1寄存器得到十六进制的值1234
10 00 00 00 01 02 12 34 => 10 00 00 00 01
5.2 等级1 指令详述
5.2.1 读线圈 (FC 1)
请求
Byte 0: FC = 01
Byte 1-2: 参考数值
Byte 3-4: 比特数(1-2000)
响应
Byte 0: FC = 01
Byte 1: 响应的字节数 (B=(比特数+7)/8)
Byte 2-(B+1): 比特值(最小意义位首先绕线圈!)
异常
Byte 0: FC = 81 (hex)
Byte 1: exception code = 01 or 02
示例
读参考值为0 (Modicon 984中为00001)时的1线圈得到的值1
01 00 00 00 01 => 01 01 01
注意到返回的数据的格式和big-endian体系结构不同。而且此请求如果调用乘法指令字且这些指令不以16位为界排列,那么该请求将在从站得到计算强化。
5.2.2 读离散输入 (FC 2)
请求
Byte 0: FC = 02
Byte 1-2: 参考数值
Byte 3-4: 比特数 (1-2000)
响应
Byte 0: FC = 02
Byte 1: 响应的字节数 (B=(比特数+7)/8)
Byte 2-(B+1): 比特值 (最小意义位首先绕线圈!)
异常
Byte 0: FC = 82 (16进制)
Byte 1: 异常代码 = 01 or 02
示例
读参考值为0 (Modicon 984中为10001)时的1离散输入得到的值1
02 00 00 00 01 => 02 01 01
注意到返回的数据的格式和big-endian体系结构不同。而且此请求如果调用乘法指令字且这些指令不以16位为界排列,那么该请求将在从站得到计算强化。
5.2.3 读输入寄存器 (FC 4)
请求
Byte 0: FC = 04
Byte 1-2: 参考数值
Byte 3-4: 指令数 (1-125)
响应
Byte 0: FC = 04
Byte 1: 响应的比特数 (B=2 x 指令数)
Byte 2-(B+1): 寄存器值
异常
Byte 0: FC = 84 (hex)
Byte 1: 异常代码 = 01 or 02
示例
读参考值为0 (Modicon 984中为30001)时的1输入寄存器得到十六进制的值1234
04 00 00 00 01 => 04 02 12 34
5.2.4 写线圈 (FC 5)
请求
Byte 0: FC = 05
Byte 1-2: 参考数值
Byte 3: = FF 打开线圈, =00 关闭线圈
Byte 4: = 00
响应
Byte 0: FC = 05
Byte 1-2: 参考数值
Byte 3: = FF 打开线圈, =00 关闭线圈(回波)
Byte 4: = 00
异常
Byte 0: FC = 85 (16进制)
Byte 1: 异常代码 = 01 or 02
示例
将值1在参考值为0(Modicon 984中为00001)时写入1线圈
05 00 00 FF 00 => 05 00 00 FF 00
5.2.5 写单一寄存器(FC 6)
请求
Byte 0: FC = 06
Byte 1-2: 参考数值
Byte 3-4: 寄存器值
响应
Byte 0: FC = 06
Byte 1-2: 参考数值
Byte 3-4: 寄存器值
异常
Byte 0: FC = 86 (16进制)
Byte 1: 异常代码= 01 or 02
示例
将十六进制值1234在参考值为0(Modicon 984中为40001)时写入1线圈
06 00 00 12 34 => 06 00 00 12 34
5.2.6 读异常状态字 (FC 7)
注意“异常状态字”和“异常响应”没有关系。“读异常状态字”消息欲在采用小波特率轮询多点网络的早期MODBUS中允许最大的响应速度。PLC’s将特别规划一个8线圈(离散输出)的范围用此消息进行询问。
请求
Byte 0: FC = 07
响应
Byte 0: FC = 07
Byte 1: 异常状态字 (通常预先确定8线圈的范围)
异常
Byte 0: FC = 87 (16进制)
Byte 1: 异常代码 = 01 or 02
示例
读异常状态字得到16进制值34
07 => 07 34
5.3 等级2 指令详述
5.3.1 强制多点线圈 (FC 15)
请求
Byte 0: FC = 0F (16进制)
Byte 1-2: 参考数值
Byte 3-4: 比特数 (1-800)
Byte 5: 字节数 (B = (比特数 + 7)/8)
Byte 6-(B+5): 写入的数据 (最小意义位 = 第一个线圈)
响应
Byte 0: FC = 0F (16进制)
Byte 1-2: 参考数值
Byte 3-4: 比特数
异常
Byte 0: FC = 8F (16进制)
Byte 1: 异常代码 = 01 or 02
示例
当参考值为0(在Modicon 984中为00001)时给3线圈写入值0,0,1
0F 00 00 00 03 01 04 => 0F 00 00 00 03
注意到返回的数据的格式和big-endian体系结构不同。而且此请求如果调用乘法指令字且这些指令不以16位为界排列,那么该请求将在从站得到计算强化。
5.3.2 读一般参考值 (FC 20)
请求
Byte 0: FC = 14 (16进制)
Byte 1: 请求余项的字节数 (=7 x 组数)
Byte 2: 第一组的参考值类型 = 适合于 6xxxx
扩展寄存外存储器的06
Byte 3-6: 第一组的参考数值
= 适于 6xxxx 外存储器的存储器偏移量
= 适于 4xxxx 寄存器的32位参考数值
Byte 7-8: 第一组的指令
Bytes 9-15: (至于2-8字节,适于第二组)
. . .
响应
Byte 0: FC = 14 (16进制)
Byte 1: 响应的全部字节数 (=组数+ 组的总的字节数)
Byte 2: 第一组的字节数 (B1=1 + (2 x 指令数))
Byte 3: 第一组的参考类型
Byte 4-(B1+2): 第一组的寄存器值
Byte (B1+3): 第二组的字节数 (B2=1 + (2 x 指令数))
Byte (B1+4): 第二组的参考类型
Byte (B1+5)-(B1+B2+2): 第二组的寄存器值
. . .
异常
Byte 0: FC = 94 (16进制)
Byte 1: 异常代码 = 01 或 02或03或04
示例
参考值为1时读1扩展寄存器: 2 (在 Modicon 984中外存储器1偏移量2)得到16进制值1234
14 07 06 00 01 00 02 00 01 => 14 04 03 06 12 34
(将来)
参考值0时读1寄存器返回16进制值1234,参考值5时读2寄存器返回16进制值5678和9abc。
14 0E 04 00 00 00 00 00 01 04 00 00 00 05 00 02
=> 14 0A 03 04 12 34 05 04 56 78 9A BC
注意传输尺寸限制很难用数学公式精确定义。概括说来,由于缓冲的大小的限制以及考虑到每个请求和响应数据帧的总长度请求和响应的消息尺寸均限于256个字节。如果从站由于响应太大而拒绝发送此消息将产生异常类型04。
5.3.3 写一般参考值(FC 21)
请求
Byte 0: FC = 15 (16进制)
Byte 1: 请求余额的字节数
Byte 2: 第一组的参考值类型= 6xxxx 扩展寄存器存储器的06
Byte 3-6: 第一组的参考数值
= 适于 6xxxx 外存储器的存储器偏移量
= 用于 4xxxx 寄存器的32 位的参考数值
Byte 7-8: 第一组的指令数 (W1)
Byte 9-(8 + 2 x W1): 第一组的寄存器数据 (从字节2开始为其它组复制组的数据帧)
. . .
响应
响应是对询问的直接回应
Byte 0: FC = 15 (16进制)
Byte 1: 请求余额的字节数
Byte 2: 第一组的参考值类型 = 6xxxx 扩展寄存器存储器的06
Byte 3-6: 第一组的参考数值
= 6xxxx 外存储器的存储器偏移量
=用于 4xxxx 寄存器的32 位的参考数值
Byte 7-8: 第一组的指令数 (W1)
Byte 9-(8 + 2 x W1): 第一组的寄存器数据 (从字节2开始为其它组复制组的数据帧)
. . .
异常
Byte 0: FC = 95 (16进制)
Byte 1: 异常代码= 01 或 02或03或04
示例
参考值为1时写1扩展寄存器: 2 (在 Modicon 984中外存储器1偏移量2)得到 16进制值1234
15 09 06 00 01 00 02 00 01 12 34 => 15 09 06
00 01 00 02 00 01 12 34
(将来)
参考值0时写1寄存器返回16进制值1234,参考值5时写2寄存器返回16进制值5678和9abc。
15 14 04 00 00 00 00 00 01 12 34 04 00 00 00 05 00
02 56 78 9A BC
ð 15 14 04 00 00 00 00 00 01 12 34 04 00 00
00 05 00 02 56 78 9A BC
注意传输尺寸限制很难用数学公式精确定义。概括说来,由于缓冲的大小的限制以及考虑到每个请求和响应数据帧的总长度请求和响应的消息尺寸均限于256个字节。如果从站由于响应太大而拒绝发送此消息将产生异常类型04。
5.3.4 掩膜写寄存器 (FC 22)
请求
Byte 0: FC = 16 (16进制)
Byte 1-2: 参考数值
Byte 3-4: AND掩膜用于寄存器
Byte 5-6: OR 掩膜用于寄存器
响应
Byte 0: FC = 16 (16进制)
Byte 1-2: 参考数值
Byte 3-4: AND 掩膜用于寄存器
Byte 5-6: OR 掩膜用于寄存器
异常
Byte 0: FC = 96 (16进制)
Byte 1: 异常代码 = 01 或 02
示例
在参考值为0(Modicon 984中为40001)时将寄存器的0-3位字段改为16进制值4 (AND 用 000F, OR用 0004)
16 00 00 00 0F 00 04 => 16 00 00 00 0F 00 04
5.3.5 读/ 写寄存器 (FC 23)
请求
Byte 0: FC = 17 (16进制)
Byte 1-2: 用于读的参考数值
Byte 3-4: 用于读的指令数 (1-125)
Byte 5-6: 用于写的参考数值
Byte 7-8: 用于写的指令数 (1-100)
Byte 9: 字节数 (B = 2 x 用于写的指令数)
Byte 10-(B+9): 寄存器值
响应
Byte 0: FC = 17 (16进制)
Byte 1: 字节数Byte count(B = 2 x 用于读的指令数)
Byte 2-(B+1) 寄存器值
异常
Byte 0: FC = 97 (16进制)
Byte 1: 异常代码 = 01 或 02
示例
参考值为3(在Modicon 984中为40004)时写入1寄存器16进制值0123,参考值为0时读2寄存器返回值0004和5678(16进制)
17 00 00 00 02 00 03 00 01 02 01 23 => 17 04 00 04 56 78
注意如果寄存器交替的进行读写操作,结果是不明确的。一部分设备先写后读,另部分则先读后写。
5.3.6 读FIFO 队列 (FC 24)
请求
Byte 0: FC = 18 (16进制)
Byte 1-2: 参考数值
响应
Byte 0: FC = 18 (16进制)
Byte 1-2: 字节数 (B = 2 + 指令数) (最大64)
Byte 3-4: 指令数 (FIFO中累积的指令数) (最大 31)
Byte 5-(B+2): 从 FIFO前开始的寄存器数据
异常
Byte 0: FC = 98 (16进制)
Byte 1: 异常代码 = 01 或02或 03
示例
读从参考值0005 (Modicon 984中为40006)开始的FIFO区段内容,其中包括2指令的值1234和5678(16进制)
18 00 05 => 18 00 06 00 02 12 34 56 78
注意到执行在984上的该功能在通用性方面非常有限-假定寄存器的该区段包括含有从0到31值的计数器,后面还跟着最大到31指令字的数据。当该功能完成,该计数器指令字不会象经过FIFO操作所期望的回复为0。
一般说来,这可被看作函数16-读乘法寄存器的有限子集,既然后者可用来完成所必须的功能性。
6. 异常代码
在出问题的时候,有一系列定义过的异常代码被从站送回。注意到主站会“投机地”发送指令,利用接收到的成功或异常代码来确定支配设备的哪一个MODBUS愿意响应以及从站不同可用数据区的大小。
所有的异常通过添加0x80 到请求的功能代码来标记,跟随此字节的是一个单一的原因字节如下例所示:
03 12 34 00 01 => 83 02
当索引0x1234响应异常类型2-“非法的数据地址”时请求读1寄存器
异常情况列举如下:
01 非法的功能
对从站来说,在询问过程中收到的功能代码是不允许的行为。这可能是由于功能代码只适用于新近的控制器,而不能在所选的单元使用。也可推断出从站处于错误的状态而发出这样的一种请求,例如未经配置而被要求返回寄存器值。
02 非法的数据地址
对从站来说,在询问过程中收到的数据地址不是允许的地址。更明确一点,参考数值和传输长度的结合是无效的。对于一个有100个寄存器的控制器来说,具有偏移96和长度4的请求将能成功,而具有偏移96和长度5的请求将产生异常02。
03 非法的数据值
对从站来说,在询问数据区段所包含的值是不允许的。这推断出在复杂请求余额的结构中的一个错误,例如隐含长度是不正确的。既然MODBUS协议不了解一些特殊寄存器的特殊值的意义,因此这并不意味着寄存器中被提交用于存储的数据对象有一个应用程序期望值之外的值,
04非法的响应长度
指出加外框的请求将产生一个尺寸超出可用MODBUS数据尺寸的响应。仅用于由功能所产生的多部分响应,如功能20和21。
05 确认
专用于关联程序设计指令。
06 从站设备忙
专用于关联程序设计指令。
07 否认
专用于关联程序设计指令。
08 存储器奇偶校验错误
专用于关联功能代码20和21,指出扩展文件区没通过一致性检验。
0A 网关通路不可用
专用于关联Modbus Plus 网关, 指出网关未能分配Modbus Plus路径以处理请求。通常意味着网关配置错误。
0B 网关目标设备响应失败
专用于关联Modbus Plus网关,指出从目标设备未能获得响应。通常意味着设备没有连接到网络上。