总结自己在opc与自控开发的经验。首先介绍OPC DA模式下的OPC各种操作。

在使用opc时需要引用到 OPCDAAuto.dll 这个类库。

在项目引用后需要注册这个类库,否则程序跑起来会报错,“未找到工厂类 。。。”

将该dll文件放在任意目录下,建议在引用程序的的同级目录下。

在 cmd 控制台  输入regsvr32  Q:\PLCDataIntegration\packages\01OPCDaAuto\OPCDAAuto.dll

注册完成后电脑会提示注册成功,这时,就可以使用工具类中的方法啦。

1.定义相关变量

        private OPCServer opcServer;
private OPCGroups opcGroups;
private OPCGroup opcGroup;
private List<int> itemHandleClient = new List<int>();
private List<int> itemHandleServer = new List<int>();
private List<string> itemNames = new List<string>();
private List<model> modelValues = new List<model>();
private OPCItems opcItems;
private OPCItem opcItem;
private Dictionary<string, string> itemValues = new Dictionary<string, string>();

  

2.使用opc从plc中读取数据。这个是使用OPC DAAuto中的Connect方法。Connect之前要先

创建OPCServer 对象

opcServer = new OPCServer(); 

OPCServer.StartTime:服务器的启动时间

OPCServer.CurrentTime:服务器的当前时间,各个客户端可以通过这个属性值完成一些同步的操作

//strHostIP 主机IP,DA模式下通常为127.0.0.1;
//strHostName opc服务名,通常为字符串,例如kepsserver 的opc名称为 Kepware.KepServerEX.V6
 private bool ConnectServer(string strHostIP, string strHostName)
{
try
{
opcServer = new OPCServer();
opcServer.Connect(strHostName, strHostIP);
}
catch (Exception ex)
{
SaveCommand("连接到OPC服务器失败!" + ex.Message);
return false;
}
txtLog.Text += "连接到OPC服务器成功!" + "\r\n";
return true;
}

3.连接成功后就可以用opcServer这个对象了。

根据自己开发OPCServer 和OPCClient的经验,这里的OPCGroups与OPCGroup可以用树来理解,OPCGroups下可以有很多OPCGroup,OPCGroup下添加很多测点item。

OPC API 里AddItem 就是往OPCGroup下添加测点

4.OPCGroups与OPCGroup

  opcGroups = opcServer.OPCGroups;
 opcGroup = opcGroups.Add("YoursGroupName");

这里从OPCServer中获取OPCGroups信息,保持一致。

而OPCGroups下的OPCGroup可自行添加,然后自己注册的测点属性都在这个组下面

可以给OPCGroup设置如下属性,这将影响到这个组下面的测点数据采集频率等。

     private void SetGroupProperty(OPCGroup opcGroup, int updateRate)
{
opcGroup.IsActive = true;
opcGroup.DeadBand = 0f;
opcGroup.UpdateRate = updateRate;
opcGroup.IsSubscribed = true;
}
UpdateRate是一个整型值,影响组中测点数据更新频率。相关属性如下
OPCGroups.Count:下属组(Group)的数量
DefaultGroupIsActive(新添加的OPC组的活动状态的默认值。默认初始值是活动状态)
DefaultGroupUpdateRate(新添加的OPC组的默认数据更新周期,默认初始值是1000亳秒)、
DefaultGrouPDeadband( 新添加的OPC组的默认不敏感区的默认值,即能引起数据变化的最小数值百分比,默认值是0%)
DefaultGroupLocaleID(新添加的OPC组区域标识符的默认值)
DefaultGroupTimeBias(新添加的OPC组的时间偏差的默认值)等。

5.设置OPCGroup属性

  opcGroups = opcServer.OPCGroups;
opcGroup = opcGroups.Add("MYOPCGROUP");
SetGroupProperty(opcGroup, UpdateRateOPC);
opcItems = opcGroup.OPCItems;

6.注册opc监控测点。根据项目实际情况将监测点取出,以字符串数组传递。

        public void AddItems(string[] itemNamesAdded)
{
itemHandleServer.Clear(); for (int i = 0; i < itemNamesAdded.Length; i++)
{
itemNames.Add(itemNamesAdded[i]);
itemValues.Add(itemNamesAdded[i], "");
}
for (int j = 0; j < itemNamesAdded.Length; j++)
{
try
{
itemHandleClient.Add((itemHandleClient.Count == 0) ? 1 : (itemHandleClient[itemHandleClient.Count - 1] + 1));
opcItem = opcItems.AddItem(itemNamesAdded[j], itemHandleClient[itemHandleClient.Count - 1]);
itemHandleServer.Add(opcItem.ServerHandle);
}
catch (Exception ex)
{
SaveCommand(itemNamesAdded[j] + ex.Message);
}
}
}

7.注册读写或数据变化事件,opc的事件很多,常用的有以下几个。

opcGroup.AsyncWriteComplete //测点写入完成后触发
opcGroup.AsyncReadComplete //读取指令完成后触发
opcGroup.DataChange  //opcc测点数值变化后触发,通常用于实时数据上报

 //注册事件,然后在自己的方法里实现相关操作
opcGroup.AsyncWriteComplete += new DIOPCGroupEvent_AsyncWriteCompleteEventHandler(opcGroup_AsyncWriteComplete);

opcGroup.DataChange += new DIOPCGroupEvent_DataChangeEventHandler(KepGroup_DataChange);

opcGroup.AsyncReadComplete += new DIOPCGroupEvent_AsyncReadCompleteEventHandler(GroupAsyncReadComplete);

//实现方法 KepGroup_DataChange

        /// <summary>
/// 数据变动转储
/// </summary>
/// <param name="TransactionID"></param>
/// <param name="NumItems"></param>
/// <param name="ClientHandles"></param>
/// <param name="ItemValues"></param>
/// <param name="Qualities"></param>
/// <param name="TimeStamps"></param>
private void KepGroup_DataChange(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps)
{
string itemID = string.Empty; try
{
string text = "hello rabbit";
int i = 0;
for (i = 1; i <= NumItems; i++)
{
//SetLogInfo($"{ItemValues.GetValue(i)}", Color.Green); if (ItemValues.GetValue(i) == null) { continue; } text = ItemValues.GetValue(i).ToString(); //SetLogInfo($"本次发布消息{text}", Color.Green); itemID = opcItems.GetOPCItem(itemHandleServer[(int)ClientHandles.GetValue(i) - 1]).ItemID; string message = itemID + ":" + text; MessageBox.Show(mesage);
} }
catch (Exception ex)
{
SaveCommand(ex.Message + itemID);
}
}

实现方法 GroupAsyncReadComplete

        private void GroupAsyncReadComplete(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps, ref Array Errors)
{ //SaveCommand("**********GroupAsyncReadComplete***********"); string itemID = string.Empty;
string empty = string.Empty; try
{ int i = 0; for (i = 1; i <= NumItems; i++)
{
//非空判断,防止程序异常中断
if (ItemValues.GetValue(i) != null)
{
empty = ItemValues.GetValue(i).ToString();
} //获取监测点id
itemID = opcItems.GetOPCItem(itemHandleServer[(int)ClientHandles.GetValue(i) - 1]).ItemID; string text = itemID + ":" + empty; MessageBox.Show("读取完成,结果为"+text);
} MessageBox.Show($"本次读取完成,共{i}个", Color.Blue, 2);
}
catch (Exception ex)
{
MessageBox.Show($"GroupAsyncReadComplete:{ex.Message},itemID:{ itemID }");
}
}

7.使用监测数据,在成功读取到数据后就可以按自己的需求使用数据了,可以存到数据库,放到Redis,或者推到Rabbit等消息队列都没问题。

8.通过opc写入测点值实现,远程控制plc

其实远程控制,在代码层面来看并没有那么复杂,因为前面的工作都做好后,opc通道已经打开的情况下,控制只是一个写入操作。把指定的值写到指定的测点中,就是这么简单。实现控制难点不在控制本身,重点难点在于保证通信网络的稳定,和监测状态的

实时返回。总而言之,控制本身不复杂,复杂在安全性和稳定型的保证上。使用opc多为IT与OT融合的情景之下,IT平台本身缺乏对底层设备的有效监管,需要借助于opc客户端充当代理中介角色。这时OPC客户端本身的稳定性,和时效型显得尤为重要。这点

需要研发人员多多考虑。这点大家有好的方法可以评论分享下。

         //调用示例

string[] array2 = {"LCU1.PLC_GATE1_OPEN"};//点号开启1号闸门
          string[] array3 = {"1"};

         AsyncWrite(array2, array3);      

/// <summary>
/// 异步写方法,支持批量操作也可以调用opc单点读写方法
/// </summary>
/// <param name="writeItemNames"></param>
/// <param name="writeItemValues"></param>
public void AsyncWrite(string[] writeItemNames, string[] writeItemValues)
{
try
{
OPCItem[] array = new OPCItem[writeItemNames.Length];
for (int i = 0; i < writeItemNames.Length; i++)
{
for (int j = 0; j < itemNames.Count; j++)
{
if (itemNames[j] == writeItemNames[i])
{
array[i] = opcItems.GetOPCItem(itemHandleServer[j]);
break;
}
}
}
int[] array2 = new int[writeItemNames.Length + 1];
array2[0] = 0;
for (int k = 1; k < writeItemNames.Length + 1; k++)
{
array2[k] = array[k - 1].ServerHandle;
}
Array ServerHandles = array2;
object[] array3 = new object[writeItemNames.Length + 1];
array3[0] = "";
for (int l = 1; l < writeItemNames.Length + 1; l++)
{
array3[l] = writeItemValues[l - 1];
}
Array Values = array3;
opcGroup.AsyncWrite(writeItemNames.Length, ref ServerHandles, ref Values, out Array _, 2009, out int _);
GC.Collect();
}
catch (Exception ex)
{ MessageBox.Show(ex.Message);
}
}

至此OPC基本操作都完成了,OPC提供的官方API很深奥,有很多可以学的东西。OPC现在已经是自动化领域,跨域提供数据的潮流了,尤其时OPC UA发布后,自动化(OT)与信息化(IT)日趋融合,opc在传统自动化企业转型中应该会担任比较重要的角色。

所以OPC还是很值得一学的。

分享一首好听的歌 错都错了 ~~~

使用OPC与PLC通讯 一的更多相关文章

  1. PLC 通讯

    几个之前整理的高级语言与PLC通讯的资源下载链接:三菱:http://blog.sina.com.cn/s/blog_16d7d3ecb0102x6wj.html倍福:http://bbs.elecf ...

  2. WeinView 与 MITSUBISHI FX 系列 PLC 通讯范例

    1. 范例操作概述 此范例将介绍如何快捷简易地建立WEINVIEW HMI与MITSUBISHI FX系列 PLC通讯. 注意事项:通讯参数设置,通讯线接法. 2. 规划说明 (1) 新建简单 PLC ...

  3. C#与西门子PLC通讯

    1.0  通讯组件概述 通讯组件用于PC与可编程控制器(PLC).智能仪表等进行数据通讯,适用于基于PC高级语言的工业自动化控制系统.组件采用动态链接库文件(*.DLL)的形式,在PC系统的项目工程里 ...

  4. 【转】常用PLC通讯协议

    三菱FX系列PLC通讯测试 发送帧(Hex): 起始(STX) 02 命令(CMD) 30 首地址(ADDRESS) 30 30 41 30 字节数(BYTES) 30 31 终止(ETX) 03 校 ...

  5. 对S7通信的连接的理解以及对比CAN通信协议来理解PLC通讯

    对S7通信的连接的理解以及对比CAN通信协议来理解PLC通讯. 对功能块 SFB12 和 SFB13 的R_ID参数的理解 ? 对于同一个数据包.发送方与接收方的R_ID应该相同. 用下图解释 双向连 ...

  6. 威纶通 与 信捷XC\XD系列PLC 通讯

    第一次使用信捷XD系列PLC正式做个项目,用的触摸屏为威纶通的 MT6071iP (注意:下面内容同样适用于 信捷XC系列PLC ,除信捷XC与XD系列编程软件不一样,其余接线设置实测均一样 ) 目前 ...

  7. 基于TCP/IP的Matlab Modbus与M340 PLC通讯

    本人原创,代码拿出来供大家交流学习经验,勿作他用. 废话不多说,代码直接上. 1.创建链接 function link = connect_create(client_addr,port) %**** ...

  8. 欧姆龙plc通讯协议格式

    欧姆龙CPM1A型plc与上位计算机通信的顺序是上位机先发出命令信息给PLC,PLC返回响应信息给上位 机.每次通信发送/接受的一组数据称为一"帧".帧由少于131个字符的数据构成 ...

  9. 基于ModBus-TCP/IT 台达PLC 通讯协议解析

    客户端发送:19 B2 00 00 00 06 06 03 00 27 00 02 上面是modbus客户端发出的报文内容,为modbus tcp/ip协议格式,其前面的六个字节为头字节( heade ...

随机推荐

  1. Spring IOC&DI 控制反转和依赖注入

    控制反转(Inversion of Control,缩写为IOC),它是把你设计好的对象交给spring控制,而不再需要你去手动 new Object(); 网上对于IOC的解释很多,对程序员而言,大 ...

  2. 面向政务企业的开发者工具集-逐浪文本大师v0.1正式发布(含代码全部开源啦!)

    这是一款基于.net 4.7环境开发的开发者工具. 一个实用的windows小工具集合,里面包含了多个常用的小软件.其中的批量修改文件名及文件内容功能,可以自定义修改规则,支持规则的导入与导出.不需要 ...

  3. C# 复制目录及其下文件

    public static void CopyDirectory(string sourceDirPath, string saveDirPath) { try { if (!Directory.Ex ...

  4. [hdu6595]Everything Is Generated In Equal Probability

    计算一对逆序对的贡献,即在n个数期望要删多少步才能删掉其中的两个数,设f(n)表示此时的期望,则有方程$f[n]=3/4+(\sum_{i=2}^{n}f[i]\cdot c(n-2,i-2))/2^ ...

  5. [hdu4747]Mex

    首先计算出以1为左端点的所有区间的mex,考虑删除左端点仍然维护这个序列:设当前删除点下一次出现在y,y~n的mex不变,从左端点到y的点中大于删除值的点要变成删除值,因为这个是不断递增的,所以是一段 ...

  6. [hdu6349]三原色图

    考虑分别求出RG和GB的最小生成树,然后剩下的边中肯定选择较小的边加入这两颗生成树 1 #include<bits/stdc++.h> 2 using namespace std; 3 # ...

  7. [loj3272]汉堡肉

    当$k\le 3$,这是一个经典的问题 设所有矩形左下角横纵坐标的最大值为$(x_{1},y_{1})$,右上角横纵坐标的最小值为$(x_{2},y_{2})$,那么必然存在一组合法解满足其中一点为$ ...

  8. 在Ubuntu上安装Docker Engine

    在Ubuntu上安装Docker Engine 这篇文章是介绍如何在在Ubuntu上安装Docker Engine,就是Google翻译官方文档的版本,英语好的直接官方原文.原文 要在Ubuntu上开 ...

  9. 洛谷 P6189 - [NOI Online #1 入门组]跑步(根号分治+背包)

    题面传送门 题意: 求有多少个数列 \(x\) 满足: \(\sum x_i=n\) \(x_i\geq x_{i+1}\) 答案对 \(p\) 取模. ...你确定这叫"入门"组 ...

  10. 【豆科基因组】普通豆/菜豆/四季豆Common bean (Phaseolus vulgaris L.) 683个自然群体重测序2020NG

    目录 一.来源 二.结果 683份材料重测序 地方种landraces和育种品系breeding lines的多样性 表型和基因-环境互作(G by E) 菜豆产量潜力相关的MTAs(显著关联位点) ...