OPC技术的上位机与PLC之间的通信现代工业控制系统通常以PC机为上位机.docx
- 文档编号:24558633
- 上传时间:2023-05-28
- 格式:DOCX
- 页数:23
- 大小:27.37KB
OPC技术的上位机与PLC之间的通信现代工业控制系统通常以PC机为上位机.docx
《OPC技术的上位机与PLC之间的通信现代工业控制系统通常以PC机为上位机.docx》由会员分享,可在线阅读,更多相关《OPC技术的上位机与PLC之间的通信现代工业控制系统通常以PC机为上位机.docx(23页珍藏版)》请在冰豆网上搜索。
OPC技术的上位机与PLC之间的通信现代工业控制系统通常以PC机为上位机
OPC技术的上位机与PLC之间的通信现代工业控制系统通常以PC机为上位机,通过与现场工控设备如PLC的数据交换与处理,实现对生产过程的自动控制。
对于小型控制系统,采用专门的组态软件成本太高,用VB设计监控系统则可以降低成本,但首先要解决上位机与PLC之间通信问题。
以往使用较多的进程间通信方式是DDE(动态数据交换)方式,随着OPC技术的发展和普及,它已成为工业过程控制的通信标准。
OPC服务器有两类接口,其中自动化接口主要用于VB、Delphi等开发工具。
本文利用罗克韦尔公司提供的OPC接口,用VB编写了客户端应用程序,实现了上位机与AB可编程控制器之间的数据交换。
2 OPC技术简介
OPC(OLEforProcessControl—用于过程控制的对象连接与嵌入)是一套以微软对象连接与嵌入OLE、组件对象模型COM、分布式组件对象模型DCOM(DistributedCOM)技术为基础,基于Windows操作平台,为工业应用程序之间提供高效的信息集成和交互功能的组件对象模型接口标准。
OPC实际上是提供了一种机制,通过这种机制,系统能够以服务器/客户端标准方式从服务器获取数据并将其传递给任何客户应用程序。
这样,只要生产商开发一套遵循OPC规范的服务器与数据进行通信,其他任何客户应用程序便能通过服务器访问设备。
OPC服务器有两类接口:
定制接口和自动化接口。
定制接口为C++程序服务,自动化接口为VB这一类可使用自动化对象的程序服务。
定制接口是服务商必须提供的,而自动化接口则是可选的,不过OPC基金会提供了一个叫做“自动化包装器”的动态连接库,用于在两者间转换。
OPC数据存取规范规定的基本对象有三类:
服务器(server)、组(group)和数据项(item)。
服务器对象包含服务器的所有信息,也是组对象的容器,一个服务器对应于一个OPCserver,即一种设备的驱动程序。
组对象除了包含它自身信息外,还负责管理数据项。
每一个数据项代表到数据源的一个连接,但它没有提供外部接口,客户端程序无法对数据项直接进行操作,应用程序必须依靠数据项的容器组对象来对它进行操作。
3 通信实现
3.1 RSLinx的配置
RSLinx是AB可编程控制器在Windows环境下建立工厂所用通信方案的工具,它不仅提供了多种网络驱动程序,而且提供了最快速的OPC、DDE和CustomC/C++接口。
本设计中上位机与Logix5550控制器采用RS-232串口方式连接,在RSLinx中要对DF1网络驱动程序组态,设置串口特性:
COM1、波特率19200bps、一个停止位、无奇偶校验、全双工、BCC校验码。
此外要使用RSLinx的OPC接口作为服务器,还要在RSLinx中对OPC进行配置。
3.2 安装OPC自动化接口服务
若要用VB开发OPC应用程序,必须安装OPC自动化接口服务,保证计算机系统目录下有OPCDAAuto.dll。
OPC基金会提供了一个叫做“自动化包装器”的动态连接库,从OPC基金会的网站(www.opcfoundation.org)可下载。
在VB环境中,按“工程”的子菜单“引用…”后,弹出对话框,选择其中的“RSLinxOPCAutomation2.0”项,这样才能使用自动化接口。
3.3 程序设计
用VB编写了OPC客户端应用程序,实现了上位机与Logix5550控制器之间的通信。
主要程序代码如下:
(1)连接OPC服务器
DimWithEventsMyOPCServerAsOPCServer ‘定义服务器对象变量MyOPCServer
DimWithEventsMyOPCGroupAsOPCGroup ‘定义OPC组对象变量MyOPCGroup
SetMyOPCServer=NewOPCServer
MyOPCServer.Connect"RSLinxOPCServer"‘连接RSLinx的OPC服务器
(2)添加OPC组对象
SetMyOPCGroup=MyOPCServer.OPCGroups.Add("Group1")
‘添加OPC组对象MyOPCGroup.IsSubscribed=True
‘设置该组数据为后台刷新
MyOPCGroup.IsActive=True
‘设置该组为激活状态
MyOPCGroup.UpdateRate=1000
‘设置数据刷新时间为1000
(3)添加数据项
DimabItemIDs()AsString
‘项标识符
DimabClientHandles()AsLong
‘客户端句柄
DimabServerHandles()AsLong
‘服务器端句柄
DimabErrors()AsLong
DimiAsLong
ItemCount=5
DimoOPCItemAsRSLinxOPCAutomation.OPCItem
Fori=1To5
abItemIDs(i)="["&txtTopic&"]"&txtItem(i) ‘将Topic名和标签名赋给项标识符
abClientHandles(i)=i
‘给客户端句柄赋值
Nexti
MyOPCGroup.OPCItems.AddItemsItemCount,abItemIDs,abClientHandles,abServerHandles,abErrors
‘添加数据项操作
(4)同步数据读写
OPC数据存取有同步方式和异步方式两种。
异步读写数据复杂,需要与事件结合使用,与同步相比速度慢但准确性高。
同步读写数据简单,直接使用OPCItem的方法即可。
DimOneAsOPCItem
DimIndexAsLong
‘Index为标签顺序号
DimOneReadAsString
DimXieAsString
SetOne=MyOPCGroup.OPCItems(Index)
One.ReadOPCCache
OneRead=One.Value
‘读数据
One.Write(Xie)
‘写数据
若只读取数据,可以使用DataChange事件,当控制器中所要访问的数据一旦发生改变时将会触发该事件,并将该数据自动读到TxtValue文本框。
PrivateSubMyOPCGroup_DataChange(ByValTransactionIDAsLong,ByValNumItemsAsLong,ClientHandles()AsLong,ItemValues()AsVariant,Qualities()AsLong,TimeStamps()AsDate)
‘自动刷新数据
DimiAsLong
Fori=1ToNumItems
txtValue(ClientHandles(i))=ItemValues(i)
‘获取项的值
txtTime(ClientHandles(i))=TimeStamps(i)
‘获取项的时间戳
txtQuantity(ClientHandles(i))=GetQualityString(Qualities(i))
‘获取项的品质
Nexti
EndSub
(5)断开OPC服务器
MyOPCServer.OPCGroups.RemoveAll
‘移除所有OPCGroup,空出资源
SetMyOPCGroup=Nothing
MyOPCServer.Disconnect
‘断开连接
4 结束语
利用本文介绍的方法,在实验室实现了上位机和PLC之间的通信,图1是OPC客户端设置界面。
此外我们还设计了城市供水监控系统,鉴于篇幅,监控界面不再一一列出。
在上一次发表的<运用VC#编程通过OPC方式实现PC机与西门子PLC通讯>主要讲的是同步通讯,本文将主要讲解如何编程实现异步通讯,通过讲解你也将会知道同步通讯与异步通讯的区别,以及在什么情况下使用异步通讯。
1、配置OPC服务器
对于服务器的配置与同步通讯的配置一样,这里不需再讲解,若有不清楚的,可以参阅之前发布的<运用VC#编程通过OPC方式实现PC机与西门子PLC通讯>
2、OPC编程
变量组、项的命名规则与同步通讯的一样,这里不再描叙,下面主要就开发一个异步通讯类AsynServer来讲解如何编程。
<1>、引用
在VC#开发环境中添加对OpcRcw.Da库以及OpcRcw.Comn库的引用,该库属于.NET库,不属于COM库,西门子虽然编写了类库,以提供对.NET平台的支持,但这些类库仍然难于编程,里面包含了大量的在托管和非托管区传输数据,因此我们需要在它的基础上再开发一个类库,以简化以后的编程,首先在类的开头使用命名空间:
usingOpcRcw.Comn;
usingOpcRcw.Da;
usingSystem.Runtime.InteropServices;
usingSystem.Collections;
<2>、编程
异步编程的原理就是在OPC服务器那边检测当前活动的变量组,一但检测到某一个变量,譬如变量Q0.0从1变成0,就会执行一个回调函数,以实现针对变量发生变化时需要实现的动作,在这里可以采用委托来实现该功能。
1、在命名空间的内部、类AsynServer声明之前添加委托的申明:
//定义用于返回发生变化的项的值和其对应的客户句柄
publicdelegatevoidDataChange(object[]values,int[]itemsID);
2、该类继承于西门子提供的库接口IOPCDataCallback
publicclassAsynServer:
IOPCDataCallback
在类的开头部分声明变量:
structgroupStru
{
publicintgroupID;
publicobjectgroupObj;
}
internalconstintLOCALE_ID=0x407;//本地语言
privateGuidiidRequiredInterface;
privatestringserverType="";
privateinthClientGroup=0;//客户组号
privateintnSvrGroupID;//servergrouphandlefortheaddedgroup
privateHashtablehashGroup;//用于把组收集到一起
privateinthClientItem=0;//Item号
3、编写构造函数,接收委托参数已确定当数据发生变化时需要执行的方法入口点:
//创建服务器
//svrType服务器类型的枚举
//dataChange提供用于在数据发生变化时需要执行的函数入口
publicAsynServer(ServerTypesvrType,DataChangedataChange)
{
switch(svrType)
{
caseServerType.OPC_SimaticHMI_PTPRO:
serverType="OPC.SimaticHMI.PTPro";break;
caseServerType.OPC_SimaticNET:
serverType="OPC.SimaticNET";break;
caseServerType.OPC_SimaticNET_DP:
serverType="OPC.SimaticNET.DP";break;
caseServerType.OPC_SimaticNET_PD:
serverType="OPC.SimaticNET.PD";break;
caseServerType.OPCServer_WinCC:
serverType="OPCServer.WinCC";break;
}
hashGroup=newHashtable(11);
dtChange=dataChange;
}
4、创建服务器
//创建一个OPCServer接口
//error返回错误信息
//若为true,创建成功,否则创建失败
publicboolOpen(outstringerror)
{
error="";boolsuccess=true;
TypesvrComponenttyp;
//获取OPCServerCOM接口
iidRequiredInterface=typeof(IOPCItemMgt).GUID;
svrComponenttyp=System.Type.GetTypeFromProgID(serverType);
try
{
//创建接口
pIOPCServer=(IOPCServer)System.Activator.CreateInstance(svrComponenttyp);
error="";
}
catch(System.Exceptionerr)//捕捉失败信息
{
error="错误信息:
"+err.Message;success=false;
}
returnsuccess;
}
5、编写添加Group的函数
///
///添加组
///
///组名
////创建时,组是否被激活
/////组的刷新频率,以ms为单位
///返回错误信息
///若为true,添加成功,否则添加失败
publicboolAddGroup(stringgroupName,intbActive,intupdateRate,outstringerror)
{
error="";boolsuccess=true;
intdwLCID=0x407;//本地语言为英语
intpRevUpdateRate;
floatdeadband=0;
//处理非托管COM内存
GCHandlehDeadband;
IntPtrpTimeBias=IntPtr.Zero;
hDeadband=GCHandle.Alloc(deadband,GCHandleType.Pinned);
try
{
pIOPCServer.AddGroup(groupName,//组名
bActive,//创建时,组是否被激活
updateRate,//组的刷新频率,以ms为单位
hClientGroup,//客户号
pTimeBias,//这里不使用
(IntPtr)hDeadband,
dwLCID,//本地语言
outnSvrGroupID,//移去组时,用到的组ID号
outpRevUpdateRate,//返回组中的变量改变时的最短通知时间间隔
refiidRequiredInterface,
outpobjGroup1);//指向要求的接口
hClientGroup=hClientGroup+1;
groupStrugrp=newgroupStru();
grp.groupID=nSvrGroupID;grp.groupObj=pobjGroup1;
this.hashGroup.Add(groupName,grp);//储存组信息
//对异步操作设置回调,初始化接口
pIConnectionPointContainer=(IConnectionPointContainer)pobjGroup1;
Guidiid=typeof(IOPCDataCallback).GUID;
pIConnectionPointContainer.FindConnectionPoint(refiid,outpIConnectionPoint);
pIConnectionPoint.Advise(this,outdwCookie);
}
catch(System.Exceptionerr)//捕捉失败信息
{
error="错误信息:
"+err.Message;success=false;
}
finally
{
if(hDeadband.IsAllocated)hDeadband.Free();
}
returnsuccess;
}
6、编写激活、或者取消激活组的函数
在同步编程中对于组的激活或者取消激活没有实质的意义,但在异步通讯编程中却异常重要,这是因为OPC服务器只对当前处于活动状态的组中的变量进行监控,同时这也是很有必要的,因为我们可以把不同界面中的变量编程不同的组,即同一界面中的变量规成一个组,而在某一时刻提供给用户的只有一个界面,让该界面中用到的组处于活动状态,这样执行委托调用时只会执行于该界面中有关的变量检测,而如果让所有的组处于活动状态,则当前没有显示给用户的界面用到的变量若发生变化也会触发对委托函数的调用,这根本是没有必要的,同时会大大降低程序的性能,请严格控制组的激活。
///
///激活或者取消激活组
///
///指定组名
///true为激活,false为取消激活
///若有错误,返回错误信息
///若为true,添加成功,否则添加失败
publicboolAciveGroup(stringgroupName,booltoActive,outstringerror)
{
error="";boolsuccess=true;
//通过名称获取组
objectgrp=((groupStru)hashGroup[groupName]).groupObj;
IOPCGroupStateMgtgroupStateMgt=(IOPCGroupStateMgt)grp;
//初始化传递参数
IntPtrpRequestedUpdateRate=IntPtr.Zero;//由客户指定的Item更新间隔时间
intnRevUpdateRate=0;//由服务器返回的能够更新的最短时间间隔
IntPtrhClientGroup=IntPtr.Zero;//客户组
IntPtrpTimeBias=IntPtr.Zero;
IntPtrpDeadband=IntPtr.Zero;
IntPtrpLCID=IntPtr.Zero;
//激活或者取消激活组
intnActive=0;
GCHandlehActive=GCHandle.Alloc(nActive,GCHandleType.Pinned);
if(toActive)
hActive.Target=1;
else
hActive.Target=0;
try
{
groupStateMgt.SetState(pRequestedUpdateRate,outnRevUpdateRate,hActive.AddrOfPinnedObject(),pTimeBias,pDeadband,pLCID,hClientGroup);
}
catch(System.Exceptionerr)
{
error="错误信息:
"+err.Message;success=false;
}
finally
{
hActive.Free();
}
returnsuccess;
}
7、向指定的组中添加变量的函数
///
///向指定的组添加一系列项
///
///指定组名
///完整的item名数组
///由服务器返回读写数据时需要使用的item号
///无错误,返回true,否则返回false
publicboolAddItems(stringgroupName,string[]itemsName,int[]itemsID)
{
boolsuccess=true;
OPCITEMDEF[]ItemDefArray=newOPCITEMDEF[itemsName.Length];
for(inti=0;i
{
hClientItem=hClientItem+1;//客户项自动加1
ItemDefArray[i].szAccessPath="";//可选的通道路径,对于SimatiicNet不需要。
ItemDefArray[i].szItemID=itemsName[i];//ItemID,seeabove
ItemDefArray[i].bActive=1;//itemisactive
ItemDefArray[i].hClient=hClientItem;//clienthandle,在OnDataChange中会用到
ItemDefArray[i].dwBlobSize=0;//blobsize
ItemDefArray[i].pBlob=IntPtr.Zero;//pointertoblob
ItemDefArray[i].vtRequestedDataType=4;//DWord数据类型
}
//初始化输出参数
IntPtrpResults=IntPtr.Zero;
IntPtrpErrors=IntPtr.Zero;
try
{
//添加项到组
objectgrp=((groupStru)hashGroup[groupName]).groupObj;
((IOPCItemMgt)grp).AddItems(itemsName.Length,ItemDefArray,outpResults,outpErrors);
int[]errors=newint[itemsName.Length];
IntPtrpos=pResults;
Marshal.Copy(pErrors,errors,0,itemsName.Length);
for(inti=0;i
{
if(errors[i]==0)
{
OPCITEMRESULTresult=(OPCITEMRESULT)Marshal.PtrToStructure(pos,typeof(OPCITEMRESULT));
itemsID[i]=result.hServer;
pos=newIntPtr(pos.ToInt32()+Marshal.SizeOf(typeof(OPCITEMRESULT)));
}
else
{
StringpstrError;
pIOPCServer.GetErrorString(errors[0],0x407,outpstrError);
success=false;
break;
}
}
SetItenClient(groupName,items
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- OPC 技术 上位 PLC 之间 通信 现代工业 控制系统 通常 PC 为上