References RFC 791, Internet Protocol, Sep81 DARPA
前言:本文是个人基于Modbus协议英文原版说明书为基础,多方面考证理解后进行的理解性翻译。网络上现有的解释驳杂不清,多数功能码也没有详细解释。既然没有轮子,荷取就只能自己造了。说实话准备翻译校对和整理的时候根本没多想.....真干起来才发现难度比预想的要大得多。借助了gpt翻译,但gpt翻译得也不尽如人意,糟糕的中英语法逻辑转换加之gpt的胡言乱语,四处校对和钻研挺花时间,预计再过个几天就能利用空闲时间消化、整理、翻译、转述完毕吧。
0x01 读线圈状态(Read Coils)
在这里首先明确一个基本概念:字节序和位序
在前篇的数据结构中已经说明,modbus采用大端字节序,会将大数据分割成多个字节,优先传输高位。这里的顺序指的是字节发送的顺序而非位序。而在串行通信中,对于位的传输都是从低位到高位,该顺序与字节的顺序相反。,因此我们可以看到如下实例:
如图实例,输出27-20的状态以字节值CD十六进制或二进制1100 1101表示。输出27是该字节的最高有效位(MSB),而输出20是最低有效位(LSB)。
0x02 读离散输入状态(Read Discrete Inputs )
0x02和0x01基本一致,唯一的区别就是离散输入是只读的。离散输入是只读的输入,线圈是可控的输出。
0x03 读保持寄存器(Read Holding Registers )
该功能码用于读取远程设备中连续一块保持寄存器的内容。和线圈类似,请求PDU=起始地址+寄存器数量。在PDU中,寄存器从零开始寻址。因此,寄存器编号为1-16的寄存器被寻址为0-15。最多允许读125个寄存器(125*8=2000)
响应消息中的寄存器数据以每个寄存器两个字节的形式打包,二进制内容在每个字节中右对齐。对于每个寄存器,第一个字节包含高位,第二个字节包含低位。
实例如图,请求报文为03(功能码)+00(起始地址高位字节)+6B(起始地址低位字节)+00(寄存器地址高位字节)+03(寄存器地址低位字节)
响应报文为03(功能码响应)+06(接下来的数据大小,6个字节)+02(0x6B+1=0x6C,也就是十进制108,108号寄存器的高位)+2B(108号寄存器的低位)+00(109高位)+00(109低位)+00(110高位)+64(110低位)
由于此处寄存器都是对字节的操作,因此不需要考虑位序的问题。
0x04 读输入寄存器(Read Input Registers)
和0x03一样,区别只在于输入寄存器是只读的。
0x05 写单线圈(Write Single Coil )
具体看实例就明白了了。如图,格式就是功能码+输出地址高位+低位+输出(写入)值高位+输出(写入)值低位,响应报文则和输入报文一模一样。
0x06 写单寄存器(Write Single Register)
和0x05基本上一模一样,区别只有目标对象是寄存器而已
0x07 读取异常状态(限串行线)(Read Exception Status (Serial Line only) )
如图,实例中返回6D,将其作为BCD码转化回二进制则为01101101。输出时从最高地址到最低地址的依次显示,也就是从右到左,从最高有效地址位到最低有效地址位。
0x08 通信系统诊断(限串行线)(Diagnostics (Serial Line only) )
功能码08用于测试客户端设备和服务器之间通信系统,或检查服务器内部的各种错误条件。
接下来列出其子功能码:
00 返回查询数据
请求数据字段中传递的数据将在响应中返回(回送)。整个响应消息应与请求完全相同。
子功能 | 请求数据字段 | 响应数据字段 |
---|---|---|
0000 | 任意 | 回显 |
01 重新启动通信选项
初始化和重新启动远程设备的串行线端口,并清除所有通信事件计数器。如果端口当前处于仅监听模式,则不返回响应。此功能是唯一将端口从仅监听模式中退出的功能。如果端口当前不处于仅监听模式,则会在重启之前返回正常响应。
当远程设备接收到请求时,它会尝试重新启动和自检测试,成功完成测试将使端口上线。
请求数据字段为FF 00十六进制会导致端口的通信事件日志也被清除。请求数据字段为00 00将保留日志在重新启动之前的状态。
子功能 | 请求数据字段 | 响应数据字段 |
---|---|---|
0001 | 00 00 | 00 01 00 00 |
0001 | FF 00 | 00 01 FF 00 |
02 返回诊断寄存器
响应中返回远程设备的16位诊断寄存器的内容。
子功能 | 请求数据字段 | 响应数据字段 |
---|---|---|
0002 | 00 00 | 诊断寄存器内容 |
03 更改ASCII输入分隔符
请求数据字段中传递的字符'CHAR'将成为未来消息的结束分隔符(替代默认的LF字符)。在ASCII消息末尾不需要换行符的情况下,此功能非常有用。
子功能 | 请求数据字段 | 响应数据字段 |
---|---|---|
0003 | CHAR 00 | 回显请求数据 |
04 强制进入仅监听模式
强制被寻址的远程设备进入仅监听模式,用于MODBUS通信。这将使其与网络上的其他设备隔离,允许它们在不受干扰的情况下继续通信。不返回响应。
当远程设备进入仅监听模式时,所有活动的通信控制都被关闭。准备就绪的看门狗定时器将被允许超时,关闭控制。在设备处于此模式时,将监视寻址到它或广播的任何MODBUS消息,但不会执行任何操作,也不会发送任何响应。
在进入该模式后,唯一会被处理的功能是重新启动通信选项功能(功能码8,子功能1)。
子功能 | 请求数据字段 | 响应数据字段 |
---|---|---|
0004 | 00 00 | 无响应返回 |
10 (0A Hex) 清除计数器和诊断寄存器
目标是清除所有计数器和诊断寄存器。计数器也会在上电时被清除。
子功能 | 请求数据字段 | 响应数据字段 |
---|---|---|
0010 | 00 00 | 回显请求数据 |
11 (0B Hex) 返回总线消息计数
响应数据字段返回远程设备自上次重新启动、清除计数器操作或上电以来在通信系统上检测到的消息数量。
子功能 | 请求数据字段 | 响应数据字段 |
---|---|---|
0011 | 00 00 | 总消息计数 |
12 (0C Hex) 返回总线通信错误计数
响应数据字段返回远程设备自上次重新启动、清除计数器操作或上电以来遇到的CRC错误数量。
子功能 | 请求数据字段 | 响应数据字段 |
---|---|---|
0012 | 00 00 | CRC错误计数 |
13 (0D Hex) 返回总线异常错误计数
响应数据字段返回远程设备自上次重新启动、清除计数器操作或上电以来返回的MODBUS异常响应数量。
异常响应在第7节中有描述和列出。
子功能 | 请求数据字段 | 响应数据字段 |
---|---|---|
0013 | 00 00 | 异常错误计数 |
14 (0E Hex) 返回服务器消息计数
响应数据字段返回自上次重新启动、清除计数器操作或上电以来远程设备处理的寻址到该远程设备或广播的消息数量。
子功能 | 请求数据字段 | 响应数据字段 |
---|---|---|
0014 | 00 00 | 服务器消息计数 |
15 (0F Hex) 返回服务器无响应计数
响应数据字段返回自上次重新启动、清除计数器操作或上电以来寻址到远程设备但未返回任何响应(既不是正常响应也不是异常响应)的消息数量。
子功能 | 请求数据字段 | 响应数据字段 |
---|---|---|
0015 | 00 00 | 服务器无响应计数 |
16 (10 Hex) 返回服务器NAK计数
响应数据字段返回自上次重新启动、清除计数器操作或上电以来寻址到远程设备并返回否定应答(NAK)异常响应的消息数量。异常响应在第7节中有描述和列出。
子功能 | 请求数据字段 | 响应数据字段 |
---|---|---|
0016 | 00 00 | 服务器NAK计数 |
17 (11 Hex) 返回服务器忙计数
响应数据字段返回自上次重新启动、清除计数器操作或上电以来寻址到远程设备并返回服务器设备忙异常响应的消息数量。
子功能 | 请求数据字段 | 响应数据字段 |
---|---|---|
0017 | 00 00 | 服务器设备忙计数 |
18 (12 Hex) 返回总线字符溢出计数
响应数据字段返回自上次重新启动、清除计数器操作或上电以来寻址到远程设备但由于字符溢出条件而无法处理的消息数量。字符溢出是由数据字符到达端口的速度超过存储速度,或由于硬件故障导致字符丢失引起的。
子功能 | 请求数据字段 | 响应数据字段 |
---|---|---|
0018 | 00 00 | 服务器字符溢出计数 |
20 (14 Hex) 清除溢出计数器和标志
清除溢出错误计数器并重置错误标志。
子功能 | 请求数据字段 | 响应数据字段 |
---|---|---|
0020 | 00 00 | 回显请求数据 |
实例如下:
如图,请求报文为功能码08+子功能码高位00+子功能码低位00(子功能码0000,实现返回查询数据)+数据高位A5+数据低位37
响应报文和返回报文一致,即实现了返回查询数据。
0x09-0x0A无
0x0B 获取串行通信事件计数器(Get Comm Event Counter (Serial Line only) )
该功能码用于从远程设备的通信事件计数器中获取状态字和事件计数。每次成功完成消息事件(各种请求响应命令等,但不包括异常响应、轮询命令和获取事件计数器的命令),都会让设备的事件计数器在增加。通过通信系统诊断功能(功能码08)的子功能码0001(重启)或000A(清除计数器和诊断计数器)可以重置事件计数器。正常的响应包含一个两字节的状态字和一个两字节的事件计数。如果先前发出的程序命令仍在远程设备中处理中(存在繁忙状态),状态字将为全1(FF FF十六进制)。否则,状态字将为全0。
在该例中,状态字为FF FF,远程设备繁忙。事件计数显示设备已经计数了264个事件(01 08十六进制)
0x0C 获取串行通信事件日志 ( Get Comm Event Log (Serial Line only) )
响应的事件字节如下:
事件字节由获取通信事件日志功能返回,可以是四种类型之一。类型由每个字节的第7位(高位)定义(可以理解为某种形式的功能码)。它可能进一步由第6位定义(可以理解成某种形式的子功能码)。下面进行解释。
设备事件:Modbus接收
存储时机:远程设备处理消息之前
补充说明:此事件由第7位设置为逻辑“1”来定义。如果相应的条件为TRUE,则其他位将设置为逻辑“1”。各位含义如下:
设备事件:设备MODBUS发送
存储时机:远程设备完成处理请求消息时
补充说明:如果远程设备返回正常或异常响应,或者没有响应,则会存储该事件。此事件由第7位设置为逻辑“0”,第6位设置为“1”来定义。如果相应的条件为TRUE,则其他位将设置为逻辑“1”。各位含义如下:
设备事件:进入仅监听模式
存储时机:远程设备进入仅监听模式。
补充说明:该事件由被定义为了十六进制的04。
设备事件:发起通信重启
存储时机:远程设备的通信端口重新启动时(通过0x08通信系统诊断诊断的子功能:0001重启通信选项)。
补充说明:该功能提供了“录错继续”或“错误终止”两种模式。如果将远程设备置于“录错继续”模式,则将事件字节添加到现有事件日志中。如果将远程设备置于“错误终止”模式,则将字节添加到日志中,并将此后的其余部分清零。该事件由被定义为了十六进制的00。
0x0D-0x0E无
0x0F 写多个线圈(Write Multiple Coils)
功能如其名,使用方法和0x01读线圈状态基本一致、这个功能码用于强制远程设备中一系列线圈中的每个线圈为打开或关闭状态。请求PDU指定要强制的线圈引用。线圈的地址从零开始。因此,编号为1的线圈被视为地址0。
请求数据字段的内容指定了所请求的打开/关闭状态。字段中的逻辑“1”表示请求相应的输出为打开状态。逻辑“0”表示请求相应的输出为关闭状态。
正常的响应返回功能码、起始地址和强制线圈的数量。
以下是一个写入从线圈20开始的一系列10个线圈的请求示例,在阅读该例子前,请先确保已经理解了我在0x01功能码中所写的有关位序和字节序的说明。
位:1 1 0 0 1 1 0 1 0 0 0 0 0 0 0 1
输出:27 26 25 24 23 22 21 20 – – – – – – 29 28
在该实例中,请求报文为:
功能码0F+起始地址高位00+起始地址低位0x13(十进制19)+输出数量高位00+输出数量低位0A(十进制10)+字节数02+输出值高位CD(11001101)+输出值低位01(00000001)
响应报文为:
功能码0F+起始地址高位00+起始地址低位13+输出数量高位00+输出数量低位0A
注意此处的响应报文和写单线圈不同,并不会回显写入的内容
0x10 写多个寄存器(Write Multiple registers)
实例如图,请求报文的格式为:
功能码10+起始地址高位00+起始地址低位01+寄存器数量高位00+寄存器数量低位02+数据字节数04+寄存器1高位00+寄存器1低位0A+寄存器2高位01+寄存器2低位02
响应报文的格式为:
功能码10+起始地址高位00+起始地址低位01+寄存器数量高位00+寄存器数量低位02
0x11 报告服务器ID(仅串行线)(Report Server ID (Serial Line only) )
该功能码用于读取远程设备的类型描述、当前状态和其他特定信息。
正常响应的格式如下所示。数据内容针对每种设备类型而不同。
如图实例,请求报文为功能码11,响应报文为功能码11+设备数据大小(用一个字节表示)+设备ID+设备开关指示符(0x00或0xFF,前者表示关闭后者表示开启)+设备附加数据
0x12-0x13无
0x14 读文件记录(Read File Record )
该功能码用于执行文件记录读取。所有请求数据长度以字节为单位提供,而记录长度以寄存器为单位提供。
文件是记录的组织形式。每个文件包含10000个记录,地址为0000到9999十进制或0X0000到0X270F。例如,记录12的地址为12。
该函数可以读取多个引用组。这些组可以是分离的(非连续的),但是每个组内的引用必须是连续的。
每个组在一个单独的“子请求”字段中定义,该字段包含7个字节:
引用类型:1个字节(必须指定为6)
文件号:2个字节
文件中的起始记录号:2个字节
要读取的记录长度:2个字节
要读取的寄存器数量与预期响应中的所有其他字段相结合,不能超过MODBUS PDU的允许长度:253个字节。
正常响应是一系列“子响应”,每个“子请求”对应一个。字节计数字段是所有“子响应”中字节总数的组合计数。此外,每个“子响应”还包含一个显示自己字节计数的字段。
以下是一个从远程设备读取两个引用组的请求示例:
- 第一组由文件4中的两个寄存器组成,从寄存器1开始(地址0001)。
- 第二组由文件3中的两个寄存器组成,从寄存器9开始(地址0009)。
0x15 写文件记录(Write File Record)
该功能码用于执行文件记录写入操作。和0x14读文件记录相似,所有请求数据长度以字节为单位提供,而记录长度以16位字(word)的数量为单位提供。
文件是记录的组织形式。每个文件包含10000个记录,地址为0000到9999十进制或0X0000到0X270F。例如,记录12的地址为12。
该函数可以写入多个引用组。这些组可以是分离的(非连续的),但是每个组内的引用必须是连续的。
每个组在一个单独的“子请求”字段中定义,该字段包含7个字节加上数据:
引用类型:1个字节(必须指定为6)
文件号:2个字节
文件中的起始记录号:2个字节
要写入的记录长度:2个字节
要写入的数据:每个寄存器2个字节
要写入的寄存器数量与请求中的所有其他字段相结合,不能超过MODBUS PDU的允许长度:253个字节。
正常响应是请求的回显。
以下是一个将一个引用组写入远程设备的请求示例:
- 该组由文件4中的三个寄存器组成,从寄存器7开始(地址0007)。
0x16 带屏蔽字写入寄存器(Mask Write Register )
该功能码使用“与字”(And_Mask)、“或字”(Or_Mask)以及寄存器当前内容进行运算来修改指定保持寄存器的内容。可用于设置或清除寄存器中的单个位。
其中,"AND_Mask"表示需要且的内容,“OR_Mask”表示需要或的内容,该功能码的算法为:
结果 = (寄存器当前内容 && 与字)||(或字 &&(与字按位取反))
实例如图:
Current Contents为寄存器当前内容,Not And_mask为与码按位取反,Result为结果
- 如果Or_Mask值为零,则结果只是当前内容和And_Mask的逻辑与操作。如果And_Mask值为零,则结果等于Or_Mask值。
- 可以使用读保持寄存器函数(功能码03)读取寄存器的内容。然而,随后在控制器扫描其用户逻辑程序时,它们可能会被更改。
通常情况下,对请求的响应在完成对寄存器的写入后返回。
如图,请求报文为:
功能码16+当前寄存器地址高位00+当前寄存器地址低位04+与字高位00+与字低位F2+或字高位00+或字低位25
响应报文为功能码16+当前寄存器地址低位04+与字高位00+与字低位F2+或字高位00+或字低位25
0x17 读/写多个寄存器(Read/Write Multiple registers)
0x18 读取先进先出(FIFO)队列(Read FIFO Queue)
0x19-0x2A无
0x2B 封装接口传输(Encapsulated Interface Transport .)
博客园作者:河城荷取
版权声明:欢迎分享本文,转载请保留出处!