OPC客户端的实现

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

1引言

OPC(OLE for Process Control)是一个工业标准,他是许多世界领先的自动化和软、硬件公司与微软公司合作的结晶。管理该标准的组织是OPC基金会。该基金会的会员单位在世界范围内超过150个,包括了世界上几乎全部的控制系统、仪器仪表和过程控制系统的主要供应商。OPC 技术建立了一组符合工业控制要求的接口规范,将现场信号按照统一的标准与SCADA、HMI等软件无缝连接起来,同时将硬件和应用软件有效地分离开。只要硬件开发商提供带有OPC接口的服务器,任何支持OPC接口的客户程序均可采用统一的方式对不同硬件厂商的设备进行存取,无须重复开发驱动程序。如果希望将数据引入数据库进行统计分析,就要进行客户端开发。

2客户程序的设计方法与比较

客户程序的设计主要是指客户程序中OPC接口部分的设计。客户程序本身可以完成很多复杂的数据处理与显示功能,但需要通过OPC接口部分访问OPC服务器,对现场数据进行存取。

开发OPC、Data、Access、Client之前,要弄清服务器的大体情况,比如需要访问的服务器是否提供自动化接口、服务器的OPC的版本等,到目前为止,OPC有1.0和2.0两个版本,两个版本的接口定义不同,2.0版是对1.0的改进,但不兼容。

OPC客户端的主要任务:

①创建服务器对象。

②建立与服务器的连接。

③浏览OPC服务器的功能。客户程序需要创建OPC基金会提供的OPC服务器浏览器对象(OPCServerList)再通过该对象的IOPCServerList接口获得OPC服务器名称的列表;可以通过枚举注册表中包含“OPC”子键的程序名来浏览符合OPC数据存取规范的服务器,但效率较低。

④通过OPC接口读写数据。

⑤断开连接。

注意事项:

设计时需要注意OPC对象的VARAINT结构类型、引用计数问题、内存管理问题和处理错误返回代码问题。由于一个OPC客户程序可能与多个OPC服务器相连,因此设计时也最好采用多线程,同时与多个OPC服务器程序进行交换以保证较高的通信效率。另外客户程序中OPC接口部分如何与其它功能模块进行数据交换需要根据实际情况仔细考虑。

2.1 使用MFC的COM库函数开发OPC客户端

直接使用COM库函数开发OPC客户端,是最基本也是最灵活的方式,这种开发方式难度和工作量都大,要求开发人员对OPC规范和COM技术原理又比较深入的了解。早些时候VisualC++编译器还不支持模板,因此,它们不得不借助非模板的其它手段来将COM功能掺入类中。Microsoft 通过加入一些虚函数到CCmdTarget类和一些宏中解决了这个问题,使得在MFC中实现COM接口有了可能。

客户要创建一个COM对象首先应得到类厂对象,再由类厂对象创建COM对象。为了实现类厂对象,MFC提供了一个通用的类厂COleObjectFactory,其从CCmdTarget派生,并实现了IclassFactory2接口。在COleObjectFactory的成员中,最主要的是对象的类标识符(CLSID)和类型信息,类厂的CreateInstance成员函数利用这些信息在运行中创建COM对象。

OPCServer应用程序包括了一个Server对象、多个Group对象、多个Item对象,Server

对象实现IOPCServer接口;Group对象实现IOPCItemMgt、IOPCSyncIO接口;Item对象不实现任何接口,只是建立与数据源的连接。

数据通信是通过OPC客户对OPC服务器的多次调用完成的。OPC客户首先要通过类厂对象创建OPCServer对象,由OPCGroup对象的IUnknown接口查询到IOPCServer接口,再通过调用这一接口根据客户需要增加多个OPCGroup对象;这样OPC客户就可以通过创建的OPCGroup对象调用IOPCItemMgt接口增加实际数量的Item对象;即创建OPCItem对象;接着通过调用OPCGroup 对象的IOPCSyncIO接口成员函数Read和Write同步读写该组所包含的Item对象的属性,即实

际数据值;最后OPC客户在退出时释放所有的接口并依次删除OPCItem、OPCGroup和OPCServer 对象。

客户端程序与OPC数据存取服务器连接的过程:

步骤1:初始化COM库。

hr=CoInitialize(NULL);

if(FAILED(HR))

{

AfxMessageBox(“CoInitialize fail!”)

return true;

}

…….

CoUninitialize();

return FALSE;

步骤2:创建Server对象(以下代码均略去变量定义、出错处理等部分)。

CLSIDFromProgID(PROGRAM_ID,&clsid);

HRESULT

hr=CoCreateInstance (clsid,NULL,CLSCTX_INPROC_SERVER,IID_IUnknown,reinterpret_cas t(&m_pUnknown));

if(FAILED(hr))

MessageBox(“can't create server”);

return TRUE;

步骤3:获得IOPCServer 接口。

m_pUnknown->QuertyIterface(IID_IOPCServer,( void**)(&m_pServer));

步骤4:添加组

m_pServer->AddGroup(“GROUP”,TURE,CLIENT_RATE,1,NULL,NULL,O,&m_hGroup,&revised UpdateRate,ID_IOPCItemMgt,(LPUNKNOWN*)(&m_pItemMgt));

步骤5:添加其他接口

m_pItemMgt->QueryInterface(IID_IOPCSyncIO, ( void**)(&m_pSyncIO));

m_pItemMgt->QueryInterface(IID_IOPCASyncIO, ( void**)(&m_pASyncIO));

利用IOPCServer接口,可以实现增加或删除组对象等管理功能;利用IOPCItemMgt接口在组中可以实现增加(IOPCItemMgt::AddItems()、删除(IOPCItemMgt::DeleteItems())及管理项等功能,利用IOPCSyncIO和IOPCASyncIO可进行数据的同步或异步读写操作,不多赘述。

2.2 通过创建包装类实现客户端

利用#import伪指令引入类型库,编辑器从类型库中读取信息并且创建包装类。不仅可以对类型库文件(.tlb)使用#import指令,也可以对组件DLL或EXE文件,甚至支持类型库的复合文件和LoadTypeLib函数可以理解的任何其他文件格式使用#import指令。#import指令将产生两个文件,他们位于输出路径,和类型库具有相同的名称,后缀分别为“.tlh”和“.tli”。用#import指令引入类型库时,在StdAfx.h文件中添加:#import

“...\...\OPCServer\OPCServer.tlb”\,其他步骤代码类似COM库函数开发方式。

包装类封装了COM库函数,Visual C++客户程序通过包装类访问组件提供的属性和方法。虽然中间多了一层,但对客户程序开发人员来说,却方便多了。#import指令利用了一个新的类:_com_ptr_t,也被成为智能指针,是一个模板类,它封装了接口指针并提供了一些方法和重载操作符来简化指针的操作。智能指针自动执行COM的CoCreateInstance和QuertyIterface、AddRef 和Release函数。要实现异常处理,可使用try/catch块。在catch块中,异常对象类型为

_com_error对象。_com_error类封装了HERSULT错误代码和IerrorInfo接口提供的相关环境信

相关文档
最新文档