
Modbus和OPC UA、mqtt本质一样,都是为实现多个设备相互通信的应用层协议
。Modbus于1979年产生于Modicon公司(现被Schneider公司收购),一经面世因其简单开放的通信方式慢慢的变成为工业系统中流行的标准。Modbus的国际组织主要有Modbus-IDA,负责推广Modbus标准及对Modbus产品做认证。Modbus官网见,网站最重要的包含协议文档,Modbus产品和厂商等内容。
之前的物联网IoT协议之OPC UA快速入门教程中提到OPC UA是工业领域常用的协议,其实在工业领域中Modbus比OPC/OPC UA更常见,市面上很多数据采集设备(如温湿度采集)都使用Modbus协议;OPC UA大量的专有名词(如节点、服务、引用等)总能把初学者弄得云里雾里,而Modbus比OPC UA简单太多了,简单之处体现包括:
Modbus最开始使用RS232,RS485等串行链路作为底层通信方式,串行总线的接口芯片成本低,而且布线也简单方便;
随着设备个数的增加,两两相连需要的线按指数级增长,所以两两相连的方式肯定是不合适了
。为了避免数据冲突,有多种处理方法,比如以太网使用的CSMA/CD(即载波侦听多路访问/冲突检测),CSMA协议要求设备在发送数据之前先监听总线/信道,如果总线空闲,设备就可以发送数据,如果总线忙,则设备不能发送数据;而Modbus采用了一种更简单的避免冲突的方式,即主从通信模式。
Modbus的主从通信模式Modbus为了尽最大可能避免多个设备数据的冲突,使用了单主机/多从机的模式,即总系统中只能有一个主机(Master)和多个从机(Slave).
,主机发送请求数据给从机,从机只有在接收到主机的请求数据后,才能发送应答数据到总线上;整个过程中
每个从机都一个唯一的从机地址,主机发起请求时,请求数据中携带了目标从机地址;主机把请求数据发送到总线上,
。Modbus的业务模型Modbus的业务模型也最简单,源码先生把Modbus业务模型简称为“读写数据”模型,即
不明白什么是线圈的话,可完全忽略线圈这一个名字,只要记住寄存器0对应数据只有0/1这两种值即可,这也是上图中single bit的含义(正好对应了线圈开/关这两种状态,其实是通过线圈这个名称告诉使用者,这个寄存器分区的数据只有0/1),这在某种程度上预示着“读”寄存器0的任何地址的数据,读到的数据不是0就是1
,读寄存器0的0x0000地址的数据,读到的是0(或者1),读取寄存器0的0x0001地址的数据,读到的也是0(或者1)。请忽略寄存器的名称,4种寄存器本质都是“内存”,每中寄存器都包含了一段内存地址空间(每种寄存器的地址取值范围为0x0000-0xFFFF),用户要做的就是“读写内存”。4种寄存器按照功能的不同分类,比如寄存器0可读可写,而寄存器1只读;寄存器0的数据是single bit(不是0就是1),而寄存器3的数据是16-bit world(两个字节),这在某种程度上预示着读取寄存器3的0x0000地址的数据,读出的是2个字节的数据,读取寄存器3的0x0001地址的数据,读出的也是2个字节的数据。
这三种报文的报文主体(包括从机地址+功能码+数据域)都相同,三者没有本质区别。由于Modbus ASCII使用ASCII编码,相比Modbus RTU使用的原始二进制,前者占用空间更大,传输效率低,所以Modbus ASCII并不常用,这里主要介绍Modbus RTU和Modbus TCP。
设备的从机地址用来标识设备的唯一性,用户都能够自定义配置设备的从机地址,只要保证总线上每个设备的从机地址唯一,不冲突即可,从机地址范围:1-247,0为广播地址,248-255为预留地址。
功能码对应了设备提供的某个服务/功能,Modbus标准中把功能码分为3类:
用户自定义功能码(User-Defined Function Codes):设备依据需求自定义的功能码,取值范围65-72和100-110;
保留功能码(Reserved Function Codes):目前没用,可忽略
虽然Modbus标准中定义了很多个公共功能码,但实际场景中,常用的只有读/写4种寄存器相关的功能码,读写又分为Single读写(一次只读写一个地址的数据)和Multiple读写(一次读写多个地址的数据):
当设备数据是开关量0/1,同时只允许读不允许写的话,读设备数据的功能码
当数据长度大于2字节长度时(比如4字节),可以选取批量读写的功能码(批量读功能码0x03和0x04,批量写功能码0x10),注意此时会遇到大端/小端的问题(另外,4个字节的数据对应是整型还是浮点数,这取决于应用程序如何解析4个字节的数据,和Modbus标准没有关)
当购买了Modbus设备时,通常要从设备配套的说明文档中查询设备使用哪些功能码、以及读写数据的含义。
Modbus业务模型为“读写数据”模型,而读写时必须要有数据地址,理论上每种寄存器的数据地址的取值范围都为0x0000-0xFFFF,注意不一样的种类的寄存器的数据地址是独立,寄存器可以有0x0000,寄存器2也可以有0x0000,数据地址虽然相同,但是读写数据不会相互影响。
虽然RS485串行链路比以太网链路简单,但是鉴于以太网太流行了,Modbus引入TCP/IP的作为通信方式。Modbus是应用层协议,不管底层使用RS485链路还是TCP,应用层变化不大。
去掉了从机地址(即上图中的附加地址),因为TCP是面向连接的,TCP必须先根据IP地址建立一对一的连接,连接建立后,已经不在需要从机地址了;
去掉了差错校验,因为TCP是可靠传输,TCP传输层已经做过了数据校验了,Modbus应用层可以不再校验;
增加了事务处理标志,这个能作为自增ID来标识不同的报文,由于Modbus标准中不允许多个消息并行发送,所以事务处理标志填为0也没问题;
增加了数据长度,即Modbus TCP报文的长度,因为TCP是流式数据,需要用数据长度来识别两个报文的边界;
增加了单元标识符,这里可以填0或者填写从机地址(可用于网关转发请求给从机);
前面提到Modbus主从通信模式主要是为了尽最大可能避免多个设备的数据冲突,而TCP底层已经使用CSMA/CD解决了数据冲突问题,而且TCP是全双工通信(RS485链路是半双工),这在某种程度上预示着Modbus TCP的从机主动发送报文也不会产生冲突的,但是如果从机主动发送报文,就不符合Modbus标准了。
TCP是面向连接的,基于Modbus TCP实现多主/多从的通信也是可行的,不会产生冲突,但是就不符合Modbus标准了
双击EasyModbusClientExample.exe,启动客户端。如下图点击connect,连接服务器。
客户端界面,点击“Read Coils -FC1”按钮,可以读取寄存器0的数据。
由于Modbus主从通信模式,从机只能被动应答,不能主动上报数据,所以Modbus其实不太适合上云,但是现存大量Modbus设备,如果支持Modbus上云的话,能够迅速把现有设备接入到云端,还是非常有必要的。
云端软件平台作为Modbus主机,云端定时发送请求报文给网关,网关再把请求报文转发Modbus总线上,Modbus总线上的从机收到请求后,返回应答数据到Modbus总线,网关读取应答报文并转发给云端;
云端和网关之间使用Modbus TCP报文通信,网关和设备之间能够正常的使用Modbus RTU,也能够正常的使用Modbus TCP报文通信;
网关作为转发的角色,在云端和从机设备之间转发数据,网关同时也作为转换协议的角色,比如把Modbus TCP转换为Modbus RTU;
云端需要不停的发送请求报文,相当于不停的轮询,当从机设备数量比较多时,云端的轮询压力大,通信带宽要求也比较高。
网关作为Modbus主机,网关主动定时发送请求报文到Modbus总线上,然后接收从机的应答报文;网关接收到从机应答报文后,能够正常的使用其他协议(比如mqtt)把应答信息转发给云端。
网关除了作为Modbus主机,还需要作为连接云端的客户端(比如Mqtt客户端)把轮询到的数据主动上报给云端;
需要把网关如何轮询从机的信息从云端配置给网关,配置稍微麻烦,但是轮询压力分散在网关上,比较符合边缘计算的思路。
Modbus缺点:实时性差(从机不能主动上报数据,必须依赖主机轮询),总线利用率低,传输速率低,另外RS485抗干扰较弱,节点错误是会影响整个总线。如果Modbus不能够满足自己的需求,能够正常的使用CAN总线。


