树莓派3使用pymodbus写入输入寄存器及HMI显示问题咨询
解答:树莓派3上的PyModbus输入寄存器写入与HMI显示问题
一、关于使用PyModbus写入输入寄存器的说明
首先得明确:Modbus协议规范中,输入寄存器(Input Registers)是只读类型,对应的功能码是04(读取输入寄存器),标准协议里没有写入输入寄存器的功能码。如果你的设备确实支持写入输入寄存器(部分厂商自定义了功能),可以参考以下方式:
- 确认设备支持的写入功能码:有些设备可能用自定义功能码来写入输入寄存器,比如复用写保持寄存器的06/16功能码,这需要你查设备文档确认。
- 使用PyModbus发送自定义功能码请求:
from pymodbus.client.sync import ModbusTcpClient as ModbusClient client = ModbusClient('192.168.4.189') client.connect() # 假设设备支持用功能码06写入输入寄存器(地址0,值200),需根据设备文档调整参数 rq = client.execute(0, 6, address=0, value=200) # 检查写入结果 if not rq.isError(): print("写入输入寄存器成功") else: print(f"写入失败: {rq}") client.close()
如果你是混淆了输入寄存器和保持寄存器,实际想写入的是保持寄存器,那你原有代码里的client.write_register(0,100)已经是正确写法(单个保持寄存器写入,功能码06),批量写入可以用client.write_registers(起始地址, [值列表])。
二、HMI Droid Studio无法显示保持寄存器值的排查与解决
你的代码能正常读取并打印寄存器值,但HMI不显示,大概率是参数不匹配或网络配置问题,按以下步骤逐一排查:
1. 检查地址偏移问题
PyModbus默认使用0-based地址(起始地址为0),而很多HMI工具(包括HMI Droid Studio)默认用1-based地址(起始地址为1)。比如你代码里读的是寄存器0,在HMI里需要设置为寄存器1,这是最常见的坑。
2. 确认Modbus功能码匹配
- 你的代码用
read_holding_registers,对应Modbus功能码03; - 在HMI Droid Studio中,要确保选择的寄存器类型是“保持寄存器”,功能码设置为03,别选错成输入寄存器(功能码04)。
3. 验证数据类型与字节序
- 确认HMI设置的数据类型和你写入的一致:比如你写入的是16位无符号整数,HMI里也要选对应的类型,别误选成32位或有符号整数;
- 部分设备和HMI存在字节序差异(大端/小端),如果值显示异常(比如写入100却显示25600),需要在HMI里调整字节序设置。
4. 检查网络与端口
- 确认树莓派和HMI设备在同一个局域网,能互相ping通;
- 树莓派的防火墙要开放502端口(Modbus TCP默认端口),可以用命令临时关闭防火墙测试:
sudo iptables -F
- 检查PyModbus客户端连接的IP和端口是否和HMI设置一致,你的代码里用的是
192.168.4.189,HMI里要填这个IP,端口设为502。
5. 优化你的测试代码
你的现有代码有部分截断,这里补全并优化,方便你测试:
from pymodbus.client.sync import ModbusTcpClient as ModbusClient import time Kanban1 = 0 # 明确指定Modbus TCP默认端口502 client = ModbusClient('192.168.4.189', port=502) connection = client.connect() if not connection: print("无法连接到Modbus服务器,请检查网络和设备状态") else: # 先写入测试值,确保寄存器有数据 write_rq = client.write_register(0, 100) if write_rq.isError(): print(f"写入保持寄存器失败: {write_rq}") try: while True: rr = client.read_holding_registers(0, 50) if not rr.isError(): print(f"读取到的寄存器值: {rr.registers}") if rr.registers[Kanban1] < 100: # 补充你原来的逻辑 print(f"Kanban1的值小于100: {rr.registers[Kanban1]}") else: print(f"读取寄存器失败: {rr}") time.sleep(1) except KeyboardInterrupt: print("程序手动终止") finally: client.close()
总结
- 输入寄存器标准为只读,若需写入必须确认设备是否支持自定义写入功能;
- HMI不显示的核心问题通常是地址偏移、功能码不匹配或数据类型设置错误,按上面的步骤排查基本能解决。
内容的提问来源于stack exchange,提问作者Aditya fedriansyah
相关产品推荐
相关产品推荐

