modbus_tk 读取浮点数的处理

轩辕乐邦
2023-12-01

modbus_tk 读取浮点数的处理

前言:
用modbus_tk读取实物PLC(信捷)的浮点数值,发现数据不正常。经分析后发现modbus_tk只是把PLC的返回值的两个字存储器按低位在前,高位在后的顺序转成浮点数(ABCD)。而实物PLC(信捷),返回的数据是高位在前,低位在后(CDAB)。所以需要把高低位互换一下位置再转换。
【如果modbus_tk带这个高低位切换,此贴终结。】

可以转换读写浮点数 还有 双字寄存器。

使用:
modbus_tk读取的数据元祖直接给下面 ReadFloat()、ReadDint() 就能返回结果。
modbus_tk寄存器的写,支持填入列表,所以直接用下面模块返回的列表就行

#读浮点数
ReadFloat(master.execute(1, cst.READ_HOLDING_REGISTERS, 10, 2))
#读双字
ReadDint(master.execute(1, cst.READ_HOLDING_REGISTERS, 10, 2))
#写浮点数
master.execute(1,cst.WRITE_MULTIPLE_REGISTERS,10,output_value=WrtieFlote(3.14))
#写双字
master.execute(1,cst.WRITE_MULTIPLE_REGISTERS,10,output_value=WriteDint(65536))

一些琐碎事项:
我不知道三菱的PLC还有其他PLC的modbus返回值的高低位是怎样排列的,所以才加了个reverse参数,可能是多余的。
反正信捷PLC的modbus返回数据是高位在前,低位在后。

顺带一提,支持 WinXP 环境的,
最高只能用 python3.4.4 、pyserial2.7,
modbus_tk 我试过 0.5.0 是可以的。
最好用pip安装一下 six模块

import struct

def ReadFloat(*args,reverse=False):
    for n,m in args:
        n,m = '%04x'%n,'%04x'%m
    if reverse:
        v = n + m
    else:
        v = m + n
    y_bytes = bytes.fromhex(v)
    y = struct.unpack('!f',y_bytes)[0]
    y = round(y,6)
    return y

def WriteFloat(value,reverse=False):
    y_bytes = struct.pack('!f',value)
    # y_hex = bytes.hex(y_bytes)
    y_hex = ''.join(['%02x' % i for i in y_bytes])
    n,m = y_hex[:-4],y_hex[-4:]
    n,m = int(n,16),int(m,16)
    if reverse:
        v = [n,m]
    else:
        v = [m,n]
    return v

def ReadDint(*args,reverse=False):
    for n,m in args:
        n,m = '%04x'%n,'%04x'%m
    if reverse:
        v = n + m
    else:
        v = m + n
    y_bytes = bytes.fromhex(v)
    y = struct.unpack('!i',y_bytes)[0]
    return y

def WriteDint(value,reverse=False):
    y_bytes = struct.pack('!i',value)
    # y_hex = bytes.hex(y_bytes)
    y_hex = ''.join(['%02x' % i for i in y_bytes])
    n,m = y_hex[:-4],y_hex[-4:]
    n,m = int(n,16),int(m,16)
    if reverse:
        v = [n,m]
    else:
        v = [m,n]
    return v

if __name__ == "__main__":
    print(ReadFloat((15729,16458)))
    print(WriteFloat(3.16))
    print(ReadDint((1734,6970)))
    print(WriteDint(456787654))
 类似资料: