WPF上位机 - S7.NETPlus批量读取数据
在编写上位机程序中,需要读取PLC数据。使用到了S7.NETPlus 这个库。
S7.NETPlus提供了很多读取和写入数据的方式。大批量读取数据的方式包括一下几个方法
- Readbytes
- ReadClass
- ReadStruct
- ReadMultipleVars
PLC侧的数据是一个Array的UDT数据,其中UDT中还包含了很多的UDT。在使用库的过程中,发现ReadClass 和 ReadStruct 面对UDT类型的数据时,有时候会报错。
试了很久放弃了ReadClass和Read Struct。 准备使用ReadMultipleVars需要一个VarList,对于使用过程中的变量映射不是很方面,最终还是使用了ReadBytes
var AxisInterface = SiemensPlc.Instance.AxisController.ReadBytes(DataType.DataBlock, SiemensPlc.Instance.InterfaceDB, SiemensPlc.instance.AxisId * 730, 730);
以上代码中使用ReadBytes 读取730个字节的数据到了AxisInterface中。接下来就需要将读取到的数据使用Coverter转换为需要的数据类型。
但是由于西门子PLC 和 PC的存储数据大小端不一致的问题,还要大小端调换一下。这样就非常的麻烦,需要先Reverse在Converter。一个变量需要操作两步。
解决
在阅读S7.NetPlus源码过程中,发现库中已经有了相关的操作。以LReal举例
using System;
namespace S7.Net.Types;
//
// 摘要:
// Contains the conversion methods to convert Real from S7 plc to C# double.
public static class LReal
{
//
// 摘要:
// Converts a S7 LReal (8 bytes) to double
public static double FromByteArray(byte[] bytes)
{
if (bytes.Length != 8)
{
throw new ArgumentException("Wrong number of bytes. Bytes array must contain 8 bytes.");
}
if (BitConverter.IsLittleEndian)
{
Array.Reverse(bytes);
}
return BitConverter.ToDouble(bytes, 0);
}
//
// 摘要:
// Converts a double to S7 LReal (8 bytes)
public static byte[] ToByteArray(double value)
{
byte[] bytes = BitConverter.GetBytes(value);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(bytes);
}
return bytes;
}
//
// 摘要:
// Converts an array of double to an array of bytes
public static byte[] ToByteArray(double[] value)
{
return TypeHelper.ToByteArray(value, ToByteArray);
}
//
// 摘要:
// Converts an array of S7 LReal to an array of double
public static double[] ToArray(byte[] bytes)
{
return TypeHelper.ToArray(bytes, FromByteArray);
}
}
在S7.NET.Type中 提供了一系列数据类型的相关操作。可以直接使用。
这样根据PLC中数据的变量地址可以快速的写出来。
#region ActualValues
SiemensPlc.instance.actualValus.ActualVelocity = LReal.FromByteArray(AxisInterface[0..8]);
SiemensPlc.instance.actualValus.ActualPosition = LReal.FromByteArray(AxisInterface[8..16]);
SiemensPlc.instance.actualValus.TargetPosition = LReal.FromByteArray(AxisInterface[16..24]);
SiemensPlc.instance.actualValus.IsHomed = Bit.FromByte(AxisInterface[24], 0);
SiemensPlc.instance.actualValus.BrakelsOpen = Bit.FromByte(AxisInterface[24], 1);
SiemensPlc.instance.actualValus.AxisAlarm =DInt.FromByteArray(AxisInterface[26..30]);
SiemensPlc.instance.actualValus.AxisError = Bit.FromByte(AxisInterface[30], 0);
SiemensPlc.instance.actualValus.ErrorDetailReaction = DInt.FromByteArray(AxisInterface[32..36]);
#endregion Actual Values