背景:做一个系统要对接OPC,所以要学习一下OPC客户端的开发。
解决:OPC实际上是为了给工业控制系统应用程序之间提供一种接口规范。作为使用最多的对接技术,OPC具有它的优势,硬件供应商只需提供符合OPC标准的server,安装到windows服务器上,软件提供商编写OPC的客户端,只需对接业务中OPC项对应的数据项即可完成对接。
C#开发OPC客户端,采用的是自动化接口(即OPCDAAuto.dll这个引用集);当然开发的话需要在机器上注册需要的程序集。
然后配置DCOM的权限,可以搜一下OPC下DCOM的权限设置。
然后就是在程序上进行开发了。
OPC客户端流程(当然这是我们这业务的流程,具体可以按OPC的属性方法增删过程)
Demo:
using OPCAutomation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
namespace OpcClient
{
class Demo
{
#region 变量
//OPCServer的IP
private String strHostIP;
//OPCServer名称
private String strOpcServerName;
//OPCServer的主机名
private String strHostName;
//是否和OPCServer建立连接
private Boolean opc_connected;
//建立的OPCServer对象
private OPCServer myServer;
//OPCServer节点浏览器
private OPCBrowser myOPCBrowser;
//分组集合
private OPCGroups myGroups;
//分组实例
private OPCGroup myGroup;
//分组的TAG节点
private OPCItems myItems;
//服务端句柄
int itmHandleServer = 0;
//要写入的叶子节点
private OPCItem[] myItemArray;
//tag点集合
private Dictionary<string, string[]> dictitems = new Dictionary<string, string[]>();
#endregion
private void Connect()
{
//通过IP来获取OPC服务器主机名
IPHostEntry ipHostEntry = Dns.GetHostEntry(strHostIP);
strHostName = ipHostEntry.HostName.ToString();
//实例化OPC服务
myServer = new OPCServer();
//获取OPCServer列表
object serverList = myServer.GetOPCServers(strHostName);
//根据选择的OPCServer进行连接
myServer.Connect(strOpcServerName, strHostIP);
//实例化Tag浏览器
myOPCBrowser = myServer.CreateBrowser();
//展开分组
myOPCBrowser.ShowBranches();
List<string> liststr = new List<string>();
foreach (object turn in myOPCBrowser)
{
liststr.Add(turn.ToString());
}
liststr.Sort((x, y) => -x.CompareTo(y));
myGroups = myServer.OPCGroups;
//添加自定义分组
myGroup = myGroups.Add("TestGroup");
//设置缺省的组属性
myServer.OPCGroups.DefaultGroupIsActive = true;
myServer.OPCGroups.DefaultGroupDeadband = 0;
myGroup.UpdateRate = 2000;//
myGroup.IsActive = true;
myGroup.IsSubscribed = true;
//定位需要发送数据的目标项
myItems = myGroup.OPCItems;
//实例化组内标签
myItemArray = new OPCItem[1];
//监听组内数据变化
myGroup.DataChange += new DIOPCGroupEvent_DataChangeEventHandler(myGroup_DataChange);
myGroup.AsyncWriteComplete += new DIOPCGroupEvent_AsyncWriteCompleteEventHandler(myGroup_AsyncWriteComplete);
for (int i = 0; i < liststr.Count; i++)
{
//填充项目组
//myItemArray[0] = myItems.AddItem(lstItems.Text, 4148120);
myItemArray[0] = myItems.AddItem(liststr[i], i);
//获取服务端句柄
itmHandleServer = myItemArray[0].ServerHandle;
string[] strarr = new string[3];
strarr[0] = itmHandleServer.ToString();
strarr[1] = i.ToString();
strarr[2] = "";
dictitems.Add(liststr[i], strarr);
lstItems.Items.Add(liststr[i]);
}
}
/// <summary>
/// 每当项数据有变化时执行的事件
/// </summary>
/// <param name="TransactionID">处理ID</param>
/// <param name="NumItems">项个数</param>
/// <param name="ClientHandles">项客户端句柄</param>
/// <param name="ItemValues">TAG值</param>
/// <param name="Qualities">品质</param>
/// <param name="TimeStamps">时间戳</param>
void myGroup_DataChange(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps)
{
for (int i = 1; i <= NumItems; i++)
{
string value = ItemValues.GetValue(i).ToString();
string clienthandle = ClientHandles.GetValue(i).ToString();
string timestamp = TimeStamps.GetValue(i).ToString();
string quality = Qualities.GetValue(i).ToString();
foreach (string key in dictitems.Keys)
{
if (dictitems[key][1] == clienthandle)
{
dictitems[key][2] = value;
break;
}
}
}
//为方便测试,显示到状态栏输出
Console.WriteLine("TransactionID:" + TransactionID.ToString() + "--" + "NumItems:" + NumItems.ToString() + " " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
}
/// <summary>
/// 写入TAG值时执行的事件
/// </summary>
/// <param name="TransactionID">处理ID</param>
/// <param name="NumItems">项个数</param>
/// <param name="ClientHandles">项客户端句柄</param>
/// <param name="Errors">服务器返回的错误信息</param>
void myGroup_AsyncWriteComplete(int TransactionID, int NumItems, ref Array ClientHandles, ref Array Errors)
{
//为方便测试,显示到状态栏输出
for (int i = 1; i <= NumItems; i++)
{
Console.WriteLine("TransactionID:" + TransactionID.ToString() + "--" + "ClientHandle:" + ClientHandles.GetValue(i).ToString() + "--" + "ErrorValue: " + Errors.GetValue(i).ToString());
}
}
}
}
再附OPC类库的说明: