Modbus协议 / Modbus Protocol
目录
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 由服务器复制返回,通常为x00x00
协议表示符 2 3-4 通常为x00x00
数据长度 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'x00x00' 15 length = b'x00x06' 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)。