以C#编写并使用NET-Framework的OPC自定义接口

描述

使用示例程序 

该程序包括多个元素,操作员可使用这些元素触发以下动作: 

OPC

 

启动程序时,仅启用“启动示例” (Start Sample)  按钮。单击此按钮后,程序将生成所需的 OPC 对象。随即会启用其它按钮。 

OPC

单击“ 启动示例” (Start Sample)  按钮后,以  C# 编写并使用  .NET- Framework 的 OPC 自定义接口(异步通信)的示例程序的启动对话框 .

程序说明 :

1  选择 .NET 组件 

2  将 ProgID 转换为 CLSID 

3  建立与 OPC 服务器的连接 

4  创建 OPC 组 

5  添加数据项 

6  请求 IConnectionPointContainer 接口 

7  请求 IOPCAsyncIO2  接口 

8  创建回调对象 

9  连接 OPC 服务器与客户端的回调对象 

10  执行所需的写入和读取操作 

11  接收 OPC 服务器的通知 

12  删除对象并释放内存 

步骤 1:选择 .NET  组件 

要配合使用 OPC 数据访问的自定义接口和 .NET,必须在您的 Visual Basic 项目中使用上述运行时可调用包装 (RCW) 。在该示例项目中,OpcRcw.Da  和 OpcRcw.Comn 组件已添完毕。 

如果它们未出现在选项中,也可使用“浏览” (Browse)  按钮从下列文件夹中进行选择: “ <安装路径> SIEMENS SIMATIC.NET opc2in” 

步骤 2:将 ProgID 转换为 CLSID  

为了对其进行标识,每个 COM 服务器都有一个 ProgID  且该 ProgID 分配给世界上唯一的类型。使用 GetTypeFromProgID() 函数可实现上述操作。SIMATIC  NET  的 OPC 服务器的 ProgID 是 L"OPC.SimaticNET": 

Type svrComponenttyp =  Type.Get TypeFromProgID(L"OPC.SimaticNET"); 

步骤 3:建立与 OPC 服务器的连接 

Activator 类的 CreateInstance() 函数生成一个具有之前指定类型的类的实例: 

pIOPCServer =  

                    (IOPCServer)Activato r.CreateInstance(svrComponenttyp

); 

该程序段的结果是 IOPCServer  类型的接口变量 pIOPCServer。 

步骤 4:创建 OPC 组 

IOPCServer 接口具有用于创建组的 AddGroup() 方法: 

pIOPCServer.AddGroup(GROUP_NAME, 

                                 0, 

                                 dwRequestedUpdateRate, 

                                 hClientGroup, 

                                 hTimeBias..AddrOfPinnedObject(),  

                                 hDeadban d.AddrOfPinnedObject(),  

                                 dwLCID, 

                   out pSvrGroupHandle,  

                   out pRevUpdateRate, 

                   ref out pobjGroup1) 

注意 

hDeadband 和 hTimeBias  的内存分配由 GCHandle.Alloc() 函数完成。 

GCHandle hTimeBias; 

hTimeBias = GCHandle.Alloc(tim ebias,GCHandleType.Pinned); 

GCHandle hDeadband; 

hDeadband = GCHandle.Alloc(deadband,GCHandleType.Pinned); 

这些函数处理传送变量时间偏倚和死区(百分比死区)的非管理型内存。 

当不再需要管理句柄时,必须按如下所示再次将其释放: 

if (hTimeBias.IsAllocated)  hTimeBias. Free(); 

if (hDeadband.IsAllocated) hDeadband.Free(); 

该程序段的结果是一个具有指定名称和所需属性的组。AddGroup() 还返回 pobjGroup1变量作为返回参数,即组对象的接口。 

使用类型调整调用 IOPCGroupStateMgt ,可以只从返回的组接口 pobjGroup1 获取该接口。该调用的简化形式对应于 COM 方法 Queryinterface()。 

稍后需使用 IOPCGroupStateMgt 接口的 S etState()  方法激活和禁用组。  

pIOPCGroupStateMgt = (IOPCGroupStateMgt)pob jGroup1;  

步骤 5:添加数据项 

IOPCItemMgt  接口具有用于创建 OPC 数据项的 AddItems()  方法: 

((IOPCItemMgt)pobjGroup1).AddItems(2,ItemDeffArray,out 

                                                      pResults,out pErrors);  

该程序段的结果是服务器添加两个具有 itemd efs 参数中所指定属性的数据项。此外,还会对结果结构 OPCITEMRESULT 的变量(服务器句柄、目标系统上数据项的数据类型等)进行初始化。 

由于结果通过基础 COM 接口写入至非管理型内存,因此来自管理型 .NET 代码的访问必须利用封送函数: 

OPCITEMRESULT result = (OPCITEMRESULT)Marshal.PtrToStructure(pos,  

                                     typeof(OPCITEMRESULT));  

Ite mSvrHandleArray[0] = result.hServer;  

pos = new IntPtr(pos.ToInt32() +  

                          Marshal.SizeOf(typeof(OPCITEMRESULT))); 

OPCITEMRESULT result = (OPCITEMRESULT)Marshal.PtrToStructure  

                                                   (pos,typ eof(OPCITEMRESULT));  

ItemSvrHandleArray[1] = result.hServer; 

步骤 6:请求 IConnectionPointContainer  接口 

IConnectionPointContainer  类型的 pIConnectionPointContainer 变量可源自 m_group_1 变量。 

pIConnectionPointContai ner =  

       (IConnectionPointContainer)pobjGroup1; 

定位 IConnectionPoint 接口需要使用该接口。 

步骤 7:请求 IOPCAsyncIO2  接口 

pIOPCAsyncIO2  类型的 pIOPCAsyncIO2  变量可源自 pobjGroup1 变量。 

pIOPCAsyncIO2 = (IOPCAsyncIO2)pobjGroup1; 

该接口提供用于异步读取和写入值的方法。 

步骤 8:创建回调对象 

为了允许 OPC 服务器返回异步操作的值,必须在客户端上执行 I OPCDataCallback 接口。 

public class OPCAsync :System.Windows.Forms.Form ,  

       IOPCDataCallback 

使用 IConnectionPointContainer 接口的 FindConnectionPoint()  方法建立 OPC 服务器的 IConnectionPoint  和 IOPCDataCallback  接口间的连接。该连接将为异步调用生成一个回调对象。 

Guid iid = typeof(IO PCDataCallback).GUID;  

pIConnectionPointContainer.FindConnectionPoint(ref iid, 

                                                                     out 

pIConnectionPoint); 

步骤 9:连接 OPC 服务器与客户端的回调对象 

OPC 服务器的回调对象与客户端应用程序间的连接通过 Advise() 方法来建立。返回变量 dwCookie 是该连接的 ID 。 

pIConnectionPoint.Advise(this,out dwCookie); 

步骤 10:执行所需的写入或读取操作 

在步骤 7  中生成的 Read()  和 Write() 方法可通过 IOPCAsyncIO2  接口来访问: 

pIOPCAsyncIO2.Read(1,ItemSvrHandleArray,nTransactionID+1, 

                             out nCancelid,out pErrors); 

步骤 11:接收 OPC 服务器的通知 

如果激活组中激活数据项的数据发生更改,服务器将调用回调对象的 OnDataC hange  方法。读取操作完成后,服务器调用 OnReadComplete() 方法;写入操作完成后,服务器调用 OnWriteComplete() 方法。服务器将返回值以参数的形式传递至方法。 

virtual void OnDataChange( 

                                        Int32 dwTransid, 

                                        Int32 hGroup,  

                                        Int32 hrMasterquality, 

                                        Int32 hrMastererror,  

                                        Int32 dwCount, 

                                        int[] phClientItems,  

                                        object[] pvValues,  

                                        short[] pwQualities, 

                                        FILETIME[] pftTimeStamps, 

                                        int[] pErrors, 

                                       )  

步骤 12:删除对象并释放内存 

退出程序前或单击“ 停止”(Stop)  后,必须删除已生成的 OPC 对象并释放所占用的内存。 

pIConnectionPoint.Unadvise(dwCookie); 

Marshal.ReleaseComObject(pIConnectionPoint);  

Mar shal.ReleaseComObject (pIConnectionPointContainer); 

Marshal.ReleaseComObject(pIOPCAsyncIO2);  

Marshal.ReleaseComObject(pIOPCGroupStateMgt);  

Marshal.ReleaseComObject(pobjGroup1); 

Marshal.ReleaseComObject(pIOPCServer);  

释放内存 

使用 COM 时,客户端有时需要释放服务器所请求的内存。相关规则如下: 

•  [out]:将从服务器请求具有该属性的参数的内存。 

•  [in,out] :将从客户端请求此类参数的内存。服务器可以再次释放内存并对其进行重新分配。 

•  [in] :客户端将请求内存。服务器不负责释放内存。 

原文标题:以 C# 编写的 OPC 自定义接口(异步通信)

文章出处:【微信公众号:机器人及PLC自动化应用】欢迎添加关注!文章转载请注明出处。

审核编辑:汤梓红
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分