表1. ModBus功能码定义
功能码 | 名称 | 作用 |
01 | 读取线圈状态 | 取得一组逻辑线圈的当前状态(ON/OFF) |
02 | 读取输入状态 | 取得一组开关输入的当前状态(ON/OFF) |
03 | 读取保持寄存器 | 在一个或多个保持寄存器中取得当前的二进制值。 |
04 | 读取输入寄存器 | 在一个或多个输入寄存器中取得当前的二进制值。 |
05 | 强置单线圈 | 强置一个逻辑线圈的通断状态。 |
06 | 预置单寄存器 | 把二进制值装入一个保持寄存器。 |
07 | 读取异常状态 | 取得8个内部线圈的通断状态,线圈的地址由控制器决定,用户逻辑可将这些线圈定义,以说明从机状态,短报文适宜于迅速读取状态。 |
08 | 回送诊断校验数据 | 把诊断校验数据发送到从机,以对通信结果进行评鉴 |
09 | 编程(只用于484) | 使主机模拟编程器作用,修改PC从机逻辑。 |
10 | 控询(只用于484) | 可使主机与一台正在执行长程序任务的从机通信,探询该从机是否已完成操作任务。仅在含功能码9的报文发送后,本功能码才得发送。 |
11 | 读取事件计数 | 可使主机发出单询问,并随即判定操作是否成功,尤其是在该功能或其应答产生通信错误时。 |
12 | 读取通信事件记录 | 可使主机检索每台从机的Modbus事务处理通信事件记录。如果某项事务处理未完成,记录会给出有关错误。 |
13 | 编程(184/384 484584) | 可使主机模拟编程器功能,修改PC从机逻辑。 |
14 | 探询(184/384 484584) | 可使主机与正在执行长程序任务的从机通信,定期探询该从机是否已完成程序操作。仅在含有功能13的报文发送后,本功能码才得发送。 |
15 | 强置多线圈 | 强置一串连续逻辑线圈的通断。 |
16 | 预置多寄存器 | 把二进制值装入一串连续的保持寄存器。 |
17 | 报告从机标识 | 可使主机判断编址从机的类型及该从机运行指示灯的状态。 |
18 | 编程(884和Micro84) | 可使主机模拟编程功能,修改PC状态逻辑。 |
19 | 重置通信链路 | 发生非可修正错误后,使从机复位于已知状态。可重置顺序字节。 |
20 | 读取通用参数( 584L) | 显示扩展存储器文件中的数据信息。 |
21 | 写入通用参数(584L) | 把通用参数写入扩展存储器文件,或修改。 |
22~64 | 保留,作扩展功能备用 | |
65~72 | 保留,作用户功能备用 | 留作用户功能的扩展编码。 |
73~119 | 非法功能 | |
120~127 | 保留 | 留作内部用。 |
128~255 | 保留 | 用于异常应答。 |
表2. ModBus功能码对应的数据类型表
功能码 | 功能 | 返回的数据类型 |
01 | 读 | 位 |
02 | 读 | 位 |
03 | 读 | 整形,字符型,浮点型,状态字 |
04 | 读 | 整形,浮点型,状态字 |
05 | 写 | 位 |
06 | 写 | 整形,字符型,浮点型,状态字 |
08 | N/A | 重复“回路反馈”信息 |
15 | 写 | 位 |
16 | 写 | 整形,字符型,浮点型,状态字 |
17 | 读 | 字符型 |
当消息从主设备发往从设备时,功能代码域将告之从设备需要执行哪些行为。例如去读取输入的开关状态,或读一组寄存器的数据内容,或读从设备的诊断状态,或允许在从设备中调入、记录、校验程序等。
当从设备回应时,它使用功能代码域来指示是正常回应(无误)还是有某种错误发生(称作异议回应)。对正常回应,从设备仅回应相应的功能代码。对异议回应,从设备返回功能代码的最高位为“1”。例如:
一条主设备发往从设备的消息要求读一组保持寄存器,将产生如下功能代码:
0 00 0 0 0 1 1 (十六进制03H)
对正常回应,从设备返回同样的功能代码。对异议回应,它将返回:
1 00 0 0 0 1 1 (十六进制83H)
除功能代码因异议回应作了修改外,从设备还将一个独特的代码放到回应消息的数据域中,告诉主设备发生了什么错误。
主设备得到异议回应后,典型的处理过程是重发消息。或者请求技术员,帮助诊断发给从设备的消息是否有错。
3.5 数据域
根据网络传输模式,数据域可以由若干个ASCII字符或RTU字节组成。数据域的值由十六进制数构成,范围为00H~FFH。
主设备发给从设备消息的数据域包含从设备必须完成的由功能代码所定义的行为。其中包括了不连续的寄存器地址、要处理项的数目、域中实际数据字节数。
例如,如果主设备需要从从设备读取一组保持寄存器(功能代码03),则必须在数据域中指定起始寄存器地址以及要读的寄存器个数。如果主设备需要向从设备写一组的寄存器(功能代码10十六进制),则必须在数据域中指明要写的寄存器起始地址、要写的寄存器个数以及要写入的数据。
在某种消息中,数据域可以是不存在的(0长度)。例如,主设备要求从设备回应通信事件记录(功能代码0BH),从设备不需任何附加的信息。
3.6 错误检测域
标准的Modbus网络有两种错误检测模式。错误检测域的内容视所选的检测模式而定。
ASCII模式:
当选用ASCII模式时,错误检测域包含两个ASCII字符。这是使用LRC(纵向冗长检测)方法对消息内容计算得出的,不包括开始的冒号符及回车换行符。LRC字符处在回车换行符前面。
RTU模式:
当选用RTU模式时,错误检测域包含一个16Bits值(用两个8位的字符来实现)。错误检测域的内容是通过CRC(循环冗长检测)方法得出的。CRC域附加在消息的最后,CRC的高位字节是发送消息的最后一个字节。
4. Modbus的错误检测方法
标准的Modbus串行网络采用两种错误检测方法。奇偶校验对每个字符都可用,帧检测(LRC或CRC)应用于整个消息。它们都是在消息发送前由主设备产生的,从设备在接收过程中检测每个字符和整个消息帧。
用户要给主设备配置一个预先定义的超时时间间隔,这个时间间隔要足够长,以使任何从设备都能作出正常反应。如果从设备检测到传输错误,消息将不会被接收,也不会向主设备作出回应。这样产生的超时事件将触发主设备来处理错误。发往不存在的从设备的地址也会产生超时。
4.1 奇偶校验
用户可以配置控制器是奇校验或偶校验,也可以是无校验。如果指定了奇或偶校验,将计算每个字符(8个Bit)中“1”的位数(ASCII模式7个数据Bit,RTU中8个数据Bit)。例如字符C5H包含以下8个数据Bit:
1 10 0 0 1 0 1
整个字符“1”的位数是4个。如果便用了偶校验,因为4是偶数,帧的奇偶校验位将是0,使得整个帧的“1”的个数仍是偶数(4)。如果使用了奇校验,帧的奇偶校验位将是1,便得整个帧的“1”的个数是奇数(4+1=5)。
如果没有指定奇偶校验位,传输时就没有校验位,也不进行校验检测。此时,在要传输的字符帧中增加一个停止位。
4.2 LRC校验
被应用于ASCII模式,消息包括了一个基于LRC方法的错误检测域。LRC域检测了消息域中除开始的冒号及结束的回车换行号以外的内容。
LRC域是一个包含8位二进制值的字节。LRC值由发送设备计算并放到消息帧中,接收设备在接收消息的过程中重新计算LRC,并将它和接收消息中的LRC值比较,如果两值不等,说明有错误。
LRC方法是将消息中的8Bit的字节连续累加,丢弃了进位。
4.3 CRC校验
被应用于RTU模式,消息包括了一个基于CRC方法的错误检测域。CRC域检测了整个消息的内容。
CRC域是两个字节,包含一个16位的二进制值。它由传输设备计算后加入到消息中。接收设备重新计算收到消息的CRC,并与接收到的CRC域中的值比较,如果两值不同,则有误。
CRC方法比LRC方法繁琐得多,受篇幅限制在此不作介绍。如需了解,请参见本人发表的《CRC校验原理与程序设计》一文。
一个通信实例:
表3是一个以RTU方式读取整数数据的例子。主机向01H号从机发出04H号(读取输入寄存器) 功能码,要求读取从0000H地址开始的2个(16Bit) 输入寄存器的值。CB71H是01H、04H、00H、00H、00H、02H六个数据的CRC校验值。从机应答时将地址和功能码原样发回,并将2个(16Bit)输入寄存器的值0107H和0251H分成4个(8Bit)数据01H、07H、02H、51H发回。258BH是01H、04H、04H、01H、07H、02H、51H七个数据的CRC校验值。
主机请求消息帧(8个字节)
地址 | 功能码 | 被读首个寄存器的高位地址 | 被读首个寄存器的低位地址 | 被读寄存器的数量的高位 | 被读寄存器的数量的低位 | CRC低位 | CRC高位 | |
01 | 04 | 00 | 00 | 00 | 02 | 71 | CB |
从机应答消息帧(9个字节)
地址 | 功能码 | 数据个数 | 第1个数据 | 第2个数据 | 第3个数据 | 第4个数据 | CRC低位 | CRC高位 |
01 | 04 | 04 | 01 | 07 | 02 | 51 | 8B | 25 |
表3. 以RTU方式读取整数数据
参考文献:
① GB/T 19582.1-2008《基于Modbus协议的工业自动化网络规范》
②Modbus协议中文版可在互联网上下载
(注:本文在发出时,微博服务器系统提示说字符超出1万字,不能通过。俺一脑袋浆糊,明明没有1万字嘛。抱歉啦,分成两部分发表)