您的位置:控制工程论坛网论坛 » 自动化软件 » OPC数据服务器开发工具研究与实现

马军成

马军成   |   当前状态:在线

总积分:13914  2024年可用积分:0

注册时间: 2006-12-01

最后登录时间: 2022-06-28

空间 发短消息加为好友

OPC数据服务器开发工具研究与实现

马军成  发表于 2006/12/15 19:32:31      5993 查看 1 回复  [上一主题]  [下一主题]

手机阅读

OPC数据服务器开发工具研究与实现
作者: linyue ,

   [关键词] OPC、OPC数据服务器、开发工具
  [Key Words] OPC、OPC Data Access Server、Toolkit
  [摘要] 介绍了OPC技术,结合OPC数据服务器设计原型,提出了OPC服务器开发工具的设计方案,并给出了开发工具的接口函数集合。
  [Abstract] The technology of OPC is expounded. Combined with the model of OPC data access server,the scheme of OPC data access server toolkit is adopted. In addition ,the interface functions of OPC toolkit are designed.
  1.引言
  OPC(OLE for Process Control)是过程控制业中的新兴标准,它的出现为基于Windows的应用和基于现场控制的应用建立了桥梁。在过去,为了存取现场设备的数据信息,每一个应用软件开发商都需要编写专用的接口函数。由于现场设备的种类繁多,且产品的不断升级,往往给用户和软件开发商带来了巨大的工作负担。通常这样也不能满足工作的实际需要,系统集成商和开发商急切需要一种具有高效性、可靠性、开放性、可互操作性的即插即用的设备驱动程序。在这种情况下,OPC标准应运而生,OPC技术的出现把开发访问设备接口的任务放在硬件生产厂家或第三方厂家,以OPC服务器的形式提供给用户,解决了软、硬件厂商的矛盾,完成了系统的集成,提高了系统的开放性和可互操作性。
  2.OPC技术与OPC数据服务器接口分析
  OPC数据服务器是以MicroSoft公司的OLE/COM/DCOM技术为依托,采用客户/服务器模式,是过程控制应用中的“软件总线”。基于OPC技术的工业软件模块自由的分布在这条软总线上,现场数据对于软件模块完全透明,软件模块可以分布在网络上的不同接点。OPC技术不仅可以灵活的应用于工控软件体系结构的各个层次,同时OPC技术也可以作为任何软件模块间数据通信的标准接口,图1是OPC技术的典型使用。OPC标准的产生将使得整个控制软件体系更趋于合理,系统的开放性和可互操作性将得到进一步的体现。
  
  OPC规范的主要目的是为了统一、标准的描述用户数据源,用户数据源可能来自于现场的硬件设备,也可能来自于某些软件模块。对于OPC客户端应用,OPC服务器表现为具有一些特定功能的COM对象集合,而这些特定功能就是OPC规范的技术细节。OPC技术细节的制定完全是为了满足设备间的互操作性,因此它们的实现完全可以脱离具体设备,或通过一些编程机制独立于具体设备。那么那些功能是依赖于设备,那些功能又是相对独立的呢?可以具体分析一下OPC数据服务器及其提供的标准接口。
  OPC数据服务器定义了两种标准的COM对象,即OPC Server 、OPC Group对象。通过实现这两种标准的COM对象及相应接口,用户就完成了OPC数据服务器的开发。OPC Server对象,是客户端软件与服务器交互的首要对象。客户端访问OPC Server对象的接口函数组织管理OPC Group对象,OPC Group对象用于组织管理服务器内部的实时数据信息。在OPC标准中使用Items对象描述实时数据,Items是非COM对象,是客户端不可见的对象。
  OPC Server对象功能主要表现为:1)创建和管理OPC Group对象;2)管理服务器内部的状态信息;3)将服务器的错误代码翻译成描述性语句;4)浏览OPC服务器内部的数据组织结构。从OPC Server对象的功能可以看出,OPCServer对象面向OPC服务器的技术细节,基本独立于实时数据源,可以统一实现,其中数据的组织结构与数据源属性与具体数据源有关,需要从用户处获取信息。
  OPC Group对象的主要功能表现为:1)管理OPC Group对象的内部状态信息;2)创建和管理Items对象。3)OPC服务器内部的实时数据存取服务(同步与异步方式)。从OPC Group对象的功能可以看出,该对象面向OPC服务器中的数据存取信息,对实时数据源的依赖性很强,需要从用户数据源处获取信息。
  3.OPC数据服务器设计
  OPC数据服务器的设计与实现是一个较为复杂与繁重的任务。设计者既需要有很高的编程水平,同时也必须掌握相应的硬件产品特性。
  OPC数据服务器的设计可以分解为不同的功能模块(图二)。OPC/COM接口管理、OPCGroup与Item管理、Item数据管理与检测模块的基本功能是完成OPC的标准接口功能,在OPC服务器的开发中,存在着共性,可以统一设计,形成可以推广的OPC数据服务器开发工具。专用设备通信协议与管理模块是依赖于具体的数据源,对于不同的服务器,该模块是不同的,应该单独设计。因此,基于软件组件化的设计思想,OPC数据服务器的开发是可以工具化的,关键是明确、完善的定义模块间的通信接口,既能保证服务器符合OPC国际标准,又能合理的同数据源特性联系起来,为用户提供高度的灵活性。
  4.OPC数据服务器开发工具实现
  OPC服务器开发工具的目的是将MicroSoft公司的OLE/COM/DCOM技术和OPC的技术细节隐藏起来,使用户开发OPC服务器的工作集中在自己特定的数据采集任务上来。目前,OPC数据服务器开发工具在国际工业控制领域中使用已经相当广泛,比较著名的供应厂商有FactorySoft、Softing等公司,这些开发工具的价格十分昂贵 。OPC服务器开发工具通常分为原码级开发工具和快速开发工具两种。原码级开发工具包括OPC服务器的全部原码(一般使用的编程语言为VC++),和实现例程。这种开发工具比较灵活,方便用户根据需要定制开发,但是使用起来对用户的要求很高,要求用户通常有良好的编程能力。另一种开发工具是快速开发工具,快速开发工具一般是以动态连接库(DLL)形式提供给用户,用户只要按照动态连接库中提供的应用编程接口(API)即可完成OPC服务器的开发,这种开发工具使用简单,虽然缺少一些灵活性,但通常能够满足多数用户的开发需求。下面将根据OPC数据存取服务器的接口要求,讨论一个完整的OPC数据服务器快速开发工具原型,给出一组OPC数据服务器开发工具需要实现的函数集合。
  1. OPC数据存取服务器快速开发工具原型
  根据上述的分析及OPC服务器设计框图,将OPC服务器开发工具的编程接口按功能划分成三大类:
  1) OPC数据与属性管理,组织OPC数据服务器的浏览地址空间,提供OPC数据的属性管理。
  2)OPC实时数据管理,提供OPC服务器的实时数据读写功能。
  3)OPC服务器管理,提供OPC服务器的启动/停止、注册等功能。
  实现这些功能,基本完成了OPC数据服务器开发工具的设计工作。图三是OPC数据服务器快速开发工具原型。采用OPC开发工具后,用户根据数据源的特性和特有的数据通信协议进行数据采集,编写数据采集程序,更新OPC服务器中的实时数据,将OPC服务器开发的工作进一步集中到数据扫描与优化处理任务上。
  
  
  2. OPC数据存取服务器快速开发工具API定义
  在实际设计中,我们定义了一组函数集合,描述了用户数据采集程序与OPC服务器之间的编程接口,现简单归纳如下:
  1) 开发工具初使化API
  BOOL InitServerDLL(HINSTANCE hInstance, CLSID* pCLSID, UINT UpdateRate, CString vendorInfo, CString progId, CString versionId, CString description );
  在使用开发工具之前,必须使用初使化函数对开发工具进行初使化,提供OPC服务器刷新率、OPC服务器的程序信息(如CLSID)、服务器的版本信息等。
  2) 注册与注册删除API。
  HRESULT RegisterOPC(void);
  HRESULT UnRegisterOPC(void);
  向注册表提供OPC服务器的注册信息,支持OPC服务器的浏览及远程访问。
  3) 启动/停止OPC开发工具API及获取开发工具的运行状态API。
  BOOL StartServerDLL()
  BOOL StopServerDLL();
  BOOL ServerDLLInUse();
  在用户程序退出之前,应该获取OPC服务器的运行状态,检查是否有OPC客户与服务器连接,决定是否退出程序。用户可以调用 ServerDLLInUse() 函数,观察是否有OPC客户程序与OPC服务器连接。
  4) OPC服务器变量写值API
  HRESULT WriteCallback( WRITEPROC lpCallback);
  为了完成OPC客户程序对现场设备中参数的修改,用户程序需要提供相应的函数指针,供OPC工具调用。用户可以利用回调函数完成设备参数的修改工作。
  5) 添加及删除数据变量API
  HANDLE AddTag(CString name,VARIANT value,BOOL readOnly);
  BOOL RemoveTag(HANDLE hTag);
  数据变量是用户提供给OPC客户的数据访问点,用户程序需要维护数据点的变化,根据现场数据的变化及时更新。同时利用变量的命名规则定义OPC服务器的浏览地址空间,如使用“.”表示树状结构的分枝,变量名称为FI302.VFD.AI.MODE.TARGET。
  6) 数据变量的更新API
  BOOL UpdateTag(HANDLE handle,VARIANT& var,WORD quality,FILETIME timeStamp);
  用户通过更新函数可以及时更新和维护开发工具中已经添加的数据变量的值、时间戳、质量。
  5.总结
   OPC开发工具的出现,方便了工业控制软件中的设计与集成,缩短了产品的开发周期。优秀的OPC开发工具将是国内工业控制领域中必不可少的工具软件。同时OPC标准的本身也在不断的改进,其范围也越来越广。OPC基金会现在已经颁布了数据访问和报警事件标准,其它的OPC标准,如历史数据OPC标准,也正在酝酿之中。OPC基金会发布的与微软公司BizTalk体系兼容的XML(Extensible Markup Laguage)纲要,将Internet技术应用在工业控制中。相信在不久的将来,OPC技术及标准将应用于更加广泛的领域,OPC开发工具也将向着多元化发展。OPC技术必将赋予现代工业控制软件更强的生命活力。
  参考文献
  1 Al Chisholm, A Technical Overview of the OPC Data Access Interface, ISA EXPO 98
  2 OPC Foundation,OPC Data Access Custom Interface Standard ,Version 2.0。
  3 OPC Foundation,OPC Data Access Automation Interface Standard ,Version 2.0。
  4 OPC Foundation, Overview,Version 1.0。
  
  文章支持: 国家“九五”重点攻关项目《新一代全分布式控制系统研究与开发》
1楼 0 0 回复
  • shangzh

    shangzh   |   当前状态:在线

    总积分:74  2024年可用积分:0

    注册时间: 2009-07-20

    最后登录时间: 2012-12-01

    空间 发短消息加为好友

    shangzh   发表于 2011/5/10 9:38:20



    提供性能稳定,易开发,价格低廉的OPC开发套件,支持DA 1.0,2.0,3.0,包括服务器端和客户端开发包Ver3.8


    OPC服务器端开发包下载地址:http://www.xdowns.com/soft/38/110/2011/Soft_72907.html

    OPC客户端端开发包下载地址:http://www.oyksoft.com/soft/18132.html

    OPC开发包详情:http://item.taobao.com/item.htm?id=9474686238


    //OPC服务器端API部分接口定义

    /// <summary>
    /// 初始化系统运行参数和分配服务器资源
    /// </summary>
    /// <param name="lpCLSID_Svr">服务器标示,以NULL结尾</param>
    /// <param name="uServerRate">服务器支持的客户端最快异步刷新速率</param>
    /// <returns>TRUE成功,FALSE失败</returns>
    BmOpcDaSvr_API  BOOL __stdcall  CreateServer(LPCSTR lpCLSID_Svr, unsigned long uServerRate);

    /// <summary>
    /// 释放服务器资源
    /// </summary>
    /// <returns>void</returns>
    BmOpcDaSvr_API  VOID __stdcall  FreeServer();

    /// <summary>
    /// 构造服务器地址空间(标签列表的组织形式)
    /// </summary>
    /// <param name="hTag">父标签句柄,对于构造平面型地址空间(只有一层的地址空间),hTag=0;对于树型地址空间的第一层节点,hTag=0</param>
    /// <param name="lpName">标签名称</param>
    /// <param name="Value">标签的初始值,其中vt域所定义的数据类型被自动认为为该标签的标准数据类型,如果想修改改标签数据类型,请调用SetTagProperty函数</param>
    /// <param name="wQuality">标签的初始数据质量</param>
    /// <param name="AccessRight">访问权限,0-不能读写(例如树型空间的枝干节点),1-只读,2-只写,3-可读可写</param>
    /// <returns>标签句柄</returns>
    BmOpcDaSvr_API  unsigned long __stdcall  RegTag(unsigned long hTag,LPCSTR lpName,VARIANT Value,unsigned short wQuality,unsigned short AccessRight);


    /// <summary>
    /// 构造服务器地址空间(标签列表的组织形式)
    /// 函数增加新节点,设置标签数据类型和初始化标签值(按照给定数据类型),设置数据质量=64(不确定)
    /// </summary>
    /// <param name="hTag">父标签句柄,对于构造平面型地址空间(只有一层的地址空间),hTag=0;对于树型地址空间的第一层节点,hTag=0</param>
    /// <param name="lpName">标签名称</param>
    /// <param name="wDatatype">标签的数据类型,3-Integer 4-Single 5-Double  8-String 11-Boolean</param>
    /// <param name="AccessRight">访问权限,0-不能读写(例如树型空间的枝干节点),1-只读,2-只写,3-可读可写</param>
    /// <returns>标签句柄</returns>
    BmOpcDaSvr_API  unsigned long __stdcall  RegTagEx(unsigned long hTag,LPCSTR lpName,unsigned short wDatatype,unsigned short AccessRight);

    /// <summary>
    /// 删除标签,尽量避免调用此函数
    /// </summary>
    /// <param name="hTag">服务器标识</param>
    /// <returns>TRUE成功,FALSE失败</returns>
    BmOpcDaSvr_API  BOOL __stdcall  UnregTag(unsigned long hTag);

    /// <summary>
    /// 设置地址空间路径分隔符
    /// </summary>
    /// <param name="Qualifier">树型地址空间标签全路径分隔符,默认为'.'</param>
    /// <returns>TRUE成功,FALSE失败</returns>
    BmOpcDaSvr_API  BOOL __stdcall  SetTagQualifier(char Qualifier);

    /// <summary>
    /// 增加标签支持的属性
    /// </summary>
    /// <param name="hTag">标签句柄</param>
    /// <param name="lpName">属性名称</param>
    /// <param name="dwPropertyID">属性标识,默认支持6个属性,例如报警限、说明、条件等</param>
    /// <param name="lpDescription">属性描述</param>
    /// <param name="value">属性值</param>
    /// <returns>TRUE成功,FALSE失败</returns>
    BmOpcDaSvr_API  BOOL __stdcall  AddTagProperty(unsigned long hTag,LPCSTR lpName,unsigned long  dwPropertyID,LPCSTR lpDescription,VARIANT value);

    /// <summary>
    /// 增加标签支持的属性
    /// 属性值按照属性值数据类型进行初始化
    /// </summary>
    /// <param name="hTag">标签句柄</param>
    /// <param name="lpName">属性名称</param>
    /// <param name="dwPropertyID">属性标识,默认支持6个属性,例如报警限、说明、条件等</param>
    /// <param name="lpDescription">属性描述</param>
    /// <param name="wDataType">属性值数据类型</param>
    /// <returns>TRUE成功,FALSE失败</returns>
    BmOpcDaSvr_API  BOOL __stdcall  AddTagPropertyEx(unsigned long hTag,LPCSTR lpName,unsigned long  dwPropertyID,LPCSTR lpDescription,unsigned short wDataType);

    /// <summary>
    /// 更新标签的属性值
    /// </summary>
    /// <param name="hTag">标签句柄</param>
    /// <param name="dwPropertyID">属性标识</param>
    /// <param name="Value">属性值</param>
    /// <returns>TRUE成功,FALSE失败</returns>
    BmOpcDaSvr_API  BOOL __stdcall  SetTagProperty(unsigned long hTag, unsigned long dwPropertyID, VARIANT Value);


    /// <summary>
    /// 更新标签的数据值和时间戳
    /// </summary>
    /// <param name="hTag">标签句柄</param>
    /// <param name="Value">标签值</param>
    /// <param name="wQuality">标签值质量</param>
    /// <param name="TimeStamp">标签刷新时间</param>
    /// <returns>TRUE成功,FALSE失败</returns>
    BmOpcDaSvr_API  BOOL __stdcall  UpdateTagWithTimeStamp(unsigned long hTag , VARIANT Value,unsigned short wQuality,FILETIME TimeStamp);

    /// <summary>
    /// 更新标签的数据值
    /// 标签的刷新时间按照OPC服务器时间设定
    /// </summary>
    /// <param name="hTag">标签句柄</param>
    /// <param name="Value">标签值</param>
    /// <param name="wQuality">标签值质量</param>
    /// <returns>TRUE成功,FALSE失败</returns>
    BmOpcDaSvr_API  BOOL __stdcall  UpdateTag(DWORD hTag, VARIANT Value,unsigned short wQuality);

    /// <summary>
    /// 设置工具包写节点的回调函数
    /// </summary>
    /// <param name="lpCallback">回调函数指针</param>
    /// <returns>TRUE成功,FALSE失败</returns>
    BmOpcDaSvr_API  BOOL __stdcall  SetWriteCallback(WRITECALLBACK lpCallback);

    /// <summary>
    /// 设置工具包写节点的回调函数,支持值之外的属性值回写
    /// </summary>
    /// <param name="lpCallback">回调函数指针</param>
    /// <returns>TRUE成功,FALSE失败</returns>
    BmOpcDaSvr_API  BOOL __stdcall  SetWriteCallbackEx(WRITECALLBACKEX lpCallback);


    //OPC客户端API部分接口定义

    /// <summary>
    /// 初始化系统运行参数和分配资源,调用此函数初始化工具包参数,分配资源等。调用此函数后工具才能正常工作。
    /// </summary>
    /// <returns>TRUE成功,FALSE失败</returns>
    BmOpcDaClt_API BOOL  __stdcall BMDAC_Init();


    /// <summary>
    /// 释放工具包占用的资源等
    /// </summary>
    /// <returns>TRUE成功,FALSE失败</returns>
    BmOpcDaClt_API BOOL  __stdcall  BMDAC_Uninit();


    /// <summary>
    /// 连接OPC服务器, 本机访问ComputerName 设为NULL即可
    /// </summary>
    /// <param name="ComputerName">主机名称或IP地址</param>
    /// <param name="ServerClassID">服务器标识,是一个GUID</param>
    /// <param name="Version">版本标志</param>
    /// <returns>服务器连接句柄</returns>
    BmOpcDaClt_API DWORD  __stdcall  BMDAC_Connect(LPCSTR ComputerName, LPCSTR ServerClassID, DWORD  Version);


    /// <summary>
    /// 断开服务器连接
    /// </summary>
    /// <param name="ServerHandle">服务器连接句柄</param>
    /// <returns>TRUE成功,FALSE失败</returns>
    BmOpcDaClt_API BOOL  __stdcall  BMDAC_Disconnect(DWORD   ServerHandle);


    /// <summary>
    /// 获取计算机上注册的OPC服务器
    /// </summary>
    /// <param name="ComputerName">主机名称或IP地址</param>
    /// <param name="Version">服务器启动时间</param>
    /// <param name="ServerNames">服务器当前时间</param>
    /// <param name="ServerClassIDs">最后数据更新时间</param>
    /// <returns>服务器数量</returns>
    BmOpcDaClt_API DWORD  __stdcall  BMDAC_GetServers(LPCSTR    ComputerName, DWORD     Version, VARIANT*  ServerNames, VARIANT*  ServerClassIDs);



    /// <summary>
    /// 获取服务器的地址空间类型
    /// </summary>
    /// <param name="ServerHandle">服务器连接句柄</param>
    /// <param name="NameSpace">服务器启动时间,OPC_NS_HIERARCHIAL=1;树型地址空间  OPC_NS_FLAT=2;平面型地址空间</param>
    /// <returns>TRUE成功,FALSE失败</returns>
    BmOpcDaClt_API BOOL  __stdcall  BMDAC_GetNameSpace(DWORD   ServerHandle,WORD*   NameSpace);



    /// <summary>
    /// 移动当前浏览节点
    /// </summary>
    /// <param name="ServerHandle">服务器连接句柄</param>
    /// <param name="Direction">移动方向,OPC_BROWSE_UP  =1   移动到上级节点,忽略NodeName  OPC_BROWSE_DOWN =2   移动到下级节点 OPC_BROWSE_TO   =3   直接移动到某一个节点</param>
    /// <param name="NodeName">节点名称</param>
    /// <returns>TRUE成功,FALSE失败</returns>
    BmOpcDaClt_API BOOL  __stdcall  BMDAC_ChangeBrowsePosition(DWORD   ServerHandle,WORD  Direction,LPCSTR  NodeName);


    /// <summary>
    /// 过滤检索节点
    /// </summary>
    /// <param name="ServerHandle">服务器连接句柄</param>
    /// <param name="FilterType">节点类型过滤,1 枝节点,  2 叶节点</param>
    /// <param name="FilterString">节点名称过滤</param>
    /// <param name="FilterDataType">数据类型过滤</param>
    /// <param name="FilterAccessRight">访问权限过滤, 0- 不能读写  1- 只读  2- 只写  3- 可读可写</param>
    /// <param name="ItemNames">节点名称</param>
    /// <returns>返回满足条件的节点个数</returns>
    BmOpcDaClt_API DWORD  __stdcall  BMDAC_BrowseItems(DWORD   ServerHandle,WORD    FilterType,LPCSTR  FilterString,WORD    FilterDataType,WORD   FilterAccessRight,VARIANT* ItemNames);

    /// <summary>
    /// 增加组
    /// </summary>
    /// <param name="ServerHandle">服务器连接句柄</param>
    /// <param name="Name">标签全名</param>
    /// <param name="Active">属性标识</param>
    /// <param name="UpdateRate">属性值</param>
    /// <param name="TimeBias">属性值</param>
    /// <param name="DeadBand">属性值</param>
    /// <param name="dsLCID">属性值</param>
    /// <returns>组句柄</returns>
    BmOpcDaClt_API DWORD  __stdcall  BMDAC_AddGroup(DWORD ServerHandle, LPCSTR Name, BOOL Active, DWORD UpdateRate, DWORD TimeBias,float DeadBand, DWORD dsLCID);

    /// <summary>
    /// 注册标签
    /// </summary>
    /// <param name="ServerHandle">服务器连接句柄</param>
    /// <param name="GroupHandle">组句柄</param>
    /// <param name="ItemFullName">标签全名</param>
    /// <returns>标签句柄</returns>
    BmOpcDaClt_API DWORD  __stdcall  BMDAC_AddItem(DWORD   ServerHandle,DWORD   GroupHandle,LPCSTR  ItemFullName);


    /// <summary>
    /// 写入标签
    /// </summary>
    /// <param name="ServerHandle">服务器连接句柄</param>
    /// <param name="GroupHandle">组句柄</param>
    /// <param name="ItemHandle">标签句柄</param>
    /// <param name="Value">写入值</param>
    /// <param name="DoAsync">写入方式,true 异步写入   false 同步写入</param>
    /// <returns>TRUE成功,FALSE失败</returns>
    BmOpcDaClt_API BOOL  __stdcall  BMDAC_WriteItem(DWORD   ServerHandle,DWORD   GroupHandle,DWORD ItemHandle,VARIANT  Value, BOOL     DoAsync);


    /// <summary>
    /// 读取标签
    /// </summary>
    /// <param name="ServerHandle">服务器连接句柄</param>
    /// <param name="GroupHandle">组句柄</param>
    /// <param name="ItemHandle">标签句柄</param>
    /// <param name="Value">标签句柄</param>
    /// <param name="pTimeStamp">标签句柄</param>
    /// <param name="pQuality">标签句柄</param>
    /// <returns>TRUE成功,FALSE失败</returns>
    BmOpcDaClt_API BOOL  __stdcall  BMDAC_ReadItem(DWORD   ServerHandle,DWORD   GroupHandle,DWORD ItemHandle,VARIANT*  Value, FILETIME* pTimeStamp,WORD*    pQuality);




      

    2楼 回复本楼

    引用 shangzh 2011/5/10 9:38:20 发表于2楼的内容

总共 , 当前 /