Modbus功能码详解
Modbus功能码是Modbus消息帧(报文)的重要组成部分,是Modubs协议中通信事务处理的基础,代表消息将要执行的动作。
功能码概要
简而言之,Modbus功能码占用一个字节,取值范围是1127,之所以127以上不能使用,是因为Modbus规定出现异常时,功能码+0x80(十进制128)代替异常状态,因此129(1+128)255(127+128)的取值代表异常码。
Modbus标准协议中规定了由3类Modbus功能码,分别是:
-
公共功能码
- 被明确定义的功能码
- 保证唯一性
- 由Modbus协会确认,并提供公开的文档;
- 可进行一致性测试
- 包括协议定义的功能码和保留将来使用的功能码
-
用户自定义功能码
- 有两个用户自定义功能码区域,分别是6572和100110;
- 用户自定义,不保证唯一性。
-
保留功能码
保留功能码是因为历史遗留原因,某些公司的传统产品上现行使用的功能码不作为公共使用。
Modbus部分功能码如下:
代码 | 名称 | 寄存器PLC地址 | 位/字操作 | 操作数量 |
---|---|---|---|---|
01 | 读线圈状态 | 00001~09999 | 位操作 | 单个或多个 |
02 | 读离散输入状态 | 10001~19999 | 位操作 | 单个或多个 |
03 | 读保持寄存器 | 40001~49999 | 字操作 | 单个或多个 |
04 | 读输入寄存器 | 30001~39999 | 字操作 | 单个或多个 |
05 | 写单个线圈 | 00001~09999 | 位操作 | 单个 |
06 | 写单个保持寄存器 | 40001~49999 | 字操作 | 单个 |
15 | 写多个线圈 | 00001~09999 | 位操作 | 多个 |
16 | 写多个保持寄存器 | 40001~49999 | 字操作 | 多个 |
功能码可分为位操作和字操作两类。位操作的最小单位为一位(bit),字操作的最小单位为两个字节。
- 位操作指令:读线圈状态功能码01,读(离散)输入状态功能码02,写单个线圈功能码06和写多个线圈功能码15.
- 字操作指令:读保持寄存器功能码03,读输入寄存器功能码04,写单个保持寄存器功能码06,写多个保持寄存器功能码16.
01(0x01)读取线圈/离散量输出状态
功能说明读取从设备的线圈或离散量输出的状态,即各DO的ON/OFF状态。消息帧中指定了需读取的线圈起始地址和线圈数目。需要注意的一点是,在Modbus协议规定的PDU中,规定所有线圈或寄存器地址从0开始计算。
查询报文查询帧的消息里,定义了从设备地址为3,并读取从设备的Modbus地址0001900055(线圈地址0002000056)共计37个状态值。起始线圈地址为0x13(即十进制00019),因为线圈地址从0开始计数。
Modbus协议规定,起始地址由2个字节构成,取值范围为0x00000xFFFF;线圈数量由2个字节构成,取值范围为0x00010x07D0(即十进制1~2000).
ASCII模式中直接按每4个位拆分为对应的字符表示。
响应报文响应报文的数据字段中,每一个线圈占用1个位(bit),状态被表示为1=ON和0=OFF两种类型。第1个数据字节的LSB(最低有效位)标识查询报文中的起始地址线圈的状态值,其他线圈依次类推,一直到这个字节的MSB(最高有效位)位置,并在后续字节中按照同样的方式(由低到高)排列。
一个字节可以表示8个线圈的状态,如果最后的数据字节中不能填满8个线圈的状态,则由0填充。对应于查询报文中需要读取37个线圈的状态,则共需要5个字节保存状态值。
02(0x02)读取离散量输入值
功能说明该功能码用于读取从设备的离散输入即DI的ON/OFF状态。消息帧中制定了需读取的离散输入寄存器起始地址和数目,可读取1~2000个连续的离散量输入状态。如果从设备接受主设备的请求则回复功能码02,并返回离散量输入各离散量的当前状态。如果返回的离散输入数量的个数不是8的整数倍,将用0填充最后数据字节的剩余位。
03(0x03)读取保持寄存器值
功能说明用于读取从设备保持寄存器的内容,不支持广播模式。消息帧中指定了需读取的保持寄存器的起始地址和数目。而保持寄存器中各地址的具体内容和意义,则由设备开发者自行规定。
查询报文在查询报文中,必须指定保持寄存器的开始地址和需读取的寄存器数量。起始位置由2个字节构成,取值范围为0x00000xFFFF;寄存器数量由2个字节构成,取值范围为0x00010x007D(即十进制1~255),即最多可以连续读取125个寄存器。
有一点特别需要注意,Modbus的保持寄存器和输入寄存器是以字(Word)为基本单位的(1Word=2byte),所以,如果读取保持寄存器地址为40001开始的一个16位(bit)的无符号数,那么返回2个字节(byte),并可以从40002开始读取下一个16位的无符号数。如果需读取寄存器地址40001开始的是一个32位浮点数,则需要返回4个字节,即必须连续读取40001和40002的内容,而且下一个32位浮点数必须从40003开始读取。对于浮点数(或者32位的整数)而言,连续读取的两个寄存器之间存在字节序和大小端的问题,这一点在开发时必须引起注意。
04(0x04)读取输入寄存器值
功能说明同功能码03类似,该功能码用于读取从设备输入寄存器的内容,不支持广播模式。消息帧中指定了需读取的输入寄存器的起始地址和数目。而输入寄存器中各地址的具体内容和意义,则由设备开发者自行规定。
查询报文在查询报文中,必须指定输入寄存器的起始地址和需读取的寄存器数量。
本功能码中,起始地址由2个字节构成,取值范围为0x00000xFFFF;寄存器数量由2个字节构成,取值范围为0x00010x007D(即十进制1~125),即最多可以连续读取125个寄存器。
同样有一点需要注意,Modbus的保持寄存器和输入寄存器是以字为基本单位的。所以对于浮点数(或32为的整数)而言,连续读取的两个寄存器之间存在字节序和大小端的问题。
05(0x05)写单个线圈或单个离散输出
功能说明用于将单个线圈寄存器(或离散输入)设置为ON或OFF,该功能码支持广播模式,在广播模式下,所有从站设备的同一地址的值将被统一修改,查询报文中的ON或OFF状态由报文数据字段的常熟指定,0xFF00表示ON状态,0x0000表示OFF状态。其他所有值均是非法的,并且对寄存器不起作用,将会返回异常相应。
查询报文本功能码中,起始地址由2个字节构成,取值范围为0x0000~0xFFFF;变更目标数据由2个字节构成,取值只能为0xFF00或0x0000.
响应报文对于从设备,在线圈或离散输出寄存器正常变更的情况下,则返回于查询报文一样的响应报文。如果修改失败,则返回一个异常响应。
06(0x06)写单个保持寄存器
用于更新从设备的单个保存寄存器的值。该功能吗支持广播模式,在广播模式下,所有设备的同一地址的值将被统一修改。
查询报文查询报文中需要指定从设备地址以及需要变更的保持寄存器地址和设定的值。同样需要注意的是,查询报文中,寄存器地址从地址0开始技术。
本功能码中,起始地址由2个字符构成,取值范围为0x00000xFFFF;变更目标数据由2个字节构成,取值范围为0x00000xFFFF。
响应报文对于从设备,在保持寄存器正常变更的情况下,则返回于查询报文一样的响应报文。如果修改失败,则返回一个异常返回。
08(0x08)诊断功能
功能说明该功能码仅用于串行链路,主要用于检测主设备和从设备之间的通信故障,或检测从设备的各种内部故障,该功能码不支持广播。为了区别各诊断类型,查询报文中提供了2各字节的子功能码字段。
通常在正常的响应报文中,从设备将鸳鸯回复功能码和子功能码。
查询报文查询报文中需要指定从设备地址、功能码以及子功能码。
例如,表4-15中表示了子功能码“原样返回查询数据”的诊断功能,其中子功能码为0(0x0000)。在子功能码0x0000的情况下,数据字段可以为任意值。
本功能码中,子功能码由2个字节构成,取值则根据意义不同;数据字段由2个字节构成,其取值由子功能码确定。
响应报文对于从设备,在保持寄存器正常变更的情况下,则返回与查询报文一样的响应报文。如果修改失败,则返回一个异常响应。
诊断子功能码
各常用诊断子功能码定义如下:
- Return Query Data(00)
诊断内容 | 原样返回查询报文 |
---|---|
子功能码 | 0x00,0x00 |
查询报文数据字段 | 任意16位数据 |
响应报文数据字段 | 同查询报文 |
- Restart Communications Option(01)
诊断内容 | 重启通信选项 用于初始化并重新启动从站设备,清除所有通信事件计数器。 如果端口处于Listen Only Mode下,不返回响应;否则在重启之前返回响应 |
---|---|
子功能码 | 0x00,0x01 |
查询报文数据字段 | 0x00,0x00 保持事件记录 |
0xFF,0x00 清除事件记录 | |
响应报文数据字段 | 同查询报文 |
- Return Diagnostics Register(02)
诊断内容 | 返回诊断寄存器 |
---|---|
子功能码 | 0x00,0x02 |
查询报文数据字段 | 0x00,0x00 |
响应报文数据字段 | 诊断寄存器的内容 |
- Force Listen Only Mode(04)
诊断内容 | 强制只听模式 强制被寻址的从站设备进入只听模式,使得此设备与网络中的其他设备断开,不返回响应 |
---|---|
子功能码 | 0x00,0x0A |
查询报文数据字段 | 0x00,0x00 |
响应 |
- Clear Counters and Diagnostic Register(10,0x0A)
诊断内容 | 清除计数器和诊断寄存器 |
---|---|
子功能码 | 0x00,0x0A |
查询报文数据字段 | 0x00,0x00 |
响应报文数据字段 | 同查询报文 |
- Return Bus Message Count(11,0x0B)
诊断内容 | 返回总线报文计数 |
---|---|
子功能码 | 0x00,0x0B |
查询报文数据字段 | 0x00,0x00 |
响应报文数据字段 | 返回报文的计数值 |
- Return Bus Communication Error Count(12,0x0C)
诊断内容 | 返回总线通信CRC差错计数 |
---|---|
子功能码 | 0x00,0x0C |
查询报文数据字段 | 0x00,0x00 |
响应报文数据字段 | 返回报文的CRC出错总数 |
- Return Bus Exception Error Count(13,0x0D)
诊断内容 | 返回总线异常差错计数 |
---|---|
子功能码 | 0x00,0x0D |
查询报文数据字段 | 0x00,0x00 |
响应报文数据字段 | 返回异常响应的总数 |
- Return Slave Message Count(14,0x0E)
诊断内容 | 返回从站设备报文总数 |
---|---|
子功能码 | 0x00,0x0E |
查询报文数据字段 | 0x00,0x00 |
响应报文数据字段 | 返回从站设备接收报文总数 |
- Return Slave No Response Count(15,0x0F)
诊断内容 | 返回从站设备无响应计数 |
---|---|
子功能码 | 0x00,0x0F |
查询报文数据字段 | 0x00,0x00 |
响应报文数据字段 | 返回加电后没有返回响应的报文数量 |
- Return Slave Busy Count(17,0x11)
诊断内容 | 返回从站设备忙计数 |
---|---|
子功能码 | 0x00,0x11 |
查询报文数据字段 | 0x00,0x00 |
响应报文数据字段 | 返回加电后异常响应忙的报文数量 |
- Return Bus Character Overrun Count(18,0x12)
诊断内容 | 返回总线字符超限的计数 |
---|---|
子功能码 | 0x00,0x12 |
查询报文数据字段 | 0x00,0x00 |
响应报文数据字段 | 返回超限的报文数量 |
11(0x0B)获取通信事件计数器
功能说明该功能码主要用于获取从设备通信计数器中的状态字和事件计数的值,本功能不支持广播模式。通过在通信报文之前和之后读取通信事件计数值,可以确定从设备是否正常处理报文。
对于正常完成报文处理和传输的场合,事件计数器增加1;而对于异常响应、轮询命令或读取事件计数器(即0x0B功能码)的场合,则计数器不变。通过【0x08】诊断功能中的子功能码【Restart Communiaction Option (0x01)】和【Clear Counters and Diagnostic Register(0x00A)】,可以复位事件寄存器。
响应报文对于从设备,在正常情况下,响应报文返回2个字节的状态字和2个字节的事件计数。其中,如果从站设备处于忙状态,那么状态字将为0xFFFF,否则状态字将为0x0000.
12(0x0C)获取通信事件记录
功能说明该功能码主要用于从从设备获取转状态字、事件计数、报文计数以及事件字节字段。其中状态字和事件计数与功能码11(0x0B)获取的值一致。
响应报文对于从站设备,在正常情况下响应报文包括一个2字节状态字字段、一个2字节事件计数字段、一个2字节消息计数字段以及0~64个字节的事件字段。因为事件字段是变长的,所以增加了一个1字节的数据长度字段,以方便读取响应数据。
15(0x0F)写多个线圈
功能说明该功能码,用于将连续的多个线圈或离散输出设置为ON/OFF状态,支持广播模式,在广播模式下,所有从站设备的同一地址被统一修改。本功能码中,起始地址字段由2个字节构成,取值范围为0x00000xFFFF;而寄存器数量字段由2个字节构成,取值范围为0x00010x07B0.
查询报文查询报文中,包含了请求数据字段,用于定义ON/OFF状态。数据字段中为逻辑1的位对应ON;逻辑0的位对应OFF。其中,ON/OFF与数据字段的对应关系可参考“01(0x01)读取线圈/离散量输出状态”中的内容
响应报文对于从设备,在正常情况下响应报文包括功能码、起始地址以及写入的线圈数量。
16(0x10)写多个保持寄存器
功能说明该功能码用于设置或写入从设备保持寄存器的多个连续的地址块(1123个寄存器),支持广播模式,在广播模式下,所有从站设备的同一地址的值将被统一修改。本功能码中,起始地址字段由2个字节构成,取值范围为0x00000xFFFF;而寄存器数量字段由2个字节构成,取值范围为0x0001~0x007B。
查询报文查询报文中,包含了请求数据字段。数据字段保存需写入的数值,各数据按每个寄存器2个字节存放。
响应报文对于从设备,在正常情况下响应报文包括功能码、起始地址以及写入的寄存器数量。
在实际开发过程中,功能码“16(0x10)写多个寄存器”常常用于方便用户写入多字节类型的数据。
17(0x11)报告从站ID(仅用于串行链路)
功能说明该功能码用于读取从站设备的ID、类型描述、当前状态以及其他信息,不支持广播模式。响应消息的构成依赖于设备而不同。
响应报文对于从设备,在正常情况下响应报文包括从站ID、运行状态以及其他附加信息。响应报文的组成由开发者决定。
Modbus异常响应
以上介绍了一些常见的公共功能码的报文(消息帧)构成,对于广播模式以外的查询报文,都希望能够获取一个正常的响应报文。在通常的情况下,从站设备将返回一个正常响应报文,但是,在某些特殊情况下,将返回异常响应报文。对于查询报文,存在以下4中处理反馈:
- 正常接收,正常处理,返回正常响应报文;
- 因为通信错误等原因,造成从站设备没有接收到查询报文,主站设备将按超时处理;
- 从站设备接收到的查询报文存在通信错误(例如LRC、CRC错误等),此时从站设备将丢弃报文不响应,主站设备将按超时处理;
- 从站设备接收到正确的报文,但是超过处理范围(例如,不存在的功能码或者寄存器等),此时从站设备将返回包括异常码(Exception Code)的响应报文。
异常响应报文由从站地址、功能码以及异常码构成。其中,功能码与正常响应报文不同,在异常响应报文中,功能码最高位(即MSB)被设置为1.因为Modbus协议中功能码占用一个字节,故用表达式描述为:异常功能码=正常功能码+0x80.
常见的异常码说明
异常码 名称 说明 01 非法功能码 从站设备不支持此功能码 02 非法数据地址 指定的数据地址在从站设备中不存在 03 非法数据值 指定的数据超过范围或者不允许使用 04 从站设备故障 从站设备处理响应的过程中,出现未知错误等