工控协议(二):Modbus TCP/IP 学习笔记

注:本文内容是对以下官方文档的整理小结。
Modbus TCP/IP
Modbus Application protocol specification
Modbus TCP Security

Modbus TCP/IP 协议就是将一般的Modbus协议封装进 TCP 协议中进行传输,其应用层的协议格式与一般的Modbus是基本一致的。对比POWERLINK的一主多从,Modbus 更加灵活,允许多主多从的存在,因为使用TCP协议需要对请求进行逐一响应,也不存在同步异步的协调问题。但正因为其使用了TCP,响应时间会相对更长,对要求低延迟的系统来说可能不是最佳选择。

一般的从机开放的 Modbus TCP 端口为502(默认端口),主机连接从机所使用的端口可以是任意端口,通常设备会自行选择。

一、协议组成:

传统 Modbus 协议格式:

工控协议(二):Modbus TCP/IP 学习笔记
四个组成部分分别为 地址信息,指令信息,数据信息及校验。 ADU( Application data unit),译为应用数据单元。PDU(protocol data unit),译为协议数据单元。

Modbus TCP/IP 协议格式:

工控协议(二):Modbus TCP/IP 学习笔记
因为Modbus TCO/IP 将 Modbus嵌入常规TCP协议中进行传输,其地址信息及校验信息将由低层协议进行控制。这里简化为三个部分,Modbus 应用层协议包头,指令信息及数据信息三个部分。

MBAP Header 包头构成:

客户端是连接发起端,应当是主机(Master)
服务端是连接接收端,应当是从机(Slave)

构成部分 长度 描述 客户端 服务端
Transaction Identifier 2 Bytes 定义Modbus 的请求及响应直接的交互确认(可以理解为顺序码,请求及相应应当一一对应,且每次新请求,该值加一) 由客户端生成 响应时该值与请求值一致
Protocol Identifier 2 Bytes 0 代表 Modbus 协议 由客户端生成 响应时该值与请求值一致
Length 2 Bytes 后续内容的长度(包含Unit Identifier) 由客户端生成 由服务端生成
Unit Identifier 1 Bytes 标识通过串行线路或其他总线连接的远程从站 由客户端生成 响应时该值与请求值一致

二、Function Code 指令集

数据单元 (Channel)

在了解具体的指令之前,应当先了解Modbus 协议中数据是如何存放的,在从机上,用户可以设定单元存储内容,Modbus提供了四种类型如下表:

对象 对象类型 读写权限 描述
Discretes Input 1 bit 只读 该类型数据可通过 I/O系统提供(协议只读)
Discretes Output(Coils) 1 bit 读/写 该类型数据可通过应用层(协议)修改
Input Registers 16 bit 只读 该类型数据可通过 I/O系统提供(协议只读)
Holding Register 16 bit 读/写 该类型数据可通过应用层(协议)修改

只有从机可以分配这些类型,主机上是没有的,除非主机同时是其它设备的从机,那么也应当分配相应类型的单元。

在Modbus 中,每一个单元叫做 Channel,每一个channel有其对应的地址,地址范围位 0~65535。
在主机对从机的数据单元进行读写操作的时候,可以以块的方式进行读写,这样可以提升读写效率。

块 (Block)

在Modbus中,相邻地址的数据单元可以看作为块,官方文件举了两个例子:

  1. 分为四个块,根据不同的数据单元类型进行分块,示例中分了四块,在实际操作中根据设备提供的服务,可以分更多块,这种分法要求每个块中的数据类型是相同的,这样才能确保发送的指令有效。
    工控协议(二):Modbus TCP/IP 学习笔记
  2. 只有一个块,所有数据类型的单元都在一个块中,同一数据可被不同的指令控制。
    工控协议(二):Modbus TCP/IP 学习笔记
    那么在对大段相同类型并且地址连续的情况下,主机就可以以块的方式来进行读写操作,在指定开始地址后(地址最靠前的被操作数据单元地址),给定需要操作的数据单元数目,即可对其进行相应操作。

下图为 主机发起Read Coil指令,起始地址为16384,请求数目 2 bit,因为一个Coil只占1个bit,所以这里2个bit代表2个数据单元。
工控协议(二):Modbus TCP/IP 学习笔记
下图对应上图的请求返回,两个请求对象的值都为1,代表为真。
工控协议(二):Modbus TCP/IP 学习笔记

指令代码(Function Code)

Modbus 的指令集分为三个部分:通用指令,自定义指令,预留指令。
通用指令是Modbus 自带的默认指令,其中包括了对上述数据单元的读写操作,以及一些基础的诊断指令。
自定义指令是留给各厂家自行发挥脑洞的代码。
PS: 该指令定义的模式与CIP(Common Industry Protocol)相仿,都有自定义的部分。

指令代码 1-65,72-100,100-127为通用指令。65-72,100-110为自定义指令。

通用指令代码表:
工控协议(二):Modbus TCP/IP 学习笔记
对于不同的指令,会需要不同的请求参数。下图以Write Multiple Coils指令为例,主机发起写入请求,写入对象的起始地址为16384,Bit Count 代表了请求对象的数目(块的大小),Byte Count 代表了输入为几个Byte,这里值为0x03,只占一个Byte。 对工控协议有所了解的应该知道03代表这两个对象都为真值,若第一个为1,第二个为0,则这里data因该为1;若第二个为1,第一个为0,则这里data因该为2。
工控协议(二):Modbus TCP/IP 学习笔记
下图是从机的响应,其中并不包含请求写入对象的当前值。如果主机要确认其状态,则要再进行一次读取请求。
工控协议(二):Modbus TCP/IP 学习笔记
如果对详细指令的使用方式敢兴趣,请参考这篇官方文档

三、Modbus TCP协议流程

因为是基于TCP通信,三次握手自然是不可少的,具体流程如下图所示,其中CLIENT请求发起端是主机,SERVER请求回复端是从机。

工控协议(二):Modbus TCP/IP 学习笔记
可以看到首先是经典的三次握手,握手成功后,主机能够开始发送MODBUS请求。
这里主机能发起的请求是基于用户如何设定程序的,并没有定式。在一般的工业环境中,MODBUS请求应该根据设定的程序来循环发送以达到实时更新主从机状态的目的。以下图为例,Read Coils,Write Multiple Coils,Read Discrete Inputs 的请求是轮流重复出现的。
工控协议(二):Modbus TCP/IP 学习笔记

四、Modbus TCP/IP Security

该协议是Modbus TCP/IP 协议的一个拓展,使用了TLS (Transport Layer Security) 对应用层内容进行加密传输,相较Modbus TCP/IP的明文传输来说更加安全。
在初始化连接阶段,主机与从机需要交换双方的**来完成连接,连接成功之后,所有传输数据会按照双方所持有的**进行加密后再传输。
需要注意不是所有支持Modbus TCP/IP 的设备都支持Modbus TCP/IP Security,具体设备情况还是要看厂商的,对该协议这里不展开介绍了。