zoukankan      html  css  js  c++  java
  • 用C#开发基于自动化接口的OPC客户端

    OPC全称是Object Linking and Embedding(OLE) for Process Control,它的出现为基于Windows的应用程序和现场过程控制应用建立了桥梁。OPC作为一整套接口、属性和方法的协议标准集,与具体的开发语言没有关系。

    1OPC客户端接口方式

    开发OPC客户端程序,其访问接口方式有多种,根据官方提供的资料大约有如下几种方式:

    • 使用OPCNetAPI,需要用到OPCNetAPI.dll,OPCNetAPI.Com.dll
    • 使用自动化接口,需要用到OPCDAAuto.dll
    • 使用自定义接口,需要用到多个Wrapper:OpcRcw.Ae.dll,OpcRcw.Batch.dll,OpcRcw.Comn.dll,OpcRcw.Da.dll,OpcRcw.Dx.dll,OpcRcw.Hda.dll,OpcRcw.Sec.dll

    对于像C++这样的语言来开发OPC客户端时,一般需要使用自定义接口的方式。而如果采用VB和C#这样的语言来开发OPC客户端时,一般就采用自动化接口。要使用OPC自动化接口,首先要引用OPCDAAuto.dll文件,并在开发环境中做好相关的引用配置。

    2、自动化接口简介

    自动化接口是OPC基金会组织为了方便并统一OPC客户端开发而发布的一个接口、属性和方法的协议集。其访问服务器的流程如下:

     

    自动化接口中共定义了6类对象:OPCServer对象、OPCBrowser对象、OPCGroups对象、OPCGroup对象、OPCItems对象、OPCItem对象。接下来简要描述一下这些对象的主要功能。

    1)、OPCServer对象

    由客户端创建的OPCServer自动化对象。然后客户端通过其方法实现连接到OPC数据访问自定义接口。OPCServer对象现在可以用来获取关于OPC服务器的一般信息,并创建和操作OPCGroup对象的集合。

    主要的属性:

    StartTime

    CurrentTime

    LastUpdateTime

    MajorVersion

    MinorVersion

    BuildNumber

    VendorInfo

    ServerState

    LocaleID

    Bandwidth

    OPCGroups

    PublicGroupNames

    ServerName

    ServerNode

    ClientName

    主要的方法:

    GetOPCServers

    Connect

    Disconnect

    CreateBrowser

    GetErrorString

    QueryAvailableLocaleIDs

    QueryAvailableProperties

    GetItemProperties

    LookupItemIDs

    2)、OPCBrowser对象

    OPCBrowser对象是在服务器中存在的分支或项目名称的集合。其是可选的。如果服务器不支持,将不会创建这个对象。

    主要的属性:

    Organization

    Filter

    DataType

    AccessRights

    CurrentPosition

    Count

    主要的方法:

    Item

    ShowBranches

    ShowLeafs

    MoveUp

    MoveToRoot

    MoveDown

    MoveTo

    GetItemID

    GetAccessPaths

    3)、OPCGroups对象

    OPCGroups是OPCGroup对象的集合,以及创建、删除和管理它们的方法。

    该对象还具有OPCGroup默认属性。当添加OPCGroups时,DefaultGroupXXXX属性设置其初始状态。可以更改默认值,以添加具有不同初始状态的opc组。更改默认值并不会影响已经创建的组。添加OPCGroup后,它的属性可以被修改。这减少了调用Add方法所需的参数数量。

    主要的属性:

    Parent

    DefaultGroupIsActive

    DefaultGroupUpdateRate

    DefaultGroupDeadband

    DefaultGroupLocaleID

    DefaultGroupTimeBias

    Count

    主要的方法:

    Item

    Add

    GetOPCGroup

    Remove

    RemoveAll

    ConnectPublicGroup

    RemovePublicGroup

    4)、OPCGroup对象

    OPC组为客户组织数据提供了一种方式。例如,组可能表示特定操作符显示或报告中的项。数据可以读写。基于异常的连接也可以在客户端和组中的项之间创建,可以根据需要启用和禁用。OPC客户机可以配置OPC服务器应该向OPC客户机提供数据更改的速率。

    主要的属性:

    Parent

    Name

    IsPublic

    IsActive

    IsSubscribed

    ClientHandle

    ServerHandle

    LocaleID

    TimeBias

    DeadBand

    UpdateRate

    OPCItems

    主要的方法:

    SyncRead

    SyncWrite

    AsyncRead

    AsyncWrite

    AsyncRefresh

    AsyncCancel

    5)、OPCItems对象

    这个对象还具有OPCItem默认的属性。当添加OPCItem时,DefaultXXXX属性设置其初始状态。可以更改默认值,以添加具有不同初始状态的OPCItems。当然,一旦添加了OPCItem,它的属性可以被修改。这减少了调用Add方法所需的参数数量。

    主要的属性:

    Parent

    DefaultRequestedDataType

    DefaultAccessPath

    DefaultIsActive

    Count

    主要的方法:

    Item

    GetOPCItem

    AddItem

    AddItems

    Remove

    Validate

    SetActive

    SetClientHandles

    SetDataTypes

    6)、OPCItem对象

    OPC项表示与服务器中的数据源的连接。与每个项目相关联的是一个值,质量和时间戳。值以变量的形式出现,质量类似于Fieldbus指定的值。

    主要的属性:

    Parent

    ClientHandle

    ServerHandle

    AccessPath

    AccessRights

    ItemID

    IsActive

    RequestedDataType

    Value

    Quality

    TimeStamp

    CanonicalDataType

    EUType

    EUInfo

    主要的方法:

    Read

    Write

    3、客户端的开发

    接下来我们基于C#开发OPC客户端。上面说明了自动化接口具体情况,我们需要进一步针对自己的具体应用编写代码。

    首先,封装一斜对象、用于存取相关的属性,如:OPC服务器信息(OPCServerInfo)、OPC数据项(OPCDataItem)、组属性(GroupProperty)等。对于组属性我们还需要赋予默认值。代码如下:

    public class OPCServerInfo
    
        {
    
            public DateTime StartTime { get; set; }
    
            public string ServerVersion { get; set; }
    
        }
    
     
    
        public class OPCDataItem
    
        {
    
            public object ItemName { get; set; }
    
            public object ItemValue { get; set; }
    
            public object Quality { get; set; }
    
            public object TimeStamp { get; set; }
    
        }
    
     
    
        public class GroupProperty
    
        {
    
            public bool DefaultGroupIsActive { get; set; }
    
            public float DefaultGroupDeadband { get; set; }
    
            public int UpdateRate { get; set; }
    
            public bool IsActive { get; set; }
    
            public bool IsSubscribed { get; set; }
    
     
    
            public GroupProperty()
    
            {
    
                DefaultGroupIsActive = true;
    
                DefaultGroupDeadband = 0;
    
                UpdateRate = 250;
    
                IsActive = true;
    
                IsSubscribed = true;
    
            }
    
        }

    接下来,为了使用方便我们封装了一个ClientHelper类用于实现相关的操作,应为在一个客户端应用中,该对象是唯一的我们为了使用方便将其声明为静态类,以便于使用。具体代码如下:

        public class ClientHelper
    
        {
    
            /// <summary>
    
            /// 获取可以使用的OPC服务器
    
            /// </summary>
    
            /// <param name="hostName">获取OPC服务器的主机名称</param>
    
            /// <returns>返回OPC服务器列表</returns>
    
            public static List<string> GetOPCServerName(string hostName)
    
            {
    
                try
    
                {
    
                    OPCServer OpcServer = new OPCServer();
    
                    object opcServers = OpcServer.GetOPCServers(hostName);
    
                    List<string> serverList = new List<string>();
    
                    foreach (string opcServer in (Array)opcServers)
    
                    {
    
                        serverList.Add(opcServer);
    
                    }
    
                    return serverList;
    
                }
    
                catch(Exception ex)
    
                {
    
                    throw ex;
    
                }
    
            }
    
     
    
            /// <summary>
    
            /// 连接到指定的OPC服务器
    
            /// </summary>
    
            /// <param name="serverName">服务器名称</param>
    
            /// <param name="serverIP">服务器IP</param>
    
            /// <returns>返回的OPC服务器</returns>
    
            public static OPCServer ConnectToServer(string serverName, string serverIP)
    
            {
    
                OPCServer opcServer = new OPCServer();
    
                try
    
                {
    
                    opcServer.Connect(serverName, serverIP);
    
                    if (opcServer.ServerState != (int)OPCServerState.OPCRunning)
    
                    {
    
                        opcServer.Disconnect();
    
                        return null;
    
                    }
    
                }
    
                catch
    
                {
    
                    opcServer.Disconnect();
    
                    return null;
    
                }
    
                return opcServer;
    
            }
    
     
    
            /// <summary>
    
            /// 获取OPC服务器的相关信息
    
            /// </summary>
    
            /// <param name="opcServer">OPC服务器对象</param>
    
            /// <returns>OPC服务器信息</returns>
    
            public static OPCServerInfo GetServerInfo(OPCServer opcServer)
    
            {
    
                OPCServerInfo serverInfo = new OPCServerInfo();
    
                serverInfo.StartTime=opcServer.StartTime;
    
                serverInfo.ServerVersion = opcServer.MajorVersion.ToString() + "." + opcServer.MinorVersion.ToString() + "." + opcServer.BuildNumber.ToString();
    
                return serverInfo;
    
            }
    
     
    
            /// <summary>
    
            /// 展开OPC服务器的节点
    
            /// </summary>
    
            /// <param name="opcServer">OPC服务器</param>
    
            /// <returns>返回展开后的节点数据</returns>
    
            public static OPCBrowser RecurBrowse(OPCServer opcServer)
    
            {
    
                OPCBrowser opcBrowser = opcServer.CreateBrowser();
    
                //展开分支
    
                opcBrowser.ShowBranches();
    
                //展开叶子
    
                opcBrowser.ShowLeafs(true);
    
                return opcBrowser;
    
            }
    
     
    
            public static OPCGroup CreateGroup(OPCServer opcServer, OPCItems opcItems, string opcGroupName, GroupProperty groupProperty)
    
            {
    
                try
    
                {
    
                    OPCGroup opcGroup = opcServer.OPCGroups.Add(opcGroupName);
    
     
    
                    opcServer.OPCGroups.DefaultGroupIsActive = groupProperty.DefaultGroupIsActive;
    
                    opcServer.OPCGroups.DefaultGroupDeadband = groupProperty.DefaultGroupDeadband;
    
                    opcGroup.UpdateRate = groupProperty.UpdateRate;
    
                    opcGroup.IsActive = groupProperty.IsActive;
    
                    opcGroup.IsSubscribed = groupProperty.IsSubscribed;
    
     
    
                    //opcGroup.DataChange += new DIOPCGroupEvent_DataChangeEventHandler(OpcGroupDataChange);
    
                    //opcGroup.AsyncWriteComplete += new DIOPCGroupEvent_AsyncWriteCompleteEventHandler(KepGroup_AsyncWriteComplete);
    
                    //opcItems = opcGroup.OPCItems;
    
                    return opcGroup;
    
                }
    
                catch (Exception err)
    
                {
    
                    throw err;
    
                }
    
            }
    
        }

    最后就是使用前述的封装。

  • 相关阅读:
    物联网操作系统HelloX开发者入门指南
    【 D3.js 高级系列 】 总结
    【 D3.js 高级系列 — 10.0 】 思维导图
    android fragment+ FragmentTabHost+viewpager 切换状态不保存的问题
    OpenGL 顶点缓存对象
    OpenGL顶点数组
    【 D3.js 高级系列 — 9.0 】 交互式提示框
    如何在 Linux 上录制你的终端操作
    程序员诗词大赛开始了_你看过吗?
    程序员与代码的搞笑日常
  • 原文地址:https://www.cnblogs.com/foxclever/p/7586824.html
Copyright © 2011-2022 走看看