pymodbus RTU写保持寄存器返回成功但值未更新问题
Modbus RTU写入收到成功响应但寄存器值未更新排查方案
按优先级从高到低排查以下问题:
- 地址偏移匹配错误
Modbus协议存在两套地址标注规则:报文中实际传输的是从0开始计数的协议地址,多数设备手册标注的是从1开始计数的PLC编号地址(比如标注为101的保持寄存器,对应报文中要传的地址是100)。你当前日志里写入请求的起始地址是0x65(十进制101),如果设备手册标注的目标寄存器地址是101,实际需要传入的协议地址应为100。这种场景下你写入的是相邻的合法地址段,从站会正常返回成功响应,但目标地址段的值完全不会改动。
验证方式:将读写操作的起始地址改为100重试,同时对比抓包得到的读写请求报文地址字段,和设备协议要求的报文地址值完全对齐即可。 - 写入值不合法被从站静默丢弃
你提到第5个寄存器目标写入值为0x58(十进制88),但传入write_registers的第5个值是56666,对应十六进制为0xDD5A,和目标值完全不符。此外你传入的多个数值(56711、56577、56666等)均大于16位有符号整数上限32767,部分从站不会返回非法值的异常码,会直接丢弃不符合寄存器取值范围、数据类型要求的写入请求,保留寄存器原值同时返回正常写入响应。
验证方式:先给单个寄存器写入手册明确给出的合法测试值(比如给第5个寄存器直接传88),确认写入生效后再批量写入其他值。 - pymodbus调用参数配置错误
2.x版本pymodbus的write_registers默认会将传入数值按16位有符号整数编码,传入大于32767的无符号值时会出现溢出转码错误。建议显式通过Payload构建器按无符号16位类型编码写入值,同时显式指定从站地址参数,参考代码:from pymodbus.constants import Endian from pymodbus.payload import BinaryPayloadBuilder # 按设备要求配置字节序、字序,多数RTU设备为大端 builder = BinaryPayloadBuilder(byteorder=Endian.Big, wordorder=Endian.Big) # 按寄存器实际类型追加写入值,16位无符号值用add_16bit_uint方法 builder.add_16bit_uint(56711) builder.add_16bit_uint(18462) builder.add_16bit_uint(0) builder.add_16bit_uint(56577) builder.add_16bit_uint(88) # 对应目标值0x58 builder.add_16bit_uint(22558) write_payload = builder.to_registers() # 注意显式传入unit参数指定从站地址,旧版本参数名为slave client.write_registers(address=101, values=write_payload, unit=17) - 串口硬件/系统配置问题
你使用的/dev/ttyAMA0是树莓派等单板机的板载串口,首先要确认运行程序的用户拥有串口权限:执行sudo usermod -aG dialout $USER后重启设备生效;其次要确认串口没有被板载蓝牙服务、串口控制台等其他进程占用,否则会出现报文收发异常、从站返回缓存响应但不执行实际操作的问题。另外可以尝试将停止位改为1测试,部分标注2停止位的设备实际兼容1停止位,2停止位配置下可能出现报文边缘校验错误,导致从站只返回响应不执行写入。
内容的提问来源于stack exchange,提问作者Adept Pomelo
相关产品推荐
相关产品推荐

