2. Modbus TCP客户端实现
任务目标
实现一个Modbus TCP客户端,连接远程PLC(或Modbus TCP从站模拟器),读取保持寄存器(Holding Register,功能码0x03)数据,并能够识别和处理异常响应(如非法地址、非法功能码等)。
环境与依赖
- Python 3.8+
- 依赖库:
pymodbus(安装命令:pip install pymodbus) - 验证工具:可使用
Modbus Slave模拟器或任意Modbus TCP从站设备
完整实现代码
from pymodbus.client import ModbusTcpClient
from pymodbus.exceptions import ModbusException, ConnectionException
from pymodbus.pdu import ExceptionResponse
def read_holding_registers(host: str, port: int, start_addr: int, count: int, unit_id: int = 1):
"""
Modbus TCP客户端:读取保持寄存器并处理异常响应。
返回: (成功标志, 寄存器列表或错误信息)
"""
client = ModbusTcpClient(host, port=port, timeout=5)
try:
# 建立TCP连接
if not client.connect():
return False, f"连接失败: {host}:{port}"
# 发送读保持寄存器请求(功能码0x03)
response = client.read_holding_registers(address=start_addr, count=count, slave=unit_id)
# 检查是否收到Modbus异常响应帧
if isinstance(response, ExceptionResponse):
# 提取异常码并映射为可读信息
exc_code = response.exception_code
exc_map = {
1: "非法功能码",
2: "非法数据地址",
3: "非法数据值",
4: "从站设备故障"
}
msg = exc_map.get(exc_code, f"未知异常码({exc_code})")
return False, f"Modbus异常响应: {msg}"
# 检查响应是否有效
if response.isError():
return False, f"响应错误: {response}"
# 正常返回寄存器值列表
return True, response.registers
except ConnectionException as e:
return False, f"TCP连接异常: {e}"
except ModbusException as e:
return False, f"Modbus协议错误: {e}"
except Exception as e:
return False, f"未预期错误: {e}"
finally:
client.close()
if __name__ == "__main__":
# 配置参数(按实际环境修改)
PLC_HOST = "127.0.0.1" # 远程PLC或模拟器IP
PLC_PORT = 502 # Modbus TCP标准端口
START_ADDR = 0 # 起始寄存器地址
REG_COUNT = 10 # 读取寄存器数量
ok, result = read_holding_registers(PLC_HOST, PLC_PORT, START_ADDR, REG_COUNT)
if ok:
print(f"读取成功,共{len(result)}个寄存器:")
for i, val in enumerate(result):
print(f" 寄存器[{START_ADDR + i}] = {val}")
else:
print(f"读取失败: {result}")
运行与验证
- 准备从站:启动Modbus TCP从站模拟器(如Modbus Slave),在地址0~9处预置10个保持寄存器值(如100~109),监听端口502。
- 运行客户端:执行
python modbus_tcp_client.py。 - 正常场景验证:观察输出应打印10个寄存器的值,且与从站预置值一致。
- 异常场景验证:将从站起始地址改为不存在的大地址(如3000),重新运行,程序应输出类似
Modbus异常响应: 非法数据地址的错误信息,而不会崩溃。
判定标准
- 正常读取时,程序能正确打印从站返回的寄存器值,数值与从站设置一致;
- 从站返回异常响应时,程序能捕获并解析异常码,输出对应的中文错误描述;
- 从站离线或端口不可达时,程序能捕获连接异常并给出明确提示,不抛出未处理异常。
关键说明
- 本实现使用
pymodbus库的同步客户端接口,timeout=5指定TCP连接超时时间; ExceptionResponse是Modbus协议层返回的异常帧,需在业务逻辑前优先判断;- 异常码映射表覆盖了Modbus标准中最常见的4种异常类型,实际工程中可按需扩展。