在与PLC进行通讯时,会发现一个问题,浮点数1.2接收过来后,居然变成了两个16位的整数。
经过一系列的分析,这是因为在PLC存储浮点数时32位,我们接收过来的数据会变成两个16位的高低字节,而且我们进行下发数据时,也需要进行转换,否则PLC那边的数据会乱码。
我这边使用的资源包是NModbus来实现ModbusTCP通讯的,可以根据自己的需求进行下载程序包。如果是其他的通讯方式遇到字节转换问题,可也以直接用核心代码。
现在开始上核心代码
读取数据浮点数处理
从104的点位开始读取了11位的数据,01、23 、45则是读取的浮点数转换为的高低字节,这时候我们需要封装一个方法 ConvertRegistersToDecimal 进行数据处理。
这里大家需要注意一下,浮点数float是32位,double是64位,decimal是128位,因为我这边的浮点数是decimal,所以进行了强制转换,如果没有强制转换的话则是32位float。
private decimal ConvertRegistersToDecimal(ushort highPart,ushort lowPart){decimal result = (decimal)BitConverter.ToSingle(new byte[]{(byte)(highPart & 0xFF),(byte)((highPart >> 8) & 0xFF),(byte)(lowPart & 0xFF),(byte)((lowPart >> 8) & 0xFF)}, 0);return result;// Incorrect, just for illustration}
还有一点需要注意,字节的顺序不要写错,比如[0]和[1]。
写入浮点数数据处理
这里和读取的概念一样,有一点需要再次强调一下,浮点数float是32位,double是64位,decimal是128位,因为我这边的浮点数是decimal,所以进行了强制转换,如果没有强制转换的话则是32位float。
我们这里进行转换时,记得把浮点数转变为32位float类型。我这里用的时decimal,转成了float。
我们在写入数据时需要进行一下数据处理,封装一个ConvertDecimalToRegisters方法,我这里用的时decimal,转成了float。
private ushort[] ConvertDecimalToRegisters(decimal value){float floatValue = (float)value; // 示例值// 将浮点数转换为字节数组(注意:这里假设PLC期望的是IEEE 754标准的32位浮点数)byte[] floatBytes = BitConverter.GetBytes(floatValue);// 发送浮点数到PLC(注意:这里假设NModbus库支持直接发送浮点数,如果不支持,则需要手动拆分字节并发送到两个16位寄存器中)// 但是,请注意,NModbus实际上并不直接支持写入浮点数到单个寄存器地址。// 你需要将其拆分为两个16位值或使用支持浮点数的库扩展。// 正确的做法应该是:ushort[] registerValues = new ushort[2];if (BitConverter.IsLittleEndian){registerValues[0] = (ushort)((floatBytes[2] << 8) | floatBytes[3]); // 高16位(对于小端字节序)registerValues[1] = (ushort)((floatBytes[0] << 8) | floatBytes[1]); // 低16位(对于小端字节序)}else{registerValues[0] = (ushort)((floatBytes[0] << 8) | floatBytes[1]); // 高16位(对于大端字节序,但不常见)registerValues[1] = (ushort)((floatBytes[2] << 8) | floatBytes[3]); // 低16位(对于大端字节序,但不常见)}ushort[] a = { BitConverter.ToUInt16(floatBytes, 0), BitConverter.ToUInt16(floatBytes, 2) };return a;}
到此我们的与PLC通讯的浮点数问题已经解决,如有疑问,欢迎大家商讨。
小白路漫漫,让我们一起加油!!!