VBOPC控件设计说明文档_第1页
VBOPC控件设计说明文档_第2页
VBOPC控件设计说明文档_第3页
VBOPC控件设计说明文档_第4页
VBOPC控件设计说明文档_第5页
已阅读5页,还剩54页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

VBOPC控件设计说明文档装配与检测自动化事业部如何建立OPC服务器与PLC的S7连接以及如何使用VB版OPC控件的说明书1软硬件环境1(1软件环境:1,Windows2000或WindowXP操作系统2)SIMATICNETPCSOFTWAREV6.2及授权3)STEP7V5.3+SP3或以上版本及授权4,VisualBasic6.0编程软件注:以上软件安装顺序无要求。1.2硬件:1)CP1613或普通10/100自适应以太网卡2)普通网线3,PS307(6ES7307-1EA00-0AA0)4)CPU315-2DP(6ES7315-2AG10-0EX0)5)CP343-1Lean,6GK7343-1CX10-0XE0,2(OPC服务器配臵2.1配臵PC站的硬件机架,当SIMATICNET软件成功安装后~在PC机桌面上可看到StationConfigurator的快捷图标~同时在任务栏(Taskbar)中也会有StationConfigurationEditor的图标。图1:StationConfigurator桌面快捷图标双击StationConfigurationEditor图标~打开配臵窗口1装配与检测自动化事业部图2StationConfigurationEditor配臵窗口1)在1#槽中插入OPCServer图3:添加OPCServer2)在3#槽中插入IE-General,插入IEGeneral后~即弹出其属性对话框。2装配与检测自动化事业部图4:添加IE-General3)点击NetworkProperties~进行网卡参数配臵,如IP地址~子网掩码等。图5:配置IE-General属性3装配与检测自动化事业部图6配臵网络属性图7配臵Internet属性4)当网卡配臵完成后~点击StationConfigurationEditor中的“StationName”按钮~指定PC站的名称~这里命名为ethernetopc。点击“OK”确认即完成了PC站的硬件组态。4装配与检测自动化事业部图8:命名PC站名称2(2配臵控制台,ConfigurationConsole,的使用与设臵1)配臵控制台,ConfigurationConsole,是组态设臵和诊断的核心工具~用于PC硬件组件和PC应用程序的组态和诊断。2)正确完成PC站的硬件组态后~打开配臵控制台~在控制台检测到OPC服务器的配臵后~就可以看到所用以太网卡的模式已从PGmode切换到Configurationmode,插槽号,Index,也自动指向3。如下图。1.5装配与检测自动化事业部图9配臵控制台,ConfigurationConsole,3)在AccessPoints设定窗口中~将S7ONLINE指向PCinternal(local)。此设定是为PC站组态的下载做准备。图10:PCStation配置控制台AccessPoint2(3在STEP7中组态PCStation1)打开SIMATICManager~通过File->New创建一个新项目。通过Insert->Station->SimaticPcStation插入一个PC站。图11在STEP7中插入PCStation6装配与检测自动化事业部2)在硬件组态中~从硬件目录窗口选择与已安装的Simaticnet软件版本相符的硬件插入到与在StationConfigurationEditor配臵的PC硬件机架相对应的插槽中。图12配臵PCStation3)分配普通以太网络参数点击IEGeneral属性对话框中Properties按钮打开以太网接口参数设臵对话框,按要求设臵以太网卡的IP地址和相应的子网掩码。IP地址应与实际硬件所设以太网卡IP地址一致。并用New按钮建立一个ethernet网络。确认所有组态参数~完成网卡设臵。7装配与检测自动化事业部图13在PCStation中配臵IE-General属性4)完成PC站组件设臵后~按下编译存盘按钮确定且存储当前组态配臵5)插入一个S7300站,通过Insert->Station->Simatic300Station,在相应的槽中插入,电源模块、CPU、cp343,1等~并cp343,1的属性窗口中配臵ip地址~子网掩码等参数~完成硬件组态.图14配臵S7-300站6)编译无误后~点击“ConfigureNetwork”按钮~进入NetPro配臵窗口。7)在NetPro网络配臵中~用鼠标选择OPCServer后在连接表第一行鼠标右键插入一个新的连接或通过“Insert>NewConnection”也可建立一个新连接。8装配与检测自动化事业部图15在NetPro网络配臵中加入一个新连接如果在同一STEP7项目中~所要连接的PLC站已经组态完成~即PLC以太网通讯处理器,CP343-1orCP443-1,网络已经使能~在选择“InsertNewConnection”后~连接会自动创建。图16S7连接属性8)确认所有配臵后~已建好的S7连接就会显示在连接列表中。点击编译存盘按9装配与检测自动化事业部钮或选择Network>SaveandCompile~如得到Noerror的编译结果~则正确组态完成。这里编译结果信息非常重要~如果有警告信息,Warning,显示在编译结果对话框中~这仅仅是一条信息。但如果有错误信息,errorMessage,~说明组态不正确~是不能下载到PCStation中的。图17组态编译存盘2(4完成PC站组态后~即可在NetPro窗口点击功能按钮栏中下载按钮将组态下载到PC站中。需注意的是~下载过程中会删除已有相关组件的数据~新的组态数据将被下载到PC机。点击OK执行下载。下载完成后~可以打开StationConfigurationEditor窗口Conn一栏一定要有连接图标~检查组件状态。下图为正确状态显示画面。OPCServer插槽此项说明连接激活。10装配与检测自动化事业部图18PCStation运行状态3(OPC控件说明OPC(OLEforProcessControl—用于过程控制的对象连接与嵌入)是一套以微软对象连接与嵌入OLE、组件对象模型COM、分布式组件对象模型DCOM(DistributedCOM)技术为基础~基于Windows操作平台~为工业应用程序之间提供高效的信息集成和交互功能的组件对象模型接口标准。OPC实际上是提供了一种机制~通过这种机制~系统能够以服务器/客户端标准方式从服务器获取数据并将其传递给任何客户应用程序。这样~只要生产商开发一套遵循OPC规范的服务器与数据进行通信~其他任何客户应用程序便能通过服务器访问设备。OPC服务器有两类接口:定制接口和自动化接口。定制接口为C++程序服务~自动化接口为VB这一类可使用自动化对象的程序服务。定制接口是服务商必须提供的~而自动化接口则是可选的~不过OPC基金会提供了一个叫做“自动化包装器”的动态连接库~用于在两者间转换。OPC数据存取规范规定的基本对象有三类:服务器(server)、组(group)和数据项(item)。服务器对象包含服务器的所有信息~也是组对象的容器~一个服务器对应于一个OPCserver~即一种设备的驱动程序。组对象除了包含它自身信息外~还负责管理数据项。每一个数据项代表到数据源的一个连接~但它没有提供外部接口~客户端程序无法对数据项直接进行操作~应用程序必须依靠数据项的容器组对象来对它进行操作。该控件的主要属性有OPCServerName、OPCGroupName、OPCBufferSize、OpcLinkStatus、OPCstartAddress~其中~OPCServerName用于配臵服务器(server)名称,OPCGroupName用于配臵组(group)名称,OPCstartAddress用于配臵连接到控件的PLC变量的起始地址,OPCBufferSize用于配臵PLC变量的长度,OpcLinkStatus用于显示OPC控件的连接状态~连接正常~则该参数为0~若该参数不为0~则连接出现问题~在该情况下~可通过编程先11装配与检测自动化事业部调用OPCDisconnect,,断开与OPC服务器的连接~再调用OPCLink,,重新连接OPC服务器。该控件的方法主要有OPCLink,,、OPCGetData,ByrefData,,asVarriant~ByvalLenasInteger,、OPCSentData,ByrefData,,asVarriant~ByvalLenasInteger,、OPCDisconnect,,~其中~OPCLink用于连接服务器(server)添加组,GROUP,和数据项(ITEM),OPCGetData,ByrefData,,asVarriant~ByvalLenasInteger,用于读取OPC服务器的数据~数组Data用于接受数据~Len指定数据长度,OPCSentData,ByrefData,,asVarriant~ByvalLenasInteger,用于向OPC服务器发送数据~数组Data用于存放被发送的数据~Len指定数据长度,OPCDisconnect,,用于断开与OPC服务器的连接。4(OPC控件使用举例4(1添加控件在VB环境中~按“工程”的子菜单“控件…”后~弹出对话框图19添加工程部件对话框12装配与检测自动化事业部图20添加Opclinker控件点击浏览按钮在添加ACTIVEX控件窗口中找到C:\WINNT\SYSTWM32下的OPCLINKER.OCX文件~点击打开~后点击部件窗口中的确定按钮~即加入控件。加入后效果如下图所示:13装配与检测自动化事业部图21添加控件后的效果4(2应用例程:PrivateSubCommand1_Click()Dimrecv(9)AsVariantOPCLinker1.OpcGetDatarecv,8Text1.Text=CStr(recv(1))Text2.Text=CStr(recv(2))Text3.Text=CStr(recv(3))Text4.Text=CStr(recv(4))Text5.Text=CStr(recv(5))Text6.Text=CStr(recv(6))Text7.Text=CStr(recv(7))Text8.Text=CStr(recv(8))EndSubPrivateSubCommand2_Click()Dimsent(9)AsVariantsent(1)=Val(Text1.Text)sent(2)=Val(Text2.Text)sent(3)=Val(Text3.Text)sent(4)=Val(Text4.Text)sent(5)=Val(Text5.Text)sent(6)=Val(Text6.Text)sent(7)=Val(Text7.Text)sent(8)=Val(Text8.Text)OPCLinker1.OpcSendDatasent,8EndSubPrivateSubForm_Load()OPCLinker1.LinkEnble=TrueOPCLinker1.OpcLinkEndSub附录1:网络文章《ActiveX控件的创建》,web地址:www_xiameng_net.htm,作者:互联网文章来源:互联网点击数:1097更新时间:2005-10-1414装配与检测自动化事业部1,概述ActiveX是一个Microsoft的术语~它指的是一组包括控件~DLL和ActiveX文档的组件~它通常是以动态链接库的形式存在,因此必须在一个叫容器的独立执行软件中运行。这样的容器包括Authorware、Delphi~VisualBasic~VisualC,,~InternetExplorer和Access等等。ActiveX控件数据输入和函数功能执行都必须通过容器~因此ActiveX控件和容器都必须支持一些特定的接口协议。根据Microsoft相应的规格标准~ActiveX控件应具备如下的性能机制。属性和方法:ActiveX控件必须提供属性的名称、方法的名称及参数,通过这项机制容器可以存取和改变ActiveX控件的属性参数。事件:ActiveX控件由这项机制通知容器在ActiveX控件中发生的事件~比如属性参数的改变~用户按下鼠标左键等。存储:容器由这项机制通知ActiveX控件存储和提取有关信息数据等。ActiveX控件只要在Windows的Registry数据库中注册后~就可以像其他Windows应用程序一样发挥各自的功能。ActiveX控件是一个模块化的灵活对象,如果某个应用程序或网页需要增加一项特殊的功能~无须重写整个程序~只要灵活地插入一个具有此项功能的ActiveX控件即可实现。ActiveX的优势还在于它的动态可交互性~用户可以动态地在使用过程中~通过改变它的属性和参数~在应用程序中实现自己的特殊要求。也许有的读者会问:目前在市面上可以找到各种各样现成的ActiveX控件~还有没有必要自己创建ActiveX控件呢,关于这个问题很容易解释~现有的控件种类是很多~功能也比较齐全~问题是有许多时候会遇到这种情况:使用现成的控件虽能完成任务~但自己需要的一些特性,属性、事件或方法,该控件却没有提供~还需要自己手工写代码来实现~而这些特性偏偏在自己的应用系统中又经常会用到~为了避免大量的重复劳动~一劳永逸的办法就是在创建自己的ActiveX控件。目前可以使用VisualBasic或其它开发工具创建ActiveX控件。无论按照哪种标准~VisualBasic都是计算机历史上最为成功的,同时也是最流行的,编程语言~其中最令人兴奋的特性就是可以创建用户自己的控件并可以像其他控件一样应用于支持ActiveX控件技术的应用程序中。下面通过一个具体实例来阐述如何在VisualBasic6.0,中文企业版,下进行ActiveX控件创建。2,创建ActiveX控件的步骤15装配与检测自动化事业部使用VisualBasic编程语言编写过应用程序的用户~一定非常熟悉诸如TextBox、Label和Data等控件。要利用这些控件~可以将它们绘制在窗体中~通过属性~方法和事件控制它们的行为。当用户创建自己的ActiveX控件时~除了确定属性、方法和事件以外~用户是在创建一个相似的对象。当创建了自己的ActiveX控件以后~就可以在其他VisualBasic工程中使用它~就像使用TextBox控件一样。可以在能使用ActiveX控件的任何应用程序或开发工具,包括其他VisualBasic工程、Authorware或者MicrosoftInternetExplorer,中使用自己的控件。在VisualBasic中创建一个ActiveX控件不同于创建一个StandardEXE应用程序。因此当创建一个新控件时~一般应遵循的步骤是:,1,确定控件将要提供的功能。因为ActiveX控件类似于一个独立的对象~所以需要明确这个对象的目的~希望它在屏幕上有什么样的外观,使用此控件时~需要什么属性、方法以及事件用于应用程序中,,2,设计控件的外观。,3,设计控件的接口~即属性、事件和方法。,4,创建由控件工程和测试工程组成的工程组。,5,通过把控件和或代码添加到UserControl对象中来实现控件的外观。,6,实现控件的接口和功能。,7,编译控件部件,.ocx文件,。下面按照上述步骤建立一个可直接显示数据库内容的DataListView控件。3,具体实现方法,1,确定DataListView控件的功能标准的ListView控件在显示数据库记录时还存在一些不足~如必须编写大量的代码等~DataListView通过在ListView的基础上添加部分功能而弥补了ListView的不足~因此它除了本身固有的属性、方法和事件外~添加了如下成员:?DataServerName属性--确定所操作的数据库服务器。?DataBaseName属性--确定所操作的数据库。?AdministratorName属性--确定操作数据库的管理员名称。?PasswordName属性--确定操作数据库的管理员口令。?ShowDataBase方法--显示Select命令所执行的数据库操作结果。?ErrorDataBase事件--当遇到错误的数据库操作时引发该事件。,2,设计控件的外观DataListView由于仅包含一个ListView控件~所以其外观没有太多需要考虑的问题。16装配与检测自动化事业部如果要创建的控件是多个控件构成~或新控件不包括任何现存控件即完全从头开始创建一个全新的控件的话~则外观问题是一个很重要的问题。,3,设计控件的接口~即属性、事件和方法对ListView控件所作的改进是为了让ListView控件支持数据库的内容显示,以便在所有能支持ActiveX控件的应用程序中使用。通过添加用户自己的属性DataServername、DataBaseName、AdministratorName、PasseordName和方法ShowDataBase等可以实现这项功能。DataListView的其他属性、事件和方法都和标准ListView一样。,4,创建由控件工程和测试工程组成的工程组?启动一个新的ActiveX控件工程。?按下CTRL+T组合键或者选择【工程】|【部件】菜单选项~显示【部件】对话框~在【控件】选择框中选择MicrosoftWindowsCommonControls6.0。?选择【工程】|【引用】菜单选项~显示【引用】对话框~在【可用的引用】选择框中选择MicrosoftActiveXDataObjects2.0Library。?在UserControl窗口中添加一ListView控件~ListView控件的左上角位臵为0~0。?设臵ActiveX工程和UserControl控件属性值~如下表所示。条目设臵工程类型ActiveX控件工程名称DataLV工程描述通过ADO~使得ListView控件能够直接操作数据库UserControl的Name属性DataListViewUserControl的Public属性True?保存这个工程。?选择【文件】|【添加工程】菜单选项。然后添加一个标准EXE工程。建立该工程的目的是为了在创建ActiveX控件时不断地进行测试。此时已建立了一个由控件工程和测试工程组成的工程组~下面就可以正式开始创建DataListView控件。,5,实现控件的外观确定控件外观的方式取决于当前控件的创建模型。如果要创建一个用户绘制控件~那么必须自己在UserControl_Paint事件过程编写代码来完成所有的绘制工作~同时还需要确定何时绘制控件~以便在需要的时候调用UserControl的Refresh方法来产生Paint事件。如果是改进一个现有控件~那么只需正确地将组成控件放臵在UserControl上即可。由于DataListView控件仅包含ListView一个组成控件~那么只需简单地在17装配与检测自动化事业部UserControl1上绘出一个标准ListView控件~控件名为缺省的ListView1~即可完成外观绘制工作。为了在使用控件时~使ListView控件和自己绘制的空间相匹配~必须建立UserControl的Resize事件过程。Resize事件过程的代码如下:PrivateSubUserControl_Resize()ListView1.Left=0ListView1.Top=0ListView1.Width=UserControl.WidthListView1.Height=UserControl.HeightEndSub仅四行代码的Resize事件过程是简单控件的用户界面的所有必须的代码~其目的是使ListView控件和UserControl对象有相同的尺寸。,6,实现控件的接口和功能这是整个创建过程中最核心、最重要也是最复杂的步骤。对于创建控件的每一属性、事件和方法均需逐一实现。?创建DataServerName属性要创建DataServerName属性值~首先需要添加一个在内部存贮属性值的局部变量。要做到这一点~在UserControl对象的GenaralDeclarations通用声明语句中创建此变量。如下所示:Dimm_DataServerNameAsString接着需要创建称为DataServerName的新属性~可以通过手工输入Get和Let过程~或者选择【工具】|【添加过程】|【类型】创建这个新属性。DataServerName属性的代码相当容易理解。当臵DataServerName属性的值时~PropertyGet过程仅将局部变量的存贮内容取出来。当设臵DataServerName属性值时~PropertyLet过程将为局部变量赋予一个有效值。以下是两个Property过程的代码:PublicPropertyGetDataServername()AsStringDataServername=m_DataServerNameEndPropertyPublicPropertyLetDataServername(ByValNew_DataServerNameAsString)m_DataServerName=New_DataServerNamePropertyChanged"DataServerName"EndProperty18装配与检测自动化事业部需要注意的是在PropertyLet过程中~有一个PropertyChanged方法~它的功能是通知容器,可以理解为存放所有属性的单元,属性值已变更~需产生一个WriteProperties事件~来保存新属性值。事实上不仅在PropertyLet过程需要调用PropertyChanged方法~在UserControl的代码模块中无论何时改变了ActiveX控件的某个属性值~均需调用该过程,以保存属性的变化。注意PropertyDataServerName方法的用法~此方法与ReadProperties和WriteProperties事件在一起使用。此时需要使用用户控件的InitProperties事件指定此属性的初始值:PrivateSubUserControl_InitProperties()m_DataServerName=m_def_DataServerNameEndSub即使用户没有设臵初始值~这些代码也会确保设臵了一个初始值。至于DataBaseName、AdministratorName、PasseordName属性的创建过程跟DataServername属性的创建过程完全一样~这里就不再重复叙述。?使用PropertyBag对象用户还需要为WriteProperties和ReadProperties事件创建代码,从而保护DataServername、DataBaseName、AdministratorName、PasseordName属性在设计阶段的属性值。这两个事件都使用PropertyBag对象保存和检索DataServername、DataBaseName、AdministratorName、PasseordName属性的值。PropertyBag对象能够保持DataServername、DataBaseName、AdministratorName、PasseordName的设计值。具体实现代码如下:PrivateSubUserControl_ReadProperties(PropBagAsPropertyBag)m_DataServerName=PropBag.ReadProperty("DataServerName",m_def_DataServerName)m_DataBaseName=PropBag.ReadProperty("DataBaseName",m_def_DataBaseName)m_AdministratorName=PropBag.ReadProperty("AdministratorName",m_def_AdministratorName)m_PasswordName=PropBag.ReadProperty("PasswordName",m_def_PasswordName)EndSubPrivateSubUserControl_WriteProperties(PropBagAsPropertyBag)CallPropBag.WriteProperty("DataServerName",m_DataServerName,19装配与检测自动化事业部m_def_DataServerName)CallPropBag.WriteProperty("DataBaseName",m_DataBaseName,m_def_DataBaseName)CallPropBag.WriteProperty("AdministratorName",m_AdministratorName,m_def_AdministratorName)CallPropBag.WriteProperty("PasswordName",m_PasswordName,m_def_PasswordName)EndSub由于这两个过程是针对"容器"对象的~因此所有属性值的保存和读取都通过这两个过程来实现~而不是每个属性都需要单独的两个过程。其中~PropertyBag就是"容器对象"的名称。WriteProperty方法有三个参数:第一个字符串标识需要保存的属性~第二个参数是需要保存的值~最后的参数是属性的缺省值。ReadProperty方法需要两个参数:一个字符串用来保存属性的名称~另一个为缺省值。在窗体上绘制ActiveX控件的那一刻~就会开始执行ActiveX控件的代码。在控件设计过程中~将DataServername、DataBaseName、AdministratorName、PasseordName属性的默认值设臵为:Constm_def_DataServerName="lyc"Constm_def_DataBaseName="pubs"Constm_def_AdministratorName="sa"Constm_def_PasswordName=""当然~也可以在程序运行时多次修改它。控件的正常行为是当程序终止时恢复其默认值~这样增加了保持属性的两种独立状态的要求。简言之~如果在设计阶段改变了一个属性值~那么控件必须得到这个新值~而不是使用默认值。相反~如果在程序运行时改变属性值~那么当返回设计状态时~控件必须检索此属性值。PropertyBag对象允许ActiveX控件存贮有关它自己的属性值~使它能执行这个动作。PropertyChanged方法会通知用户已经改变了一个属性。通过了解程序的状态以及是否调用了PropertyChanged方法~VB就可以激发WriteProperties和ReadProperties事件。?为ShowDataBase方法编写代码ShowDataBase方法实现在ListView控件中显示Select命令所执行的数据库操作结果。在其具体实现过程中采用了ADO,ActiveXDataObjects,的数据存取方法。ADO的主要特点是使用更加容易~访问速度更快,而对磁盘和存储容量的要求更小,ADO支持建立各种客户20装配与检测自动化事业部/服务器模式与基于Web的应用程序~具有远程数据服务RDS,RemoteDataService,的特性~通过RDS能够在一次往返中将服务器端的数据传送到客户端的应用程序或Web页面中~并在客户端对数据进行处理后~立即更新服务器端的数据。采用ADO所基于的OLEDB技术~可以对电子邮件、文本文件、数据表格等各类数据通过统一的接口API接口进行存取~是远程数据存取的一个主要发展方向。ShowDataBase方法具有一个字符串参数~但无任何返回值~具体代码如下所示:PublicSubshowdatabase(ssqlAsString)DimAdoDatabaseAsNewADODB.ConnectionDimAdoTableAsNewADODB.RecordsetDimscnnAsStringDimresponseAsStringDimIAsIntegerOnErrorGoToerrorhandlescnn="Provider=SQLOLEDB;DataSource="&Trim(m_DataServerName)&";InitialCatalog="&Trim(m_DataBaseName)&";UserId="&Trim(m_AdministratorName)&";Password="&Trim(m_PasswordName)&";"AdoDatabase.OpenscnnAdoTable.CursorType=adOpenKeysetAdoTable.LockType=adLockOptimisticAdoTable.CursorLocation=adUseClientAdoTable.Openssql,AdoDatabase,,,adCmdTextIfAdoTable.BOFAndAdoTable.EOFThenresponse=MsgBox("没有符合条件的记录::",vbOKOnly+vbInformation,"数据库控件")AdoTable.CloseSetAdotable=NothingAdoDatabase.CloseSetAdoDataBase=NothingExitSubEndIfListView1.ColumnHeaders.ClearListView1.ListItems.ClearDimclmXAsColumnHeaderForI=0ToAdoTable.Fields.Count-1SetclmX=ListView1.ColumnHeaders.Add()WithclmX.Text=AdoTable.Fields(I).NameEndWithNextDimitmXAsListItemAdoTable.MoveFirst21装配与检测自动化事业部DoWhileNotAdoTable.EOFSetitmX=ListView1.ListItems.Add()WithitmXIfIsNull(AdoTable.Fields(0).Value)Then.Text="NULL"Else.Text=AdoTable.Fields(0).ValueEndIfEndWithForI=1ToAdoTable.Fields.Count-1IfIsNull(AdoTable.Fields(I).Value)ThenitmX.SubItems(I)="NULL"ElseitmX.SubItems(I)=AdoTable.Fields(I).ValueEndIfNextAdoTable.MoveNextLoopListView1.View=lvwReportAdoTable.CloseSetAdotable=NothingAdoDatabase.CloseSetAdoDataBase=NothingExitSuberrorhandle:RaiseEventErrordatabaseEndSub当对数据库的操作发生错误后~除了不能正常显示以外~还应通知宿主程序用户。可以通过创建一个叫做Errordatabase的事件实现上述功能。要创建这个事件~把下述代码添加到UserControl对象的GeneralDeclarations段中。PublicEventErrordatabase()此事件的工作像其他控件的事件一样。使用控件的用户可以将代码放到这个事件中~用户要做的唯一的事情就是用RaiseEvent方法激发此事件。,7,编译控件部件,.ocx文件,。现在已经完成了DataListView控件的创建工作~为了在DataLV工程外也可以使用该控件~只需将DataLV工程编译.ocx控件部件即可。22装配与检测自动化事业部在【工程组】窗口单击【DataLV】以选择该工程~在【文件】菜单上单击【生成DataLV.ocx】~在【生成工程】对话框中选择控件存放的目录后~单击【确定】即可创建.ocx文件。一旦生成了.ocx文件的控件~就可以象使用其它控件一样来随心所欲地使用它了。4,结束语ActiveX技术可以灵活、高效的实现可交互、重入、重用、完全分布式、与语言无关的各种应用。随着ActiveX技术的发展~ActiveX控件在应用程序中的作用将会显得越来越重要~那么创建一个功能完善、具有自己特色的ActiveX控件就非常具有现实意义。只要掌握了创建ActiveX控件的基本方法~就不难创建自定制的可在各种应用领域使用的ActiveX控件。但是~ActiveX技术也有一些明显缺点~ActiveX技术依赖于Windows平台~对广泛应用的UNIX平台目前仍不兼容~另外ActiveX在许多方面的性能还较弱~ActiveX技术仍需要不断完善和发展。附录2:网络文章《OPC异步客户程序》,1,建立新工程或项目~在“工程”菜单下选择“引用”~如图5-3所示。只有引用OPCDAAuoto.DLL后~在程序中才能创建服务器对象~然后进行一系列的操作。,2,在弹出的引用窗口里单击“浏览(B)…”按钮~弹出添加引用窗口~选择OPCDAAuoto.DLL文件。,3,在引用窗口里的OPCAutomation2.0前面打钩~按“确定”按钮。,4,定义全局变量~这样可以在窗体的任何方法的代码内应用。变量类型应该指定为对象型。这些对象最好在窗体的通用部分声明加上“OptionExplicit”语句~表示模块里的所有变量都需要显式声明。由于OPC自动化接口的数组的索引要求必须从1开始~而系统默认是从0开始~为了避免错误最好在代码的最初加上“OptionBase1”语句。为了使对象可以处理事件~必须将objTestGrp和objServer的声明中加上“WithEvents”语句~表示声明的对象可以响应事件。OptionExplicitOptionBase1DimWithEventsobjServerAsOPCServerDimobjGroupsAsOPCGroupsDimWithEventsobjTestGrpAsOPCGroupDimobjItemsAsOPCItems,5,连接OPC服务器和建立OPC组考虑到代码的可反复使用性~采用子程序进行编程。SubConnect(strProgIDAsString,OptionalstrNodeAsString)IfobjServerIsNothingThen23装配与检测自动化事业部'建立一个OPC服务器对象SetobjServer=NewOPCServerEndIf服务器状态ServerState属性一共有OPCRunning、OPCFailed、OPCNoconfig、OPCSuspended、OPCTest和OPCDisconnected六个值~分别表示正在运行、失败、没有配臵、暂停、测试和没有连接六种OPC服务器当前的状态。如果OPC服务器没有连接~我们才执行objServer.ConnectstrProgID,strNode语句。strProgID就是ProgID~strNode就是用于远程通信的IP地址。IfobjServer.ServerState=OPCDisconnectedThen'连接OPC服务器objServer.ConnectstrProgID,strNodeEndIf在VisualBasic中~通过执行一个Set操作实现调用其它接口的方法。IfobjGroupsIsNothingThen'建立一个OPC组集合SetobjGroups=objServer.OPCGroupsEndIfIfobjTestGrpIsNothingThen'添加一个OPC组SetobjTestGrp=objGroups.Add("Group")EndIfEndSub,6,添加OPC标签对服务器进行访问前~必须先在OPC组里添加要访问的OPC标签。OPC客户端程序要按照用户指定的标签或者从组态文件里读取需要添加的OPC标签。SubAddItem()DimstrItemIDs(17)AsStringDimlClientHandles(17)AsLongDimlErrors()AsLongDimIAsIntegerIfobjTestGrpIsNothingThenExitSubEndIfIfNotobjItemsIsNothingThenIfobjItems.Count>0ThenExitSubEndIfEndIf'设臵组活动状态。只有处于活动状态的OPC才进行定期的数据更新。非活动状态的OPC组~除了在接到显然的数据读写要求外~并不收集任何数据。IfmnuSubscribtion.Checked=TrueThenobjTestGrp.IsActive=True24装配与检测自动化事业部ElseobjTestGrp.IsActive=FalseEndIf'启动组异步通知。进行订阅的OPC组可以自动收到从服务器送来的数据变化通知。objTestGrp.IsSubscribed=True'建立OPC项集合SetobjItems=objTestGrp.OPCItems'生成从TAG1到TAG17的项标识符ForI=1To17strItemIDs(I)="Server.Group.TAG"&IlClientHandles(I)=INext'添加OPC项CallobjItems.AddItems(17,strItemIDs,lClientHandles,lServerHandles,lErrors)EndSub,7,异步读取代码的实现在定时器事件内进行执行AsyncRead子程序的读取代码~而在读取完成事件处理返回的数据访问结果。SubAsyncRead()DimlErrors()AsLongIfobjTestGrpIsNothingThenExitSubEndIfIfobjTestGrp.OPCItems.Count>0Then'异步读取lTransID_Rd=lTransID_Rd+1objTestGrp.AsyncRead17,lServerHandles,lErrors,lTransID_Rd,lCancelID_RdEndIfEndSubPrivateSubobjTestGrp_AsyncReadComplete(_ByValTransactionIDAsLong,ByValNumItemsAsLong,_ClientHandles()AsLong,ItemValues()AsVariant,_Qualities()AsLong,TimeStamps()AsDate,Errors()AsLong)……Sub,8,在按钮中执行AsyncWrite子程序~完成异步写的操作。SubAsyncWrite(nIndexAsInteger,ByRefvtItemValues()AsVariant,_ByReflErrors()AsLong)DimlHandle(1)AsLongIfobjTestGrpIsNothingThenExitSub25装配与检测自动化事业部EndIfIfobjTestGrp.OPCItems.Count>0ThenlHandle(1)=lServerHandles(nIndex)'异步写入lTransID_Wt=lTransID_Wt+1objTestGrp.AsyncWrite1,lHandle(),vtItemValues,_lErrors,lTransID_Wt,lCancelID_WtEndIfEndSub,9,断开OPC服务器连接着OPC服务器的OPC客户应用程序~在退出前必须断开和OPC服务器的连接。因为OPC服务器并不知道OPC客户应用程序的退出。如果不先断开连接~那么OPC服务器使用的计算机资源就不会被释放。如果这样的问题反复发生~久而久之~连续运转的自动控制系统可能会计算机资源渐渐枯竭从而发生严重问题~可以显式地把它设臵为“Nothing”。SubDisconnect()DimlErrors()AsLongIfNotobjItemsIsNothingThenIfobjItems.Count>0ThenobjItems.Remove17,lServerHandles,lErrors'清除OPC项EndIfSetobjItems=NothingEndIfIfNotobjTestGrpIsNothingThenobjGroups.Remove"Group"'清除OPC组SetobjTestGrp=NothingEndIfIfNotobjGroupsIsNothingThenSetobjGroups=NothingEndIfIfNotobjServerIsNothingThenIfobjServer.ServerState<>OPCDisconnectedThenobjServer.Disconnect'断开OPC服务器.EndIfSetobjServer=NothingEndIfEndSub附录3:OPC客户程序,VB篇——同步,来源网络建立如下窗体:引用如下:26装配与检测自动化事业部代码如下:OptionExplicitDimWithEventsServerObjAsOPCServerDimWithEventsGroupObjAsOPCGroupDimItemObjAsOPCItemPrivateSubCommand_Start_Click()DimOutTextAsStringOnErrorGoToErrorHandlerCommand_Start.Enabled=FalseCommand_Read.Enabled=TrueCommand_Write.Enabled=TrueCommand_Exit.Enabled=TrueOutText="连接OPC服务器"SetServerObj=NewOPCServerServerObj.Connect("XXXSERVER")'XXXSERVER为某OPC服务器名称OutText="添加组"SetGroupObj=ServerObj.OPCGroups.Add("Group")OutText="AddinganItemtothegroup"SetItemObj=GroupObj.OPCItems.AddItem("XXXITEM",1)'XXXITEM为添加的ITEM名称ExitSubErrorHandler:'如果出现异常~则报出错误。MsgBoxErr.Description+Chr(13)+_OutText,vbCritical,"ERROR"EndSubPrivateSubCommand_Read_Click()'同步读DimOutTextAsStringDimmyValueAsVariantDimmyQualityAsVariant27装配与检测自动化事业部DimmyTimeStampAsVariantOnErrorGoToErrorHandlerOutText="读ITEM值"ItemObj.ReadOPCDevice,myValue,myQuality,myTimeStampEdit_ReadVal=myValueEdit_ReadQu=GetQualityText(myQuality)Edit_ReadTS=myTimeStampExitSubErrorHandler:MsgBoxErr.Description+Chr(13)+_OutText,vbCritical,"ERROR"EndSubPrivateSubCommand_Write_Click()'同步写DimOutTextAsStringDimServerhandles(1)AsLongDimMyValues(1)AsVariantDimMyErrors()AsLongOutText="写值"OnErrorGoToErrorHandlerServerhandles(1)=ItemObj.ServerHandleMyValues(1)=Edit_WriteValGroupObj.SyncWrite1,Serverhandles,MyValues,MyErrorsEdit_WriteRes=ServerObj.GetErrorString(MyErrors(1))ExitSubErrorHandler:MsgBoxErr.Description+Chr(13)+_OutText,vbCritical,"ERROR"EndSub28装配与检测自动化事业部PrivateSubCommand_Exit_Click()'停止~删除ITEM,删除GROUP~删除SERVER。DimOutTextAsStringOnErrorGoToErrorHandlerCommand_Start.Enabled=TrueCommand_Read.Enabled=FalseCommand_Write.Enabled=FalseCommand_Exit.Enabled=FalseOutText="删除对象"SetItemObj=NothingServerObj.OPCGroups.RemoveAllSetGroupObj=NothingServerObj.DisconnectSetServerObj=NothingExitSubErrorHandler:MsgBoxErr.Description+Chr(13)+_OutText,vbCritical,"ERROR"EndSubPrivateFunctionGetQualityText(Quality)AsStringSelectCaseQualityCase0:GetQualityText="BAD"Case64:GetQualityText="UNCERTAIN"Case192:GetQualityText="GOOD"Case8:GetQualityText="NOT_CONNECTED"Case13:GetQualityText="DEVICE_FAILURE"Case16:GetQualityText="SENSOR_FAILURE"Case20:GetQualityText="LAST_KNOWN"Case24:GetQualityText="COMM_FAILURE"Case28:GetQualityText="OUT_OF_SERVICE"Case132:GetQualityText="LAST_USABLE"Case144:GetQualityText="SENSOR_CAL"Case148:GetQualityText="EGU_EXCEEDED"29装配与检测自动化事业部Case152:GetQualityText="SUB_NORMAL"Case216:GetQualityText="LOCAL_OVERRIDE"CaseElse:GetQualityText="UNKNOWNERROR"EndSelectEndFunction控件程序清单:OptionExplicitOptionBase1PrivateMyOPCServerAsOPCServerPrivateWithEventsMyOPCGroupAsOPCGroupPrivateMyOPCItems(32767)AsOPCItemPrivateItemsAsOPCItemConstm_def_OpcServerName="OPC.SimaticNET"Constm_def_OpcGroupName="Group"Constm_def_OpcStartAddress="MB0"Constm_def_OpcBufferSize=16'Constm_def_OpcBufStartAddr=0Constm_def_OpcLinkStatus=0Constm_def_LinkEnble=FalseConstm_def_ConnectionType="S7CONNECTION_1"Dimm_OpcServerNameAsStringDimm_OpcGroupNameAsStringDimm_OpcStartAddressAsStringDimm_OpcBufferSizeAsIntegerDimm_LinkEnbleAsBoolean'Dimm_OpcBufStartAddrAsIntegerDimm_OpcLinkStatusAsIntegerDimm_ConnectionTypeAsString'PublicEventOpcDataExchage()PublicPropertyGetOpcServerName()AsVariantOpcServerName=m_OpcServerNameEndProperty30装配与检测自动化事业部PublicPropertyLetOpcServerName(ByValvNewValueAsVariant)m_OpcServerName=vNewValuePropertyChanged"OpcServerName"EndPropertyPrivateSubUserControl_InitProperties()m_OpcServerName=m_def_OpcServerNamem_OpcGroupName=m_def_OpcGroupNamem_OpcStartAddress=m_def_OpcStartAddressm_OpcBufferSize=m_def_OpcBufferSizem_LinkEnble=m_def_LinkEnble'm_OpcBufStartAddr=m_def_OpcBufStartAddrm_OpcLinkStatus=m_def_OpcLinkStatusm_ConnectionType=m_def_ConnectionTypeEndSubPublicPropertyGetOpcGroupName()AsVariantOpcGroupName=m_OpcGroupNameEndPropertyPublicPropertyLetOpcGroupName(ByValvNewGroupValueAsVariant)m_OpcGroupName=vNewGroupValuePropertyChanged"OpcGroupName"EndPropertyPrivateSubUserControl_Paint()UserControl.Height=675UserControl.Width=825EndSubPrivateSubUserControl_ReadProperties(PropBagAsPropertyBag)m_OpcServerName=PropBag.ReadProperty("OpcServerName",m_def_OpcServerName)m_OpcGroupName=PropBag.ReadProperty("OpcGroupName",m_def_OpcGroupName)m_OpcStartAddress=PropBag.ReadProperty("OpcStartAddress",m_def_OpcStartAddress)m_OpcBufferSize=PropBag.ReadProperty("OpcBufferSize",m_def_OpcBufferSize)m_LinkEnble=PropBag.ReadProperty("LinkEnble",m_def_LinkEnble)'m_OpcBufStartAddr=PropBag.ReadProperty("OpcBufStartAddr",31装配与检测自动化事业部m_def_OpcBufStartAddr)m_OpcLinkStatus=PropBag.ReadProperty("OpcLinkStatus",m_def_OpcLinkStatus)m_ConnectionType=PropBag.ReadProperty("ConnectionType",m_def_ConnectionType)EndSubPrivateSubUserControl_WriteProperties(PropBagAsPropertyBag)CallPropBag.WriteProperty("OpcServerName",m_OpcServerName,m_def_OpcServerName)CallPropBag.WriteProperty("OpcGroupName",m_OpcGroupName,m_def_OpcGroupName)CallPropBag.WriteProperty("OpcStartAddress",m_OpcStartAddress,m_def_OpcStartAddress)CallPropBag.WriteProperty("OpcBufferSize",m_OpcBufferSize,m_def_OpcBufferSize)CallPropBag.WriteProperty("LinkEnble",m_LinkEnble,m_def_LinkEnble)'CallPropBag.WriteProperty("OpcBufStartAddr",m_OpcBufStartAddr,m_def_OpcBufStartAddr)CallPropBag.WriteProperty("OpcLinkStatus",m_OpcLinkStatus,m_def_OpcLinkStatus)CallPropBag.WriteProperty("ConnectionType",m_ConnectionType,m_def_ConnectionType)EndSubPublicPropertyGetOpcStartAddress()AsVariantOpcStartAddress=m_OpcStartAddressEndPropertyPublicPropertyLetOpcStartAddress(ByValvNewAddressAsVariant)m_OpcStartAddress=vNewAddressPropertyChanged"OpcStartAddress"EndPropertyPublicPropertyGetOpcBufferSize()AsIntegerOpcBufferSize=m_OpcBufferSizeEndPropertyPublicPropertyLetOpcBufferSize(ByValvNewDataLenAsInteger)m_OpcBufferSize=vNewDataLenPropertyChanged"OpcBufferSize"EndProperty32装配与检测自动化事业部PublicPropertyGetLinkEnble()AsBooleanLinkEnble=m_LinkEnbleEndPropertyPublicPropertyLetLinkEnble(ByValvEnbleAsBoolean)m_LinkEnble=vEnblePropertyChanged"LinkEnble"EndPropertyPublicSubOpcLink()DimItemName(32767)AsStringDimSHandles(32767)AsLong'parametervalueDimValues()AsVariant'returnvalueDimErrors()AsLong'returnvalueDimQualAsVariant'returnvalueDimTSAsVariant'returnvalueDimiAsIntegerDimItemName1,BufferType,strAddrIndexNoDot,strAddrIndexDotAsStringDimstrAddress,strAddressConverted,strAddrIndexAsStringDimCharInputAsStringDimAddrStrTotalLen,BufferTypeLen,AddrIndexLenAsIntegerDimiStep0,iStep1,iStep2,iAddrIndex,iIndexDotPosAsIntegerDimIsBitTypeAsBooleanDimstrIndexIntPart,strIndexDecPartAsStringDimiIndexIntPart,iIndexDecPartAsIntegerDimstrDBNo,strDBBufType,strVarTypeAsStringDimstrItemName(32767)AsStringDimCountAsIntegerCount=1IsBitType=False'm_OpcStartAddress=Text1.Text'获得OPC起始地址字符AddrStrTotalLen=Len(m_OpcStartAddress)'获得OPC起始地址字符长度'------------------获得寄存器类型字符------------------------'ForiStep2=1ToAddrStrTotalLenCharInput=Mid(m_OpcStartAddress,iStep2,1)If((Asc(CharInput)>=65AndAsc(CharInput)<=90)Or(Asc(CharInput)>=97AndAsc(CharInput)<=122))ThenBufferType=BufferType+CharInputElse33装配与检测自动化事业部BufferTypeLen=iStep2-1ExitForEndIfNextiStep2BufferType=UCase(BufferType)'寄存器类型字符变大写'----------------------获得地址数据字符---------------------'ForiStep0=AddrStrTotalLenTo1Step-1CharInput=Mid(m_OpcStartAddress,iStep0,1)If((Asc(CharInput)>=48AndAsc(CharInput)<=57)OrAsc(CharInput)=46)ThenstrAddrIndexDot=CharInput+strAddrIndexDotElseAddrIndexLen=AddrStrTotalLen-iStep0ExitForEndIfNextiStep0ForiStep1=1ToAddrIndexLenCharInput=Mid(strAddrIndexDot,iStep1,1)If((Asc(CharInput)>=48AndAsc(CharInput)<=57))ThenstrAddrIndexNoDot=strAddrIndexNoDot+CharInputElseIsBitType=TrueEndIfNextiStep1IfIsBitType=TrueTheniIndexDecPart=Val(Right(strAddrIndexNoDot,1))

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论