【OPCAutomation】 使用OPCAutomation实现对OPC数据的访问
折腾了一段时间研究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数据的访问的更多相关文章
- C# - VS2019 通过DataGridView实现对Oracle数据表的增删改查
前言 通过VS2019建立WinFrm应用程序,搭建桌面程序后,通过封装数据库操作OracleHelper类和业务逻辑操作OracleSQL类,进而通过DataGridView实现对Oracle数据表 ...
- 使用JWT来实现对API的授权访问
目录 什么是JWT JWT的结构 Header Payload Signature 解码后的JWT JWT是怎样工作的 在JAVA里使用JWT 引入依赖 JWT Service 生成JWT 解码JWT ...
- SILVERLIGHT实现对HTML DOM的访问
实现对HTML DOM的访问.Silverlight 2在命名空间System.Windows.Browser下内置了很多对于HTML DOM访问和操作的支持,我们最常用的一个对象是HtmlEleme ...
- js实现对json数据的序列化(兼容ie6以上浏览器)
/** * 增加对JSON数据的序列化方法, * 主要用于IE6.7不支持JSON对象的浏览器 */ var xue = xue || {};xue.json = xue.json || {}; xu ...
- python实现对excel数据进行修改/添加
import osimport xlrdfrom xlutils.copy import copydef base_dir(filename=None): return os.path.join(os ...
- C++实现对Json数据的友好处理
背景 C/C++客户端需要接收和发送JSON格式的数据到后端以实现通讯和数据交互.C++没有现成的处理JSON格式数据的接口,直接引用第三方库还是避免不了拆解拼接.考虑到此项目将会有大量JSON数据需 ...
- SQLite帮助类SQlitehelper 实现对SQLite数据的增删改查
public class SQLiteHelper { public const string sConn = "Data Source=" + @"path" ...
- Java Web学习系列——Maven Web项目中集成使用Spring、MyBatis实现对MySQL的数据访问
本篇内容还是建立在上一篇Java Web学习系列——Maven Web项目中集成使用Spring基础之上,对之前的Maven Web项目进行升级改造,实现对MySQL的数据访问. 添加依赖Jar包 这 ...
- 写出java8实现对List<User>中的username字段过滤出不等于张三的数据
写出java8实现对List<User>中的username字段过滤出不等于张三的数据... 对...这个是一道面试题.当时没有看过java8的新特性...所以有点懵. 看完之后感觉 真. ...
随机推荐
- 如何在CentOS 7上安装Node.js和npm
Node.js是一个跨平台的JavaScript运行时环境,允许在服务器端执行JavaScript代码.Node.js主要用于后端,但也作为全栈和前端解决方案而流行. npm,Node软件包管理器的缩 ...
- MySQL 简介
MySQL 简介 点击查看MySQL官方网站 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,后来被Sun公司收购,Sun公司后来又被Oracle公司收购,目前属于Oracle旗 ...
- python基础-文件操作的其他方法
# f=open('code.txt','rb')#b的方式不能指定打开编码格式,以二进制的方式打开文件 # data=f.read() # print(data) # #encode 编码 deco ...
- leetcode 实现-168.Excel表列名称
168.Excel表列名称 描述 给定一个正整数,返回它在 Excel 表中相对应的列名称. 例如, 1 -> A 2 -> B 3 -> C … 26 -> Z 27 -&g ...
- 重启uwsgi
sudo pkill -f uwsgi -9 uwsgi --ini mysite.uwsgi.ini
- BZOJ 1911 特别行动队 (斜率优化)
$ BZOJ~1911~*~ $ 特别行动队: (斜率优化) $ solution: $ 感觉这道题目还是比较常规的,首先我们很容易想到DP,因为题目里面说了选出的人都是连续的,这意味着我们可以从前往 ...
- mongodb 用户 权限 设置 详解
原文地址:http://blog.51yip.com/nosql/1575.html 我知道的关系型数据库都是有权限控制的,什么用户能访问什么库,什么表,什么用户可以插入,更新,而有的用户只有读取权限 ...
- 信号量计算问题--n个进程, 共享3个资源, 当前信号量为-1, 其他进程继续执行P操作, 那么信号量应该继续减
选B
- Python---基础-小游戏用户猜数字2
一.使用int()将小数转换成整数,结果是向上取数还是向下取数 int(3,4) print(int(3,4)) ####写一个程序,判断给定年份是否为闰年 - 闰年的定义,能够被4整除的年份就叫闰年 ...
- PyTorch 手动提取 Layers
Model NeuralNet( (l0): Linear(in_features=6, out_features=256, bias=True) (relu): ReLU() (bn0): Batc ...