您好,欢迎访问三七文档
当前位置:首页 > 外语资料 > 英语基础 > 学习用VB写OPC CLIENT
学习用VB编写OPCClient(1)作者:大头大头下雨不愁,2008-8-621:03:00发表于:《自动化软件论坛》共有0人回复,0次点击加为好友发送留言Opc在1995年就由fiser-rosement、intellution(难怪ifix对opc这么起劲^_^)、rockwell等发起了,如今已经是2008年啦,这么多年来,opc虽然发展很快但是也没能统一河山。不过很多时候都要碰到opc这个玩意,因为大多数自动化厂商都提供了opc接口,可以从这个标准接口中读/写较为实时的数据,用来做一些不同系统的数据整合或者复杂点的实时数据输出打印之类的也许更合适。在网上也看到了有人对于opc的抱怨,后面再研究研究。几年前网上有人写过《opc七日谈》,如今百度搜搜还常常能看到这个帖子,作者还是很能钻研的。看了资料,初步了解了opc的分层结构:Opcserver服务器――――opcGroups组集合―――――――――opcgroup组――――――――――――――opcitems标签集合――――――――――――――――――opcitem标签看了下百度找到了一些文章和代码,程序开始是要连接一个opc对象,然后建立下一层的groups-group-items-item,有点疑问:1、能不能browse出本机中所有的opcservr?然后去connect。2、为什么在vb的工程里面开始就要引用一个指定的opcserver对象,那么如何能根据browse出来然后选择的对象再去引用呢?――好像有点问题3、item如何browse出来?例子里面都是自定义好了tag名称,可是实际应用中不可能是这么固定的吧?例子里面也承认实际应用中标签要安装用户指定或读取组态文件取得和处理。先到这里,后面有心情了再继续:)学习用VB编写OPCClient(2)找到一段代码,可以实现获得所有本电脑上运行的opc服务PrivateSubCommand1_Click()DimAllOPCServersAsVariantDimiAsIntegerSetAnOPCServer=NewOPCServerList1.ClearAllOPCServers=AnOPCServer.GetOPCServersFori=LBound(AllOPCServers)ToUBound(AllOPCServers)List1.AddItemAllOPCServers(i)NextiSetAnOPCServer=NothingEndSub试了一下果然可以。点击list中某一个opcserver,然后调用opcserver对象的connect方法就可以连接上去了。我试着定时检查opcserver的serverstatus属性(服务器状态ServerState属性一共有OPCRunning、OPCFailed、OPCNoconfig、OPCSuspended、OPCTest和OPCDisconnected六个值,分别表示正在运行、失败、没有配置、暂停、测试和没有连接六种OPC服务器当前的状态。)连接成功后的却返回了opcrunning值,而断开后也能返回“opcdisconnected”值。不过不知道在非正常中断连接(比如远程服务器网络中断等)的时候,该属性是否能真正反应状态?ms有人说不行,需要从标签变bad来判断。回头在虚拟机上装个opcserver来测试一下。学习用VB编写OPCClient(3)添加标签的方法。首先看了看本机上一个opcserver运行起来以后,发现里面有好几个group,那么我总不能定义一摸一样的几个group吧?看了下网上有人写的帖子,说client里面无须指定跟server一样的group,我想这是很合理的,毕竟只要以标签名作为唯一标识就可以了(这里就应该隐含着opcserver上标签名称是唯一的,不管其在不在一个group中)网上的例子里面是做了个示范,标签名用了个循环赋值,ForI=1To17strItemIDs(I)=Server.Group.TAG&IlClientHandles(I)=INext’添加OPC项CallobjItems.AddItems(17,strItemIDs,lClientHandles,lServerHandles,lErrors)但是例子里面也承认“OPC客户端程序要按照用户指定的标签或者从组态文件里读取需要添加的OPC标签。”那么,实际上来说,要么用browse标签的方法去一个一个选择标签,要么事先在程序里面指定好各个标签名字了(当然可以用一个类似与ini配置文件的方法存储好要各个标签的名字,这个以后再说吧)。从实际应用考虑,我觉得browse的方法没有必要,因为一般来说直接确定好哪些标签就行了,而且如果用参数文件的话也算比较容易后期进行配置(前提应该是tag名字要写正确)。Items有个additems的方法,用于添加标签,参数比较多,认真看了下例子,还是有点技巧的,从第二个参数开始都是数组类型的参数,而前两个数组必须指定好长度,后面三个数组则无须指定长度,很怪啊,反正vb认可就ok了,难怪例子里面这么定义的几个数组。下一步就是标签的读写了,里面牵涉的内容好像挺多,主要是同步和异步读写问题,后面再研究吧。学习用VB编写OPCClient(4)关于引用对象的问题从下载的资料看,需要在工程里面引用一个opc对象。我看的是用opc访问wincc的文章,里面提到“先在“引用”将近SiemensOPCDAAutomation2.0加入”,试了下去掉这个引用,运行程序就报告“变量未定义”,指向的就是定义的几个opc对象变量。试着引用另外一个opc对象-OPCAutomation2.0,就可以了。看来引用只是为了能够声明和定义opc对象而已,所以随便找个就可以了。关于同步读的问题百度上搜到csdn上有同步读写的代码,看了下很奇怪PrivateSubCommand_Read_Click()’同步读DimOutTextAsStringDimmyValueAsVariantDimmyQualityAsVariantDimmyTimeStampAsVariantOnErrorGoToErrorHandlerOutText=读ITEM值ItemObj.ReadOPCDevice,myValue,myQuality,myTimeStampEdit_ReadVal=myValueEdit_ReadQu=GetQualityText(myQuality)Edit_ReadTS=myTimeStampExitSubErrorHandler:MsgBoxErr.Description+Chr(13)+_OutText,vbCritical,ERROREndSub其中GetQualityText是自定义函数,标签质量代码的解释PrivateFunctionGetQualityText(Quality)AsStringSelectCaseQualityCase0:GetQualityText=BADCase64:GetQualityText=UNCERTAINCase192:GetQualityText=GOODCase8:GetQualityText=NOT_CONNECTEDCase13:GetQualityText=DEVICE_FAILURECase16:GetQualityText=SENSOR_FAILURECase20:GetQualityText=LAST_KNOWNCase24:GetQualityText=COMM_FAILURECase28:GetQualityText=OUT_OF_SERVICECase132:GetQualityText=LAST_USABLECase144:GetQualityText=SENSOR_CALCase148:GetQualityText=EGU_EXCEEDEDCase152:GetQualityText=SUB_NORMALCase216:GetQualityText=LOCAL_OVERRIDECaseElse:GetQualityText=UNKNOWNERROREndSelectEndFunction问题关键在于上面代码的同步读采用的是item对象的read方法,而别的资料则是用group的syncread方法,显然后者效率高。形如:objGroup.SyncReadOPCCache,UBound(lServerHandles),lServerHandles,vItemData,lErrors其中opccache是个关键字,也可以用opcdevice关键字,在规范里面讲了一下两者的区别。运行了下,老是报告参数错误然后竟然vb出错了,以为是前面错误多了导致突然退出程序没有释放定义的对象,于是重启机器,还是依旧,看来不是这个原因了。换个引用的opc对象试试看?果然ok了,数据读上来了。想到csdn的代码里面有标签质量,那么group的syncread方法也有质量参数不过是可选的,于是加上一个参数,定义为variant即可,但是在显示这个质量参数的时候却出错了。我猜想应该是数组的形式来引用――――尽管其被调用的时候被定义为variant,果然如此。然后借用前面csdn的GetQualityText函数即可显示出标签的质量了,正常就是good,否则是bad。同样道理,时间标戳(TIMESTAMP)也可以显示出来。下一步是同步写的问题。读的问题解决了,写就简单了,语法是:SyncWrite(NumItemsAsLong,ServerHandles()AsLong,Values()AsVariant,ByRefErrors()AsLong)不过发现opc官方文档里面的例子居然有错,就是Values()这个数组在定义的时候必须指定长度否则vb报告下标错。我猜想这是因为在调用syncwrite方法之前,肯定要对values数组元素赋值,此时没有调用syncwrite造成系统不能划出values数组的大小,悖论啊,瞎猜瞎猜。问题又来了,实际应用中,可能仅仅是指定某几个标签写下去,怎么办?受到前面csdn的代码启示,用item的write方法,写了一个小函数:SubSingleWrite(IndexAsLong,ValueAsVariant)’单个写DimobjItemAsOPCItemIfNotobjItemsIsNothingThenSetobjItem=objItems.Item(Index)objItem.WriteValueEndIfSetobjItem=NothingEndSub下一步研究下异步读写的问题。学习用VB编写OPCClient(5)关于异步读写所联想到的……粗粗的浏览了一下资料里面关于异步读写的描述,包括订阅更新,感觉是一种很好的做法,特别是数据量大的时候。因为同步读写必须等待服务器返回结果才能继续后面的代码。看到这里,我想到了前面研究modbus通讯时,对于485总线多站点轮询,曾经想当然的考虑过一个方法:主站先把所有报文统统发送出去,然后等待各条报文返回来,或者是发送一条报文就接收一次再发送一次再接收一次如此循环,当然由于速度问题,每次接收的报文基本上不可能是上条发送的请求报文的返回了,我以为如此可以达到很高的效率。但是当实际动手开始编的时候,才发现这种想法是不能实现的,原因在于无法完全识别返回的报文是哪条发送报文的正确返回。例如第一条报文请求读取站号=2的从站的8个bool量,而第二条报文则是请求读取站号=2的另外8个bool量,那么主站收到返回报文后就无法识别读到的这8个bool量是从站中哪片地址区的(因为返回报文中只包含了功能码、站号、返回的字节数和数据内容)。所以只能是发送请求报文以后,“耐心”等待返回的报文。这样看来,modbus是一种同步读写的机制,而我所设想的所谓方法是一种不能实现的“异步”读写机制。说句瞎话,其实只要修改一下slave返回的报文格式就能够使得maste
本文标题:学习用VB写OPC CLIENT
链接地址:https://www.777doc.com/doc-3307581 .html