Modbus通讯协议由Modicon公司(现已经为施耐德公司并购,成为其旗下的子品牌)于1979年发明的,是全球最先用于工业现场的总线规约。因为其免费公开发行,使用该协议的厂家无需缴纳任何费用,Modbus通讯协议采用的是主从通讯模式(即Master/Slave通讯模式),其在分散控制方面应用极其普遍,从而使得Modbus协议在全球获得了普遍的应用。算法
Modbus通讯协议具备多个变种,其具备支持串口(主要是RS-485总线),以太网多个版本,其中最著名的是Modbus RTU,Modbus ASCII和Modbus TCP三种。其中Modbus RTU与Modbus ASCII均为支持RS-485总线的通讯协议,其中Modbus RTU因为其采用二进制表现形式以及紧凑数据结构,通讯效率较高,应用比较普遍。而Modbus ASCII因为采用ASCII码传输,而且利用特殊字符做为其字节的开始与结束标识,其传输效率要远远低于Modbus RTU协议,通常只有在通讯数据量较小的状况下才考虑使用Modbus ASCII通讯协议,在工业现场通常都是采用Modbus RTU协议,通常而言,你们说的基于串口通讯的Modbus通讯协议都是指Modbus RTU通讯协议。服务器
在此咱们着重讨论Modbus RTU协议,而Modbus TCP协议则是在RTU协议上加一个MBAP报文头,因为TCP是基于可靠链接的服务,RTU协议中的CRC校验码就再也不须要,因此在Modbus TCP协议中是没有CRC校验码,用一句比较通俗的话说就是:Modbus TCP协议就是Modbus RTU协议在前面加上五个0以及一个6,而后去掉两个CRC校验码字节就OK.虽然这句话说得不是特别准确,可是也基本上把RTU与TCP之间的区别说得比较清楚了。数据结构
RTU协议中的指令由地址码(一个字节),功能码(一个字节),起始地址(两个字节),数据(N个字节),校验码(两个字节)五个部分组成,其中数据又由数据长度(两个字节,表示的是寄存器个数,假定内容为M)和数据正文(M乘以2个字节)组成,而RTU协议是采用3.5个字节的空闲时间做为指令的起始和结束,通常而言,只有当从机返回数据或者主机写操做的时候,才会有数据正文,而其余时候好比主机读操做指令的时候,没有数据正文,只须要数据长度便可。(本章的讨论只涉及寄存器的读写,其余好比线圈的读写指令咱们暂时不涉及)。在此咱们经过两个指令(0x03H:读多个寄存器指令以及0x10H:写多个寄存器指令)来解释Modbus RTU协议。在此咱们使用的RTU设备是深圳市国科伟业通讯技术有限公司的ND-1084型485总线I/O模块。tcp
ND-1084型485总线I/O模块采用RS-485总线通讯,支持四路开关量输出以及八路开关量输入,咱们只讲述读取开关量输出的状态以及经过写指令控制开关量的输出。其中储存开关量输出状态的四个寄存器分别:0x18E,0x18F,0x190,0x191。在此咱们假设模块的地址为默认的0x01,当咱们要去读取开关量输出对应的四个寄存器的状态的时候,咱们下发的十六进制的指令为:“01 03 01 8E 00 04 25 DE”,其中“01”为模块的地址码,“03”为功能码,即表示读寄存器,“01 8E”为寄存器地址,即从该寄存器地址开始读取数据,“00 04”则表示读取4个寄存器,而“25 DE”则为前面“01 03 01 8E 00 04”的CRC校验码,该数值经过CRC16校验算法计算出来的,咱们会在其余文章中阐述。该指令的完整解读就是,在地址码为“01”的模块中,从“01 8E”寄存器开始,读取4个寄存器的数据返回至主机。在此,咱们能够看到,读取指令中并无什么数据正文,由于它只是读取相应数量的寄存器,并不须要数据正文,而写操做指令则相反,咱们会在后面讲到。htm
模块返回的指令是:“01 03 08 00 01 00 01 00 01 00 01 28 D7”,返回的指令内容解读就是:“01”表示模块的地址码,“03”表示该指令是读操做返回的指令,“08”表示数据长度,在此表示的是8个字节数据正文(即4个寄存器,每一个寄存器两个字节表示),“00 01 00 01 00 01 00 01”是数据正文,表示四个寄存器的状态,“28 D7”就是CRC16校验码。开发
一样的当咱们执行写操做的是,咱们举例写第一个开关量输出,即寄存器“0x18E”,主机下发的指令为:“01 10 01 8e 00 01 02 00 00 A8 7E”,该指令的解读就是:“01”表示模块的地址,“10”表示该指令为写寄存器,“01 8E”表示从该寄存器地址开始执行写操做指令“00 01”表示写多少个寄存器,在此为写1个寄存器,“02”表示数据长度,表示数据长度为两个字节,“00 00”表示写入寄存器的数据,在此表示连通,“A8 7E”为CRC校验码。模块返回的指令和读取寄存器的返回的指令相似。get
前文所述,Modbus TCP协议是在RTU协议前面添加MBAP报文头,共七个字节长度,其分别的意义是:1.传输标志,两个字节长度,标志Modbus询问/应答的传输,通常默认是00 00。2.协议标志,两个字节长度,0表示是Modbus,1表示UNI-TE协议,通常默认也是00 00。3.后续字节计数,两个字节长度,其实际意义就是后面的字节长度,具体状况详见下文。4.单元标志,一个字节长度,通常默认为00,单元标志对应于Modbus RTU协议中的地址码,当RTU与TCP之间进行协议转换的时候,特别是Modbus网关转换协议的时候,在TCP协议中,该数据就是对应RTU协议中的地址码,具体状况详见下文。table
经过上面的描述咱们差很少可以理解Modbus RTU协议,咱们再说说Modbus TCP通讯协议,前面就已经说过TCP协议就是在RTU协议的基础上去掉校验码以及加上五个0和一个6,当是读取相关寄存器的时候,该说法是没有错的,好比上文的“01 03 01 8E 00 04 25 DE”读取指令,用TCP协议来表述的话,指令是“00 00 00 00 00 06 00 03 01 8E 00 04”,因为TCP是基于TCP链接的,不存在所谓的地址码,因此06后面通常都是“00”(当其做为Modbus网关服务器挂接多个RTU设备的时候,数值从01-FF).即“00 03 01 8E 00 04”对应的是RTU中去掉校验码的指令,前面则是五个0以及一个6。其中6表示的是数据长度,即“00 03 01 8E 00 04”有6个字节长度。而当其为写操做指令的时候,其指令是“00 00 00 00 00 09 01 10 01 8e 00 01 02 00 00”,其中“00 09”表示后面有9个字节。ast
Modbus RTU与Modbus TCP读指令对比效率
MBAP报文头
|
地址码
|
功能码
|
寄存器地址
|
寄存器数量
|
CRC校验
|
|
Modbus RTU |
无
|
01
|
03
|
01 8E
|
00 04
|
25 DE
|
Modbus TCP |
00 00 00 00 00 06 00
|
无
|
03
|
01 8E
|
00 04
|
无
|
指令的涵义:从地址码为01(TCP协议单元标志为00)的模块0x18E(01 8E)寄存器地址开始读(03)四个(00 04)寄存器。
Modbus RTU与Modbus TCP写指令对比
MBAP报文头
|
地址码
|
功能码
|
寄存器地址
|
寄存器数量
|
数据长度
|
正文
|
CRC校验
|
|
RTU |
无
|
01
|
10
|
01 8E
|
00 01
|
02
|
00 00
|
A8 7E
|
TCP |
00 00 00 00 00 09 00
|
无
|
10
|
01 8E
|
00 01
|
02
|
00 00
|
无
|
指令的涵义:从地址码为01(TCP协议单元标志为00)的模块0x18E(01 8E)寄存器地址开始写(10)一个(00 01)寄存器,具体数据长度为2个字节(02),数据正文内容为00 00(00 00)。