C#实现OPC客户端与S7-1200 PLC的通信

实现OPC客户端与S7-1200 PLC的通信(收发数据、同步/异步方式),遵循S7-1200配置为OPC UA服务器客户端选择对应协议(OPC UA为主流)实现同步/异步通信的流程。

一、前置条件

  1. S7-1200硬件与固件要求

    • S7-1200 CPU需支持OPC UA服务器功能(V4.4及以上固件,如CPU 1214C DC/DC/DC V4.4)。

    • 需安装SIMATIC OPC UA S7-1200 Basic许可证(每个PLC1个,纸质或电子)。

  2. 软件环境

    • TIA Portal:V16及以上版本(用于配置S7-1200的OPC UA服务器)。

    • 客户端开发工具:推荐使用C#(.NET Framework 4.6+或.NET Core 3.1+),配合OPC Foundation官方库(如Opc.Ua.Client)。

二、S7-1200配置为OPC UA服务器

需通过TIA Portal激活并配置S7-1200的OPC UA服务器功能,步骤如下:

  1. 创建PLC项目:在TIA Portal中添加S7-1200 CPU(如1214C),设置IP地址(如192.168.1.10)。

  2. 激活OPC UA服务器

    • 进入“设备视图”→选中CPU→“属性”→“OPC UA”→“服务器”→勾选“激活OPC UA服务器”。

    • 设置服务器端口号(默认4840,URL为opc.tcp://192.168.1.10:4840)。

  3. 配置服务器参数

    • 在“选件→常规”中,设置最大会话超时时间(默认30秒)、最大OPC UA会话数(取决于CPU性能,如10个)。

    • 在“安全策略”中,选择Basic256Sha256(平衡安全性与兼容性),并禁用“无安全设置”。

  4. 定义通信变量

    • 在PLC程序中创建数据块(DB)(如DB100),取消“优化的块访问”(以便通过绝对地址访问)。

    • 在DB块中定义变量(如DB100.DBW0为温度值,DB100.DBX2.0为设备状态),并设置读写权限(如温度为只读,状态为可写)。

三、OPC客户端实现(C#示例)

客户端需通过OPC UA协议连接S7-1200服务器,实现同步读写(实时性要求高)和异步订阅(监控数据变化)两种通信方式。以下是核心代码框架:

1. 依赖库安装

在Visual Studio中通过NuGet安装OPC Foundation官方库

Install-Package Opc.Ua.Client
Install-Package Opc.Ua

2. 客户端核心类

using Opc.Ua;
using Opc.Ua.Client;
using System;
using System.Threading.Tasks;

public class S71200OpcClient
{
    private Session _session; // OPC UA会话
    private string _endpointUrl; // 服务器端点URL(如opc.tcp://192.168.1.10:4840)

    // 构造函数
    public S71200OpcClient(string endpointUrl)
    {
        _endpointUrl = endpointUrl;
    }

    /// <summary>
    /// 连接OPC UA服务器(异步)
    /// </summary>
    public async Task ConnectAsync()
    {
        try
        {
            // 创建端点配置
            EndpointDescription[] endpoints = CoreClientUtils.SelectEndpoint(_endpointUrl, false);
            EndpointConfiguration endpointConfig = EndpointConfiguration.Create();

            // 建立会话
            _session = await Session.CreateAsync(
                configuration: Configuration.Create(),
                endpoint: new ConfiguredEndpoint(null, endpoints[0], endpointConfig),
                checkDomain: false,
                applicationName: "S71200OpcClient",
                timeout: 60000,
                identity: UserIdentity.Null,
                preferredLocales: null
            );
            Console.WriteLine("连接OPC UA服务器成功!");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"连接失败:{ex.Message}");
            throw;
        }
    }

    /// <summary>
    /// 断开OPC UA连接
    /// </summary>
    public void Disconnect()
    {
        if (_session != null && _session.Connected)
        {
            _session.Disconnect();
            Console.WriteLine("已断开OPC UA连接");
        }
    }

    /// <summary>
    /// 同步读取变量(实时性高,适用于紧急数据获取)
    /// </summary>
    /// <param name="nodeId">变量节点ID(如ns=2;s=DB100.DBW0)</param>
    /// <returns>变量值</returns>
    public object ReadNodeSync(string nodeId)
    {
        if (_session == null || !_session.Connected)
        {
            throw new InvalidOperationException("未连接到OPC UA服务器");
        }

        try
        {
            // 创建读取请求
            ReadValueId[] nodesToRead = new ReadValueId[]
            {
                new ReadValueId { NodeId = new NodeId(nodeId), AttributeId = AttributeIds.Value }
            };

            // 执行读取
            DataValueCollection results;
            DiagnosticInfoCollection diagInfos;
            _session.Read(
                null,
                0,
                TimestampsToReturn.Neither,
                nodesToRead,
                out results,
                out diagInfos
            );

            // 检查结果
            if (results.Count > 0 && StatusCode.IsGood(results[0].StatusCode))
            {
                return results[0].Value;
            }
            else
            {
                throw new Exception($"读取失败:{results[0].StatusCode}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"同步读取异常:{ex.Message}");
            throw;
        }
    }

    /// <summary>
    /// 异步订阅变量(监控数据变化,适用于趋势分析)
    /// </summary>
    /// <param name="nodeId">变量节点ID</param>
    /// <param name="callback">数据变化回调函数</param>
    public void SubscribeNodeAsync(string nodeId, Action<object> callback)
    {
        if (_session == null || !_session.Connected)
        {
            throw new InvalidOperationException("未连接到OPC UA服务器");
        }

        try
        {
            // 创建订阅请求
            MonitoredItemCreateRequest request = new MonitoredItemCreateRequest
            {
                ItemToMonitor = new ReadValueId { NodeId = new NodeId(nodeId), AttributeId = AttributeIds.Value },
                MonitoringMode = MonitoringMode.Reporting,
                RequestedParameters = new MonitoringParameters
                {
                    SamplingInterval = 1000, // 采样间隔(ms)
                    QueueSize = 10 // 队列大小
                }
            };

            // 创建订阅
            var subscription = _session.CreateSubscription(request.RequestedParameters, false, "S71200Subscription");
            var monitoredItem = subscription.AddItem(request.ItemToMonitor, request.MonitoringMode, request.RequestedParameters);

            // 绑定回调函数(数据变化时触发)
            monitoredItem.Notification += (sender, e) =>
            {
                if (e.NotificationValue is MonitoredItemNotification notification)
                {
                    callback(notification.Value.Value);
                }
            };
        }
        catch (Exception ex)
        {
            Console.WriteLine($"异步订阅异常:{ex.Message}");
            throw;
        }
    }
}

3. 客户端使用示例

class Program
{
    static async Task Main(string[] args)
    {
        // 1. 初始化客户端(替换为S7-1200的实际IP)
        S71200OpcClient client = new S71200OpcClient("opc.tcp://192.168.1.10:4840");

        try
        {
            // 2. 连接服务器
            await client.ConnectAsync();

            // 3. 同步读取变量(如DB100.DBW0,温度值)
            object temperature = client.ReadNodeSync("ns=2;s=DB100.DBW0");
            Console.WriteLine($"同步读取温度:{temperature} °C");

            // 4. 异步订阅变量(如DB100.DBX2.0,设备状态)
            client.SubscribeNodeAsync("ns=2;s=DB100.DBX2.0", (status) =>
            {
                Console.WriteLine($"异步订阅状态变化:{status}(0:停止,1:运行)");
            });

            // 保持程序运行(模拟实时监控)
            while (true)
            {
                await Task.Delay(1000);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"客户端异常:{ex.Message}");
        }
        finally
        {
            // 5. 断开连接
            client.Disconnect();
        }
    }
}

四、同步与异步通信说明

方式 特点 适用场景
同步读写 客户端发送请求后阻塞等待服务器响应,实时性高,但可能占用线程资源。 实时控制(如设备启停、紧急报警)
异步订阅 客户端注册回调函数,服务器主动推送数据变化,不阻塞线程,效率高。 趋势监控(如温度、压力变化)

参考代码 C# OPC通信客户端(S7-1200 Control) www.youwenfan.com/contentcnn/93782.html

五、注意事项

  1. 网络配置:确保客户端与S7-1200在同一局域网,防火墙开放4840端口(OPC UA默认端口)。
  2. 变量节点ID:需与S7-1200中定义的DB块地址一致(如ns=2;s=DB100.DBW0中的DB100为数据块编号)。
  3. 错误处理:客户端需添加重连机制(如连接失败后自动重试3次),避免因网络波动导致通信中断。
  4. 性能优化:异步订阅时,调整采样间隔(如1000ms)以平衡实时性与网络负载。

六、扩展建议

  • 跨平台支持:若需在Linux或嵌入式设备上运行客户端,可使用.NET Core(跨平台)替代.NET Framework。
  • 数据存储:将订阅的数据存入数据库(如SQL Server、InfluxDB),用于后续分析(如设备健康评估)。
  • 可视化:结合WinFormWPF开发可视化界面,实时显示S7-1200的状态(如温度曲线、设备运行状态)。
posted @ 2025-12-17 16:30  kang_ms  阅读(4)  评论(0)    收藏  举报