背景:工业数采,采集Siemens西门子S7-1200数据,其中一个32位浮点数无法直接读取,分为了两个16位字去读
DB27.DBD116--->DB27.DBW116 DBD27.DBW118
目标:通过python边缘计算,将两个字Uint16合为32位浮点数float
Los geht's!
目录
了解S7-1200寻址
了解S7-1200浮点数使用标准
编写python算法
从以下回答可以总结:
字节,字和双字的起始地址,最高有效字节和最低有效字节,例题求解-SIMATIC S7-200-找答案-西门子中国 (siemens.com.cn)https://www.ad.siemens.com.cn/service/answer/solved_226956_1028.html
WORD类型的结构问题-SIMATIC S7-300(F)/S7-400(F/H/FH)-找答案-西门子中国 (siemens.com.cn)https://www.ad.siemens.com.cn/service/answer/solved_40622_1029.html
需要读取的DBD116分成了DBW116和DBW118,DBW118存储低字节,DBW116存储高字节
读取的数据如下:
DBW116 = 17981(十进制)= 01000110 00111101(二进制)
DBW118 = 52892(十进制)= 11001110 10011100(二进制)
十进制转二进制/二进制转十进制
十进制与二进制在线转换工具,在线计算,在线计算器,计算器在线计算 (osgeo.cn)https://www.osgeo.cn/app/s3090
需要合并为DBD116 =12147.6523 (十进制,浮点数)
=01000110 00111101 11001110 10011100(二进制)
十进制/十六进制转浮点数
浮点数-Float-Double转二进制 - ToolTT在线工具箱https://tooltt.com/floatconverter/
使用IEEE 754标准
参考:
SIMATIC S7-1500 自动化系统, ET 200MP 自动化系统 (siemens.com)https://cache.industry.siemens.com/dl/files/384/86140384/att_1093122/v1/s71500_et200mp_manual_collection_zh-CH.pdf
分为三部分:
S-符号位 E-阶数 M-尾数
公式为:
这里的M不能简单理解为十进制,而是二进制
以我上面提到的需要化为浮点数的二进制为例
0 | 100 0110 | 0 | 011 1101 | 1100 1110 | 1001 1100 |
DBW116 | DBW118 | ||||
S | E | M |
S = 0 正数 (-1)的0次方 = 1
E = 10001100 = 140 阶数 3的(140-127=13)次方
M = 01111011100111010011100 = 4050588 1.M=1.01111011100111010011100
=
=1.4828677177429199
import math
a = 0.0
a = 1+pow(2,-2)+pow(2,-3)+pow(2,-4)+pow(2,-5)+pow(2,-7)+pow(2,-8)+pow(2,-9)+pow(2,-12)+pow(2,-13)+pow(2,-14)+pow(2,-16)+pow(2,-19)+pow(2,-20)+pow(2,-21)
print(a)
三者相乘 = 12147.65234375
import math
a = 0.0
a = (1+pow(2,-2)+pow(2,-3)+pow(2,-4)+pow(2,-5)+pow(2,-7)+pow(2,-8)+pow(2,-9)+pow(2,-12)+pow(2,-13)+pow(2,-14)+pow(2,-16)+pow(2,-19)+pow(2,-20)+pow(2,-21))*(2**13)*((-1)**(0))
print(a)
参考计算方法,这个写的很好,很详细,看上面不理解可以看这个:
用二进制如何表示浮点型数值_思维态度行动的博客-CSDN博客_二进制转浮点数
首先明确中间变量的类型
注意num的变量类型一定为无符号32位Int,被坑了一把,若仅在电脑VS运行则无需在意
先在电脑上面用VS调试
VS添加python可以参考:
VS Code配置Python环境 - 暄踽 - 博客园VSCode配置Python环境,步骤详细,适合新手小白。https://www.cnblogs.com/kint216/p/16004937.html使用Jupyter Notebooks
import math
#调试时,Low和High作为模拟数采输入值
#Low为DBW118 High为DBW116
#若作为正式的边缘计算算法,Low和High为数采得到的数据,应删掉下面两行
Low = 52892
High = 17981
num = 0
MM = 0.0
MM1 = 0.0
count = 1
S = int(High >> 15) #获取符号位
E = int((High >> 7) & 255) #获取阶数
M = int(Low |((High & 127) << 16) ) #获取尾数取高位低七位和低位
num = (M<<9) & 0xffffffff #将尾数的有效位都移到最左边,num为无符号32位整型!!
while num>0:
if (num & 0x80000000) == 0x80000000: #获取尾数M的最高位(最左边)
MM1 = float(0.5**count) #count为1时,2的(-1)次幂 = (0.5)的1次幂
else:
MM1 = 0.0
MM = MM+ MM1 #循环累加结果
count = count + 1 #幂数加一
num = (num & 0x7FFFFFFF) << 1 #迭代,将尾数M的次高位(左边第二位)变为最高位,便于下次运算
if count > 23 : #尾数M的位数为23,当大于23即24时,退出循环
break
Result = pow(-1,S)*pow(2,E-127)*(1.0 + MM) #得到最后的结果
print(Result) #调试时才需要添加这一句,显示结果
得到结果,是正确的