使⽤OPC与PLC通讯⼀
总结⾃⼰在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还是很值得⼀学的。
分享⼀⾸好听的歌  ~~~

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。