文章目录
- 一、功能码概要
- 二、(0x01)读取线圈
- 2.1 功能说明
- 2.2 查询报文
- 2.3 响应报文
- 三、 (0x02) 读取离散量输入值
- 3.1 功能说明
- 3.2 查询报文
- 3.3 响应报文
- 三、(0x03)读取保持寄存器值
- 3.1 功能说明
- 3.2 查询报文
- 3.3 响应报文
- 五、 (0x04)读取输入寄存器值
- 5.1 功能说明
- 5.2 查询报文
- 5.3 响应报文
- 六、 (0x05)写单个线圈
- 6.1 功能说明
- 6.2 查询报文
- 6.3 响应报文
- 七、 (0x06) 写单个保持寄存器
- 7.1 功能说明
- 7.2 查询报文
- 7.3 响应报文
- 八、(0x08) 诊断功能
- 8.1 功能说明
- 8.2 查询报文
- 8.3 响应报文
- 8.4 诊断子功能码
- 九、 (0x0B) 获取通信事件计数器
- 9.1 功能说明
- 9.2 查询报文
- 9.3 响应报文
- 十、 (0x0C) 获取通信事件记录
- 10.1 功能说明
- 10.2 查询报文
- 10.3 响应报文
- 十一、(0x0F)写多个线圈
- 11.1 功能说明
- 11.2 查询报文
- 11.3 响应报文
- 十二、(0x10) 写多个保持寄存器
- 12.1 功能说明
- 12.2 查询报文
- 12.3 响应报文
- 十三、 (0x11) 报告从站ID (仅用于串行链路)
- 13.1 功能说明
- 13.2 查询报文
- 13.3 响应报文
- 13.4 Modbus异常响应
一、功能码概要
Modbus标准在协议中规定了以下3类Modbus功能码。
-
公共功能码:
- 被明确定义的功能码;
- 保证唯一性;
- 由Modbus协会确认,并提供公开的文档;
- 可进行一致性测试;
- 包括协议定义的功能码和保留将来使用的功能码。
-
用户自定义功能码:
- 有两个用户自定义功能码区域,分别是6572和100110;
- 用户自定义,无法保证唯一性。
-
保留功能码:
保留功能码因为历史遗留原因,某些公司的传统产品现行使用的功能码不作为公共使用。
二、(0x01)读取线圈
2.1 功能说明
01功能码用于读取从设备的线圈或离散量输出的状态,即各Do(Discrete Output,离散输出)的ON/OFF状态。消息帧中指定了需要读取的线圈起始地址和线圈数目。需要注意的是,在Modbus协议规定的PDU中,所有线圈或寄存器地址都必须从0开始计算
。
2.2 查询报文
如下表所示,查询帧的消息中定义了从设备地址为3,并读取从设备的Modbus地址0001900055(线圈地址0002000056)共计37个状态值。起始线圈地址为0x13(即十进制00019),因为线圈地址是从0开始计数的。
功能码01查询报文示例
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x03 | “0”,“3” | 0x03 |
功能码 | 0x01 | “0”,“1” | 0x01 |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x13 | “1”,“3” | 0x13 |
寄存器数(高位) | 0x00 | “0”,“0” | 0x00 |
寄存器数(低位) | 0x25 | “2”,“5” | 0x25 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 17 | 8 |
Modbus协议规定,起始地址由2字节构成,取值范围为0x0000 ~ 0xFFFF: 线圈数量由2字节构成
,取值范围为0x0001~ 0x07D0 (即+进制1~2000)另外,注意观察ASCII模式和RTU模式的区别,ASCII模式直接按每4位拆分成对应的字符表示。(高位在前 低位在后)
2.3 响应报文
在响应报文的数据字段中,每个线圈占用1位 (bit)
,状态被表示为1=ON和O=OFF两种类型。第1个数据字节的LSB(最低有效位)标识查询报文中的起始地址线圈的状态值,其他线圈以此类推,一直到这个字节的MSB(最高有效位)为止,并在后续字节中按照同样的方式(由低到高)排列。
例如,下表中线圈20~27的状态值分别是ON - ON - OFF OFF - ON - OFF - ON - OFF表示为二进制则为01010011 (0x53),注意观察对应的顺序。1字节可以表示8个线圈的状态如果最后的数据字节中不能填满8个线圈的状态,则用0填充。对应于查询报文中需要读取37个线圈的状态,共需要5字节保存状态值。
功能码01响应报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x03 | “0”,“3” | 0x03 |
功能码 | 0x01 | “0”,“1” | 0x01 |
数据域字节数 | 0x05(后面有多少字节的数据) | “0”,“5” | 0x05 |
数据1 | 0x53 | “5”,“3” | 0x53 |
数据2 | 0x6B | “6”,“B” | 0x6B |
数据3 | 0x01 | “0”,“1” | 0x01 |
数据4 | 0xF4 | “F”,“B” | 0xF4 |
数据5 | 0x1B | “1”,“B” | 0x1B |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 21 | 10 |
01功能码是位寄存器,读到的是一位一位的数据,假设查询报文示例表中起始地址高位和地位读取的是N位的数据,那么在相应报文中返回的数据会根据是否有余数而不同,如果能够 N/8 没有余数则直接返回;如果 N/8 有余数则在 N/8 的基础上加1,得到的为返回的数据。比如现在读到的数据为9,那么返回的数据为 9/8 + 1 = 2。
以主设备(左边)为例,发送(Tx)数据中第一个字节01为设备地址,第二个字节01表示功能码,第三、四个字节00 00表示起始地址,第五、六个字节00 0A表示要读取多少个位寄存器,第七、八个字节BC 0D为校验码。接收(Rx)数据中第一个字节01为设备地址,第二个字节01表示功能码,在发送数据中要读取10个寄存器,所以这里第三个字节02为 10/8 余 2,这里表示返回的数据个数为2个字节(byte)(因为这里读取10位寄存器,每位寄存器中对应一位数据,八位数据对应一个字节,所以这里需要两个字节),第四、五个字节05 00 表示返回的数据,用十六进制表示为0000 0101 0000 0000,这里只需要看前面的,从右往左为 1010 0000 ,刚好对应上modbus软件从上到下的数据,第六、七个字节BA AC为校验码。
三、 (0x02) 读取离散量输入值
3.1 功能说明
02功能码用于读取从设备的离散输入,即DI (Discrete Input) 的ON/OFF状态。消息顿中指定了需要读取的离散输入寄存器的起始地址和数目,可以读取1 ~ 2000个连续的离散量输入状态如果从设备接受主设备的请求则回复功能码02,并返回离散量且输入各变量的当前状态。如果返回的离散输入数量的个数不是8的整数倍,将用0填充最后的数据字节的剩余位。
3.2 查询报文
如下表所示,查询顿的消息中定义了从设备的地址为3,并读取从设备的离散输入寄存器中地址10101~10120 (Modbus地址表示为十进制100~119) 共计20个离散输入状态值。从下表中可以发现,起始地址为0x64 (即十进制100),因为消息PDU中的Modbus地址从0开始计数。
功能码02查询报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x03 | “0”,“3” | 0x03 |
功能码 | 0x02 | “0”,“2” | 0x02 |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x64 | “6”,“4” | 0x64 |
寄存器数(高位) | 0x00 | “0”,“0” | 0x00 |
寄存器数(低位) | 0x14 | “1”,“4” | 0x14 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 17 | 8 |
与5.4.2节中的功能码 (01 (0x01) 读取线圈/离散量输出状态 (Read Coil status/DOs))一样,本功能码的起始地址由2字节构成,取值范围为0x0000 ~ 0xFFFF;离散量数量由2字节构成,取值范围为0x0001 ~0x07D0 (即十进制1~ 2000),最多一次性可读取2000人离散输入状态值。
3.3 响应报文
响应报文的各项构成和意义与5.4.2章节的功能码(01(0x01)读取线圈/离散量输出状态(Re-ad Coil Status/DOs))一样,如下表所示:
功能码02响应报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x03 | “0”,“3” | 0x03 |
功能码 | 0x02 | “0”,“2” | 0x02 |
数据域字节数 | 0x03 | “0”,“3” | 0x03 |
数据1 | 0x53 | “5”,“3” | 0x53 |
数据2 | 0x6B | “6”,“B” | 0x6B |
数据3 | 0x01 | “0”,“1” | 0x01 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 21 | 10 |
三、(0x03)读取保持寄存器值
3.1 功能说明
03功能码用于读取从设备保持寄存器的内容,不支持广播模式。消息顿中指定了需要读取的保持寄存器的起始地址和数目。而保持寄存器中各地址的具体内容和意义则由设备开发者自行规定。
3.2 查询报文
在查询报文中,必须指定保持寄存器的开始地址和需要读取的寄存器数量,例如,如下表所示,从设备地址为7 (0x07),需要读取保持寄存器地址40201 ~ 40203共计3个寄存器的内容即读取Modbus协议地址200~ 202的内容,在报文中表示如下。
起始地址: 0x00C8 (十进制200)。
读取数量: 0x0003 (十进制3)。
功能码03查询报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x07 | “0”,“7” | 0x07 |
功能码 | 0x03 | “0”,“3” | 0x03 |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0xC8 | “C”,“8” | 0xC8 |
寄存器数(高位) | 0x00 | “0”,“0” | 0x00 |
寄存器数(低位) | 0x03 | “0”,“3” | 0x03 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 17 | 8 |
本功能码的起始地址由2字节构成,取值范围为0x00000xFFFF;寄存器数量由2字节构成取值范围为0x00010x007D (即十进制1~125) ,即最多可以连续读取125个寄存器。
需要特别注意的是,Modbus的保持寄存器和输入寄存器是以字 (Word) 为基本单位的(1Word=2Byte),所以如果读取保持寄存器地址为40001开始的一个16位 (bit) 的无符号数,那么返回2字节,并可以从40002开始读取下一个16位的无符号数。如果需要读取寄存器地址为40001开始的一个32位浮点数,则需要返回4字节,即必须连续读取40001和40002的内容,而且下一个32位的浮点数必须从40003开始读取。对于浮点数(或者32位的整数)而言,连续读取的两个寄存器之间存在字节序和大小端的问题,这一点在开发时必须引起注意。
3.3 响应报文
响应报文的各项构成和意义如下表所示。因为Modbus的保持寄存器和输入寄存器是以字为基本单位的,在上面的例子中,查询报文连续读取3个寄存器的内容,将返回6字节,参考表下表中数据1~3的高位和低位。
功能码03响应报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x07 | “0”,“7” | 0x07 |
功能码 | 0x03 | “0”,“3” | 0x03 |
数据域字节数 | 0x06 | “0”,“6” | 0x06 |
数据1(高位) | 0x03 | “0”,“3” | 0x03 |
数据1(低位) | 0x53 | “5”,“3” | 0x53 |
数据2(高位) | 0x01 | “0”,“1” | 0x01 |
数据2(低位) | 0xF3 | “F”,“3” | 0xF3 |
数据3(高位) | 0x01 | “0”,“1” | 0x01 |
数据3(低位) | 0x05 | “0”,“5” | 0x05 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 23 | 11 |
五、 (0x04)读取输入寄存器值
5.1 功能说明
与功能码03类似,04功能码用于读取从设备输入寄存器的内容,不支持广播模式。消息顿中指定了需要读取的输入寄存器的起始地址和数目,而输入寄存器中各地址的具体内容和意义则由设备开发者自行规定。
5.2 查询报文
在查询报文中必须指定输入寄存器的起始地址和需要读取的寄存器数量。例如,如表4-9所示,从设备地址为7 (0x07),需要读取输入寄存器地址30301 ~ 30303共计3个寄存器的内容即读取Modbus协议地址300 ~302的内容,在报文中表示如下。
起始地址: 0x012C (十进制300) 。
读取数量: 0x0003 (十进制3)。
功能码04查询报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x07 | “0”,“7” | 0x07 |
功能码 | 0x04 | “0”,“4” | 0x04 |
起始地址(高位) | 0x01 | “0”,“1” | 0x01 |
起始地址(低位) | 0x2C | “2”,“C” | 0x2C |
寄存器数(高位) | 0x00 | “0”,“0” | 0x00 |
寄存器数(低位) | 0x03 | “0”,“3” | 0x03 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 17 | 8 |
本功能码中,起始地址由2字节构成,取值范围为0x0000 ~ 0xFFFF;寄存器数量由2字节构成,取值范围为0x0001 ~0x007D (即十进制1~125) ,即最多可以连续读取125个寄存器同样有一点需要注意,Modbus的保持寄存器和输入寄存器是以字为基本单位的。所以对于浮点数(或者32位的整数)而言,连续读取的两个寄存器之间存在字节序和大小端的问题,这一点在开发时必须引起注意。
5.3 响应报文
响应报文的各项构成和意义如下表所示。因为Modbus的保持寄存器和输入寄存器是以字为基本单位的,上面的例子中,查询报文连续读取3个寄存器的内容,那么将返回6字节,参考下表中数据1~3的高位和低位。
功能码04响应报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x07 | “0”,“7” | 0x07 |
功能码 | 0x04 | “0”,“4” | 0x04 |
数据域字节数 | 0x06 | “0”,“6” | 0x06 |
数据1(高位) | 0x03 | “0”,“3” | 0x03 |
数据1(低位) | 0x53 | “5”,“3” | 0x53 |
数据2(高位) | 0x01 | “0”,“1” | 0x01 |
数据2(低位) | 0xF3 | “F”,“3” | 0xF3 |
数据3(高位) | 0x01 | “0”,“1” | 0x01 |
数据3(低位) | 0x05 | “0”,“5” | 0x05 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 23 | 11 |
六、 (0x05)写单个线圈
6.1 功能说明
05功能码用于将单个线圈寄存器 (或离散输入)设置为ON或OFF,该功能码支持广播模式在广播模式下,所有从站设备的同一地址的值将被统一修改。查询报文中的ON/OFF状态由报文数据字段的常数指定,0xFF00表示ON状态,0x0000表示OFF状态。其他值均是非法的,并且对寄存器不起作用,将会返回异常响应。
6.2 查询报文
查询报文中需要指定从设备地址以及需要变更的线圈地址和设定的状态值。需要注意的是,在查询报文中,线圈地址从地址0开始计数。例如,如下表所示,从设备地址为3,设置线圈地址00150为ON状态,则查询报文中的线圈地址设置为0x95 (149)。
功能码05查询报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x03 | “0”,“3” | 0x03 |
功能码 | 0x05 | “0”,“5” | 0x05 |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x95 | “9”,“5” | 0x95 |
变更数据(高位) | 0xFF | “F”,“F” | 0xFF |
变更数据(低位) | 0x00 | “0”,“0” | 0x00 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 17 | 8 |
本功能码中,起始地址由2字节构成,取值范围为0x0000~0xFFFF:变更目标数据由2字节构成,取值只能为0xFF00或0x0000。
6.3 响应报文
响应报文的各项构成和意义如下表所示。对于从设备,在线圈或离散输出寄存器正常变更的情况下会返回与查询报文相同的响应报文。如果修改失败,则会返回一个异常响应,对于异常响应,后续章节会进一步详细介绍。
功能码05响应报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x03 | “0”,“3” | 0x03 |
功能码 | 0x05 | “0”,“5” | 0x05 |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x95 | “9”,“5” | 0x95 |
变更数据(高位) | 0xFF | “F”,“F” | 0xFF |
变更数据(低位) | 0x00 | “0”,“0” | 0x00 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 17 | 8 |
七、 (0x06) 写单个保持寄存器
7.1 功能说明
06功能码用于更新从设备的单个保持寄存器的值,该功能码支持广播模式,在广播模式下所有从设备的同一地址的值将被统一修改。
7.2 查询报文
查询报文中需要指定从设备地址以及需要变更的保持寄存器地址和设定的值。需要注意的是查询报文中,寄存器地址从地址0开始计数。例如,如下表所示,从设备地址为3,设置寄存器地址40150为1200 (即0x04B0) ,则查询报文中的地址字段设置为0x95 (149)。
功能码06查询报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x03 | “0”,“3” | 0x03 |
功能码 | 0x06 | “0”,“6” | 0x06 |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x95 | “9”,“5” | 0x95 |
变更数据(高位) | 0x04 | “0”,“4” | 0x04 |
变更数据(低位) | 0xB0 | “B”,“0” | 0xB0 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 17 | 8 |
本功能码中,起始地址由2字节构成,取值范围为0x0000~0xFFFF; 变更目标数据由2字节构成,取值范围为0x0000~0xFFFF。
7.3 响应报文
响应报文的各项构成和意义,如下表所示。对于从设备,在保持寄存器正常变更的情况下会返回与查询报文相同的响应报文。如果修改失败,则返回个异常响应。
功能码06响应报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x03 | “0”,“3” | 0x03 |
功能码 | 0x06 | “0”,“6” | 0x06 |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x95 | “9”,“5” | 0x95 |
变更数据(高位) | 0x04 | “0”,“4” | 0x04 |
变更数据(低位) | 0xB0 | “B”,“0” | 0xB0 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 17 | 8 |
八、(0x08) 诊断功能
8.1 功能说明
08功能码仅用于串行链路,主要用于检测主设备和从设备之间的通信故障,或检测从设备的各种内部故障,该功能码不支持广播。为了区别各诊断类型,查询报文中提供了2字节的子功能码字段。
通常在正常的响应报文中,从设备将原样回复功能码和子功能码.
8.2 查询报文
查询报文中需要指定从设备地址、功能码以及子功能码。
例如,下表中标识了子功能码“原样返回查询数据”的诊断功能,其中子功能码为0(0x0000)。在子功能码为0x0000的情况下,数据字段可以为任意值。各子功能码的详细意义可参考下表。
功能码08查询报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x05 | “0”,“5” | 0x05 |
功能码 | 0x08 | “0”,“8” | 0x08 |
子功能码(高位) | 0x00 | “0”,“0” | 0x00 |
子功能码(低位) | 0x00 | “0”,“0” | 0x00 |
数据(高位) | 0x04 | “0”,“4” | 0x04 |
数据(低位) | 0xB0 | “B”,“0” | 0xB0 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 17 | 8 |
本功能码中,子功能码由2字节构成,取值则根据意义而不同;数据字段由2字节构成,其取值由子功能码确定。
8.3 响应报文
响应报文的各项构成和意义如下表所示。对于从设备,在保持寄存器正常变更的情况下会返回与查询报文相同的响应报文。如果修改失败,则返回一个异常响应。
功能码08响应报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x05 | “0”,“5” | 0x05 |
功能码 | 0x08 | “0”,“8” | 0x08 |
子功能码(高位) | 0x00 | “0”,“0” | 0x00 |
子功能码(低位) | 0x00 | “0”,“0” | 0x00 |
数据(高位) | 0x04 | “0”,“4” | 0x04 |
数据(低位) | 0xB0 | “B”,“0” | 0xB0 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 17 | 8 |
8.4 诊断子功能码
各常用的诊断子功能码的定义如下。
Return Query Data(00)
诊断内容 | 原样返回查询报文 |
---|---|
子功能码 | 0x00,0x00 |
查询报文数据字段 | 任意16位数据 |
响应报文数据字段 | 同查询报文 |
Restart Communication Option(01)
诊断内容 | 重启通信选项; 用于初始化并重新启动从站设备,清楚所有通信事件计数器; 如果端口处于 Listen Only Mode,则不返回响应;否则在重启之前返回响应 |
---|---|
子功能码 | 0x00,0x01 |
查询报文数据字段 | 0x00, 0x00 保持事件记录; 0xFF,0x00 清除事件记录 |
响应报文数据字段 | 同查询报文 |
Return Diagnostics Register(02)
诊断内容 | 返回诊断寄存器 |
---|---|
子功能码 | 0x00,0x04 |
查询报文数据字段 | 0x00,0x00 |
响应报文数据字段 | 诊断寄存器的内容 |
Force Listen Only Mode
诊断内容 | 强制只听模式; 强制被寻址的从站设备进入只听模式,使得此设备与网络中的其他设备断开,不返回响应 |
---|---|
子功能码 | 0x00,0x04 |
查询报文数据字段 | 0x00,0x00 |
响应报文数据字段 | 不返回响应 |
Clear Counters and Diagnostic Register
诊断内容 | 清除计数器和诊断寄存器 |
---|---|
子功能码 | 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 Counrt(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 |
响应报文数据字段 | 返回超限的报文数量 |
九、 (0x0B) 获取通信事件计数器
9.1 功能说明
11功能码主要用于获取从设备通信计数器中的状态字和事件计数的值,本功能码不支持广播模式。通过在通信报文之前和之后读取通信事件计数值,可以确定从设备是否正常处理报文。
对于正常完成报文处理和传输的场合,事件计数器增加1;而对于异常响应、轮询命令或读事件计数器(即Ox0B功能码)的场合,则计数器不变。通过【0x08诊断功能】 中的子功能码【Restart Communication Option ( 0x0001 )】 和 【Clear Counters and Diagnostic Register (0x000A) 】 可以复位事件寄存器。
9.2 查询报文
下表中的示例表示获取通信事件计数器的查询报文内容,其中从站设备地址为5.
功能码11查询报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x05 | “0”,“5” | 0x05 |
功能码 | 0x0B | “0”,“B” | 0x0B |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 9 | 4 |
9.3 响应报文
对于从设备,在正常情况下,响应报文返回2字节的状态字和2字节的事件计数。其中,如果从站设备处于忙状态,那么状态字为0xFFFF,否则状态字为0x0000。在表4-18的示例中,状态字为0x0000,表示从站设备外于空闲状态。事件计数的值为0x03E8,表示记录了1000 (0x03E8)个事件。
功能码11响应报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x05 | “0”,“5” | 0x05 |
功能码 | 0x0B | “0”,“B” | 0x0B |
子功能码(高位) | 0x00 | “0”,“0” | 0x00 |
子功能码(低位) | 0x00 | “0”,“0” | 0x00 |
数据(高位) | 0x03 | “0”,“3” | 0x03 |
数据(低位) | 0xE8 | “E”,“8” | 0xB8 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 17 | 8 |
十、 (0x0C) 获取通信事件记录
10.1 功能说明
12功能码主要用于从从设备获取状态字、事件计数、报文计数以及事件字节字段。其中,状态字和事件计数与功能码11 (0x0B) 获取的值一致。报文计数包含加电重启、清除计数器之后的报文数量,报文计数与通过诊断功能码08 (0x08)、子功能码11 (0x0B) 获取的值一致。事件字节字段包含0~64字节,用来定义各种事件。
10.2 查询报文
下表中的示例表示获取通信事件记录的查询报文内容,其中从站地址位5。
功能码12查询报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x05 | “0”,“5” | 0x05 |
功能码 | 0x0C | “0”,“C” | 0x0C |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 9 | 4 |
10.3 响应报文
对于从站设备,在正常情况下,响应报文包括一个2字节的状态字字段、一个2字节的事件计数字段、一个2字节的消息计数字段以及0~ 64字节的事件字段。因为事件字段是变长的,所以增加了一个1字节的数据长度字段,以方便读取响应数据,如下表所示;
功能码12响应报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x05 | “0”,“5” | 0x05 |
功能码 | 0x0C | “0”,“C” | 0x0C |
字节数 | 0x08 | “0”,“8” | 0x08 |
状态字(高位) | 0x00 | “0”,“0” | 0x00 |
状态字(低位) | 0x00 | “0”,“0” | 0x00 |
事件计数(高位) | 0x03 | “0”,“3” | 0x03 |
事件计数(低位) | 0xE8 | “E”,“8” | 0xE8 |
消息计数(高位) | 0x01 | “0”,“1” | 0x01 |
消息计数(低位) | 0xF6 | ”F“,”6“ | 0xF6 |
事件0 | 0x20 | ”2“,”0“ | 0x20 |
事件1 | 0x00 | ”0“,”0“ | 0x00 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 17 | 8 |
十一、(0x0F)写多个线圈
11.1 功能说明
15功能码用于将连续的多个线圈或离散输出设置为ON/OFF状态,支持广播模式,在广播模式下,所有从站设备的同一地址的值将被统一修改。15功能码中,起始地址字段由2字节构成,取值范围为0x00000xFFFF:而寄存器数量字段由2字节构成,取值范用为0x00010x07B0.
11.2 查询报文
查询报文中包含请求数据字段,用于定义ON或OFF状态。数据字段中为逻辑1的位对应ON;逻辑0的位对应OFF。其中,ON/OFF与数据字段的对应关系可参考前面的童节“01 (0x01) 读取线圈,离散量输出状态 (Read Coil status/DOs)” 中的内容举例说明,假设从站设备地址为5,需要设置线圈地址20 ~30的状态如下表所示。
线圈状态:
值 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
线圈 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | — | — | — | — | — | 30 | 29 | 28 |
那么,写入的数据字段被划分为2字节,值分别为0xD1,对应于27 ~ 20的线圈,值0x05对应于30~28的线圈,注意细体会其中的高低位的对应关系。需要注意的是,在查询报文中,Modbus协议的起始地址为19 (0x13) ,即比线圈起始地址20少1。如下表所示,其中字节数字段表示需要变更数据的字节总数。
功能码15查询报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x05 | “0”,“5” | 0x05 |
功能码 | 0x0F | “0”,“F” | 0x0F |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x13 | “1”,“3” | 0x13 |
寄存器数(高位) | 0x00 | “0”,“0” | 0x00 |
寄存器数(低位) | 0x0B | “0”,“B” | 0x08 |
字节数 | 0x02 | “0”,“2” | 0x02 |
变更数据(高位) | 0xD1 | ”D“,”1“ | 0xD1 |
变更数据(低位) | 0x05 | ”0“,”5“ | 0x05 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 23 | 11 |
以主设备为例,发送(Tx)数据中第一个字节01为设备地址;第二个字节0F为功能码(写多个线圈);第三、四个字节00 02为起始地址,从图中可以看见我们设置的起始地址为2;第五、六个字节00 05为寄存器数,从图中可以看见我们设置的线圈个数为5;第七个字节为数据的字节数,这里设置线圈个数为5,每一个线圈对应一位数据,那么总共有5位数据,8位以内包括8位都是一个字节,所以这里为01;第八个字节1F对应寄存器,为0001 1111,从右开始起始地址为2,总共有五个寄存器被设置为1;第九、十个字节57 5E为校验码。
11.3 响应报文
对于从设备,在正常情况下,响应报文包括功能码、起始地址以及写入的线圈数量,如下表所示。
功能码15响应报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x05 | “0”,“5” | 0x05 |
功能码 | 0x0F | “0”,“F” | 0x0F |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x13 | “1”,“3” | 0x13 |
寄存器数(高位) | 0x00 | “0”,“0” | 0x00 |
寄存器数(低位) | 0x0B | “0”,“B” | 0x08 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 17 | 8 |
十二、(0x10) 写多个保持寄存器
12.1 功能说明
16功能码用于设置或写入从设备保持寄存器的多个连续的地址块 (1 ~ 123个寄存器),支持广播模式,在广播模式下,所有从站设备的同一地址的值将被统一修改。本功能码中,起始地址字段由2字节构成,取值范围为0x0000 ~ 0xFFFF;而寄存器数量字段由2字节构成,取值范围为0x0001~0x007B。
12.2 查询报文
查询报文包含请求数据字段。数据字段保存需要写入的数值,各数据按每个寄存器2字节存放。举例说明,从站设备地址为5,需要将保持寄存器地址40020 ~ 40022设置为如下表所示的数值。
寄存器的设置:
寄存器地址 | 设定值 | 寄存器地址 | 设定值 |
---|---|---|---|
40020 | 0x0155 | 40022 | 0x0157 |
40021 | 0x0156 |
对应于40020~40022的寄存器,注意仔细体会其中的高低位的对应关系。需要注意的是,在查询报文中,Modbus协议的起始地址为19 (0x13),即比寄存器起始地址20少1。如下表所示,其中字节数字段表示需要变更数据的字节总数。
功能码16查询报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x05 | “0”,“5” | 0x05 |
功能码 | 0x10 | “0”,“F” | 0x0F |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x13 | “1”,“3” | 0x13 |
寄存器数(高位) | 0x00 | “0”,“0” | 0x00 |
寄存器数(低位) | 0x03 | “0”,“B” | 0x08 |
字节数 | 0x06 | ”0“,”6“ | 0x06 |
变更数据1(高位) | 0x01 | ”0“,”1“ | 0x01 |
变更数据1(低位) | 0x55 | ”5“,”5“ | 0x56 |
变更数据2(高位) | 0x01 | ”0“,”1“ | 0x01 |
变更数据2(低位) | 0x56 | ”5“,”6“ | 0x56 |
变更数据3(高位) | 0x01 | ”0“,”1“ | 0x01 |
变更数据3(低位) | 0x57 | ”5“,”7“ | 0x57 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 31 | 15 |
以主设备为例,发送(Tx)数据中第一个字节01为设备地址;第二个字节0F为功能码(写多个保持寄存器);第三、四个字节00 00为寄存器起始地址,在图中可以看见起始地址设置为0;第五、六个字节00 02为寄存器数,在图中可以看见寄存器数量为2;第七个字节04为字节数,有两个寄存器,每个寄存器是16位(2字节),所以两个寄存器总字节为2*2=4字节;第八、九个字节00 38为第一个寄存器中的数据,0x38 对应的就是56;第十、十一个字节00 4E为第二个寄存器中的数据,0x4E对应的就是78;最后两个字节F2 56为校验码。
12.3 响应报文
对于从设备,在正常情况下,响应报文包括功能码、起始地址及写入的寄存器数量,如下表所示。
功能码16响应报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x05 | “0”,“5” | 0x05 |
功能码 | 0x10 | “1”,“0” | 0x10 |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x13 | “1”,“3” | 0x13 |
寄存器数(高位) | 0x00 | “0”,“0” | 0x00 |
寄存器数(低位) | 0x03 | “0”,“3” | 0x03 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 17 | 8 |
在实际开发过程中,功能码“16 (0x10) 写多个寄存器 (Preset Multiple Registers) ”通常用于方便用户写入多字节类型的数据。
例如,假设从站设备地址为5,需要向保持寄存器写入一个32位 (4字节) 的浮点数,那么此浮点数将占用2个寄存器地址。假设浮点数将存放在40001和40002寄存器中,设定值为1.235(即0x3F9E 147A)实际的查询和响应报文如下(其中标记部分为设定的浮点数值,假设字节序为AB-CD,参考第5.3.7章字节序和大小端的内容)。
查询报文: 05 10 00 00 00 02 04 3F 9E 14 7A 05 86
响应报文: 05 10 00 00 00 02 40 4C
对于64位(8字节)的双精度浮点数,同理将占用4个寄存器地址共8字节的空间。特别需要注意的是字节序及大小端的问题,前面讨论过多字节存在大小端问题,因此主站设备和从站设备必须保持一致的规则处理,约定Modbus传输中的数据字段的字节序,否则会因为大小端不一致而产生数据处理错误。
十三、 (0x11) 报告从站ID (仅用于串行链路)
13.1 功能说明
17功能码用于读取从站设备的ID、类型描述、当前状态以及其他信息,不支持广播模式。响应消息的构成依赖于设备而不尽相同。
13.2 查询报文
查询报文中不包含请求数据字段。举例说明,从站设备地址为5,获取相关信息,如下表所示。
功能码17查询报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x05 | “0”,“5” | 0x05 |
功能码 | 0x11 | “1”,“1” | 0x11 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 9 | 4 |
13.3 响应报文
对于从设备,在正常情况下,响应报文包括从站ID、运行状态以及其他附加信息,如下表所示。运行状态字段占用1字节,且0x00=OFF,0xFF=ON,而响应报文的组成则由开发者决定。
功能码17响应报文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x05 | “0”,“5” | 0x05 |
功能码 | 0x11 | “1”,“1” | 0x11 |
字节数 | 设备相关 | 设备相关 | 设备相关 |
从设备ID | 设备相关 | 设备相关 | 设备相关 |
运行状态 | 0xFF | “F”,“F” | 0xFF |
附加情报1 | 设备相关 | 设备相关 | 设备相关 |
…… | 设备相关 | 设备相关 | 设备相关 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 17 | 8 |
13.4 Modbus异常响应
以上介绍了一些常见的公共功能码的报文 (消息顿)构成,广播模式以外的查询报文都希望能够获取一个正常的响应报文。在通常情况下,从站设备将返回一个正常响应报文,但是在某些特殊情况下将返回异常响应报文。
对于查询报文,存在以下4种处理反馈:
- 正常接收,正常处理,返回正常响应报文;
- 因为通信错误等原因造成从站设备没有接收到查询报文,主站设备将按超时处理:从站设备接收到的查询报文存在通信错误 (如LRC、CRC错误等),此时从站设备将丢弃报文不响应,主站设备将按超时处理;
- 从站设备接收到正确的报文,但是超过处理范围(如不存在的功能码或者寄存器等),此时从站设备将返回包含异常码 (Exception Code) 的响应报文。
- 异常响应报文由从站地址、功能码以及异常码构成。其中,功能码与正常响应报文不同,在异常响应报文中,功能码最高位 (即MSB) 被设置为1。因为Modbus协议中的功能码占用1字节故用表达式描述为:
异常功能码=正常功能码+0x80
举例说明,如下表所示,查询报文的起始地址为0x012C (十进制300) ,即需要读取寄存器地址为30301开始的值。若从站设备中不存在输入寄存器30301,则从站设备将返回一个异常响应报文,参见下表的功能码和异常码。
异常响应示例(功能码04查询报文 ):
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x07 | “0”,“7” | 0x07 |
功能码 | 0x04 | “0”,“4” | 0x04 |
起始地址(高位) | 0x01 | “0”,“1” | 0x01 |
起始地址(低位) | 0x2C | “2”,“C” | 0x2C |
寄存器数(高位) | 0x00 | “0”,“0” | 0x00 |
寄存器数(低位) | 0x03 | “0”,“3” | 0x03 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 17 | 8 |
异常响应示例(功能码04响应报文 ):
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
帧头 | “:” | ||
从设备地址 | 0x07 | “0”,“7” | 0x07 |
功能码 | 0x84 | “8”,“4” | 0x84 |
异常码 | 0x02 | “0”,“2” | 0x02 |
差错校验 | LRC(2字符) | CRC(2字节) | |
帧尾 | CR/LF | ||
合计字节数 | 11 | 5 |
常见的异常码如下表所示:
常见异常码说明:
异常码 | 名称 | 说明 |
---|---|---|
01 | 非法功能码 | 从站设备不支持此功能码 |
02 | 非法数据地址 | 指定的数据地址在从站设备中不存在 |
03 | 非法数据值 | 指定的数据超过范围或者不允许使用 |
04 | 从站设备故障 | 从站设备处理响应的过程中出现未知错误等 |