在工业自动化领域,设备之间的通信是实现高效生产的关键。而 Modbus 协议作为工业通信领域的“老大哥”,自 1979 年诞生以来,一直扮演着至关重要的角色。今天,就让我们深入探索 Modbus 协议的奥秘,从原理到代码示例,全方位了解它如何让工业设备“对话”。
Modbus 协议最初是为了解决工业环境中设备之间的通信问题而设计的。它是一种应用层协议,位于 OSI 模型的第 7 层,主要在客户机/服务器架构下工作。无论是串行链路(如 RS-232 和 RS-485)还是基于 TCP/IP 的以太网,Modbus 协议都能大显身手。
Modbus 协议主要分为两大类:串行链路上的 Modbus 和 TCP/IP 上的 Modbus。串行链路的 Modbus 依赖于 TIA/EIA 标准,而 Modbus TCP/IP 则基于 IETF 的 RFC793 和 RFC791 标准。这种灵活性使得 Modbus 协议能够适应不同的网络环境,满足各种工业场景的需求。
Modbus 协议的核心是协议数据单元(PDU),它是一个与基础通信层无关的简单数据结构。PDU 包括功能码和数据两部分。功能码告诉服务器需要执行什么操作,而数据则是操作的具体内容。
在实际通信中,Modbus 协议使用应用数据单元(ADU)。ADU 在 PDU 的基础上增加了地址域和差错校验域。地址域用于标识子节点,差错校验则确保数据传输的准确性。
一个完整的 Modbus 帧包括起始帧、数据帧和校验帧。起始帧标志着数据传输的开始,数据帧包含了实际的通信内容,而校验帧用于验证数据的完整性。
功能码是 Modbus 协议中的关键部分,它定义了服务器需要执行的操作。如果操作成功,服务器会返回一个与请求功能码相同的响应;如果出现错误,则返回一个异常响应,异常响应的功能码是请求功能码加上 0x80。
Modbus 协议的数据模型基于四个基本表格:线圈状态表、离散输入状态表、保持寄存器表和输入寄存器表。每个表格都可以存储 65536 个数据项,这些数据项可以通过不同的功能码进行读写操作。
线圈状态表用于存储布尔值(0 或 1),通常用于控制设备的开关状态。例如,一个简单的应用场景是通过 Modbus 协议控制一个电机的启动和停止。
离散输入状态表用于读取设备的输入状态,这些状态通常是只读的。例如,它可以用来读取传感器的输入信号。
保持寄存器表用于存储 16 位的整数值,这些值可以被读取和写入。保持寄存器表常用于存储设备的配置参数或运行状态。
输入寄存器表与保持寄存器表类似,但它只能被读取,不能被写入。它通常用于存储设备的实时数据。
以下是一个使用 Python 和 pymodbus 库实现的 Modbus TCP 客户端和服务器的简单示例。
pip install pymodbus
from pymodbus.server.sync import StartTcpServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
def run_server():
# 创建数据存储
store = ModbusSlaveContext(
di=ModbusSequentialDataBlock(0, [0]*100), # 离散输入
co=ModbusSequentialDataBlock(0, [0]*100), # 线圈
hr=ModbusSequentialDataBlock(0, [0]*100), # 保持寄存器
ir=ModbusSequentialDataBlock(0, [0]*100)) # 输入寄存器
context = ModbusServerContext(slaves={1: store}, single=True)
# 设置设备信息
identity = ModbusDeviceIdentification()
identity.VendorName = 'pymodbus'
identity.ProductCode = 'PM'
identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
identity.ProductName = 'pymodbus Server'
identity.ModelName = 'pymodbus Server'
identity.MajorMinorRevision = '1.5'
# 启动服务器
StartTcpServer(context, identity=identity, address=("localhost", 502))
if __name__ == "__main__":
run_server()
from pymodbus.client.sync import ModbusTcpClient as ModbusClient
def run_client():
client = ModbusClient('localhost', port=502)
client.connect()
# 读取保持寄存器
rr = client.read_holding_registers(1, 1, unit=1)
print("保持寄存器值:", rr.registers)
# 写入保持寄存器
rq = client.write_register(1, 10, unit=1)
print("写入保持寄存器:", rq)
# 读取线圈状态
rr = client.read_coils(1, 1, unit=1)
print("线圈状态:", rr.bits)
client.close()
if __name__ == "__main__":
run_client()
Modbus RTU 是一种基于串行链路的通信方式,以下是一个使用 Python 和 pyserial 库实现的 Modbus RTU 客户端示例。
pip install pyserial
import serial
import struct
def calculate_crc(data):
crc = 0xFFFF
for byte in data:
crc ^= byte
for _ in range(8):
if crc & 0x0001:
crc >>= 1
crc ^= 0xA001
else:
crc >>= 1
return crc
def send_modbus_request(port, address, function_code, data):
request = struct.pack('>B', address) + struct.pack('>B', function_code) + data
crc = calculate_crc(request)
request += struct.pack('>H', crc)
port.write(request)
def read_modbus_response(port):
response = port.read(1024)
return response
def run_client():
port = serial.Serial('/dev/ttyUSB0', baudrate=9600, timeout=1)
address = 1
function_code = 3 # 读取保持寄存器
start_address = 0x0001
quantity = 1
data = struct.pack('>H', start_address) + struct.pack('>H', quantity)
send_modbus_request(port, address, function_code, data)
response = read_modbus_response(port)
print("响应数据:", response)
if __name__ == "__main__":
run_client()
Modbus 协议在工业自动化领域有着广泛的应用。例如,通过 Modbus 协议,可以实现对工厂生产线上设备的远程监控和控制。操作人员可以在控制中心通过 Modbus 客户端软件发送指令,控制生产线上的电机、阀门等设备。
在能源管理系统中,Modbus 协议用于采集和传输设备的能耗数据。例如,通过 Modbus 协议连接的智能电表可以将实时的电能数据传输到能源管理服务器,服务器可以根据这些数据进行能耗分析和优化。
在智能建筑中,Modbus 协议用于连接各种设备,如空调、照明、电梯等。通过 Modbus 协议,可以实现对这些设备的集中控制和管理,提高建筑的能源利用效率和舒适度。
Modbus 协议作为工业通信领域的经典协议,凭借其简单、灵活和高效的特点,一直受到广泛应用。无论是串行链路还是 TCP/IP 网络,Modbus 协议都能提供可靠的通信解决方案。通过本文的介绍,相信你对 Modbus 协议的原理、数据模型和代码实现有了更深入的理解。在实际应用中,掌握 Modbus 协议可以帮助你更好地实现工业设备之间的互联互通,提升工业自动化的水平。
如果你对 Modbus 协议还有其他疑问,或者想了解更多相关的技术细节,欢迎在评论区留言,我们一起探讨!