opc是object linking and embedding(ole)for process control 的缩写,它是微软公司的对象链接和嵌入技术在过程控制方面的应用。opc以ole/com/dcom技术为基础,采用客户/服务器模式,为工业自动化软件面向对象的开发提供了统一的标准,这个标准定义了应用microsoft操作系统在基于pc的客户机之间交换自动化实时数据的方法,采用这项标准后,硬件开发商将取代软件开发商为自己的硬件产品开发统一的opc接口程序,而软件开发者可免除开发驱动程序的工作,充分发挥自己的特长,把更多的精力投入到其核心产品的开发上。
simaticnet是西门子全集成自动化系统中的一个重要组成部分,它为完善的工业自动化控制系统的通讯提供部件和网络,同时提供多个opcserver,为数据的外部访问提供接口,本文主要以opc.simaticnet为例说明。
采用不同的通信方式,通过opc.simaticnet,现场数据可以方便地提供给用户:
opc的读写方式
在实际使用中,主要包括对现场数据的读写操作。
opc读数有三种方式:同步、异步、订阅。
同步通讯时,opc客户程序向opc服务器进行请求时,opc客户程序必须等到opc服务器对应的响应全部完成以后才能返回,在此期间opc客户程序一直处于等待状态,若进行读操作,那么必须等待opc服务器响应后才返回。因此在同步通讯时,如果有大量数据进行操作或者有很多opc客户程序对opc服务器进行读操作,必然造成opc客户程序的阻塞现象。因此同步通讯适用于opc客户程序较少,数据量较小时的场合。
异步通讯时,opc客户程序对服务器进行请求时,opc客户程序请求后立刻返回,不用等待opc服务器的响应,可以进行其它操作。opc服务器完成响应后再通知opc客户程序,如进行读操作,opc客户程序通知opc服务器后离开返回,不等待opc服务器的读完成,而opc服务器完成读后,会自动的通知opc客户程序,把读结果传送给opc客户程序。因此相对于同步通讯,异步通讯的效率更高。
订阅方式时,opc客户程序对服务器进行请求时,opc客户程序操作后立刻返回,不用等待opc服务器的操作,可以进行其它操作, opc 服务器的group组在组内有数据发生改变时,自动根据更新周期刷新相应的客户端数据,如下图,客户端只向opc服务发送一次请求,之后不再对服务器请求。
opc写数有两种方式:同步、异步。区别与上面讲的机制一样,在生产应用中,如果写数据参与控制,一般采用同步方式。
opc访问接口方式:
opc主要包含两种接口:custom标准接口和ole自动化标准接口,自定义接口是服务商必须提供的,而自动化接口则是可选的。
自定义接口是一组com接口,主要用于采用c++语言的应用程序开发;
自动化接口是一组ole接口,主要用于采用vb,delphi,excel等基于脚本编程语言的应用程序开发。
许多opc服务器,包括opc.simaticnet,是在com平台开发的,从而对于基于.net 框架下的c#语言,作为客户端程序语言访问opcserver,需要解决两个平台间无缝迁移的问题。opc基金会对会员提供了opcrcw动态链接库,opc net com包装器和opc net api,将opc复杂的规范封状成简单易用的c#类,可以比较容易地实现数据访问。
本文中通过实验,逐步讲解了通过c#编写客户端程序,访问opc.simaticnet,对plc数据进行读写的实现过程。自定义接口及自动化接口都进行了测试,但基于c#的语言特性,建议采用自定义接口访问,同时有很多opcserver服务商,对外是不提供自动化接口的,西门子的simaticnet及wincc的opcserver都提供自动化接口。
opc server端组态配置:
如上图建立连接s7_connection_1,然后在opc scout测试连接的正确性。
从上面可以看到数据访问都是正常的。
c#自动化接口
using system;
using system.collections.generic;
using system.componentmodel;
using system.data;
using system.drawing;
using system.text;
using system.windows.forms;
using system.collections;
using opcsiemensdaautomation;//引用连接库
第一步,添加下列命名空间(首先在com组件中添加相应组件)
using opcsiemensdaautomation;
第二步,定义opc相关变量
opcserver myopcserver; //定义opcserver
opcgroup myopcgroup; //定义组
opcitem myopcitem1; //item
opcitem myopcitem2; //值
long[] serverhandle = new long[2]; //item的句柄
第三步,建立连接及对象
myopcserver = new opcserver();
myopcserver.connect(opc.simaticnet, 192.168.0.102);
myopcgroup = myopcserver.opcgroups.add(mygroup1);
myopcitem1 = myopcgroup.opcitems.additem(s7:[s7 connection_1]db10,int0,1);
myopcitem2 = myopcgroup.opcitems.additem(s7:[s7 connection_1]db10,int2, 2);
serverhandle[0] = myopcitem1.serverhandle;
serverhandle[1] = myopcitem2.serverhandle;
第四步,同步读数据,
private void btn_read_s_click(object sender,eventargs e)//同步读数据
{
……
myopcitem1.read(1,out itemvalues,out qualities, out timestamps);
//itemvalues,qualities,timestamps分别是值,质量码
//也可以通过调用syncread函数,参数可参考异步读函数
……
}
第四步,同步写数据
private void btn_write_s_click(object sender,eventargs e)
{
……
myopcitem1.write(txt_w1.text);
//也可以通过调用syncwrite函数,参数可参考异步写函数
……
}
第五步,异步事件定义,
在异步操作情况下,需要定义相应的异步事件
myopcgroup.datachange +=new
diopcgroupevent_datachangeeventhandler(myopcgroup_datachange); //
//订阅方式下数据改变
itecomplete +=new
diopcgroupevent_asyncwritecompleteeventhandler(myopcgroup_writecomplete);
//写完成事件
myopcgroup.asyncreadcomplete += new
diopcgroupevent_asyncreadcompleteeventhandler(myopcgroup_readcomplete);
//读完成事件
myopcgroup.asynccancelcomplete += new
diopcgroupevent_asynccancelcompleteeventhandler(myopcgroup_cancelcomplete);
//取消操作事件
在使用中注意,其事件函数要按照特定接口:
void myopcgroup_datachange(int transactionid, int numitems,ref array clienthandles,
ref array itemvalues,ref array qualities, ref array timestamps)
void myopcgroup_writecomplete(int transactionid, int numitems, ref array clienthandles,
ref array errors)
void myopcgroup_readcomplete(int transactionid, int numitems,ref system.array
clienthandles,ref system.array itemvalues,ref system.array qualities,
ref system.array timestamps,ref system.array errors)
void myopcgroup_cancelcomplete(int cancelid)
第六步订阅方式读
void myopcgroup_datachange(int transactionid, int numitems,ref array clienthandles,
ref array itemvalues,ref array qualities, ref array timestamps)
{
……
//注意数据改变时,item数量要通过numitems得到,也就是说只有数据改变时,才对一
遍,所以降低了服务器负担。要注意读语句写法。
……
}
第七步异步读
private void btn_read_a_click(object sender,eventargs e)//异步读事件
{
int[] handle = new int[3] {serverhandle[0], serverhandle[1],0};//注意方式
array myserverhandles = (array)handle;
array errors;
int cancelid;
……
myopcgroup.asyncread(2, ref myserverhandles, out errors, readasync_id, out
cancelid);
……
}
void myopcgroup_readcomplete(int transactionid, int numitems,ref system.array
clienthandles,ref system.array itemvalues,ref system.array qualities,
ref system.array timestamps,ref system.array errors)
{
……
//注意transactionid的对应
……
}
注意array在函数内部做参数时,数据下标是从1开始的,所以要考虑将第0位空出
来,n个item,就要定义n+1列数组,添加一个0,但在函数使用时,又是从左开始读的。
否则会报错。
第八步异步写
private void btn_write_a_click(object sender,eventargs e)
{
……
myopcgroup.asyncwrite(2,ref myserverhandles, ref myvalues,out errors,
writeasync_id,out cancelid);
……
}
void myopcgroup_writecomplete(int transactionid, int numitems, ref array clienthandles
ref array errors)
{
……
}
同样要注意array在函数内部做参数的传递。
第九步释放对象
private void btn_disconn_click(object sender,eventargs e)
{
……
}
opcitem的数据类型:
在通过自定义接口访问时,
itemarray[1].szaccesspath = ;
itemarray[1].szitemid = s7:[s7 connection_1]db10,real4;//地址,不同数据类型表示
itemarray[1].bactive = 1;//是否激活
itemarray[1].hclient = 2;//表示id
itemarray[1].dwblobsize = 0;
itemarray[1].pblob =intptr.zero;
itemarray[1].vtrequesteddatatype = 5;
itemarray[2].szaccesspath = ;
itemarray[2].szitemid = s7:[s7 connection_1]db10,string26.10;//地址,不同数据类型表
示方法不同
itemarray[2].bactive = 1;//是否激活
itemarray[2].hclient = 3;//表示id
itemarray[2].dwblobsize = 0;
itemarray[2].pblob =intptr.zero;
itemarray[2].vtrequesteddatatype = 8;
中兴事件背后深层原因,思索企业体制外创新发展的新模式
中国尚无国产机器能够对28nm CMOS进行光刻?
微软向世人展示48核ARM服务器
关于嵌入式处理系统与个人计算机的架构
太阳能移动电源 户外爱好者必备神器
OPC访问接口方式以及读写方式
分布式存储服务器面临的问题有哪些
欧胜世界领先音频解决方案被OPPO电子选用
2021年云计算的发展趋势预测
!!销售/收购!AGILENT54835A 示波器 HP
EPC概念和技术的产生及其特性分析
携手高通,“一起重新定义汽车”!
如何选择一款适合的功率放大器,要注意哪些方面
博通高通合并不被支持,会伤害微软和谷歌
打印机加装RFID控制模块方案
电流传感器在轨道交通行业中的应用
移动充电宝哪个最便宜?便宜又耐用的充电宝推荐
关于CPU指令集架构详细讲解
pfa热缩管热缩温度是多少?
新能源补贴政策还未出来 电动车生产企业却率先涨价