pymodbus RTU与ModPoll通信超时、接收字节不足问题求解
故障原因
原代码存在4个直接导致通信异常的问题:
timeout参数单位为秒而非毫秒,原配置200相当于等待200秒超时,完全不符合Modbus RTU常规通信逻辑,正常超时设置为1~3秒即可- pymodbus寄存器地址采用0基偏移规则,ModPoll默认使用1基地址规则,若两边地址不做偏移匹配,从站不会返回有效响应,直接触发超时、接收字节不足报错
- 代码执行完写操作后未主动释放串口资源,会导致串口被进程占用,ModPoll无法正常访问端口
- 旧版pymodbus同步客户端在Windows环境下默认未关闭流控,会导致串口收发电平异常,报文传输不完整
正确可运行代码
注意:如果ModPoll中配置的保持寄存器起始地址为1,代码中传入的地址值需要做减1偏移,以下代码已做对应适配,串口参数默认和原代码保持一致(9600波特率、8数据位、1停止位、无校验),可根据实际硬件配置修改
from pymodbus.client.sync import ModbusSerialClient from pymodbus.exceptions import ModbusIOException, ConnectionException # 初始化客户端,修正超时配置,显式关闭硬流控 client = ModbusSerialClient( method="rtu", port="COM1", stopbits=1, bytesize=8, parity='N', baudrate=9600, timeout=3, rtscts=False, dsrdtr=False ) if __name__ == "__main__": try: # 建立串口连接 connect_status = client.connect() print(f"串口连接状态:{connect_status}") if not connect_status: raise ConnectionException("串口连接失败,请检查端口占用、端口号配置") # 写寄存器示例:对应ModPoll中1~5号保持寄存器(对应pymodbus 0基地址0~4) write_value = 45 for reg_addr_1base in range(1, 6): reg_addr_0base = reg_addr_1base - 1 write_resp = client.write_register(reg_addr_0base, write_value, unit=1) if isinstance(write_resp, ModbusIOException): print(f"写{reg_addr_1base}号寄存器失败:无有效响应") else: print(f"写{reg_addr_1base}号寄存器成功,写入值:{write_value}") # 读寄存器测试:对应ModPoll中103号保持寄存器(对应pymodbus 0基地址102) read_resp = client.read_holding_registers(102, 1, unit=1) if not isinstance(read_resp, ModbusIOException): print(f"读取103号寄存器值:{read_resp.registers[0]}") else: print("读寄存器失败:无有效响应") except Exception as e: print(f"运行异常:{str(e)}") finally: # 操作完成后主动关闭连接,释放串口资源 client.close() print("串口连接已关闭")
联调注意事项
- 运行Python程序和打开ModPoll测试时,不能同时占用同一个COM口,否则会报端口占用错误
- 两边串口参数(波特率、数据位、停止位、校验位)、从站ID必须完全一致
- 若使用USB转RS485模块,确认模块A/B线接线正确,终端电阻匹配正常
内容的提问来源于stack exchange,提问作者Sharad Patil
相关产品推荐
相关产品推荐

