折腾了一段时间研究OPC,理清了下位机、OPCServer 和OPCClient的关系和通信模型,终于能够来写一篇相关的博客了。

我们使用西门子的 S7 200 SMART作为下位机端,通过3G路由器从vpn与公司服务器通信,服务器运行配置好的PC Access SMART 作为OPC Server, 完成对下位机内存地址的定义后,使用自动化接口开发中间件负责将OPC Server得到的PLC数据存放至SQL Server

中间件和数据库的设计思路是:

数据库按真实设备类型分别建表用作存储,数据库建有数据字典表用作配置功能,包括配置内存地址和opc服务等。

中间件作用是调用OPCAutomation 类访问OPCServer端,并进行可控制读取间隔的OPC数据读取、存储工作。

由于第一次接触这类开发,在设计功能时花费了很多精力,从完全不懂到基本理解这种通信模式和原理,也绕了不少远路。

本文主要介绍OPCAutomation类的使用。

简单说下流程就是:

1. 创建OPC Server的连接

2. 创建OPC组对象并初始化设置

3. 获取组的OPCItems对象,为读取数据作准备

4. opcItem的操作。

5. 退出程序的资源释放

创建连接很简单,需要指定OPCServer所在的服务器(内网可以指定ip或者计算机名),指定OPC服务的名称(同一服务器可能运行多个OPC服务以适配同的下位机)

        private bool ConnectRemoteServer(string remoteServerIP, string remoteServerName)
{
try
{
this.opcServer.Connect(remoteServerName, remoteServerIP);
string status;
if (opcServer.ServerState == (int)OPCServerState.OPCRunning)
{
status = "已连接到-" + opcServer.ServerName + " ";
}
else
{
//这里你可以根据返回的状态来自定义显示信息,请查看自动化接口API文档
status = "状态:" + opcServer.ServerState.ToString() + " ";
}
Console.WriteLine(status);
}
catch (Exception err)
{
Console.WriteLine("连接远程服务器出现错误:" + err.Message, "提示信息");
return false;
}
return true;
}

其中 this.opcServer.Connect(remoteServerName, remoteServerIP);即OPCAutomation类提供的连接方法。

需要注意的是,在实际配置时,需要完全对OPC 服务端所在服务器上配置防火墙出入站规则后,OPC服务才能够被其他服务器上的中间件访问到。故我们选择最简单的方式,在本机运行中间件。

创建组相当于读取到OPC上特定的项目,而具体的数据值是在每个项目下根据开发人员的定义而确定。

opcGroups = opcServer.OPCGroups;
opcGroup = opcGroups.Add("OPCDOTNETGROUP");
SetGroupProperty();
opcGroup.DataChange += new DIOPCGroupEvent_DataChangeEventHandler(opcGroup_DataChange); //opcGroup.AsyncWriteComplete += new DIOPCGroupEvent_AsyncWriteCompleteEventHandler(KepGroup_AsyncWriteComplete); opcItems = opcGroup.OPCItems;

注释的代码是绑定写操作的事件。

这段代码是为OPCGroup对象进行初始化。 比较关键的是两句绑定事件的,第一个绑定的是每当OPC数据有变化时触发的事件。

数据变化的时间是由以下代码中UpdateRate控制。

        private void SetGroupProperty()
{
opcServer.OPCGroups.DefaultGroupIsActive = true;
opcServer.OPCGroups.DefaultGroupDeadband = ;
opcGroup.UpdateRate = this.updateRate;
opcGroup.IsActive = true;
opcGroup.IsSubscribed = true;
}

关于逐项配置的具体说明,建议参考OPCAutomation的api,如果有看到翻译比较合适的后续会补充上来。

之后是为全局变量里的OPCGroup对象添加Items,在OPC中,每个opcItem会被分配一个客户端句柄值,同时会被配置上服务端句柄。几乎所有有关获取指定OpcItem对象的方法均要求指定客户端句柄值。

        void AddAllOpcItem()
{
opcBrowser.ShowBranches();
opcBrowser.ShowLeafs(true);
int count = this.opcBrowser.Count;
if (this.opcItemsArray == null)
{
opcItemsArray = new List<string>();
}
foreach (var item in opcBrowser)
{
opcItemsArray.Add(item.ToString());
}
AddOpcItems();
}
//逐项绑定句柄值
void AddOpcItems()
{
foreach (var item in this.opcItemsArray)
{
itmHandleClient = ;
opcItem = opcItems.AddItem(item, itmHandleClient);
itmHandleServer = opcItem.ServerHandle;
}
}

这段代码是为了把获取到的全部OPCItem添加到所创建的OPCGroup对象的opcItem集合中,以便我们所绑定的DataChange事件能够被触发并且正确对应到每个地址值上

基本上到此,只要在所绑定的DataChange的实现代码中完成具体的数据读取业务,中间件的核心部分已经完成。

稍微提一下,OPC的数据项主要包含:名称、条目id、地址、数据类型、数据值、工程单位上下限、时间戳和质量几项,在实际业务中我们关注条目ID、数据类型、值、时间戳和质量,对于读取的opc数据值而言,需要注意的是得到值是Dynamic类型的,需要正确进行判断和转换。质量返回值为0时基本可以认为下位机到服务端的数据链断了,或者下位机对应项目没有收到数据,据此可进行日志和提示的业务操作。

在OPC的数据类型中,REAL对应float, WORD对应16位整型,BOOL可以用bit或者Bool进行转换,用bit和sql server的数据项可以比较方便对接。

第一次做这类开发,谬误难免,希望多多指点。

感谢阅读。

【OPCAutomation】 使用OPCAutomation实现对OPC数据的访问的更多相关文章

  1. C# - VS2019 通过DataGridView实现对Oracle数据表的增删改查

    前言 通过VS2019建立WinFrm应用程序,搭建桌面程序后,通过封装数据库操作OracleHelper类和业务逻辑操作OracleSQL类,进而通过DataGridView实现对Oracle数据表 ...

  2. 使用JWT来实现对API的授权访问

    目录 什么是JWT JWT的结构 Header Payload Signature 解码后的JWT JWT是怎样工作的 在JAVA里使用JWT 引入依赖 JWT Service 生成JWT 解码JWT ...

  3. SILVERLIGHT实现对HTML DOM的访问

    实现对HTML DOM的访问.Silverlight 2在命名空间System.Windows.Browser下内置了很多对于HTML DOM访问和操作的支持,我们最常用的一个对象是HtmlEleme ...

  4. js实现对json数据的序列化(兼容ie6以上浏览器)

    /** * 增加对JSON数据的序列化方法, * 主要用于IE6.7不支持JSON对象的浏览器 */ var xue = xue || {};xue.json = xue.json || {}; xu ...

  5. python实现对excel数据进行修改/添加

    import osimport xlrdfrom xlutils.copy import copydef base_dir(filename=None): return os.path.join(os ...

  6. C++实现对Json数据的友好处理

    背景 C/C++客户端需要接收和发送JSON格式的数据到后端以实现通讯和数据交互.C++没有现成的处理JSON格式数据的接口,直接引用第三方库还是避免不了拆解拼接.考虑到此项目将会有大量JSON数据需 ...

  7. SQLite帮助类SQlitehelper 实现对SQLite数据的增删改查

    public class SQLiteHelper { public const string sConn = "Data Source=" + @"path" ...

  8. Java Web学习系列——Maven Web项目中集成使用Spring、MyBatis实现对MySQL的数据访问

    本篇内容还是建立在上一篇Java Web学习系列——Maven Web项目中集成使用Spring基础之上,对之前的Maven Web项目进行升级改造,实现对MySQL的数据访问. 添加依赖Jar包 这 ...

  9. 写出java8实现对List<User>中的username字段过滤出不等于张三的数据

    写出java8实现对List<User>中的username字段过滤出不等于张三的数据... 对...这个是一道面试题.当时没有看过java8的新特性...所以有点懵. 看完之后感觉 真. ...

随机推荐

  1. TCP 和 UDP 的区别---还有一个UTP一

    面试的时候会经常问到这些问题,所以要对比了解一下他们之间的差别,能讲出个所以然来.多积累多总结,懵逼中... TCP 和 UDP TCP与UDP基本区别 : 1.基于连接与无连接 2.TCP要求系统资 ...

  2. 记录将CentOS7linux系统python升级到3后yum安装是报错File "/usr/bin/yum", line 30 except KeyboardInterrupt, e: ^ SyntaxError: invalid syntax问题解决

    前两天将CentOS7里的python版本升级到了3.5.2 今天想装个解压软件,在执行yum install -y XXX 的时候报错 然后按照提示打开这个文件 vi /usr/bin/yum yu ...

  3. [Git] 006 在本地新建一个仓库

    1. 方法一 1.1 思路 在 GitHub 上新建一个仓库 clone 到本地 1.2 行动 1.2.1 在 GitHub 上选好自己已有的仓库 点击 "Clone or download ...

  4. [Python3 练习] 005 汉诺塔1 递归解法

    题目:汉诺塔 I (1) 描述 传说,在世界中心贝拿勒斯(在印度北部)的圣庙外有左中右三根足够长的柱子(塔) 左边柱子上套着 64 片金片,金片按"上小下大"排,其余两根是空柱子 ...

  5. [2019杭电多校第七场][hdu6655]Just Repeat

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6655 题意是说两个人都有一些带有颜色的牌,两人轮流出牌,但是不能出对面出过的颜色的牌,最后谁不能出牌谁 ...

  6. GooglePlay

    如何下载googlePLay的apk文件? 1.首先要知道apk的package名: 打开GooglePlay的页面,在地址栏里就会有https://play.google.com/store/app ...

  7. eclipse 使用技巧、经验 (编码、格式化模板、字体)

    版权声明:本文为博主原创文章,未经博主同意不得转载.安金龙 的博客. https://blog.csdn.net/smile0198/article/details/28697515 1.设置编码为U ...

  8. 21、前端知识点--html5和css3新特性汇总

    跳转到该链接 新特性汇总版: https://www.cnblogs.com/donve/p/10697745.html HTML5和CSS3的新特性(浓缩好记版) https://blog.csdn ...

  9. css盒子模型之边框宽度,边框颜色与边框样式

    /* width和height只是设置盒子内容区的大小,而不是盒子的整个大小, 盒子可见框的大小由内容区,内边距和边框共同决定. */ .box1 { /* 设置内容区的宽度为400px */ wid ...

  10. VS Code 设置双快捷键(快速移动光标)

    平时写代码会经常用到上下左右键,比如打出两个括号 () ,编辑完之后得按到右括号后面 难免有这样的场景需要在编辑代码的时候小范围地移动光标,笔者在别的ide的习惯是通过“alt + jkli”来实现光 ...