如何用C#的S7.Net读取含嵌套结构体的西门子PLC数据块?
问题描述
使用S7.Net库读取西门子PLC数据块时,简单结构可以正常读取,但嵌套结构体的数据块读取失败或数据不正确。
可正常读取的简单数据块示例
PLC数据块定义:
DATA_BLOCK "Data_block_2" { S7_Optimized_Access := 'FALSE' VERSION : 0.1 NON_RETAIN STRUCT Data_1 : Real; Data_2 : Real; Data_3 : String; END_STRUCT; }
对应的C#类:
public class DB2 { public float Data_1 { get; set; } public float Data_2 { get; set; } [S7String(S7StringType.S7String, 254)] public string Data_3 { get; set; } }
读取代码:
plc.ReadClass<DB2>(2);
出现问题的嵌套结构体数据块示例
PLC数据块定义:
DATA_BLOCK "Data_block_5" { S7_Optimized_Access := 'FALSE' VERSION : 0.1 NON_RETAIN STRUCT data_1 : Bool; data_2 : Real; data_3 : Int; data_4 : Word; data_5 : Struct deneme_1 : Struct data_1 : Real; data_2 : Struct sensor_1 : Bool; sensorler : Struct _1 : Bool; _2 : Bool; _3 : Bool; END_STRUCT; END_STRUCT; END_STRUCT; deneme_2 : Real; deneme_3 : Bool; END_STRUCT; ddd : String[25]; END_STRUCT; }
尝试的C#建模(未完成/不正确):
public class DB6 { public bool data_1 { get; set; } public float data_2 { get; set; } public short data_3 { get; set; } public ushort data_4 { get; set; } public Data5 data_5 { get; set; } [S7String(S7StringType.S7String, 25)] public string ddd { get; set; } } public class Data5 { public Deneme1 deneme_1 { get; set; } // Other properties... }
使用ReadClass或ReadStruct读取时数据不正确或报错,需要解决嵌套结构体的正确读取方法及最佳实践。
解决方案与最佳实践
1. 严格匹配PLC结构体的层级与字段定义
S7.Net的ReadClass/ReadStruct依赖C#类与PLC结构体的字段顺序、数据类型、层级结构完全一致,必须完整定义所有嵌套层级:
正确的C#类建模
// 对应最外层DB块 public class DB5 { public bool data_1 { get; set; } public float data_2 { get; set; } public short data_3 { get; set; } public ushort data_4 { get; set; } public Data5 data_5 { get; set; } [S7String(S7StringType.S7String, 25)] public string ddd { get; set; } } // 对应data_5结构体 public class Data5 { public Deneme1 deneme_1 { get; set; } public float deneme_2 { get; set; } public bool deneme_3 { get; set; } } // 对应deneme_1结构体 public class Deneme1 { public float data_1 { get; set; } public Deneme1Data2 data_2 { get; set; } } // 对应data_2结构体 public class Deneme1Data2 { public bool sensor_1 { get; set; } public Sensorler sensorler { get; set; } } // 对应sensorler结构体 public class Sensorler { public bool _1 { get; set; } public bool _2 { get; set; } public bool _3 { get; set; } }
读取代码
var dbData = plc.ReadClass<DB5>(5); // 注意DB编号是5,不是6
2. 关键注意事项
- 字段顺序必须完全一致:PLC结构体的字段顺序和C#类的属性顺序不能有偏差,S7.Net是按内存偏移量映射的,顺序错会导致数据错位。
- 数据类型严格对应:
- PLC的
Real对应C#的float - PLC的
Int对应C#的short - PLC的
Word对应C#的ushort - PLC的
Bool对应C#的bool
- PLC的
- 字符串属性必须加
S7String特性:指定字符串类型和长度,必须和PLC中定义的长度一致(比如示例中的String[25]对应[S7String(S7StringType.S7String, 25)])。 - 禁用优化访问:确保PLC数据块的
S7_Optimized_Access设置为FALSE,优化访问会改变内存布局,导致S7.Net无法正确解析。 - 嵌套类必须完整定义:不能遗漏任何嵌套层级的字段,哪怕是暂时用不到的字段,否则会破坏内存偏移的计算。
3. 排查问题的实用技巧
- 如果读取后数据错位,先检查字段顺序是否和PLC结构体完全一致。
- 如果出现类型转换错误,核对每个字段的数据类型对应关系。
- 可以用
ReadBytes读取整个DB块的字节数组,手动解析部分字段,对比ReadClass的结果,定位错位的位置。 - 确保PLC和C#端的变量名大小写一致(S7.Net默认区分大小写,若需要不区分可以配置,但建议严格匹配)。
内容的提问来源于stack exchange,提问作者Adem Ülker
相关产品推荐
相关产品推荐

