




已阅读5页,还剩10页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
用VB编写OPC客户端访问WINCC作者:顾恺文章来源:/freeboy20sui点击数:25更新时间:2006-2-10OPC是一个工业标准,它是由一些世界上著名的自动化系统和硬件、软件公司和Microsoft(微软)紧密合作而建立的。O代表OLE(对象链接和嵌入),P (process过程),C (control控制)。OLE已从面向对象重新定义为基于对象并更名为Active X。WinCC是西门子公司在自动化领域采用最先进的技术与微软公司在共同开发的居于世界领先地位的工控软件。WinCC即WINDOWS CONTROL CENTER(视窗控制中心)。WinCC是一个功能强大的全面开放的监控系统,既可以用来完成小规模的简单的过程监控应用,也可以用来完成复杂的应用。在任何情况下WinCC都可以生成漂亮而便捷的人机对话接口,使操作员能够清晰地管理和优化生产过程。它集成的OPC(OLE for process control)服务器使得过程数据可由其它应用程序(OPC客户机)访问。WinCC在安装时提供了OPC的客户端控件: Siemens OPC DAAutomation 2.0( SOPCDAAuto.dll),这个控件就是我们在VB中要用到的控件,我们也可以使用通用的OPC客户端控件: OPC Automation 2.0.在WINCC的帮助中,有Siemens OPC DAAutomation 2.0使用的简略帮助,但说得不很详细,我在使用中碰到不少问题,现一并写出来,与大家共享。一、OPC的连接 先在“引用”将近 Siemens OPC DAAutomation 2.0加入,然后开始定义全局变量。在本程序中,我使用了两个OPC组进行OPC访问,所以定义了全局变量。我们要首先定义OPC服务类型与计算机结点名。定义OPC组与OPC标签组。并定义OPC的标签数组与值数,注意,值数组一定要设为Variant。OPC处理:只对WINCCConst ServerName = OPCServer.WinCCOPC的类型Const NodeName = GUK结点名,即计算机名Dim NodeName As StringDim WithEvents MyOPCServer As OPCServerOPC服务Dim MyOPCGroupColl As OPCGroups Dim WithEvents MyOPCGroupOut As OPCGroupOPC组,本程序用两个组进行OPC连接Dim WithEvents MyOPCGroupIn As OPCGroupDim MyOPCItemCollIn As OPCItemsOPC标签组Dim MyOPCItemCollOut As OPCItemsDim ServerHandlesIn() As Long句柄Dim ServerHandlesOut() As LongDim ErrorsIn() As Long错误句柄Dim ErrorsOut() As LongDim WatchDataReadItem(100) As String 记录OPC的标签Dim WatchDataReadValue(100) As Variant 存放OPC的值Dim WatchDataWriteItem(100) As String 记录OPC的标签Dim WatchDataWriteValue(100) As Variant 存放OPC的值 在定义所有变量后,我们就要进行OPC连接了,要进行OPC连接之前,先要配置要访问的OPC标签名,我们WatchDataReadItem、WatchDataWriteItem中加入相应的标签名,注意:这两个数组必须由1开始,不能由0开始。 配置好标签后就要进行OPC连接了。如下面子程序:1、 ClientHandles1先配置名柄索引,这将在读取OPC标签的值时可要用到2、 生成OPC对象,3、 进行OPC标签连接 至此:OPC连接就成功了,我们可以对OPC进行读与写的操作了。- Sub StartClient() 目的:连接至OPC_server,创建组和添加条目-Private Sub StartClient() Dim ItemNum As Integer Dim TarnscationID As Long Dim CanceID As Long Dim ClientHandles1(100) As Long Dim ii As Integer On Error GoTo HANDLEeRROR For ii = 0 To 100 ClientHandles1(ii) = ii先配置名柄索引,这将在读取OPC标签的值时可要用到 Next ii TarnscationID = 1 NodeName = xProfile.GetValue(SYSTEM, NodeName) 生成OPC对象, Set MyOPCServer = New OPCServer MyOPCServer.Connect ServerName, NodeName Set MyOPCGroupColl = MyOPCServer.OPCGroups MyOPCGroupColl.DefaultGroupIsActive = True Set MyOPCGroupIn = MyOPCGroupColl.Add(MYGROUPIN) Set MyOPCGroupOut = MyOPCGroupColl.Add(MYGROUPOUT) Set MyOPCItemCollIn = MyOPCGroupIn.OPCItems Set MyOPCItemCollOut = MyOPCGroupOut.OPCItems 进行OPC标签连接 If WriteItemIdex 0 Then MyOPCItemCollOut.AddItems WriteItemIdex, WatchDataWriteItem, ClientHandles1, ServerHandlesOut, ErrorsOut 初始化OCP连接 MyOPCGroupOut.IsSubscribed = True End If If ReadItemIdex 0 Then MyOPCItemCollIn.AddItems ReadItemIdex, WatchDataReadItem, ClientHandles1, ServerHandlesIn, ErrorsIn 初始化OCP连接 MyOPCGroupIn.IsSubscribed = TrueEnd If Exit SubHANDLEeRROR: needOPCRestart = True xLog1.log OPCl连接发生错误End Sub二、OPC的标签读写对OPC标签的读可以通过MyOPCGroupIn组与MyOPCGroupOut的DataChange事件来读取。该事件有多个参数:其中NumItems是指标签改变值的个数,ClientHandles是改变值的标签索引,ItemValues为改变值的数据,具体的意思是ClientHandles(1)的值是其对应的标签数组的索引,其所指的OPC标签的值在ItemValues(1)中。一般来说,刚连接上时,该事件会把全部所要求访问的OPC标签值全部读取过来(顺序不一,要通过ClientHandles索引),此后只有数据发生变化时才会触发该事件。也只会传输发生了变化的数据,没有变化的数据不会出现在本事件的ItemValues中。Private Sub MyOPCGroupOut_DataChange(ByVal TransactionID As Long, ByVal NumItems As Long, ClientHandles() As Long, ItemValues() As Variant, Qualities() As Long, TimeStamps() As Date)产生要通知下一级的数据变化,根椐不再的控件有不同的处理 For ii = 1 To NumItems WatchDataWriteValue(ClientHandles(ii) - 1) = ItemValues(ii) 对改变的值读入本数组 Next iiEnd Sub对OPC的写可以有同步与异步之分,对于大量的数据传输,异步是更佳的选择,但对少量的数据传输,同步表现得更好。 要进行数据传输,先要将值数据进行赋值,注意:值数据要由0开始,也就是说,值数组与标签数据不是一、一对应,值要比标签前一位,这一点,在WINCC说明中没有,但在我的实际的使用中一直要这样,不然数据就产生错位,看下面程序。这是一个拔号完毕后返回的数据进行OPC传递的程序。包含解包过程,Private Sub showSuccess(msg As String) Dim location As String Dim nowTime As String Dim logStr As String Dim Value() As String Dim ii, temp As Integer Dim isPack As Boolean Dim sHead, sDelimited, sTail As String location = xProfile.GetValue(WatchPoint(nowRunID), LOCATION) nowTime = Now logStr = 拔 & location & 取数成功 & msg xLog1.log logStr logStr = & msg xLog2.log logStr 记录数据 数据上传 如果有包结构,则显示包结构, isPack = xProfile.GetValue(WatchPoint(nowRunID), ISRECHEAD) If WatchPointRBegin(nowRunID) WatchPointREnd(nowRunID) Then Exit For WatchDataReadValue(temp - 1) = Value(ii + 1) VALUE要从0开始,比ITEM少1,所以减一。 有包头,占去一位,向后延一 Next ii Else WatchDataReadValue(WatchPointREnd(nowRunID) - 1) = msg End If MyOPCGroupIn.SyncWrite ReadItemIdex, ServerHandlesIn, WatchDataReadValue, ErrorsIn 数据上传 记录上次成功执行的时间 xProfile.SetValue WatchPoint(nowRunID), LASTTIME, nowTimeEnd Sub三、OPC连接断开。OPC客户端连接后要占用服务器资源,所以如果不需要使用OPC时,必须进行OPC连接断开。断开的程序相当简单,释放资源即可。如下,Sub StopClient() On Error Resume Next - 释放组和服务器对象 MyOPCGroupColl.RemoveAll - 与服务器断开连接并且清除 MyOPCServer.Disconnect Set MyOPCItemCollIn = Nothing Set MyOPCItemCollOut = Nothing Set MyOPCGroupIn = Nothing Set MyOPCGroupOut = Nothing Set MyOPCGroupColl = Nothing Set MyOPCServer = NothingEnd Sub但在实际的使用中发现,频繁的连接与断开,将使服务器的资源被大量的消耗,最终让服务器出错。所以尽量减少无谓的OPC连接与断开。结语: OPC的使用是作为一个DCOM在使用,所以OPC客户端可以网络上任一计算机运行,但你必须配置DCOM的访问权限,如果你不想费神,把服务器与客户端都用相同的用户名与密码登录就成了。如果想配置DCOM,请参看DCOM的配置。参考资料: WinCC在线帮助 作者简介:顾恺,高级程序员,湖南大学毕业,曾从事过LINUX的内核研究,从事过企业信息化平台的开发,当前从事SCADA的开发,主要将各种不同类型的远程设备通过同一手段进行数据采集,并集成到企业信息化平台中去。喜欢将工作中的一些积累形成文字。come from:/monkst/archive/2003/02/13/15037.aspx如何开发OPCServer作者:风间月文章来源:本站原创点击数:49更新时间:2006-2-10首先我们先来看一下什么是OPC OPC (OLE for Process Control用于过程控制的OLE)是基于Microsoft公司的DNA(Distributed Internet Application)构架和COM(Component Object Model)技术的一个工业标准接口,是根据易于扩展性而设计的。再来了解一下OPC的用途OPC主要适用于过程控制和制造自动化等应用领域。 OPC是以OLE/COM机制作为应用程序的通讯标准。OLE/COM是一种客户/服务器模式,具有语言无关性、代码重用性、易于集成性等优点。OPC规范了接口函数,不管现场设备以何种形式存在,客户都以统一的方式去访问,从而保证软件对客户的透明性,使得用户完全从低层的开发中脱离出来然后我们再来看看OPC Server的组成 一个设备的OPC Server主要有两部组成,一是OPC标准接口的实现;二是与硬件设备的通信模块。 实现OPC 标准接口图1在这些接口中,IOPCServer 是OPC Server的主接口,通过它实现OPC Server在操作系统中的安装和注册。此接口是必须要实现的,其所有方法也必须实现。其它的接口都是可选的我们就不做介绍了,下面主要来介绍如何实现IOPCServer接口。在IOPCServer接口中共有六个法:1、 IOPCServer:AddGroup HRESULT AddGroup( in, string LPCWSTR szName, in BOOL bActive, in DWORD dwRequestedUpdateRate, in OPCHANDLE hClientGroup, unique, in LONG *pTimeBias, in FLOAT * pPercentDeadband, in DWORD dwLCID, out OPCHANDLE * phServerGroup, out DWORD *pRevisedUpdateRate, in REFIID riid, out, iid_is(riid) LPUNKNOWN * ppUnk ); 此方法是在OPC Server上建立一个组。下在我们来实现这个方法:.首先要对组名(szName)进行检查,看是否有效或是否已经有这个组。if (szName != NULL) RequestedName = szName; if (RequestedName = ) RequestedName = pSvrObject-DefaultGroupName(); else RequestedName = pSvrObject-DefaultGroupName(); for (i=0; iNumbrGroups(); i+) pGroup = pSvrObject-GetGroup(i); if (RequestedName = pGroup-Name) return (OPC_E_DUPLICATENAME); 这需要在内存中维护OPC Group(组)的列表(还要有OPC 项的列表)。 如果szName(组名)正确并且没有建立过该组,就开始根据传过来的参数进行组的建立,建立好后将该组加到自己的组列表中以备后用。 if (dwRequestedUpdateRate = 0) | (dwRequestedUpdateRate ServerTickRate) ActualRate = pApp-ServerTickRate; else ActualRate = dwRequestedUpdateRate; MinRate = pApp-ServerTickRate; ActualRate += (MinRate/2); ActualRate /= MinRate; ActualRate *= MinRate; if (pRevisedUpdateRate) *pRevisedUpdateRate = ActualRate; pGroup = new (COPCGroup); if(pGroup = NULL) return (E_OUTOFMEMORY); pGroup-Name = RequestedName; pGroup-pSvrObject = pSvrObject; pGroup-MarkedForDeletion = FALSE; pGroup-ClientGroupHandle = hClientGroup; pGroup-UpdateRate = ActualRate; pGroup-IsActive = bActive; if (pPercentDeadband) pGroup-Deadband = *pPercentDeadband; else pGroup-Deadband = 0.0; pGroup-LCID = dwLCID; if (pTimeBias) pGroup-TimeBias = *pTimeBias; else _ftime( &timebuffer ); pGroup-TimeBias = timebuffer.timezone; / pGroup-TimeBias = 300L; r1 = pGroup-QueryInterface(riid, (LPVOID*) ppUnk); if(FAILED(r1) / If error - delete group and return delete (pGroup); return r1; pSvrObject-AddNewGroup(pGroup); 最后将新建组的接口指针返回给客户端。 *phServerGroup = pGroup-ServerGroupHandle;2、IOPCServer:GetErrorString HRESULT GetErrorString( in HRESULT dwError, in LCID dwLocale,out, string LPWSTR *ppString ); 为Server的错误代码返回相应的错误字符串。 char buf128; BOOL bFound = FALSE; for( int i = 0; i hrErr) != FALSE ) strcpy( buf, e-ErrText ); break; if( !bFound ) DWORD dwStatus = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, / Arguments is not a va_list NULL, / LPCVOID pointer to message source hr, / DWORD requested message identifier LANG_NEUTRAL, / DWORD language identifier for message buf, / LPTSTR pointer to message buffer 127, / DWORD maximum size of message buffer NULL ); / va_list *Arguments address of array of message inserts if( !dwStatus ) _snprintf( buf, 127, , hr, hr ); *ppString = pApp-WSTRFromCString( buf, TRUE);3、 IOPCServer:GetGroupByName HRESULT GetGroupByName( in, string LPCWSTR szName, in REFIID riid,out, iid_is(riid) LPUNKNOWN * ppUnk ); 通过指定的组名(由同一客户端建立的)找到该组的接口指针。此方法实现比较简单,只要根据提供的名子循环从组列表中找到该组的接口指针,并返回给客户端*ppUnk = 0;RequestedName = szGroupName; for (i=0; iNumbrGroups(); i+) pGroup = pSvrObject-GetGroup(i); if (pGroup-Name = RequestedName) r1 = pGroup-QueryInterface(riid, (LPVOID*) ppUnk); return (r1); 4、 IOPCServer:GetStatus HRESULT GetStatus( out OPCSERVERSTATUS * ppServerStatus ); 返回当前Server的状态信息。此方法比较简单,但要注意的是在使用OPCSERVERSTAUS前要进行内存分配。pServerStatus=(OPCSERVERSTATUS*) pApp-AllocZero( sizeof(OPCSERVERSTATUS) ); if (pServerStatus = NULL) return (E_OUTOFMEMORY); pServerStatus-szVendorInfo = pApp-WSTRFromCString (pApp-VendorInfo, TRUE); pServerStatus-ftStartTime = pApp-OPCServerStartTime; CoFileTimeNow( &pServerStatus-ftCurrentTime); pServerStatus-ftLastUpdateTime = pSvrObject-mLastUpdate; /RWD allow user to manipulate returned OPCSERVERSTATUS, lined up layout for clarity. pServerStatus-dwServerState = pApp-ServerState; /endRWD pServerStatus-dwGroupCount = 0; pServerStatus-dwBandWidth = 0; pServerStatus-wMajorVersion = 0; pServerStatus-wMinorVersion = 0; pServerStatus-wBuildNumber = 0; pServerStatus-wReserved = 42; 返回服务器状态 *ppServerStatus = pServerStatus;5、 IOPCServer:RemoveGroupHRESULT RemoveGroup( in OPCHANDLE hServerGroup, in BOOL bForce ); 从服务器中删除指定组 在组列表中找到指定的组,并将其删除。for (i=0; iNumbrGroups(); i+) pGroup = pSvrObject-GetGroup(i); if (groupHandleID = pGroup-ServerGroupHandle) pSvrObject-RemoveGroup(i); / if no outstanding references / delete it if (pGroup-RefCount = 0) pSvrObject-LockGroupList(); delete (pGroup); pSvrObject-UnlockGroupList(); else if (bForce) DeletedGroupList.Add(CObject *)pGroup); else pGroup-MarkedForDeletion = TRUE; pGroup-pSvrObject = NULL; return (OPC_S_INUSE); return (S_OK); 6、 IOPCServer:CreateGroupEnumerator HRESULT CreateGroupEnumerator( in OPCENUMSCOPE dwScope, in REFIID riid, out, iid_is(riid) LPUNKNOWN* ppUnk );为Server上所提供的组建立不同的列举器。if ( riid = IID_IEnumUnknown) pEnumerator = new(COPCGroupEnum); if (pEnumerator = NULL) return (E_OUTOFMEMORY); pEnumerator-pSvrObject = pSvrObject; pEnumerator-AddRef(); / will increment refere
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 年月日课件吴正宪
- 年月日教学课件
- 工业电梯安全培训中心课件
- 年前安全教育培训内容课件
- 法律顾问协议7篇
- 年假安全培训教学课件
- 平顶山安安全培训课件
- 平面设计配色原理课件
- 平面直线垂直判定课件
- exo-α-1-2-Arabinofuranosidase-Cellvibrio-japonicus-生命科学试剂-MCE
- 2025年9月20日云南省直机关遴选公务员笔试真题及答案解析
- 合同纠纷民事起诉状模板示例
- 2025广东广州市花都区招聘社区专职工作人员50人考试参考题库及答案解析
- 2025四川蜀道养护集团有限公司招聘15人考试参考题库及答案解析
- 2025年秋季上饶银行招聘考试参考题库及答案解析
- 2025至2030中国汽车模塑件行业项目调研及市场前景预测评估报告
- 投标服务响应应急方案(3篇)
- 自动控制原理课件第九章状态空间分析法
- 2025年安全工程师《安全生产管理》考前模拟卷(一)
- 综合实践 记录我们的校园(教案)北师大版数学三年级上册
- 第4课 探究智慧农业应用领域 课件【教科版】《信息科技》八年级上册
评论
0/150
提交评论