如何将Modbus-tk RTU Slave保持寄存器设为读取有符号整数
解决modbus-tk Slave设置为有符号整数的问题
刚好之前折腾过modbus-tk的Slave符号类型问题,你的情况我太懂了——-999的16位补码被当成无符号解析成64537,本质就是Slave默认按无符号整数处理寄存器数据,咱们只需要调整下数据类型的配置就行,分两种方法:
方法1:直接在寄存器定义时指定有符号类型
这是最省心的方式,modbus-tk本身提供了内置的有符号类型常量。你在给Slave添加寄存器区块的时候,加上data_type参数指定为cst.INT(16位有符号整数)就行,示例代码如下:
import modbus_tk import modbus_tk.defines as cst from modbus_tk import modbus_rtu # 初始化RTU Slave(根据你的实际串口参数调整) slave = modbus_rtu.RtuSlave(port="COM3", baudrate=9600, parity='N', data_bits=8, stop_bits=1) slave.start() # 添加保持寄存器区块,指定data_type为有符号整数 # 参数分别是:区块名、寄存器类型、起始地址、寄存器数量、数据类型 slave.add_block('holding_regs', cst.HOLDING_REGISTERS, 0, 10, data_type=cst.INT) # 直接写入有符号整数-999到起始地址0 slave.set_values('holding_regs', 0, [-999])
这里的cst.INT对应16位有符号,还有cst.LONG(32位有符号)、cst.UINT(默认的无符号16位)等类型可选,按需使用即可。
方法2:手动做补码转换(兼容旧代码场景)
如果你的代码已经写得差不多了,不想改寄存器的定义,也可以手动把有符号数转成16位补码(无符号形式)写入,读取时再转回来:
# 把16位有符号整数转成无符号补码 def signed_to_unsigned_16(value): return value & 0xFFFF # 这个写法比判断正负更简洁,自动处理补码 # 写入-999 slave.set_values('holding_regs', 0, [signed_to_unsigned_16(-999)]) # 读取时把无符号转成有符号 def unsigned_to_signed_16(value): return (value ^ 0x8000) - 0x8000 # 同样是简洁的补码转换方式 read_val = slave.get_values('holding_regs', 0, 1)[0] signed_val = unsigned_to_signed_16(read_val)
别忘了主站的设置!
光改Slave还不够,你用的Simply Modbus Master软件也要对应设置数据类型——读取的时候选择Signed 16-bit Integer,这样软件才会把收到的十六进制值按有符号解析,显示正确的-999。
另外你提到官方示例只有Master的,其实modbus-tk仓库里有Slave的示例(比如rtuslave_example.py),核心逻辑就是通过add_block的data_type参数控制符号,和上面的方法1一致。
内容的提问来源于stack exchange,提问作者Yang




