VB开发OPC与PLC通信.docx
《VB开发OPC与PLC通信.docx》由会员分享,可在线阅读,更多相关《VB开发OPC与PLC通信.docx(23页珍藏版)》请在冰豆网上搜索。
VB开发OPC与PLC通信
0
VB开发WinCC的OPC客户机实例
组态 2009-07-0319:
52 阅读101 评论0
字号:
大大 中中 小小
VB开发WinCC的OPC客户机实例
发布时间:
2006.04.29阅览次数:
1804作者:
林启宽单位:
厦门市海沧新阳工业区厦门卷烟厂
关键词:
OPCVB6.0WinCC上位机
WinCC是西门子公司在自动化领域采用最先进的技术与微软公司在共同开发的居于世界领先地位的工控软件。
WinCC即WINDOWSCONTROLCENTER(视窗控制中心)。
WinCC是一个功能强大的全面开放的监控系统,既可以用来完成小规模的简单的过程监控应用,也可以用来完成复杂的应用。
在任何情况下WinCC都可以生成漂亮而便捷的人机对话接口,使操作员能够清晰地管理和优化生产过程。
它集成的OPC(OLEforprocesscontrol)服务器使得过程数据可由其它应用程序(OPC客户机)访问。
WinCC在安装时提供了OPC的客户端控件:
SiemensOPCDAAutomation2.0(SOPCDAAuto.dll),在WINCC的帮助中,有SiemensOPCDAAutomation2.0使用的简略帮助,但说得不很详细,我在使用VB6.0开发WinCC的OPC客户机中碰到不少问题,现一并写出来,与大家共享。
希望起到抛砖引玉,举一反三的作用。
一、开发实例背景:
我厂包装机BE电气改造后,由原来了单片机、直流调试板、温度控制板等控制改为带有通讯端口PLC、变频器、温控仪等控制,上位机监控软件为WinCC。
在控制系统中,变频器、温控仪的控制信号通过串口、OPC客户机接入上位机WinCC,报警信号接入PLC。
其硬件组态结构如图一
OPC开发要求:
①通过WinCC建立内部变量Tag
(1),Tag
(2),Tag(3),Tag(4)……;在视图窗口建立相应了I/O输入输出域。
通过更改WinCC中I/O域的值,来设定或更改变频器、温控仪等的参数。
②通过VB开发了串口驱动程序,读取变频器、温控仪等的参数,通过OPC控件把值传递给WinCC中的I/O域。
二、VB6开发WinCC的OPC客户机具体步骤:
1、打开VB6,建立如图二窗体:
其中,文本框组Text4.text为写入WinCC内部变量名称;文本框组Text5.text为显示相应了WinCC内部变量值;文本框组Text8.text为写入期望了WinCC内部变量值。
单选框为OPC连接成功标志。
3个命令按钮分别为“连接”,“断开”,“退出”。
2、OPC的连接
先在工具栏中“工程\引用”将近SiemensOPCDAAutomation2.0加入,然后开始定义全局变量。
在本程序中,我使用了一个OPC组进行OPC访问,所以定义了全局变量。
我们要首先定义OPC服务类型与计算机结点名。
定义OPC组与OPC标签组。
并定义OPC的标签数组与值数,注意,值数组一定要设为Variant。
OptionExplicit
OptionBase1‘这数组必须由1开始,不能由0开始
ConstServerName="OPCServer.WinCC"'OPC的类型
DimNodeNameAsString'结点名,即计算机名
DimWithEventsMyOPCServerAsOPCServer'OPC服务
DimWithEventsMyOPCGroupAsOPCGroup'OPC组
DimMyOPCGroupCollAsOPCGroups
DimMyOPCItemCollAsOPCItems'OPC标签组
DimMyOPCItemsAsOPCItems
DimMyOPCItemAsOPCItem
DimClientHandles
(1)AsLong'句柄
DimServerHandles()AsLong
DimErrors()AsLong
DimItemIDs(4)AsString'记录OPC的标签
DimItemIDsValue(4)AsVariant'存放OPC的值
DimGroupNameAsVariant
在定义所有变量后,我们就要进行OPC连接了,要进行OPC连接之前,先要配置要访问的OPC标签名(即WinCC内部变量名),我们ItemIDs中加入相应的标签名,注意:
这数组必须由1开始,不能由0开始。
配置好标签后就要进行OPC连接了。
如下面子程序:
①ClientHandles1先配置名柄索引,这将在读取OPC标签的值时可要用到。
②生成OPC对象,③进行OPC标签连接此,OPC连接就成功了,我们可以对OPC进行读与写的操作了。
PrivateSubCommand1_Click()
DimiiAsInteger
DimClientHandles1(4)AsLong
Forii=1To4
ClientHandles1(ii)=ii
ItemIDs(ii)=Text4(ii).Text'指明WinCC内部变量名称
Nextii
OnErrorGoToErrorHandler
GroupName="MyGroup"
NodeName=Text1.Text'结点名,即计算机名
SetMyOPCServer=NewOPCServer
MyOPCServer.ConnectServerName,NodeName
SetMyOPCGroupColl=MyOPCServer.OPCGroups
MyOPCGroupColl.DefaultGroupIsActive=True
SetMyOPCGroup=MyOPCGroupColl.Add(GroupName)
SetMyOPCItemColl=MyOPCGroup.OPCItems
Forii=1To4
ClientHandles1(ii)=ii
ItemIDs(ii)=Text4(ii).Text
MyOPCItemColl.AddItems4,ItemIDs,ClientHandles1,ServerHandles,Errors'初始化OCP连接
Nextii
MyOPCGroup.IsSubscribed=True
Option1.Value=True'连接成功标志
ExitSub
ErrorHandler:
MsgBox"Error:
"&Err.Description,vbCritical,"ERROR"'连接发生错误
EndSub
3、OPC的标签读写
对OPC标签的读可以通过ItemIDsValue(4)组的DataChange事件来读取。
该事件有多个参数:
其中NumItems是指标签改变值的个数,ClientHandles是改变值的标签索引,ItemValues为改变值的数据,具体的意思是ClientHandles(ii)的值是其对应的标签数组的索引,其所指的OPC标签的值在ItemValues(ii)中。
一般来说,刚连接上时,该事件会把全部所要求访问的OPC标签值全部读取过来(顺序不一,要通过ClientHandles索引),此后只有数据发生变化时才会触发该事件。
也只会传输发生了变化的数据,没有变化的数据不会出现在本事件的ItemValues中。
读取
PrivateSubMyOPCGroup_DataChange(ByValTransactionIDAsLong,ByValNumItemsAsLong,ClientHandles()AsLong,ItemValues()AsVariant,Qualities()AsLong,TimeStamps()AsDate)
DimiiAsLong
Forii=1To4
ItemIDsValue(ClientHandles(ii))=ItemValues(ii)'对改变的值读入本数组
Text5(ClientHandles(ii)).Text=ItemIDsValue(ClientHandles(ii))
Nextii
EndSub
写入
PrivateSubText8_Change(IndexAsInteger)
Dimvaluess(4)AsVariant
DimiiAsLong
Forii=1To4
valuess(ii)=Text8(ii).Text
MyOPCGroup.SyncWrite4,ServerHandles,valuess,Errors
Next
EndSub
对OPC的写可以有同步与异步之分,对于大量的数据传输,异步是更佳的选择,但对少量的数据传输,同步表现得更好。
4、OPC连接断开。
OPC客户端连接后要占用服务器资源,所以如果不需要使用OPC时,必须进行OPC连接断开。
断开的程序相当简单,释放资源即可。
如下:
PrivateSubCommand2_Click()
OnErrorResumeNext
MyOPCGroupColl.RemoveAll'-----------释放组和服务器对象
MyOPCServer.Disconnect
'-----------与服务器断开连接并且清除
SetMyOPCItemColl=Nothing
SetMyOPCGroup=Nothing
SetMyOPCGroupColl=Nothing
SetMyOPCServer=Nothing
Option1.Value=False'连接成功标志
EndSub
至此,用VB6.0开发WinCC的OPC客户机开发完毕。
三、测试运行
在使用中,通过串口读取过来了值(例如温控器的实际温度)可以赋给VB的变量(例如Text8(0).text)。
通过PrivateSubText8_Change(IndexAsInteger)函数,当串口读取了值有变化时,在WinCC组态界面中实际值I/O域中,就可以看到其实际值了(Tag
(1))。
也可通过WinCC的组态界面对设定值I/O域中进行参数设定,通过上述程序的PrivateSubMyOPCGroup_DataChange(ByValTransactionIDAsLong,ByValNumItemsAsLong,ClientHandles()AsLong,ItemValues()AsVariant,Qualities()AsLong,TimeStamps()AsDate)函数,把WinCC的设定值(Tag
(2))赋给VB的变量(例如Text8
(1).text),再通过串口通讯把值写入(例如温控器的设定值)。
程序运行
图三,OPC与WinCC通讯测试
图三,OPC与WinCC通讯测试
测试运行结果如图三。
1
一、OPC的连接
先在“引用”将近SiemensOPCDAAutomation2.0加入,然后开始定义全局变量。
在本程序中,我使用了两个OPC组进行OPC访问,所以定义了全局变量。
我们要首先定义OPC服务类型与计算机结点名。
定义OPC组与OPC标签组。
并定义OPC的标签数组与值数,注意,值数组一定要设为Variant。
'OPC处理:
只对WINCC
ConstServerName="OPCServer.WinCC" ‘OPC的类型
ConstNodeName="GUK" ‘结点名,即计算机名
‘DimNodeNameAsString
DimWithEventsMyOPCServerAsOPCServer ‘OPC服务
DimMyOPCGroupCollAsOPCGroups ‘
DimWithEventsMyOPCGroupOutAsOPCGroup ‘OPC组,本程序用两个组进行OPC连接
DimWithEventsMyOPCGroupInAsOPCGroup
DimMyOPCItemCollInAsOPCItems ‘OPC标签组
DimMyOPCItemCollOutAsOPCItems
DimServerHandlesIn()AsLong ‘句柄
DimServerHandlesOut()AsLong
DimErrorsIn()AsLong ‘错误句柄
DimErrorsOut()AsLong
DimWatchDataReadItem(100)AsString '记录OPC的标签
DimWatchDataReadValue(100)AsVariant '存放OPC的值
DimWatchDataWriteItem(100)AsString '记录OPC的标签
DimWatchDataWriteValue(100)AsVariant '存放OPC的值
在定义所有变量后,我们就要进行OPC连接了,要进行OPC连接之前,先要配置要访问的OPC标签名,我们WatchDataReadItem、WatchDataWriteItem中加入相应的标签名,注意:
这两个数组必须由1开始,不能由0开始。
配置好标签后就要进行OPC连接了。
如下面子程序:
1、 ClientHandles1先配置名柄索引,这将在读取OPC标签的值时可要用到
2、 生成OPC对象,
3、 进行OPC标签连接
至此:
OPC连接就成功了,我们可以对OPC进行读与写的操作了。
'---------------------------------------------------------------------
'SubStartClient()
'目的:
连接至OPC_server,创建组和添加条目
'---------------------------------------------------------------------
PrivateSubStartClient()
DimItemNumAsInteger
DimTarnscationIDAsLong
DimCanceIDAsLong
DimClientHandles1(100)AsLong
DimiiAsInteger
OnErrorGoToHANDLEeRROR
Forii=0To100
ClientHandles1(ii)=ii 先配置名柄索引,这将在读取OPC标签的值时可要用到
Nextii
TarnscationID=1
‘ NodeName=xProfile.GetValue("SYSTEM","NodeName")
‘生成OPC对象,
SetMyOPCServer=NewOPCServer
MyOPCServer.ConnectServerName,NodeName
SetMyOPCGroupColl=MyOPCServer.OPCGroups
MyOPCGroupColl.DefaultGroupIsActive=True
SetMyOPCGroupIn=MyOPCGroupColl.Add("MYGROUPIN")
SetMyOPCGroupOut=MyOPCGroupColl.Add("MYGROUPOUT")
SetMyOPCItemCollIn=MyOPCGroupIn.OPCItems
SetMyOPCItemCollOut=MyOPCGroupOut.OPCItems
‘进行OPC标签连接
IfWriteItemIdex>0Then
MyOPCItemCollOut.AddItemsWriteItemIdex,WatchDataWriteItem,ClientHandles1,ServerHandlesOut,ErrorsOut '初始化OCP连接
MyOPCGroupOut.IsSubscribed=True
EndIf
IfReadItemIdex>0Then
MyOPCItemCollIn.AddItemsReadItemIdex,WatchDataReadItem,ClientHandles1,ServerHandlesIn,ErrorsIn '初始化OCP连接
MyOPCGroupIn.IsSubscribed=True
EndIf
ExitSub
HANDLEeRROR:
needOPCRestart=True
xLog1.log"OPCl连接发生错误"
EndSub
二、OPC的标签读写
对OPC标签的读可以通过MyOPCGroupIn组与MyOPCGroupOut的DataChange事件来读取。
该事件有多个参数:
其中NumItems是指标签改变值的个数,ClientHandles是改变值的标签索引,ItemValues为改变值的数据,具体的意思是ClientHandles
(1)的值是其对应的标签数组的索引,其所指的OPC标签的值在ItemValues
(1)中。
一般来说,刚连接上时,该事件会把全部所要求访问的OPC标签值全部读取过来(顺序不一,要通过ClientHandles索引),此后只有数据发生变化时才会触发该事件。
也只会传输发生了变化的数据,没有变化的数据不会出现在本事件的ItemValues中。
PrivateSubMyOPCGroupOut_DataChange(ByValTransactionIDAsLong,ByValNumItemsAsLong,ClientHandles()AsLong,ItemValues()AsVariant,Qualities()AsLong,TimeStamps()AsDate)
'产生要通知下一级的数据变化,根椐不再的控件有不同的处理
Forii=1ToNumItems
WatchDataWriteValue(ClientHandles(ii)-1)=ItemValues(ii)'对改变的值读入本数组
Nextii
EndSub
对OPC的写可以有同步与异步之分,对于大量的数据传输,异步是更佳的选择,但对少量的数据传输,同步表现得更好。
要进行数据传输,先要将值数据进行赋值,注意:
值数据要由0开始,也就是说,值数组与标签数据不是一、一对应,值要比标签前一位,这一点,在WINCC说明中没有,但在我的实际的使用中一直要这样,不然数据就产生错位,看下面程序。
这是一个拔号完毕后返回的数据进行OPC传递的程序。
包含解包过程,
PrivateSubshowSuccess(msgAsString)
DimlocationAsString
DimnowTimeAsString
DimlogStrAsString
DimValue()AsString
Dimii,tempAsInteger
DimisPackAsBoolean
DimsHead,sDelimited,sTailAsString
location=xProfile.GetValue(WatchPoint(nowRunID),"LOCATION")
nowTime=Now
logStr="拔"&location&"取数成功"&msg
xLog1.loglogStr
logStr=""&msg
xLog2.loglogStr '记录数据
'数据上传
'如果有包结构,则显示包结构,
isPack=xProfile.GetValue(WatchPoint(nowRunID),"ISRECHEAD")
IfWatchPointRBegin(nowRunID)<0ThenExitSub
IfisPackThen
sHead=xProfile.GetValue(WatchPoint(nowRunID),"RECHEAD")
sDelimited=xProfile.GetValue(WatchPoint(nowRunID),"RECDELIMITER")
sTail=xProfile.GetValue(WatchPoint(nowRunID),"RECEND")
Value=Split(msg,sDelimited)
Forii=0ToUBound(Value)-1
temp=WatchPointRBegin(nowRunID)+ii
Iftemp>WatchPointREnd(nowRunID)ThenExitFor
WatchDataReadValue(temp-1)=Value(ii+1) 'VALUE要从0开始,比ITEM少1,所以减一。
有包头,占去一位,向后延一
Nextii
Else
WatchDataReadValue(WatchPointREnd(nowRunID)-1)=msg
EndIf
MyOPCGroupIn.SyncWriteReadItemIdex,ServerHandlesIn,WatchDataReadValue,ErrorsIn '数据上传
'记录上次成功执行的时间
xProfile.SetValueWatchPo