在Node-red中使用Modbus节点读取float类型数值
FBP流程

流程主体分为两步:
- 读取寄存器值
- 对默认的uint类型转化为float
Modbus-Read模块配置

debug16
[0,17113,26214,17137,26214,17473,49152,17473]
debug15
[108,119.6,774.4,775]
此时debug16调试窗口输出的值为原始的uint类型需要转换为debug15的float类型
释义
转换示意图

32位浮点数(单精度浮点数)在计算机中使用 IEEE 754 标准表示。一个32位浮点数由以下三部分组成:
符号位(1位):最高位(第31位)表示符号,0表示正数,1表示负数。
指数位(8位):从第23位到第30位表示指数部分。指数部分是一个有偏移的值,偏移量为127。实际的指数值等于存储的值减去127。
尾数位(23位):从第0位到第22位表示尾数部分。尾数部分是一个小数,范围在1到2之间(不包括2)。实际的尾数值等于1加上存储的值乘以2的-23次方
32位浮点数的二进制表示
假设 pay[0] 是 0,pay[1] 是 17417,我们来详细解释如何将这两个值组合成一个32位浮点数。
写入缓冲区:
pay[0] 写入第3和第4字节:0x0000
pay[1] 写入第1和第2字节:0x4409(17417的十六进制表示)
缓冲区的内容为:0x44090000
解析为32位浮点数:
0x44090000 的二进制表示为:0100 0100 0000 1001 0000 0000 0000 0000
按照 IEEE 754 标准解析:
- 符号位:0(表示正数)
- 指数位:10001000(二进制)= 136(十进制)
- 尾数位:00001001000000000000000(二进制)
- 实际的指数值:136 - 127 = 9
- 实际的尾数值:1 + 00001001000000000000000 * 2^-23 ≈ 1 + 0.000000113
因此,浮点数的值为:1 * 2^9 * (1 + 0.000000113) ≈ 512 * 1.000000113 ≈ 512.000576
示例
假设输入的 msg.payload 是 [0, 17417],此逻辑处理后,msg.payload 将变为一个浮点数 512.000576。
单寄存器示例
// 获取输入消息的 payload,假设它是一个包含两个16位无符号整数的数组
let pay = msg.payload;
// 创建一个长度为 4 字节的缓冲区,因为一个浮点数需要 4 字节
const buf = Buffer.allocUnsafe(4);
// 将第一个16位无符号整数写入缓冲区的高16位(即第3和第4字节)
buf.writeUInt16BE(pay[0], 2);
// 将第二个16位无符号整数写入缓冲区的低16位(即第1和第2字节)
buf.writeUInt16BE(pay[1], 0);
// 从缓冲区中读取一个32位的浮点数,从第0字节开始
msg.payload = buf.readFloatBE(0);
// 返回修改后的消息对象
return msg;
多寄存器读取(8寄存器4组float数值)
let pay = msg.payload;
// 创建一个长度为 16 字节的缓冲区,因为每个浮点数需要 4 字节
const buf = Buffer.allocUnsafe(16);
// 将输入的 8 个无符号整数写入缓冲区,每两个整数组合成一个浮点数
buf.writeUInt16BE(pay[0], 2); // 写入第 3 和 4 字节
buf.writeUInt16BE(pay[1], 0); // 写入第 1 和 2 字节
buf.writeUInt16BE(pay[2], 6); // 写入第 7 和 8 字节
buf.writeUInt16BE(pay[3], 4); // 写入第 5 和 6 字节
buf.writeUInt16BE(pay[4], 10); // 写入第 11 和 12 字节
buf.writeUInt16BE(pay[5], 8); // 写入第 9 和 10 字节
buf.writeUInt16BE(pay[6], 14); // 写入第 15 和 16 字节
buf.writeUInt16BE(pay[7], 12); // 写入第 13 和 14 字节
// 从缓冲区中读取 4 个浮点数
const floatArray = [
buf.readFloatBE(0), // 从第 1 和 2 字节读取第一个浮点数
buf.readFloatBE(4), // 从第 5 和 6 字节读取第二个浮点数
buf.readFloatBE(8), // 从第 9 和 10 字节读取第三个浮点数
buf.readFloatBE(12) // 从第 13 和 14 字节读取第四个浮点数
];
// 将浮点数数组赋值给 msg.payload
msg.payload = floatArray;
return msg;
格式化-小数位截取
// 获取输入消息的 payload,假设它是一个包含浮点数的数组
let pay = msg.payload;
// 使用 map 方法遍历数组,将每个浮点数格式化为保留两位小数
pay = pay.map(num => {
// 使用 toFixed 方法将数字格式化为保留两位小数的字符串
return parseFloat(num.toFixed(2));
});
// 将格式化后的数组赋值回 msg.payload
msg.payload = pay;
// 返回修改后的消息对象
return msg;
小结:
对modebus协议不熟悉,对其的寄存器数据结构的存储方式很模糊,卡在这一步很长时间,好在终于柳暗花明。

浙公网安备 33010602011771号