概述
最近在做一个跟控制相关的项目,需要通过modbus对控制器进行数据读写,代码用python编写的,在进行real型数据读取时,并没有发生问题,但对于浮点数进行操作时,发现读取到的数据很奇怪。后来发现是字节序的问题,使用的控制器浮点数定义为32 bit float,并且是高低位互换的形式,及ABCD转为CDAB。
struct提供了编码二进制的方法,但是其字节序只有大小端两种,即只能将浮点数表示为ABCD或DCBA,这就导致通信时的数据有误。
import modbus_tk.defines as cst
from modbus_tk import modbus_tcp
def TCP_write(a,start_address=0): #a为写入的数据
master = modbus_tcp.TcpMaster(host) #host为IP地址
master.master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, start_address, output_value=a)
定义一个TCP_Master用于写入数据,考虑到控制器的浮点数分为高低位,所以尝试先将须写入的浮点数进行拆分。
从struct库中的定义可知,浮点数占4字节,而整数占2字节,对于ABCD 4字节浮点数,可拆分为两个整数,即AB和CD,然后将这两个整数大小端互换,就可以得到控制器中的字节序CDAB。
import struct
def float2int(a):
return struct.unpack('<hh',struct.pack('<f',a)) #两次操作都为小端形式
>>> float2int(11.2)
>>> (13107,16691)
这里先将浮点数a已浮点数的形式编码为二进制数据,然后解码时可将其拆分为两个有符号整数,然后将这两个按顺序写入控制器即可。
global host
host = '127.0.0.1'
a = float2int(11.2)
b = float2int(1.5)
c = float2int(12.3456798)
x = (a[0],a[1],b[0],b[1],c[0],c[1])
TCP_write_set_point(x,start_address=0)
在ModbusSlave中使用Float CD AB形式显示,可以看到正常的浮点数
读取数据时也可以使用相同的思路,使用TcpMaster 读取保持寄存器数据的功能,读取上图中从站的数据,可得:
def TCP_read():
master = TCP_Master(host)
res_tuple = master.master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 8)
return res_tuple
>>>a = TCP_read()
>>>(13107, 16691, 0, 16320, 34792, 16709, 0, 0)
可以看到所读取的数据是按CDAB格式的十进制形式表达的,使用小端的两位整数编码高低两位数据,并同样使用小段浮点数解码,即可得到原始的数据。
>>>res = struct.unpack('<f',struct.pack('<hh',a[0],a[1]))
>>>(11.199999809265137,)
由于时间紧急,当时没考虑modbus_tk是否自带有解决方案,如果有更好的方案欢迎大家分享。
最后
以上就是传统哑铃为你收集整理的使用modbus_tk进行通信时遇到的浮点数问题的全部内容,希望文章能够帮你解决使用modbus_tk进行通信时遇到的浮点数问题所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复