Modbus概述
- 应用层消息协议;
- 采用请求/应答方式;
- 通过功能码提供特定服务;
- 能轻松完成不同总线或网络间的设备的通信。
1979年后成为工业领域串行通信协议的业界标准。
实现方式
主要实现方式如下:
- 基于以太网的TCP/IP实现,见Modbus消息实现指南V1.0a;
- 通过多种介质进行异步串行传输;
- Modbus+,一种高速令牌传递网络。
网络架构
Modbus协议可以在所有类型的网络架构中轻松通信。
术语:
- ADU: Application Data Unit 应用数据单元
- HDLC: High level Data Link Control 高级数据链路控制
- HMI: Human Machine Interface 人机界面
- IETF: Internet Engineering Task Force 互联网工程任务组
- I/O: Input/Output
- IP: Internet Protocol
- MAC: Media Access Control 媒体访问控制
- MBAP: MODBUS Application Protocol
- PDU: Protocol Data Unit
- PLC: Programmable Logic Controller 可编程逻辑控制
- TCP: Transmission Control Protocol 传输控制协议
Modbus详述
协议描述
Modbus协议定义了一个独立于底层通信层的简单协议数据单元(PDU)。在特定的总线或网络上,Modbus协议映射(mapping of Modbus protocol)可以在应用数据单元(ADU)里引入一些额外的字段。
Modbus应用数据单元(ADU)由发起Modbus事务的客户端构建。功能码指示服务端执行什么动作(action)。Modbus应用协议建立起由客户端发起的请求格式。
功能码字段:占一个字节,有效值为1~255,。某些功能码还有子功能码以定义更多的动作(action)。 数据字段:可能没有。数据字段包含的内容可以有离散地址和寄存器地址、要处理的项的数量以及字段中实际数据字节的计数(count)。
正常请求示例:
异常响应示例:
Modbus PDU的大小受限于串行网络上第一个Modbus实现的大小约束(max. RS485 ADU = 256 bytes)。
因此:
Modbus串行通信的PDU大小为253字节:256 - Server address(1字节) - CRC(2字节)。
所以:
RS232/RS465 ADU = 253字节 + Server address(1字节) + CRC(2字节) = 256字节。
TCP MODBUS ADU = 253字节 + MBAP(7字节) = 260字节。
Modbus协议定义了三种PDU,分别是:
- MODBUS请求PDU:mb_req_pdu = {function_code, request_data}
- MODBUS响应PDU:mb_rsp_pdu = {function_code, response_data}
- MODBUS异常响应PDU:mb_excep_rsp_pdu = {exception-function_code, request_data}
数据编码
Modbus使用大端表示地址和数据项。这意味着,当传输一个大于单个字节的数值时,将首先发送最高有效字节。如:寄存器大小为16位,其值为0x1234,那么将先发送0x12,然后再发送0x34。
数据模型
Modbus将其数据模型建立在一系列具有显著特征的表之上。4个主表(Primary table)分别是:
| 主表 | 对象类型 | 类型 | 注释 |
|---|---|---|---|
| 离散输入(discretes input) | 1bit | 只读 | 该类型的数据可以由I/O系统提供 |
| 线圈(coils) | 1bit | 读写 | 该类型的数据可以由应用程序改变 |
| 输入寄存器(input registers) | 16-bit word | 只读 | 该类型的数据可以由I/O系统提供 |
| 保持寄存器(holding registers) | 16-bit word | 读写 | 该类型的数据可以由应用程序改变 |
如下展示了两种在设备中组织数据的方式:
- 设备有4个独立的块。
- 设备只有1个块。
寻址模型
在MODBUS PDU addresses中,数据的寻址范围是0~65535。
在MODBUS data model中,数据块中的元素编号从1到n标记。
从图中可以看出,编号为
X的Modbus数据对应X-1的Modbus PDU
定义事务
服务器端MODBUS事务的一般处理过程如下:
当请求被服务器接收处理时,服务器会使用合适的MODBUS服务器事务构建一个MODBUS响应。
功能码分类
功能码可以分为三类,分别是:
- 公共功能码:官方发布的,主要关注这个即可。
- 自定义功能码:范围为
65~72和100~110。一般不需要自定义。 - 保留功能码:在一些公司的历史遗留项目中使用但不公开,不用管。
公共功能码定义
从左往右看,前三列是功能分类,第四列是具体功能,第五和第六列为对应的功能码和子功能码,第7列为功能码对应的16进制表示形式,最后一列表示能在第几章节中找到具体功能说明。例如,第四列的Read Holding Registers功能,分类上属于数据访问中16 bits访问,对应功能码为03,没有子功能码,功能码的16进制表示形式为03,具体功能说明可以在章节6.3中查看。
功能码描述
这里只对功能码03(0x03)Read Holding Registers进行描述,其它功能码同理,按实际需求再去阅读、理解即可。
该功能码用于在远程设备上读取1~125个连续输入寄存器的数据。请求PDU指定了寄存器起始地址和寄存器个数
。在PDU中,寄存器从0开始寻址。因此,寄存器编号1-16对应的寻址为0-15。
响应消息中的寄存器数据打包为每个寄存器两个字节,二进制内容在每个字节内右对齐。对于每个寄存器,第一个字节包含高阶位,第二个包含低阶位。
这段话可能有点费解,往下看到请求示例就理解了。
请求格式
| 功能码 | 1字节 | 0x03 |
| 起始地址 | 2字节 | 0x0000~0xFFFF |
| 寄存器个数 | 2字节 | 1~125(0x7D) |
正常响应格式
| 功能码 | 1字节 | 0x03 |
| 字节个数 | 1字节 | 2N |
| 寄存器值 | 2N字节 |
异常响应格式
| 功能码 | 1字节 | 0x03 |
| 异常码 | 1字节 | 01 或 02 或 03 或 04 |
读寄存器108-110的请求示例
从Request列看出,功能码为0x03(Read Holding Registers),寄存器起始地址为0x006B,寄存器个数为0x0003(0x006B的10进制为108,0x0003的10进制为3,即对应上了读寄存器108-110)。
从Response列看出,功能码为0x03,字节个数为0x06,寄存器108、109、110的值分别为0x022B,0x0000,0x0064(0x022B的10进制为555,0x0000的10进制为0,0x0064的10进制为100)。
读保持寄存器状态图: