You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PLC通信中内存位与数据寄存器传递及pymodbus读写故障排查

Modbus RTU 通信失败排查与正确配置方法

核心配置错误修正

首先逐一修正现有配置和代码里的硬错误:

  • 超时参数错误:原配置里超时时间设为0是完全错误的,Modbus RTU为请求-响应式通信,客户端必须预留等待PLC返回数据的时间,将超时设置为timeout=1(单位秒,可根据总线长度微调,0.5~3s均为合理值)即可。
  • 寄存器地址越界+映射错误:你代码里读写的地址0x1017(十进制4119)远超出你声明的D0~D100寄存器范围,必然无法读写。pymodbus中传入的address参数是Modbus协议层从0开始的偏移地址,和PLC原生的D、M区地址的对应关系由PLC厂商的Modbus映射规则决定,常规通用映射规则为:
    • 保持寄存器(功能码03/06/16)对应D数据寄存器:D0对应address=0,D1对应address=1,以此类推D100对应address=100
    • 线圈(功能码01/05/15)对应M内存位:M0对应address=0,M1对应address=1,以此类推M100对应address=100
      注意:如果是特定品牌PLC(如三菱Q系列、欧姆龙CP系列),请以PLC编程手册里标注的Modbus映射地址为准,不要直接套用通用规则
  • 串口参数双向核对:不要只在Python端配置参数,必须进入PLC的编程配置页面,确认PLC侧串口参数和代码完全一致:RTU模式、8数据位、无校验、1停止位、9600波特率、从站地址1,任意参数不匹配都会导致通信完全失败。另外要注意COM口不能被PLC编程软件、串口调试助手等其他程序占用,否则client.connect()会直接返回失败。
  • API方法调用错误:写单个寄存器请用write_register()方法,原代码用的write_registers()是批量写多个寄存器的方法,部分旧版本pymodbus对单值传入的兼容性有问题。
  • 缺少异常判断:原代码直接访问返回值的registers属性,若通信失败返回的是异常对象,会直接触发属性错误,必须先判断响应是否正常。

修正后的可运行参考代码

from pymodbus.client.sync import ModbusSerialClient
from pymodbus.exceptions import ModbusIOException

# 初始化客户端,补全超时参数,所有串口参数和PLC侧严格对齐
client = ModbusSerialClient(
    method="rtu",
    port="COM5",
    stopbits=1,
    bytesize=8,
    parity="N",
    baudrate=9600,
    timeout=1  # 必须设置非0超时
)

# 检查串口连接状态
conn_status = client.connect()
if not conn_status:
    print("串口连接失败,请检查串口号、驱动、端口占用情况")
    exit()

# --------------------------
# D寄存器(保持寄存器)读写示例:读写D0、D1两个寄存器
# --------------------------
# 读D0开始的2个寄存器(对应D0、D1)
read_d_res = client.read_holding_registers(address=0, count=2, unit=1)
if not isinstance(read_d_res, ModbusIOException):
    print("D0、D1寄存器值:", read_d_res.registers)
else:
    print("读D寄存器失败:", read_d_res)

# 写单个寄存器D0,写入值445
write_d_res = client.write_register(address=0, value=445, unit=1)
if not isinstance(write_d_res, ModbusIOException):
    print("写D0寄存器成功")
else:
    print("写D寄存器失败:", write_d_res)

# --------------------------
# M内存位(线圈)读写示例:读写M1、M2两个位
# --------------------------
# 读M1开始的2个位(对应M1、M2)
read_m_res = client.read_coils(address=1, count=2, unit=1)
if not isinstance(read_m_res, ModbusIOException):
    print("M1、M2位状态:", read_m_res.bits)
else:
    print("读M位失败:", read_m_res)

# 写单个位M1,写入值True(导通)
write_m_res = client.write_coil(address=1, value=True, unit=1)
if not isinstance(write_m_res, ModbusIOException):
    print("写M1位成功")
else:
    print("写M位失败:", write_m_res)

# 通信结束关闭连接
client.close()

额外排查点

如果按上述配置后仍无法通信,可先用串口调试助手接在485总线上抓包,确认Python端是否正常发送请求报文、PLC是否返回响应:

  • 正常读D0的请求报文为01 03 00 00 00 02 C4 0B
  • 若PLC无任何报文返回,优先检查485的A/B线是否接反、终端电阻是否匹配、PLC站号是否配置正确
  • 若PLC返回异常码(比如02非法地址),说明传入的地址和PLC实际映射不匹配,重新核对PLC手册里的Modbus地址表即可。

内容的提问来源于stack exchange,提问作者Pandurang Fatangade

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 10:06:34