來源:https://blog.csdn.net/ryanzll/article/details/42109739
准備工作
下載 Opc.NET Api,可以從 OPC Foundation網站,也可以google,csdn上也有。下載到安裝包之后,安裝即可,相應的文件會拷貝到
“C:\Windows\assembly\GAC_MSIL\OpcNetApi\2.0.2.0__9a40e993cbface53\OpcNetApi.dll”
“C:\Windows\assembly\GAC_MSIL\OpcNetApi.Com\2.0.1.0__9a40e993cbface53\OpcNetApi.Com.dll”
...
這樣在這台電腦上的所有.net項目都可以使用 Opc.NET Api了。但這也有不方便的地方,如果是團隊開發,那么就要求團隊所有人都必須按照這個庫。那么你也可以把這些dll從GAC里面放到你工程的第三方庫中,然后讓工程的引用指向那里就可以了。
BTW:只要在本地新建個指向本機”C$\Windows “的網絡映射,然后通過這個映射就可以任性的操作這些文件了。
新建工程
打開VS,新建c#工程,並添加OpcNetApi.dll,OpcNetApi.Com.dll的引用
讀寫數據項(Item)
static void Main( string [] args)
{
// Create a server object and connect to the TwinCATOpcServer
Opc. URL url = new Opc. URL ( "opcda://localhost/BECKHOFF.TwinCATOpcServerDA" );
Opc.Da. Server server = null ;
OpcCom. Factory fact = new OpcCom. Factory ();
server = new Opc.Da. Server (fact, null );
server.Connect(url, new Opc. ConnectData ( new System.Net. NetworkCredential ()));
// Create a group
Opc.Da. Subscription group;
Opc.Da. SubscriptionState groupState = new Opc.Da. SubscriptionState ();
groupState.Name = "Group" ;
groupState.Active = false ;
group = (Opc.Da. Subscription )server.CreateSubscription(groupState);
// add items to the group
Opc.Da. Item [] items = new Opc.Da. Item [3];
items[0] = new Opc.Da. Item ();
items[0].ItemName = "PLC1.Value1" ;
items[1] = new Opc.Da. Item ();
items[1].ItemName = "PLC1.Value2" ;
items[2] = new Opc.Da. Item ();
items[2].ItemName = "PLC1.Value3" ;
items = group.AddItems(items);
// write items
Opc.Da. ItemValue [] writeValues = new Opc.Da. ItemValue [3];
writeValues[0] = new Opc.Da. ItemValue ();
writeValues[1] = new Opc.Da. ItemValue ();
writeValues[2] = new Opc.Da. ItemValue ();
writeValues[0].ServerHandle = group.Items[0].ServerHandle;
writeValues[0].Value = 0;
writeValues[1].ServerHandle = group.Items[1].ServerHandle;
writeValues[1].Value = 0;
writeValues[2].ServerHandle = group.Items[2].ServerHandle;
writeValues[2].Value = 0;
Opc. IRequest req;
group.Write(writeValues, 321, new Opc.Da. WriteCompleteEventHandler (WriteCompleteCallback), out req);
// and now read the items again
group.Read(group.Items, 123, new Opc.Da. ReadCompleteEventHandler (ReadCompleteCallback), out req);
Console .ReadLine();
}
static void WriteCompleteCallback( object clientHandle, Opc. IdentifiedResult [] results)
{
Console .WriteLine( "Write completed" );
foreach (Opc. IdentifiedResult writeResult in results)
{
Console .WriteLine( "\t{0} write result: {1}" , writeResult.ItemName, writeResult.ResultID);
}
Console .WriteLine();
}
static void ReadCompleteCallback( object clientHandle, Opc.Da. ItemValueResult [] results)
{
Console .WriteLine( "Read completed" );
foreach (Opc.Da. ItemValueResult readResult in results)
{
Console .WriteLine( "\t{0}\tval:{1}" , readResult.ItemName, readResult.Value);
}
Console .WriteLine();
}
這里有個要注意的地方,在創建 Opc.Da.Subscription 的時候,會設置其Name屬性,這個名稱僅僅是給 Subscription 個名字,與OPC服務器中的組(group)名是兩回事。
同時,在創建Item的時候,如果它是屬於某個group的話,在設置其ItemName屬性的時候,需要加上group的名字。
下面以MatrikonOPC Server for Simulation為例,如下圖。當中有個名為"Group"的組,其下面有名為“Item”數據項,那么連接這個服務器,創建Item的時候,Item的名字應該是“ New_Intouch_000.Item ”。否則連接不上的,但是大小寫貌似不區分的。
監視數據項變化(subscriptions)
所謂監視數據項變化,就是添加關心的數據項,也可設定更新頻率,然后當這些數據項的值變化時就會通知你(事件機制)。
static void Main(string[] args)
{
// Create a server object and connect to the TwinCATOpcServer
Opc.URL url = new Opc.URL("opcda://localhost/BECKHOFF.TwinCATOpcServerDA");
Opc.Da.Server server = null;
OpcCom.Factory fact = new OpcCom.Factory();
server = new Opc.Da.Server(fact, null);
server.Connect(url, new Opc.ConnectData(new System.Net.NetworkCredential()));
// Create a group
Opc.Da.Subscription group;
Opc.Da.SubscriptionState groupState = new Opc.Da.SubscriptionState();
groupState.Name = "Group";
groupState.Active = true;
group = (Opc.Da.Subscription)server.CreateSubscription(groupState);
// add items to the group.
Opc.Da.Item[] items = new Opc.Da.Item[3];
items[0] = new Opc.Da.Item();
items[0].ItemName = "PLC1.dyn_R8[1]";
items[1] = new Opc.Da.Item();
items[1].ItemName = "PLC1.dyn_R4[1]";
items[2] = new Opc.Da.Item();
items[2].ItemName = "PLC1.dyn_I4[1]";
items = group.AddItems(items);
group.DataChanged += new Opc.Da.DataChangedEventHandler(OnTransactionCompleted);
Console.ReadLine();
}
static void OnTransactionCompleted( object group, object hReq, Opc.Da.ItemValueResult[] items)
{
Console.WriteLine("------------------->");
Console.WriteLine("DataChanged ...");
for (int i = 0; i < items.GetLength(0); i++)
{
Console.WriteLine("Item DataChange - ItemId: {0}", items[i].ItemName);
Console.WriteLine(" Value: {0,-20}", items[i].Value);
Console.WriteLine(" TimeStamp: {0:00}:{1:00}:{2:00}.{3:000}",
items[i].Timestamp.Hour,
items[i].Timestamp.Minute,
items[i].Timestamp.Second,
items[i].Timestamp.Millisecond);
}
Console.WriteLine("-------------------<");
}
如果需要撤銷監視,可以通過“Array.Clear(subscription.Items,0,subscription.Items.Length)”的方式。此外添加監視必須調用Subscription.AddItems函數,通過直接修改Subscription.Items的方式貌似無效。
“OnTransactionCompleted”第一次被調用會傳回所有監視項(很好理解,如果都沒有變化,你怎么知道當前是什么值),第二次及以后 傳回的是監視的數據項中變化項。
//刪除儀表
//Opc.Da.Item[] items1 = new Opc.Da.Item[1];
//items1[0] = items[1];
//group.RemoveItems(items1);