【OPCAutomation】 使用OPCAutomation實現對OPC數據的訪問


折騰了一段時間研究OPC,理清了下位機、OPCServer 和OPCClient的關系和通信模型,終於能夠來寫一篇相關的博客了。

我們使用西門子的 S7 200 SMART作為下位機端,通過3G路由器從vpn與公司服務器通信,服務器運行配置好的PC Access SMART 作為OPC Server, 完成對下位機內存地址的定義后,使用自動化接口開發中間件負責將OPC Server得到的PLC數據存放至SQL Server

中間件和數據庫的設計思路是:

數據庫按真實設備類型分別建表用作存儲,數據庫建有數據字典表用作配置功能,包括配置內存地址和opc服務等。

中間件作用是調用OPCAutomation 類訪問OPCServer端,並進行可控制讀取間隔的OPC數據讀取、存儲工作。

由於第一次接觸這類開發,在設計功能時花費了很多精力,從完全不懂到基本理解這種通信模式和原理,也繞了不少遠路。

 

本文主要介紹OPCAutomation類的使用。

簡單說下流程就是:

1. 創建OPC Server的連接

2. 創建OPC組對象並初始化設置

3. 獲取組的OPCItems對象,為讀取數據作准備

4. opcItem的操作。

5. 退出程序的資源釋放

 

創建連接很簡單,需要指定OPCServer所在的服務器(內網可以指定ip或者計算機名),指定OPC服務的名稱(同一服務器可能運行多個OPC服務以適配同的下位機)

        private bool ConnectRemoteServer(string remoteServerIP, string remoteServerName)
        {
            try
            {
                this.opcServer.Connect(remoteServerName, remoteServerIP);
                string status;
                if (opcServer.ServerState == (int)OPCServerState.OPCRunning)
                {
                    status = "已連接到-" + opcServer.ServerName + "   ";
                }
                else
                {
                    //這里你可以根據返回的狀態來自定義顯示信息,請查看自動化接口API文檔
                    status = "狀態:" + opcServer.ServerState.ToString() + "   ";
                }
                Console.WriteLine(status);
            }
            catch (Exception err)
            {
                Console.WriteLine("連接遠程服務器出現錯誤:" + err.Message, "提示信息");
                return false;
            }
            return true;
        }
View Code

其中 this.opcServer.Connect(remoteServerName, remoteServerIP);即OPCAutomation類提供的連接方法。

需要注意的是,在實際配置時,需要完全對OPC 服務端所在服務器上配置防火牆出入站規則后,OPC服務才能夠被其他服務器上的中間件訪問到。故我們選擇最簡單的方式,在本機運行中間件。

創建組相當於讀取到OPC上特定的項目,而具體的數據值是在每個項目下根據開發人員的定義而確定。

opcGroups = opcServer.OPCGroups;
opcGroup = opcGroups.Add("OPCDOTNETGROUP");
SetGroupProperty();
opcGroup.DataChange += new DIOPCGroupEvent_DataChangeEventHandler(opcGroup_DataChange);

//opcGroup.AsyncWriteComplete += new DIOPCGroupEvent_AsyncWriteCompleteEventHandler(KepGroup_AsyncWriteComplete);

opcItems = opcGroup.OPCItems;

注釋的代碼是綁定寫操作的事件。

這段代碼是為OPCGroup對象進行初始化。 比較關鍵的是兩句綁定事件的,第一個綁定的是每當OPC數據有變化時觸發的事件。

數據變化的時間是由以下代碼中UpdateRate控制。

        private void SetGroupProperty()
        {
            opcServer.OPCGroups.DefaultGroupIsActive = true;
            opcServer.OPCGroups.DefaultGroupDeadband = 0;
            opcGroup.UpdateRate = this.updateRate;
            opcGroup.IsActive = true;
            opcGroup.IsSubscribed = true;
        }
View Code

關於逐項配置的具體說明,建議參考OPCAutomation的api,如果有看到翻譯比較合適的后續會補充上來。

 

之后是為全局變量里的OPCGroup對象添加Items,在OPC中,每個opcItem會被分配一個客戶端句柄值,同時會被配置上服務端句柄。幾乎所有有關獲取指定OpcItem對象的方法均要求指定客戶端句柄值。

        void AddAllOpcItem()
        {
            opcBrowser.ShowBranches();
            opcBrowser.ShowLeafs(true);
            int count = this.opcBrowser.Count;
            if (this.opcItemsArray == null)
            {
                opcItemsArray = new List<string>();
            }
            foreach (var item in opcBrowser)
            {
                opcItemsArray.Add(item.ToString());
            }
            AddOpcItems();
        }
        //逐項綁定句柄值
        void AddOpcItems()
        {
            foreach (var item in this.opcItemsArray)
            {
                itmHandleClient = 1234;
                opcItem = opcItems.AddItem(item, itmHandleClient);
                itmHandleServer = opcItem.ServerHandle;
            }
        }

這段代碼是為了把獲取到的全部OPCItem添加到所創建的OPCGroup對象的opcItem集合中,以便我們所綁定的DataChange事件能夠被觸發並且正確對應到每個地址值上

基本上到此,只要在所綁定的DataChange的實現代碼中完成具體的數據讀取業務,中間件的核心部分已經完成。

稍微提一下,OPC的數據項主要包含:名稱、條目id、地址、數據類型、數據值、工程單位上下限、時間戳和質量幾項,在實際業務中我們關注條目ID、數據類型、值、時間戳和質量,對於讀取的opc數據值而言,需要注意的是得到值是Dynamic類型的,需要正確進行判斷和轉換。質量返回值為0時基本可以認為下位機到服務端的數據鏈斷了,或者下位機對應項目沒有收到數據,據此可進行日志和提示的業務操作。

 

在OPC的數據類型中,REAL對應float, WORD對應16位整型,BOOL可以用bit或者Bool進行轉換,用bit和sql server的數據項可以比較方便對接。

 

第一次做這類開發,謬誤難免,希望多多指點。

 

感謝閱讀。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM