MODBUS协议
Modbus是一个工业上常用的通讯协议。此协议定义了一个控制器能认识使用的消息结构;描述了一个控制器请求访问其它设备的过程,如何回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。
1、Modbus协议描述
Modbus协议定义了一个与基础通信层无关的简单协议数据单元(PDU)。特定总线或网络上的Modbus协议映射能够在应用数据单元(ADU)上引入一些附加域。

启动Modbus事务处理的客户机(主机)创建Modbus应用数据单元。功能码向服务器(从机)指示将执行哪种操作。Modbus协议规范了主机的请求格式,如上图所示。
一个Modbus ADU最大长度为256字节。
1字节地址域,指示从机地址。可以编码0-255共256个地址。Modbus主机没有地址,从机必须有唯一的地址。地址0为广播模式,即主机向所有从机发布消息。地址1-247为从机单独地址,248-255为保留地址。一对一通信时,通常将从机地址定义为1。
1字节功能码,编码Modbus数据单元的功能码域。有效的功能码范围是十进制1-255(128-255 为异常响应保留)。当从主机向从机设备发送消息时,功能码通知从机执行哪种操作。有些功能码具有子功能码,来实现多项操作。
若干位含有请求和响应参数的数据域,从机使用这些数据执行功能码定义的操作。这个域还包括离散项目和寄存器地址、处理的项目数量以及域中的实际数据字节数。在某种请求中,数据域可以是不存在的(0长度),在此情况下服务器不需要任何附加信息。功能码仅说明操作。
2字节错误检验,对报文内容执行"冗余校验" 的计算结果,具体实现在后文介绍。
Modbus串行链路协议是一个主-从协议。在同一时刻,只有一个主机连接于总线,一个或多个从机(最大编号为247 )连接于同一个串行总线。Modbus通信总是由主机发起。从机在没有收到来自主机的请求时,从不会发送数据。从机之间从不会互相通信。主机在同一时刻只会发起一个Modbus事务处理。
如果在一个正确接收的Modbus ADU 中,不出现与请求Modbus 功能有关的差错,那么从机至主机的响应数据域包括请求数据。如果出现与请求Modbus 功能有关的差错,那么域包括一个异常码,从机应用能够使用这个域确定下一个执行的操作。
当从机对主机响应时,它使用功能码域来指示正常(无差错)响应或者出现某种差错(称为异常响应)。对于一个正常响应来说,从机仅对原始功能码响应。下图显示了事务处理正常和异常的过程。

对于异常响应,从机返回一个与原始功能码等同的码,设置该原始功能码的最高有效位为逻辑1。

Modbus 协议定义了三种PDU。它们是:
Modbus请求PDU,mb_req_pdu;
Modbus响应PDU,mb_rsp_pdu;
Modbus异常响应PDU,mb_excep_rsp_pdu。
2、Modbus数据模型
Modbus以4种具有不同特征表格上的数据模型为基础。
以下主要介绍写线圈和写保持寄存器的方法。

3、功能码
3.1 功能码定义
写多个线圈:功能码0x0F
写多个寄存器:功能码0x10
3.2 写多个寄存器(0x10)
表 2 主机请求PDU
表 3 从机响应
N为寄存器数量。
如果出现错误,则从机返回1字节差错码0x90,1字节异常码01或02或03或04
例如,主机发送:01 10 00 0B 00 01 02 00 01 66 EB
01 表示向地址为1的从机写数据,10是功能码,00 0B是起始地址,00 01表示1个寄存器,02表示写入的数据长度为2个字节,00 01是写入的数据内容,66 EB是主机自动生成的校验位。
因此这条信息表示:将“00 01”写入1号从机00 0B开始的地址处。
3.3 写多个线圈(0x0F)
表 4 主机请求PDU
输出字节数N=输出线圈数量/8,如果余数不等于0,则加1取整。
表 5 从机响应
逻辑1对应开关量输出为“ON”,逻辑0对应开关量输出为“OFF”。
如果写入线圈个数不是8的倍数,最后字节中未被使用的比特会用0填充。
如果出现错误,则从机返回1字节差错码0x8F,1字节异常码01或02或03或04。
例如,主机发送:01 0F 00 00 00 0A 02 A0 01 5C F8
01 表示向地址为1的从机写线圈,0F是功能码,00 00是起始地址,00 0A表示写10个线圈,02表示写入的数据占据2个字节,A0 01是写入的数据内容,5C F8是主机自动生成的校验位。
A0 01写成二进制形式是:1010 0000 0000 0001,其中1010 0000是实际数据的第7位——第0位,0000 0001中的最后两位01是实际数据的第9位和第8位,前面6位是补0。因此,实际传输的10个线圈量从低位到高位是:0000 0101 10。
因此这条信息表示:将0000 0101 10这10个线圈写入1号从机00 00开始的地址处。
4、RTU传输模式
设备使用RTU模式。
当设备使用RTU (Remote Terminal Unit) 模式在Modbus 串行链路通信,报文中每个8位字节含有两个4 位十六进制字符。这种模式的主要优点是较高的数据密度,在相同的波特率下比ASCII 模式有更高的吞吐率。每个报文必须以连续的字符流传送。
RTU 模式每个字节( 11 位) 的格式为 :
编码系统: 8位二进制
报文中每个8 位字节含有两个4 位十六进制字符(0–9, A–F)
Bits per Byte: 1 起始位
8 数据位, 首先发送最低有效位
1 位作为奇偶校验
1 停止位
为了保证与其它产品的最大兼容性,建议不使用奇偶校验校验模式。默认校验模式必须为偶校验。使用无校验时要求2个停止位。
传送时,每个字符或字节均由此顺序发送(从左到右):
Modbus报文RTU帧
由发送设备将Modbus 报文构造为带有已知起始和结束标记的帧。这使设备可以在报文的开始接收新帧,并且知道何时报文结束。不完整的报文必须能够被检测到而错误标志必须作为结果被设置。在 RTU 模式,报文帧由时长至少为3.5个字符时间的空闲间隔区分。在后续的部分,这个时间区间被称作t3.5。

5、CRC校验
在RTU模式包含一个对全部报文内容执行的,基于循环冗余校验(CRC - Cyclical Redundancy Checking)算法的错误检验域。CRC域检验整个报文的内容。不管报文有无奇偶校验,均执行此检验。
CRC包含由两个8位字节组成的一个16位值。
CRC域作为报文的最后的域附加在报文之后。计算后,首先附加低字节,然后是高字节。CRC高字节为报文发送的最后一个子节。
附加在报文后面的CRC的值由发送设备计算。接收设备在接收报文时重新计算CRC的值,并将计算结果于实际接收到的CRC值相比较。如果两个值不相等,则为错误。
CRC的计算, 开始对一个16位寄存器全部预装1。然后将报文中的连续的8 位字节对其进行后续的计算。只有字符中的8个数据位参与生成CRC的运算,起始位,停止位和校验位不参与CRC计算。
CRC 的生成过程中, 每个 8位字符与寄存器中的值异或。然后结果向最低有效位(LSB)方向移动(Shift) 1位,而最高有效位(MSB)位置充零。然后提取并检查LSB:如果LSB 为1, 则寄存器中的值与一个固定的预置值异或;如果LSB 为 0, 则不进行异或操作。
这个过程将重复直到执行完8 次移位。完成最后一次(第8 次)移位及相关操作后,下一个8位字节与寄存器的当前值异或,然后又同上面描述过的一样重复8 次。当所有报文中字节都运算之后得到的寄存器中的最终值,就是CRC。