You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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
  • 字符串属性必须加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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 03:44:59