簡單的OPC與C#通訊,別想複雜了

簡單的OPC與C#通訊,別想複雜了

 

複製代碼

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using OPCAutomation;
namespace OPC
{
    public partial class Form1 : Form
    {
        OPCServer ObjOPCServer;
        OPCGroups ObjOPCGroups;
        OPCGroup ObjOPCGroup;
        string OPCServerName;
        public Form1()
        {
            try
            {
                InitializeComponent();
                OPCServerName = "{Here comes your OPC server’s name,(OPC服務器名稱)}";
                ObjOPCServer = new OPCServer();
                ObjOPCServer.Connect(OPCServerName, "";);
                ObjOPCGroups = ObjOPCServer.OPCGroups;
                ObjOPCGroup = ObjOPCGroups.Add("OPCGroup1");
                ObjOPCGroup.DataChange += new DIOPCGroupEvent_DataChangeEventHandler(ObjOPCGroup_DataChange);
                ObjOPCGroup.OPCItems.AddItem("{tag name or address,(標籤名稱或地址名) (like {plc name on server}!%mw0)}", 1);
                ObjOPCGroup.UpdateRate = 10;
                ObjOPCGroup.IsActive = true;
                ObjOPCGroup.IsSubscribed = true;
            }
            catch (Exception e){
                MessageBox.Show(e.ToString());
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
        }

        private void ObjOPCGroup_DataChange(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps)
        {
            for (int i = 1; i <= NumItems; i++)
            {
                if ((Convert.ToInt32(ClientHandles.GetValue(i)) == 1))
                {
                    textBox1.Text =  ItemValues.GetValue(i).ToString();
                }
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            OPCServerClass GlobalOPCServer = new OPCServerClass();
            Array ServerList = (Array)GlobalOPCServer.GetOPCServers(""); 
            for (int i = 1; i <= ServerList.Length; i++)
            {
                comboBox1.Items.Add(ServerList.GetValue(i).ToString());
            }
        }
    }
}

複製代碼

在工業自動化領域,計算機早已成爲必不可少的工具,計算機技術的不斷髮展,大大加速了工業自動化技術的進步,而各種各樣的工業控制應用軟件正是具體實現這一進程的最重要的工具。

往,應用軟件開發商要爲每一種硬件開發驅動程序,由於硬件的種類繁多,特徵各異,軟件開發商的負擔異常繁重,尤其是如果硬件特徵發生了變化,整個應用軟件
相應的驅動程序也要相應地修改,這對軟件開發商,對整個工程都是很不利的。而且由於驅動程序的不統一,不同應用程序訪問同一硬件設備時常常發生衝突。
OPC(OLE for Process Control)技術標準正是在這種情況下產生的。OPC基於微軟的OLE、COM和DCOM技術,而且它本身
就是一種特殊的COM,也正因爲有微軟的參與,以及以已經成熟的技術爲基礎,它比一般的工業標準制定的效率更高,它從開始制定到第一個可運行的規範開始運
行,只用了不到一年的時間。
二、OPC原理及應用

OPC技術爲工業自動化軟件面向對象的開發提供了統一的
標準。它大大減輕了軟件開發商的負擔,軟件開發商不必再爲每一硬件單獨編寫驅動程序,只要硬件的特徵符合統一的OPC接口程序標準,或者硬件生產商提供
OPC服務器,如圖一所示,不同的應用軟件開發商都可以採用OPC標準設計工控軟件,以標準規定的統一接口通過OPC服務器存取現場數據。

樣,當現場設備發生變化或系統中加入新設備時,OPC服務器的提供商需要重新實現服務器接口,以適應硬件的變化,但由於服務器所提供的接口的一致性,工控
軟件不作更改即可繼續使用,只是某些情況下可能需要重新組態(如添加新的PLC站點等),這樣,軟件開發商可以節省大量的時間致力於工控軟件的性能方面的
提高,不必再考慮硬件變化帶來的影響,大大減小了軟件維護的工作量。這正如OPC規範裏所說,OPC將應用軟件和硬件設備劃清了界限。
2.1 OPC基本結構

OPC
服務器有兩類接口:定製接口(Custom Interface) 、自動化接口(Automation Interface),定製接口比較低級,它提
供更多的功能,效率也比後者高,可以用C++語言調用此類接口,自動化接口主要用於VB、DELPHI等開發工具。按照OPC規範,定製接口是服務商必須
提供的,而自動化接口則是可選的,不過,OPC基金會(管理OPC標準的國際組織)提供了一個叫做“自動化包裝器”的動態連接庫,用於在兩者間轉換。如圖
二所示:
在OPC的早期規範裏主要包括OPC數據存取規範、OPC報警和事件、OPC歷史數據存取規範。OPC數據存取規範詳細規定了客戶程序
和服務器程序進行數據通信的機制,其它類型的OPC服務器往往是在數據存取服務器的基礎上通過增加對象、擴展接口而來的,所以該規範也是其它OPC規範的
基礎。OPC數據存取規範規定的基本對象有三類:OPC Server、OPC Group和OPC Item,OPC Server包含服務器的所有信
息,也是OPC Group的容器,OPC Group除了包含它自身信息外,還負責管理OPC Item。它們的結構如圖三所示。每一個
OPC Item代表到數據源的一個連接,但它沒有提供外部接口,客戶端程序無法對OPC Item直接進行操作,應用程序必須依靠OPC Item的容
器OPC Group來對它進行操作,這在下面的程序中會有具體說明。
2.2 OPC數據訪問方式

OPC客戶程序對
OPC服務器中數據的存取方式分爲同步讀寫方式和異步讀寫方式。客戶程序可按照一定的週期調用OPC Group對象的IOPCSyncIO接口對服務器
程序進行數據同步存取操作,此時客戶方的調用函數一直運行到所有數據讀寫完成,然後才能執行其它操作,因此,這種方法適合與讀取少量數據,如果數據多的
話,會使系統處於假死狀態,無法進行操作。IOPCSyncIO2是從3.0版纔出現的,是對IOPCSyncIO的增強。IOPCAsyncIO2和
IOPCAsyncIO3是異步方式中使用的接口,異步訪問時,當客戶端對服務器提出訪問要求後,立即返回到OPC應用程序執行其它操作,無須等待,當
OPC服務器完成數據讀取後通知OPC應用程序,應用程序從而得到數據。其中前者是在2.0版本中新定義的,具有較高的通信性能;後者則是在3.0版本中
纔剛剛出現,同IOPCSyncIO2類似,IOPCAsyncIO3是對IOPCAsyncIO2的增強。在異步方式下,服務器程序收到讀請求後,調用
客戶程序方的IOPCDataCallback接口,將數據發送給客戶程序。異步方式中允許服務器將讀寫操作進行排隊,使客戶方的調用函數可立刻返回,當
服務器讀寫操作完成後再通知客戶程序。顯然,異步通報方式的通信效率更高,這種方式也是本文所要討論的方式,但有多個客戶程序與服務器相連時,同步讀寫方
式更具時效性。對於每個組對象,客戶程序可根據需要採用其中一種數據存取方式,而不能兩者都使用。
異步讀取還有一種特殊的方式,叫做訂閱方式(Subscribe)這種情況下,應用程序不需要發出讀請求,OPC服務器在定期更新數據的時候,如果發現數據有一定變化,則自動向應用程序發出通知和傳輸變化的數據。
2.3 編寫OPC客戶端應用程序

VB
簡單實用,是比較理想的OPC應用程序快速開發工具,若要用VB開發OPC應用程序,必須要使用OPC自動化包裝器,這在前文已經提過,這種包裝器一般由
OPC服務器的供應商以DLL形式提供,下面就以SIEMENS提供的sopcdaauto.dll爲例,介紹如何開發OPC應用程序,這也正是筆者在最
近的工程中實際應用到的,這是基於DA2.0的版本。
首先,新建VB工程後,作圖四所示的引用:
2.3.1 建立OPC對象

首先申明OPC對象:
Option Base 1
Dim WithEvents ServerObj As OPCServer ''OPC Server對象,連接OPC服務器
Dim GroupsObj As OPCGroups ''OPC Groups對象,添加OPC組
Dim WithEvents GroupObj As OPCGroup ''OPC Group對象
Dim ItemsObj As OPCItems ''OPC Item集合
Dim ServerHandles() As Long ''服務器端OPC Item的句柄
Dim ClientHandles() as Long ''客戶端OPC Item的句柄
Dim ItemId(2) As String
Dim Errors() As Long
接下來,生成各個對象:
If ServerObj Is Nothing Then Set ServerObj = New OPCServer
''連接OPC服務器
If ServerObj.ServerState = OPCDisconnected Then
ServerObj.Connect ("OPC.SimaticNET") ''假設OPC服務器運行在本機
End If
If GroupsObj Is Nothing Then Set GroupsObj = ServerObj.OPCGroups
If GroupObj Is Nothing Then Set GroupObj = GroupsObj.Add
If ItemsObj Is Nothing Then Set ItemsObj = GroupObj.OPCItems
GroupObj.IsActive = True ''設置組爲活動狀態
''假設有兩個數據源,一個是8位開關量輸入,一個是8位開關量輸出
ItemId(1) = "S7:[S7 connection_1]IB0"
ItemId(2) = "S7:[S7 connection_1]QB0"
ClientHandles(1) = 1
ClientHandles(2) = 2
''添加組項目,ServerHandles數組的值爲各個OPC Item的服務器句柄,
'' ClientHandles數組的值爲各個OPC Item的客戶端句柄,由應用程序設定
Call ItemsObj.AddItems(2, ItemId, ClientHandles, ServerHandles, Errors)

2.3.2異步數據讀取

'' OPC Item的服務器句柄,添加OPC Item時由服務器分配
Dim TempServerHandles(1) As Long
''事務標誌符,由客戶端產生,它包含的信息提供給OnReadComplete事件
Dim TransactionID As Long
''取消標誌符,服務器端產生,用於操作需要被取消的時候
Dim CancelID As Long
''包含讀取每個OPC Item時返回的信息
Dim ErrorNr() As Long
TempServerHandles(1) = ServerHandles(1) ''對應第一個OPC Item
GroupObj.AsyncRead 1, TempServerHandles, ErrorNr, TransactionID, CancelID
第一個參數是要讀的OPC Item的個數,這裏只含有一個OPC Item。讀取的結果由OPC服務器通過IconnectionPointContainer接口配合IOPCDataCallback接口反調用應用程序的事務處理程序:

Private Sub GroupObj_AsyncReadComplete(ByVal TransactionID As Long, ByVal NumItems As Long, ClientHandles() As Long, ItemValues() As Variant, Qualities() As Long, TimeStamps() As Date, Errors() As Long)
這裏的參數ClientHandles和AddItems方法中的ClientHandles是對應的,用於判斷哪一個OPC Item在被讀取。其它參數的說明如下:
TransactionID:客戶端自由使用,應用程序開發商自定義;
NumItems:表示讀取的OPC Item的個數;
ItemValues():各個OPC Item連接的數據源的值,類型爲Variant;
Qualities():OPC Item的品質值;
TimeStamps():時間戳;
Errors():記錄服務器返回的信息。
2.3.3 異步數據寫入

Dim TempServerHandles (1) As Long
Dim VValue(1) As Variant
Dim ErrorNr() As Long
Dim TransactionID As Long
Dim CancelID As Long
TempServerHandles(1)=ServerHandles(2)
VValue(1)=1''假設要將“1”寫入ClientHandle爲2的OPC Item
GroupObj.AsyncWrite 1,TempServerHandles,VValue, ErrorNr, TransactionID, CancelID

同樣,AsyncWrite也對應一個事務處理程序:
Private Sub groupObj_AsyncWriteComplete(ByVal TransactionID As Long, ByVal NumItems As Long, ClientHandles() As Long, Errors() As Long)
它的參數的含義和AsuncReadComplete中的含義是類似的,這裏一般需要處理的是寫數據之後的返回狀態,這裏不再贅述。
2.3.4斷開與服務器的連接

ItemsObj.Remove ItemsObj.Count,ServerHandles, Errors ''清除OPC Item
Set ItemsObj = Nothing ''釋放資源,下同
If Not GroupObj Is Nothing Then
GroupsObj.Remove GroupObj.ServerHandle ''刪除組
End If
If Not GroupsObj Is Nothing Then
Set GroupsObj = Nothing
End If
If Not ServerObj Is Nothing Then
If ServerObj.ServerState <> OPCDisconnected Then
ServerObj.Disconnect ''斷開與服務器的連接
End If
Set ServerObj = Nothing
End If

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章