(9条消息) Modbus应用协议详解
Modbus应用协议
- 缩略语
- 协议描述
- 服务器正常响应
- 服务器异常响应
- 三种PDU
- mb_req_pdu
- mb_rsp_pdu
- mb_excep_rsp_pdu
- 数据编码
- Modbus数据模型
- Modbus模型实现的实例
- 实例一:有四个独立块的设备
- 实例二:仅有一个块的设备
- Modbus寻址模型
- Modbus事务处理的定义
- 功能码分类
- 公共功能码定义
- 功能码描述
- (0x01)读线圈
- mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
- 实例与状态图
- (0x02)读离散量输入
- mb_req_pdu/ mb_rsp_pdu/mb_excep_rsp_pdu
- 实例与状态图
- (0x03)读保持寄存器
- mb_req_pdu/ mb_rsp_pdu/ mb_excep_rsp_pdu
- 实例与状态图
- (0x04)读输入寄存器
- mb_req_pdu/ mb_rsp_pdu/ mb_excep_rsp_pdu
- 实例与状态图
- (0x05)写单个线圈
- mb_req_pdu/ mb_rsp_pdu/ mb_excep_rsp_pdu
- 实例与状态图
- (0x06)写单个寄存器
- mb_req_pdu/ mb_rsp_pdu/ mb_excep_rsp_pdu
- 实例与状态图
- (0x07)读异常状态(仅用于串行链路)
- mb_req_pdu/ mb_rsp_pdu/ mb_excep_rsp_pdu
- 实例与状态图
- (0x08)诊断(仅用于串行链路)
- mb_req_pdu/ mb_rsp_pdu/ mb_excep_rsp_pdu
- 串行链路设备支持的子功能码
- (0000)返回询问数据
- (0001)重新启动通信选项
- (0002)返回诊断寄存器
- (0003)改变ASCII输入分隔符
- (0004)强制只听模式
- (000A)清除计数器和诊断寄存器
- (000B)返回总线报文计数
- (000C)返回总线通信错误计数
- (000D)返回总线异常错误计数
- (000E)返回从站报文计数
- (000F)返回从站无响应计数
- (0011)返回从站忙计数
- (0012)返回总线字符超限计数
- (0014)清除超限计数器和标志
- 实例与状态图
- (0x0B)获得通信事件计数器(仅用于串行链路)
- mb_req_pdu/ mb_rsp_pdu/ mb_excep_rsp_pdu
- 实例与状态图
- (0x0C)获得通信事件记录(仅用于串行链路)
- mb_req_pdu/mb_rsp_pdu/mb_excep_pdu
- 实例与状态图
- (0x0F)写多个线圈
- mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
- 实例与状态图
- (0x10)写多个寄存器
- mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
- 实例与状态图
- (0x11)报告从站ID(仅用于串行链路)
- mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
- 实例与状态图
- (0x14/0x06)读文件记录
- mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
- 实例与状态图
- (0x15/0x06)写文件记录
- mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
- 实例与状态图
- 屏蔽写寄存器
- mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
- 实例与状态图
- (0x17)读/写多个寄存器
- mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
- 实例与状态图
- (0x18)读FIFO队列
- mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
- 实例与状态图
- (0x2B)封装接口传输
- mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
- (0x2B/0x0E)读设备标识
- mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
- 请求参数描述
- 响应参数描述
- 实例与状态图
- Modbus异常响应
- 异常码表
缩略语
协议描述
Modbus是一个请求/应答协议,并且提供功能码规定的服务。Modbus功能码是Modbus请求/应答PDU 的元素。
Modbus协议定义了一个与基础通信层无关的简单协议数据单元(PDU),特定总线或网络上的Modbus协议映射能够在应用数据单元(ADU)上引入一些附加域
启动Modbus事务处理的客户机(主)创建Modbus应用数据单元,功能码向服务器(从)指示将执行哪种操作,Modbus协议建立了客户机启动的请求格式。
用一个字节编码Modbus数据单元的功能码域,有效的码字范围是十进制1-255(128-255为异常响应保留),当从客户机向服务器设备发送报文时,功能码域通知服务器执行哪种操作。
向一些功能码加入子功能码来定义多项操作
从客户机向服务器设备发送的报文数据域包括附加信息,服务器使用这个信息执行功能码定义的操作。这个域还包括离散量和寄存器地址、处理的项目数量以及域中的实际数据字节数。
在某种请求中,数据域可以是不存在的(0长度),在此情况下服务器不需要任何附加信息,功能码仅说明操作
如果在一个正确接收的Modbus ADU中,不出现与请求Modbus功能有关的差错,那么服务器至客户机的响应数据域包括所请求的数据。如果出现与所请求Modbus功能有关的差错,那么该域包括一个异常码,服务器应用能够使用这个域确定下一个执行的操作
服务器正常响应
当服务器对客户机响应时,它使用功能码域来指示正常(无差错)响应或者出现某种差错(称为异常响应),对于一个正常响应来说,服务器仅复制原始功能码
服务器异常响应
对于异常响应,服务器将原始功能码的最高有效位设置为逻辑1后返回
注:需要管理超时,以避免无限期的等待可能不会出现的应答
三种PDU
Modbus最初在串行链路上的实现(最大RS485 ADU=256字节)限制了Modbus PDU的长度,因此对串行链路通信来说,Modbus PDU=256-服务器地址(1字节)-CRC(2字节)=253字节,从而,RS232/RS485 ADU=253字节+服务器地址+CRC=256字节
Modbus协议定义了三种PDU,他们是:1.Modbus请求PDU,mb_req_pdu2.Modbus响应PDU,mb_rsp_pdu3.Modbus异常响应PDU,mb_excep_rsp_pdu
mb_req_pdu
mb_req_pdu={function_code,request_data}其中fuction_code:1字节,Modbus功能码request data:n字节,这个域与功能码有关,并且通常包括诸如参考变量、变量计数、数据偏移、子功能码等信息
mb_rsp_pdu
mb_rsp_pdu={function_code,response_data},其中function code:1字节,modbus功能码response data:n字节,这个域与功能码有关,并且通常包括诸如参考变量、变量计数、数据偏移、子功能码等信息
mb_excep_rsp_pdu
mb_excep_rsp_pdu={function_code,exception_code},其中function code:1字节,modbus功能码+0x80exception code:1字节,modbus异常码
数据编码
Modbus使用最高有效字节在低地址存储的方式表示地址和数据项,这意味着当发送多个字节时,首先发送最高有效字节,例如:
0x1234,发送的第一个字节为0x12,然后是0x34
Modbus数据模型
Modbus的数据模型是以一组具有不同特征的表为基础建立的
输入与输出之间以及位寻址和字寻址的数据项之间的区别并不意味着应用特性的差别,如果所有4个表相互覆盖是对该目标机器最自然的解释,也是完全可接受的,而且很普遍
对于每个基本表,协议都允许单个的选择65536个数据项,而且其读写操作被设计为可以越过多个连续数据项直到数据大小规格限制,这个数据大小规格限制与事务处理功能码有关
很显然,必须将Modbus处理的所有数据(位,寄存器)放置在设备应用存储器中,但是存储器的物理地址不应该与寄存器编号混淆,仅要求将寄存器编号与物理地址链接
Modbus功能码中使用的Modbus寄存器逻辑编号是以0开始的无符号整数索引
Modbus模型实现的实例
下列实例表示了两种在设备中组织数据的方法,有多种数据组织的方法,在本部分中没有被全部描述,每个设备根据其应用都有它自己的组织数据的方法
实例一:有四个独立块的设备
下图表示了含有数字量、模拟量、输入量和输出量的设备中的数据组织,由于不同块中的数据不相关,每个块是相互独立的,可通过不同Modbus功能码访问每个块
实例二:仅有一个块的设备
设备仅有一个数据块,通过几个Modbus功能码能够得到相同的数据,既可以通过16位访问也可以通过1位访问
Modbus寻址模型
Modbus应用协议精确地定义了PDU寻址规则
在Modbus PDU中,从0-65536寻址每个数据
Modbus应用协议还明确的定义了由4个块构成的Modbus数据协议,每个块由编号为1-n的元素构成
在Modbus数据模型中,从1-n为数据块中的每个元素编号
然后必须将Modbus模型与设备应用结合
Modbus数据模型和设备应用之间的映射完全与特定设备相关
下图表示了用Modbus PDU的X-1寻址编号为X的Modbus数据
Modbus事务处理的定义
下图描述了在服务器侧Modbus事务处理的一般处理过程
一旦服务处理请求,使用合适的Modbus服务器事务处理建立Modbus响应
根据处理结果,可以建立两种类型响应:
- 一个正常的Modbus响应,响应功能码=请求功能码
- 一个异常的Modbus响应
a) 用来为客户机提供处理过程中与所发现的差错相关的信息
b) 异常功能码=请求功能码+0x80
c) 提供一个异常码来指示差错原因
功能码分类
有三类Modbus功能码,它们是:
- 公共功能码
a) 被确切定义的功能码
b) 保证是唯一的
c) 由Modbus.org确认的
d) 公开的文档
e) 可进行一致性测试
f) 在MB ITEF RDC中归档
g) 包含已被定义的公共功能码和保留给未来使用的功能码 - 用户自定义功能码
a) 有两个用户定义功能码的区域,即十进制的65-72和100-110
b) 用户无需Modbus组织的任何批准就可以选择和实现一个功能码
c) 不能保证被选功能码的使用是唯一的
d) 如果用户希望将某种功能设置为一个公共功能码,那么用户必须启动RFC,以便将改变引入公共分类中,并且指配一个新的公共功能码 - 保留功能码
a) 某些公司在传统产品上现行使用的功能码,不作为公共使用
公共功能码定义
功能码描述
(0x01)读线圈
使用该功能码从一个远程设备中读1-2000个连续的线圈状态,请求PDU指定了起始地址,即指定了第一个线圈地址和线圈数目,地址从0开始
响应报文中的线圈按数据域的每位一个线圈进行打包,状态被表示为1=ON和0=OFF,第一个数据的LSB包含询问中所寻址的输出,其他线圈以此类推,直到这个字节的高位端为止,并在后续字节中按照从低位到高位的顺序排列
如果返回的输出数量不是8的倍数,将用0填充最后数据字节中的剩余位,字节数量域说明了数据的全部字节数
mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
实例与状态图
下图是一个请求读离散量输出20-38的实例:
将输出27-20的状态表示为十六进制字节值0xCD或二进制11001101,输出27是这个字节的MSB,输出20是LSB
第一个字节的输出从左到右为27-20,下一个字节的输出从左到右为35-28,当串行发送位时,从LSB向MSB传输:20…27…35…
在最后的数据字节中,将输出38-36的状态表示为十六进制值0x05或二进制00000101,输出38是左侧第6个位置,输出36是这个字节LSB,用0填充高5位
(0x02)读离散量输入
使用该功能码从一个远程设备中读1-2000个连续的离散量输入状态,请求PDU指定了起始地址,即指定了第一个离散量输入地址和离散量输入数目,在PDU中从0开始寻址离散量输入,因此编号1-16的离散量输入寻址为0-15
响应报文中的离散量输入按数据域的每位一个离散量输入进行打包,状态表示成1=ON和0=OFF,第一个数据字节的LSB包含询问中所寻址的输入,其他离散量输入以此类推,直到这个字节的高位端为止,并在后续的字节中按照从低位到高位的顺序排列
如果返回的输入数量不是8的倍数,将用0填充最后数据字节中的剩余位,字节数量域说明了数据的全部字节数
mb_req_pdu/ mb_rsp_pdu/mb_excep_rsp_pdu
实例与状态图
下图是一个请求离散量输入197-218的实例:
将离散量输入204-197的状态表示为十六进制值0xAC或二进制10101100,输入204是这个字节的MSB,输入197是这个字节的LSB
将离散量输入218-213的状态表示为十六进制值0x35或二进制00110101,离散量输入218位于左侧第三位,离散量输入213是这个字节的LSB,用0填充高2位
(0x03)读保持寄存器
使用该功能码从远程设备中读保持寄存器连续块的内容,请求PDU说明了起始寄存器地址和寄存器数量,在PDU中,从0开始寻址寄存器,因此编号1-16的寄存器寻址为0-15
将响应报文中的寄存器数据打包成每个寄存器有两字节
对于每个寄存器,第一个字节为高位字节,第二个字节为低位字节
mb_req_pdu/ mb_rsp_pdu/ mb_excep_rsp_pdu
实例与状态图
下图是一个请求读寄存器108-110的实例:
将寄存器108的内容表示为两个十六进制字节值0x022B,将寄存器109-110的内容分别表示为十六进制0x000和0x0064
(0x04)读输入寄存器
使用该功能码从一个远程设备中读1-125个连续输入寄存器,请求PDU说明了起始地址和寄存器数量,在PDU中从0开始寻址寄存器,因此编号为1-16的寄存器寻址为0-15
将响应报文中的寄存器数据打包成每个寄存器两个字节
对于每个寄存器,第一个字节为高位字节,第二个字节为低位字节
mb_req_pdu/ mb_rsp_pdu/ mb_excep_rsp_pdu
实例与状态图
下图是一个请求读输入寄存器9的实例:
将输入寄存器9的内容表示为两个十六进制值0x000A
(0x05)写单个线圈
使用该功能码将一个远程设备中的一个输出写为ON/OFF
请求数据域中的常数指定所请求的ON/OFF状态,十六进制0xFF00请求输出为ON,十六进制0x0000请求输出为OFF,其他所有值均是非法的,并且对输出不起作用
请求PDU说明了被强制的线圈地址,从0开始寻址线圈,因此编号为1的线圈寻址为0
正常的响应是请求的复制,在写入线圈状态之后被返回
mb_req_pdu/ mb_rsp_pdu/ mb_excep_rsp_pdu
实例与状态图
下图是一个请求写线圈173为ON的实例:
(0x06)写单个寄存器
使用该功能码在一个远程设备中写一个保持寄存器
请求PDU指定了被写入的寄存器地址,从0开始寻址寄存器,因此编号为1的寄存器被寻址为0
正常的响应是请求的复制,在写入寄存器内容之后被返回
mb_req_pdu/ mb_rsp_pdu/ mb_excep_rsp_pdu
实例与状态图
下图是一个请求将十六进制0x0003写入寄存器2的实例:
(0x07)读异常状态(仅用于串行链路)
使用这个功能码从一个远程设备中读8个异常状态输出的内容
因为异常码输出参量是已知的(在这个功能中不需要输出参量),该功能提供一种简单的访问这种信息的方法
正常的响应包括8个异常状态输出的内容,将这些输出打包成一个字节,每个输出一个位,在该字节的LSB中包含最低位输出参量的状态
mb_req_pdu/ mb_rsp_pdu/ mb_excep_rsp_pdu
实例与状态图
下图是一个请求读异常状态的实例:
在这个实例中,输出数据是十六进制0x6D(01101101),从左到右,输出为OFF-ON-ON-OFF-ON-ON-OFF-ON,从最高到最低寻址输出的方式显示状态
(0x08)诊断(仅用于串行链路)
Modbus功能码提供一系列测试,用于检测客户机(主站)与服务器(从站)之间的通信系统,或服务器中的各种内部差错状态
这个功能使用询问中的2个字节的子功能码域来定义所执行的测试类型,服务器在正常的响应中复制功能码和子功能码,一些诊断会导致远程设备通过正常响应的数据域返回相应数据
通常,向远程设备发送诊断功能,不影响远程设备中的用户程序运行,诊断不能访问用户逻辑,某些功能可以任意的复位远程设备中的差错计数器
但是,可以强制服务器进入“只听”模式,在这种模式中服务器监视通信系统中的报文而不对报文进行响应,如果应用程序与远程设备的进一步数据交换有关,就可能影响应用程序的结果,一般情况下,这种模式被强制用来从通信系统中去除有故障的远程设备
下列诊断功能专门用于串行链路设备
对返回询问数据请求的正常响应是回送相同的数据,同时还复制功能码和子功能码
mb_req_pdu/ mb_rsp_pdu/ mb_excep_rsp_pdu
串行链路设备支持的子功能码
下图是串行链路设备所支持的子功能码列表,所列出的每个子功能码均附带用于诊断的数据域内容的实例
(0000)返回询问数据
在响应中返回请求数据域中传递的数据,响应报文应该与请求报文全部一致
(0001)重新启动通信选项
必须初始化和重新启动远程设备串行链路端口,并且清除所有通信事件计数器。如果端口正在只听模式下,不返回响应,它是唯一的能将端口带出只听模式的功能,如果端口不是处于只听模式,返回正常的响应,在进行重新启动之前,会出现这种状况
当远程设备接收到请求时,它设法进行重新启动,并进行加电确认测试,成功的完成测试将端口带入联机状态
请求数据域内容是十六进制0xFF00时,能够清除端口通信事件记录,内容是0x0000时,保持记录与重新启动之前相同
(0002)返回诊断寄存器
在响应中返回远程设备的16位诊断寄存器内容
(0003)改变ASCII输入分隔符
请求数据域中传递的字符“CHAR”作为报文结束分隔符(替代默认的LF字符),为以后报文使用,在ASCII报文结束不要求换行的情况下,使用这种功能
(0004)强制只听模式
强制被寻址的远程设备进入Modbus通信的只听模式,这就使远程设备与网络中的其他设备断开,允许网络中其他未被强制只听的设备继续通信,没有返回响应
当远程设备进入只听模式时,关闭所有激活的通信控制,允许就绪看门狗定时器超时,锁定控制关断,当设备在这种模式下,监视对设备寻址的报文和广播,但不进行任何操作,不发送任何响应
进入这种模式后处理的唯一功能是重新启动通信选项
(000A)清除计数器和诊断寄存器
目的是清除所有计数器和诊断寄存器,上电时也会清除计数器
(000B)返回总线报文计数
响应数据域返回上一次重启动、清除计数器操作或加电之后远程设备在通信系统中检测到的报文数量
(000C)返回总线通信错误计数
响应数据域返回上一次重新启动、清除计数器操作或加电之后远程设备遇到的CRC错误数量
(000D)返回总线异常错误计数
响应数据域返回上一次重新启动、清除计数器操作或加电之后远程设备Modbus异常响应数量
(000E)返回从站报文计数
响应数据域返回上一次重新启动、清除计数器操作或加电之后对远程设备寻址的报文数量或远程设备处理的广播报文数量
(000F)返回从站无响应计数
响应数据域返回上一次重启动、清除计数器或加电之后对没有返回响应(既没有正常响应又没有异常响应)的远程设备寻址的报文数量
(0011)返回从站忙计数
返回数据域返回上一次重启动、清除计数器操作或加电之后对返回从站设备忙异常响应的远程设备寻址的报文数量
(0012)返回总线字符超限计数
响应数据域返回上一次重启动、清除计数器操作或加电之后,对由于字符超限状况而无法处理的远程设备寻址的报文数量,字符抵达端口的速度高于存储字符的速度,或者由于硬件故障而丢失字符均产生字符超限
(0014)清除超限计数器和标志
清除超限错误计数器,并复位错误标志
实例与状态图
下图是一个请求远程设备返回询问数据的实例,它使用子功能码0x000,用两字节数据域0xA537发送返回的数据
(0x0B)获得通信事件计数器(仅用于串行链路)
使用这个功能码从远程设备通信事件计数器中获取状态字和事件计数,通过在一系列报文之前和之后获取的当前计数,客户机可以确定远程设备是否正确的处理报文
每次成功的完成报文传输就将远程事件计数器加1,异常响应、轮询命令或读事件计数器命令不增加计数器
利用重新启动通信选项的子功能码(0001),或者清除计数器和诊断寄存器(000A),复位事件计数器
正常响应包括两字节状态字和两字节事件计数,如果远程设备一直在处理前面发出的程序命令(存在忙状态),那么状态字将全为1(FFFF),否则状态字全为0
mb_req_pdu/ mb_rsp_pdu/ mb_excep_rsp_pdu
实例与状态图
下图是一个请求获得远程设备中通信事件计数器的实例
(0x0C)获得通信事件记录(仅用于串行链路)
使用这个功能码从远程设备中获得状态字、事件计数、报文计数以及一个事件字节域
该状态字和事件计数与获得通信事件计数器(0x0B)返回的信息一致
报文计数器包含上一次重启动、清除计数器操作或加电之后远程设备处理的报文数量,报文计数与诊断功能(0x08)子功能总线报文计数(0x0B)返回的报文一致
事件字节域包含0-64个字节,每个字节与远程设备的一个Modbus发送或接收操作状态对应,远程设备按时间顺序将事件放入域中,字节0是最新事件,新字节替代域中的旧字节
正常响应包括2字节状态字、2字节事件计数、2字节报文计数、一个含有0-64个事件字节的域和1个字节计数域,包括这四个域的总数据长度
mb_req_pdu/mb_rsp_pdu/mb_excep_pdu
实例与状态图
下图是一个请求获得远程设备中通信事件记录的实例
在这个实例中,状态字是十六进制0x00,表示远程设备没有正在处理程序功能,事件计数表示了远程设备已经计数0x0108个事件,报文计数表示了已经处理了0x0121个报文
用事件0字节表示最新通信事件,最新通信事件的内容0x20表示远程设备最近进入了只听模式
用事件1字节表示前一个事件,前一个事件的内容0x00表示远程设备接收一个通信重启动
下面说明响应事件字节的格式
由获得通信事件记录功能返回的事件字节可以是以下四种类型中的任何一种,每个字节中的BIT7定义了这种类型,还可以由BIT6进一步定义:
- 远程设备Modbus接收事件
当远程设备收到询问报文时,存储这种类型的事件字节,在远程设备处理报文之前存储,通过将BIT7设置为逻辑1定义这种事件,其他位在相应状态为真时被设置为逻辑1 - 远程设备Modbus发送事件
当远程设备处理完请求报文时,存储这种类型的事件字节,远程设备返回正常响应、异常响应或者没有响应后存储,通过将BIT7 置为逻辑0,BIT6置为逻辑1定义这种事件,其他位在相应状态为真时设置为逻辑1 - 远程设备进入只听模式
当远程设备进入只听模式时,存储种类型的事件字节,内容十六进制0x04定义了这个时间 - 远程设备开始重启通信
当远程设备重新启动通信端口时,存储这种类型的事件字节,通过附带子功能重新启动通信选项的诊断功能可以重新启动远程设备
该功能还能将远程设备置于“错误状态下继续”或“错误状态下停止”模式,如果将设备置于“错误状态下继续”模式,则将事件字节加入现存事件记录汇总,如果将设备置于“错误状态下停止”模式,则将事件字节加入事件记录中,并将其与记录清0
内容0定义了该事件
(0x0F)写多个线圈
该功能码将一个远程设备中的一个线圈序列的每个线圈强制为ON/OFF,请求PDU指定了被强制的线圈编号,从0开始寻址线圈
请求数据域的内容指定了被请求的ON/OFF状态,逻辑1=ON,逻辑0=OFF
正常的响应返回功能码、起始地址和被强制的线圈数量
mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
实例与状态图
下图是一个请求从线圈20开始写入10个线圈的实例
传输的第一个字节0xCD对应线圈为27-20,LSB对应20
(0x10)写多个寄存器
使用该功能码在一个远程设备中写连续寄存器块(1-123) 寄存器
在请求数据域中指定了请求写入的值,将数据打包成每寄存器2字节
正常的响应返回功能码、起始地址和被写入寄存器的数量
mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
实例与状态图
下图是一个请求将0x000A和0x0102写入以2开始的两个寄存器的实例
(0x11)报告从站ID(仅用于串行链路)
使用这个功能码读远程设备特定的类型描述、当前状态以及其他信息
mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
实例与状态图
下图是一个请求报告ID和状态的实例
(0x14/0x06)读文件记录
使用该功能码读文件记录,根据字节数量提供所有请求数据长度,并且根据寄存器提供所有记录长度
文件是记录的结构,每个文件包括10000个记录,寻址这些记录为0-9999,记录12的寻址为12(非从0计数)
该功能可以读多个参量组,这些组可以是分散的,但每组中的参量必须是连续的
用含有7个字节的单独的“子请求”域定义每个组:
-参量类型:1个字节,必须指定为6
-文件号:2个字节
-文件中的起始记录号:2个字节
-所读记录的长度:2个字节
被读取的的寄存器数量加上预期响应中的所有其他域不能超过Modbus报文PDU允许的长度:253字节
正常的响应是一系列“子响应”与“子请求”一一对应,字节计数域是所有“子响应”中的全部字节数,另外每个“子响应”都包括一个表示自身字节计数的域
mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
实例与状态图
下图是一个请求从远程设备读两个参量组的实例:
组1包括文件4中的2个寄存器,以寄存器1开始(地址0001)
组2包括文件3中的2个寄存器,以寄存器9开始(地址0009)
(0x15/0x06)写文件记录
使用该功能码进行文件记录写入
文件是记录的结构,每个文件包括10000个记录,寻址这些记录为0-9999
该功能可以写多个参量组,这些组可以是分散的即不连续的,但每组内的参量必须是连续的
用含有7个字节的“子请求”域定义每个组:
参量类型:1字节,必须指定为6
文件号:2字节
文件中起始记录号:2字节
被写入的数据:每个寄存器为2字节
被写入的寄存器数量加上询问中的所有其他域不能超过Modbus报文PDU允许的长度:253字节
正常的响应是请求的复制
mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
实例与状态图
下图是一个请求将一个参考组写入远程设备的实例:
组包括文件4中的3个寄存器,以寄存器7开始
屏蔽写寄存器
该功能码用于通过利用“AND”屏蔽、“OR”屏蔽以及当前寄存器内容的组合来修改保持寄存器的内容,使用这个功能设置或清除寄存器中不同的位
请求指定了被写入的保持寄存器,被用于“AND”屏蔽的数据和被用于“OR”屏蔽的数据
从0开始寻址寄存器,因此寄存器编号为1-16的寻址为0-15
mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
实例与状态图
下图是一个利用屏蔽值在远程设备中对寄存器5的屏蔽写入的实例:
(0x17)读/写多个寄存器
这个功能码实现了在一个单独的Modbus事务中一个读操作和一个写操作的组合,在读之前进行写操作
从0开始寻址保持寄存器,因此寄存器编号为1-16的寻址为0-15
请求指定了被读取的保持寄存器的起始地址和数目,以及被写入的保持寄存器的起始地址和数目,在写数据域中,字节计数指定随后的字节数目
正常的响应包括所读寄存器组中的数据,在读数据域中,字节计数指定了随后的自己数目
mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
实例与状态图
下图是一个请求从寄存器4开始读6个寄存器并且从寄存器15开始写3个寄存器的实例:
(0x18)读FIFO队列
这个功能码允许读远程设备中的FIFO寄存器队列内容,这个功能码返回队列中寄存器的计数,随后为队列的数据,最大可以读32个寄存器:计数+31个寄存器,首先返回队列计数寄存器然后是队列数据寄存器
这个功能码读取队列内容,但是不能清除队列内容
在正常的响应中,字节计数标识了随后的字节数量,包括队列计数字节和数值寄存器字节(不包括差错校验)
队列计数是队列中数据寄存器的数量,不包括计数寄存器
如果队列计数大于31,返回一个含有差错码03的异常响应
mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
实例与状态图
下图是一个对远程设备读FIFO队列请求的实例,请求读寄存器0x04DE开始的队列
在这个实例中,FIFO指针寄存器返回的队列计数器值0x02,队列计数后面是两个数据寄存器0x01B8和0x1284
(0x2B)封装接口传输
Modbus封装接口(MEI)传输是一个在Modbus PDU内部将服务请求、方法调用和相关返回隧道化机制
MEI传输的主要特征是封装作为已定义接口的一部分方法调用或服务请求,以及方法调用返回和服务响应
网络接口可以是用于发送Modbus PDU的任何通信栈,诸如:TCP/IP或穿行链路
MEI类型是Modbus指配的编号,因此它是唯一的,值1-127是公共的,值128-255是用户定义的
MEI传输实现使用MEI类型来分派对所指定的方法调用
由于MEI传输服务是接口未知的,因此接口所需的任何特性或策略需由该接口提供,例如MEI事务处理和MEI接口差错处理等
mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
(0x2B/0x0E)读设备标识
这个功能码允许读取与远程设备物理和功能描述相关的标识和附加信息
读设备标识接口由一组可寻址的数据元素组成的地址空间构成,数据元素被称作对象,由对象ID标识他们
接口由3类对象组成:
- 基本设备标识:所有此种对象都是必备的:厂商名称、产品代码和修订版本号
- 常规设备标识:除基本数据对象外,设备提供了附加的可选择的标识以及数据对象描述
- 扩展设备标识:除常规数据对象外,设备提供了附加的可选择的标识以及专用数据描述
mb_req_pdu/mb_rsp_pdu/mb_excep_rsp_pdu
请求参数描述
功能码:0x2B
MEI类型:Modbus指配的编号
ReadDevId码:允许定义四种访问类型:
01:请求获得基本设备标识(流访问)
02:请求获得常规设备标识(流访问)
03:请求获得扩展设备标识(流访问)
04:请求获得特定标识对象(单个访问)
如果ReadDevId是无效的,在响应中返回异常码03
在设备标识不适用单独响应的情况下,需要进行多个事务处理,对象ID字节给出了要获得的第一个对象标识,对于一个事物处理来说,客户机必须设置对象ID为0,以便获得设备标识数据的起始信息,对于随后事务处理来说,客户机必须设置对象ID为服务器在此前响应中的返回值
如果流访问中对象ID不匹配任何已知对象,那么服务器的响应如同指向对象0
在单个访问的情况下:ReadDevId代码04,请求中的对象ID给出了要获取的对象标识
如果在单个访问中对象ID不匹配任何已知对象,那么服务器返回一个异常码02(非法数据地址)的异常响应
如果服务器设备被要求高于其一致性的描述,服务器必须根据其对应的实际等级响应
响应参数描述
功能码:0x2B
ReadDevId码:与请求的ReadDevID码相同:01、02、03或04
一致性等级:设备的标识一致性等级和支持访问的类型
0x01:基本标识(仅流访问)
0x02:常规标识(仅流访问)
0x03:扩展标识(仅流访问)
0x81:基本标识(流访问和单个访问)
0x82:常规标识(流访问和单个访问)
0x83:扩展标识(流访问和单个访问)
接续标识:在ReadDevId码01、02或03(流访问)的情况下,在标识数据不适用单独响应的情况下,需要进行多个事物处理
0x00:没有后续对象
0xFF:有后续对象,并且需要更多Modbus事务处理
在ReadDevId码04(单个访问)情况下,必须设置这个域为0
下一个对象ID:如果“接续标识=0xFF”,那么该值就是请求下一个对象的标识码
如果“接续标识=0x00”,那么必须设置为0
对象数目:在响应中返回的对象标识数目(对于单个访问,对象数目=1)
对象0.Id:PDU中返回的第一个对象识标识(流访问)或请求对象的标识(单个访问)
对象0.长度:第一个对象的字节长度
对象0.值:第一个对象的值
…
对象N.id:在响应中最后对象的标识
对象N.长度:最后对象的字节长度
对象N.值:最后对象的值
实例与状态图
下图是一个读基本设备标识的实例,一个响应PDU中发送的所有报文
如果一个设备需要多个事务处理发送响应,那么启动随后事务处理
第一个事务处理
第二个事务处理
Modbus异常响应
当客户机设备想服务器设备发送请求时,客户机希望得到一个正常的响应,主站的询问可能导致下列四种事件之一:
- 如果服务器设备接收无通信错误的请求,并且可以正常的处理询问,那么服务器将返回一个正常响应
- 如果由于通信错误,服务器没有收到请求,那么不能返回响应,客户机程序将视为超时
- 如果服务器收到请求,但是检测到一个通信错误(奇偶校验、LRC、CRC…)那么不能返回响应,客户机视为超时
- 如果服务器收到无通信错误的请求,但不能处理这个请求(例如请求读一个不存在输出或保持寄存器),服务器将返回一个异常响应,通知客户机错误的实际情况
异常响应有2个与正常响应不同的域:
- 功能码域:在正常的响应中,服务器响应的功能码复制请求功能码,所有功能码的MSB都为0,在异常响应中,服务器设置功能码的MSB为1
- 数据域:在正常的响应中,服务器可以在数据域返回数据或统计信息,在异常响应中服务器在数据域返回异常码