Modbus协议 / Modbus Protocol
目录
- Modbus 协议简介
- Modbus RTU协议
- Modbus TCP协议与 Python 实现
- Modbus 功能码
- Modbus TCP/RTU对比
1 Modbus 协议简介
Modbus协议MODICON公司1979年开发的一种通信协议,是一种工业现场总线协议标准,1996年施耐德公司推出了基于以太网TCP/IP的Modbus协议—ModbusTCP。
Modbus协议是一项应用层报文传输协议,包括ASCII / RTU / TCP三种报文类型,协议本身不定义物理层,只定义了控制器能够认识和使用的消息结构,而不管消息是经过何种网络进行通信的。
标准的Modbus协议物理层接口主要有RS232 / RS422 / RS485和以太网。采用Master/Slave主从方式通信。
2 Modbus RTU协议 / Modbus RTU Protocol
Modbus RTU协议报文格式主要如下,
名称 字节数 位号 描述
------------ --------- ------ ------
设备地址 1 1
功能码 1 2 03H读寄存器/06H写单个寄存器/10H写多个寄存器
寄存器地址 2 3-4 高位在前
数据长度 2 5-6 传送数据总长度
CRC校验 2 7-8
下面是不同操作时使用的报文格式
3 Modbus TCP协议 / Modbus TCP Protocol
3.1 Modbus TCP协议格式
Modbus TCP协议报文格式主要可分为两段,MBAP和PDU,
MBAP:
名称 字节数 位号 描述
------------ --------- ------ ------
事物标识符 2 1-2 由服务器复制返回,通常为\x00\x00
协议表示符 2 3-4 通常为\x00\x00
数据长度 2 5-6 传送数据总长度,高位通常\x00(数据不超过256),低位为后续字节长度
单元标识符 1 7 通常为\x00
PDU:
名称 字节数 位号 描述
------------ --------- ------ ------
功能码 1 8 定义功能
起始寄存器 2 9-10 操作的寄存器起始位
寄存器/数据 2 11-12 读/多个写模式下,为寄存器数量,单个写模式为写入数据
3.2 Modbus TCP 加解码的 Python 实现 / Modbus TCP Encode and Decode by Python
1 import struct
2
3
4 class ModbusCodeC():
5 """
6 This CodeC class implement partly of Modbus encode and decode
7 The chamber only offer 03H and 06H function-code for using
8 """
9
10 @staticmethod
11 def MBAP_encode():
12 transFlagHi = b'\x00'
13 transFlagLo = b'\x00'
14 protoFlag = b'\x00\x00'
15 length = b'\x00\x06'
16 unitFlag = b'\x00'
17 mbap = transFlagHi + transFlagLo + protoFlag + length + unitFlag
18 return mbap
19
20 @staticmethod
21 def PDU_encode(func, regi, num=1, data=None):
22 funcList = {'r': b'\x03',
23 'w': b'\x06'}
24 funcCode = funcList[func]
25 registerStart = struct.pack('!H', regi)
26 registerNum = struct.pack('!H', num)
27 if data and func == 'w':
28 dataCode = struct.pack('!H', data)
29 pdu = funcCode + registerStart + dataCode
30 return pdu
31 pdu = funcCode + registerStart + registerNum
32 return pdu
33
34 @staticmethod
35 def encode(func, regi, num, data=None):
36 return ModbusCodeC.MBAP_encode() + ModbusCodeC.PDU_encode(func, regi, num, data)
37
38 @staticmethod
39 def MBAP_decode(s):
40 m = {}
41 m['transFlagHi'] = s[:1]
42 m['transFlagLo'] = s[1:2]
43 m['protoFlag'] = s[2:4]
44 m['length'] = s[4:6]
45 m['unitFlag'] = s[6:]
46 return m
47
48 @staticmethod
49 def PDU_decode(s):
50 p = {}
51 '''
52 p['funcCode'] = s[:1]
53 p['registerStart'] = s[1:3]
54 p['registerNum'] = s[3:5]
55 p['data'] = s[5:]
56 '''
57 # TODO: Add bit number and data length check here
58 p['funcCode'] = s[:1]
59 p['bitNum'] = s[1:2]
60 p['data'] = s[2:]
61 return p
62
63 @staticmethod
64 def decode(msg):
65 msg_de = {}
66 mbap, pdu = msg[:7], msg[7:]
67 msg_de['MBAP'] = ModbusCodeC.MBAP_decode(mbap)
68 msg_de['PDU'] = ModbusCodeC.PDU_decode(pdu)
69 return msg_de
70
71 if __name__ == '__main__':
72 print(ModbusCodeC.encode('r', 5, 3))
73 print(ModbusCodeC.encode('w', 5, 1, 8))
4 Modbus 功能码/ Modbus Function Code
在Modbus功能码中,1-65位为公共功能码,定义了一些通用的功能
5 Modbus TCP/RTU对比 / Modbus TCP/RTU Comparison
5.1 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)寄存器。
5.2 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)。