1 OPC技术简介
1.1 什么是OPC
OPC(OLE for Process Control),即用于过程控制的对象链接与嵌入技术,是一种规范,是在工业控制和生产自动化领域中使用的硬件和软件的接口标准。OPC以组件对象模型和分布式组件对象模型(COM/DCOM)技术为基础,采用客户/服务器(Client/Server)的模式,定义了一组COM对象及其接口标准。
OPC规范是由世界范围内自动化领域中处于领导地位的硬件和软件开发商,在微软的协作下制定的,并且已经得到越来越多的客户和硬件制造商的认可。
1.2 OPC的意义
在传统的控制系统中,针对同一个硬件设备,每个应用软件都要根据自己的需求开发一套硬件驱动程序。这不仅加大了开发和维护费用,而且带来了访问冲突问题。
OPC技术将各个硬件设备驱动程序和通讯程序封装成独立的OPC服务器,上层应用软件(作为OPC客户端)可以不关心硬件的性能特点,而通过标准的OPC接口访问OPC服务器。
这样不仅解决了上述问题,而且实现了软件的“即插即用”。OPC相当于一块软件“主板”,它能够直接与现场的PLC、工业网络、数据采集和Windows CE设备连接,快速有效地获取现场实时数据。PC机内的各种监视、控制和管理等应用软件则像是插在OPC主板上的软件“芯片”,芯片可以通过OPC获得现场实时数据,芯片之间也可以按照OPC协议进行通讯,从而实现软件的“即插即用”。
1.3 OPC对象与接口
OPC的核心是COM/DCOM技术。在COM模型中,软件的功能被分解为一些组件,这些组件通过COM协议在一定条件下连接起来,实现相应的功能。COM对象分为客户端和服务器两类,客户端通过COM接口访问服务器[2]。
OPC数据访问规范描述了OPC服务器需要实现的COM对象及其接口,它定义了定制接口(custom interface)和自动化接口(automation interface)[1]。OPC客户程序通过接口与服务器通讯,间接读取数据。OPC服务器必须实现定制接口,也可以有选择地实现自动化接口。一般来说,自动化接口能为VB等高级语言客户程序提供极大的便利,但数据传输效率较低;而定制接口则为用C/C++语言编写的程序带来灵活高效的调用手段。
OPC客户程序访问服务器时,创建一个服务器对象(这里指的是逻辑对象,目的是利用这个逻辑对象建立与实际服务器的连接),调用这个服务器对象的接口,服务器对象创建组对象并返回组对象的指针,客户程序获得组对象的指针后调用其接口。
注意,OPC项并不是OPC客户直接操作的对象,因为OPC项没有定义外部接口,对象的所有操作都是通过包容该项的组对象进行的。
2 OPC数据访问服务器的结构及设计步骤
2.1 OPC数据访问服务器的结构
本文实现的OPC数据访问服务器具有数据采集的功能,提供符合OPC规范的定制接口。主要由OPC 服务器对象、OPC 组对象、OPC 项对象和针对CAN(Controller Area Network控制器局域网)通讯卡编写的I/O 动态链接库(DLL)组成,采用如图1所示的结构。
OPC 服务器对象是客户端与服务器交互的首要对象。客户端通过访问服务器对象的接口函数与之进行交互。一个服务器对象里可以设置一个以上的组对象。OPC 服务器对象的主要功能是:①创建和管理OPC 组对象;②管理服务器内部的状态信息;③将服务器的错误代码翻译成描述性语句;④浏览服务器内部的数据组织结构。
OPC 组对象用于组织管理服务器内部的实时数据信息,它是OPC 项对象的集合。正因为有了组对象,OPC应用程序就可以成批地对所需要的数据进行访问,也可以以组为单位启动或停止数据访问。其主要功能是:①管理组对象内部的状态信息;②创建和管理项对象;③OPC服务器内部的实时数据存取服务(同步或异步方式)。
OPC 服务器对象和组对象支持的接口由OPC规范定义,但并未规定具体如何实现,需要开发人员自己完成。
OPC项则与现场设备中的模块相对应,它包含数据项的值(value)、品质(quality)和时间戳(time stamp)。
I/O DLL是针对具体硬件设备开发的驱动程序,实现从现场设备读取数据的功能。
2.2 实现OPC数据访问服务器的主要步骤:
2.2.1 获得并注册OPC标准组件
根据COM规范,COM服务器可分为进程内服务器、本地服务器和远程服务器。后两种服务器与客户程序运行在不同的进程空间,属于进程外服务器。为了实现进程间通讯,需要用到代理/存根模块。代理/存根模块由接口描述语言(IDL)直接生成。OPC基金会为每种OPC服务器提供了相应的代理/存根动态链接库,这些文件可以在OPC基金会的网站(www.opcfoundation.org)上免费下载。
注意,设计OPC服务器时可以在OPC对象上增加接口以满足特定的要求,但不能修改标准的OPC IDL文件或相应的 proxy/stub DLL。新增的接口描述应定义在独立的IDL文件中,并由该文件生成独立的代理/存根模块来完成接口的调用工作。
组件的注册将在后面介绍。
2.2.2 编写OPC服务器代码
首先定义0PC数据服务器的名称(ProgID)和类标识(CLSID),实现COM库的初始化功能和0PC数据服务器类厂对象的接口功能。然后实现OPC对象和数据缓冲区。接下来针对具体硬件编写I/O DLL,实现数据的实时读取。这项工作是十分繁重的,要求开发人员具有良好的COM编程知识,具体过程限于篇幅不能详述,这里指出两点引起注意:
⑴全局唯一标识符(GUID)
GUID是为每个COM对象提供的十六字节标识数。COM类至少有两个GUID:类标识(CLSID)和接口标识(IID)。CLSID用于标识COM类,登记在Windows注册表中,包含指向包括COM类的DLL或EXE组件的路径。IID用于标识该类的接口,被应用程序用来查询和触发该类的方法,也登记在注册表中。由于对象类是由GUID标识的,所以必须保证它们的唯一性,才能使最终用户在使用由不同软件商开发的组件时不会发生冲突。
可以使用宏DEFINE_GUID (name , long , word , word , word , byte1 , … ,byte8 )
其中 name 是标识数的名字,其余参数是实际的ID码。类标识的命名惯例是CLSID_ClassName ,而接口ID的命名惯例是IID_InterfaceName。
有两种途径来获得GUID:
①Microsoft Visual C++提供了两个工具来产生GUID:UUIDGen.exe和GUIDGen.exe(大小写没有影响)。前者是一个命令行程序,直接产生一个GUID;后者是一个基于对话框的应用程序,运行UUIDGen.exe,产生一个Create GUID对话框。它提供四种格式,选定之后,按New GUID键产生新的GUID,显示在Result栏中;按Copy键可以复制产生的结果。
②利用COM库提供的API函数来产生GUID:
HRESULT CoCreateGuid (GUID *pguid )
如果创建GUID成功,则函数返回S_OK,并且pguid将指向所得到的GUID值。