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

.NET Core使用libplctag批量读取AB Micro 820 PLC所有标签值方法

最优实现方案

@tags 是PLC内置的标签枚举接口,设计上仅返回标签元数据(ID、类型、长度、维度),不支持同步返回实时值,不用在这个接口上找额外配置。
针对Micro820、500个标签的采集场景,用libplctag自带的TagGroup批量读能力即可实现单连接下的高效采集,局域网环境下全量标签读取耗时通常在100~300ms,完全满足实时图表展示的要求,性能比逐标签循环读高10倍以上。


实现逻辑

libplctag底层会自动对同网关、同PLC参数的标签复用同一个EIP连接,不需要手动维护连接;TagGroup会自动把组内所有标签的读请求合并打包为最少数量的CIP报文,同时自动适配Micro820的单报文长度限制做拆分重组,不需要手动计算内存偏移。

步骤1:初始化阶段做标签预处理

程序启动时先调用@tags接口拉取全量标签元数据,提前做类型映射过滤:

  • 0xC1 对应BOOL类型
  • 0xC2 对应SINT(sbyte)
  • 0xC3 对应INT(short)
  • 0xC4 对应DINT(int)
  • 0xCA 对应REAL(float)
  • 0xD0 对应STRING
    过滤掉不需要采集的系统保留标签、未使用的标签,避免无效读取增加耗时。

步骤2:初始化全局TagGroup

不要每次读取都新建标签实例,全局初始化一次TagGroup,把所有待采集的标签按对应类型加入组,整个生命周期复用:

// 全局单例,整个后台任务常驻复用
private readonly TagGroup _plcTagGroup = new TagGroup();
private const string PlcGateway = "10.29.56.31";

// 初始化方法,程序启动时执行一次
public void InitPlcTags()
{
    // 拉取标签元数据,复用现有读@tags的逻辑即可
    var tagMetaList = GetTagMetadataFromPlc();
    
    foreach (var meta in tagMetaList)
    {
        ITag tag = meta.Type switch
        {
            0xC1 => new Tag<BoolPlcMapper, bool>
            {
                Gateway = PlcGateway,
                PlcType = PlcType.Micro800,
                Protocol = Protocol.ab_eip,
                Name = meta.Name,
                Timeout = TimeSpan.FromSeconds(2)
            },
            0xC3 => new Tag<IntPlcMapper, short>
            {
                Gateway = PlcGateway,
                PlcType = PlcType.Micro800,
                Protocol = Protocol.ab_eip,
                Name = meta.Name,
                Timeout = TimeSpan.FromSeconds(2)
            },
            0xC4 => new Tag<DintPlcMapper, int>
            {
                Gateway = PlcGateway,
                PlcType = PlcType.Micro800,
                Protocol = Protocol.ab_eip,
                Name = meta.Name,
                Timeout = TimeSpan.FromSeconds(2)
            },
            0xCA => new Tag<RealPlcMapper, float>
            {
                Gateway = PlcGateway,
                PlcType = PlcType.Micro800,
                Protocol = Protocol.ab_eip,
                Name = meta.Name,
                Timeout = TimeSpan.FromSeconds(2)
            },
            _ => null
        };

        if (tag != null) _plcTagGroup.Add(tag);
    }
}

步骤3:后台任务循环批量读取

在你的BackgroundService循环里直接调用ReadAll()方法,执行完成后组内所有标签的Value属性就是最新实时值,不需要逐个发起读请求:

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    InitPlcTags();
    while (!stoppingToken.IsCancellationRequested)
    {
        try
        {
            // 单次调用完成全量标签读取
            _plcTagGroup.ReadAll();

            // 采集所有标签的当前值
            var tagValues = new Dictionary<string, object>();
            foreach (dynamic tag in _plcTagGroup.Tags)
            {
                tagValues[tag.Name] = tag.Value;
            }

            // 推送到前端,比如用SignalR推送即可实现实时图表更新
            await _hubContext.Clients.All.SendAsync("ReceivePlcData", tagValues, stoppingToken);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "PLC标签读取异常");
        }

        // 按实际需求设置采集间隔,1s间隔完全无压力
        await Task.Delay(1000, stoppingToken);
    }
}

避坑说明

  • 不要每次循环都新建Tag、TagGroup实例,反复初始化会触发连接重建、标签句柄重新申请,性能会下降90%以上,还容易触发Micro820的连接数上限(Micro820默认仅支持4~8个并发CIP连接)
  • 不要多线程并发调用读方法,单线程循环调用ReadAll()的性能已经足够跑满PLC的通信带宽,并发反而会因为连接争抢导致耗时飙升
  • 数组类标签不要拆成单个元素逐个加组,按数组总长度创建单个标签实例读取,性能比逐元素读高几个数量级
  • Micro800系列不需要配置Path参数,保持默认即可,加了Path反而会导致连接失败
  • 逐标签读取慢的核心原因是每个读请求都需要一次网络往返,就算局域网单次往返仅2ms,500个标签串行读也需要1s以上,批量读会把所有请求打包为3~5个报文,总耗时仅为几次网络往返的时间,差距非常明显。

内容的提问来源于stack exchange,提问作者Jesus Sanchez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 22:06:11