本文將使用庫技術來讀寫橫河PLC數據,使用的是基於橫河自身協議實現,不需要額外的組件,讀取操作只要放到后台線程就不會卡死線程,本組件支持超級方便的高性能讀寫操作
github地址:https://github.com/dathlin/HslCommunication 如果喜歡可以star或是fork,還可以打賞支持,打賞請認准源代碼項目。
聯系作者及加群方式:http://www.hslcommunication.cn/Cooperation
在Visual Studio 中的NuGet管理器中可以下載安裝,也可以直接在NuGet控制台輸入下面的指令安裝:
Install-Package HslCommunication
如果需要教程:Nuget安裝教程:http://www.cnblogs.com/dathlin/p/7705014.html
組件的完整信息和API介紹參照: http://api.hslcommunication.cn 組件的使用限制,更新日志,都在該頁面里面。
如果你需要在讀取PLC數據之后,還要群發客戶端來實現遠程辦公室同步監視,可以參考如下的項目(基於該組件擴展起來的,帶有賬戶驗證,版本控制,數據群發,公告管理等等功能)
https://github.com/dathlin/ClientServerProject
本文將展示如何配置網絡參數及怎樣使用代碼來訪問PLC數據,希望給有需要的人解決一些實際問題。主要對基恩士的數據進行讀寫操作,具體的參照下面的地址信息
此處使用了網線直接的方式,如果PLC接進了局域網,就可以進行遠程讀寫了^_^
此處使用到了2個命名空間:
using HslCommunication; using HslCommunication.Profinet.Yokogawa;
隨便聊聊
當我們一個上位機需要讀取100台西門子PLC設備(此處只是舉個例子,凡是都是使用Modbus tcp的都是一樣的)的時候,你采用服務器主動去請求100台設備的機制對性能來說是個極大的考驗,如果開100個線程去輪詢100台設備,那么性能損失將是非常大的,更不用說再增加設備,如果搭建Modbus tcp服務器,就可以完美的解決性能問題,因為連接的壓力將會平均分攤給每一台PLC,服務器端只要新增一個時間戳就可以知道客戶端有沒有連接上。
我們在100台PLC里都增加發送Modbus tcp方法,將數據發送到服務器的ip和端口上去,服務器根據站號來區分設備。這樣就可以搭建一個高性能總站。 本組件支持快速搭建一個高性能的Modbus tcp總站。
http://www.cnblogs.com/dathlin/p/7782315.html
關於兩種模式
在PLC端,包括三菱,西門子,歐姆龍,橫河以及Modbus Tcp客戶端的訪問器上,都支持兩種模式,短連接模式和長連接模式,現在就來解釋下什么原理。
短連接:每次讀寫都是一個單獨的請求,請求完畢也就關閉了,如果服務器的端口僅僅支持單連接,那么關閉后這個端口可以被其他連接復用,但是在頻繁的網絡請求下,容易發生異常,會有其他的請求不成功,尤其是多線程的情況下。
長連接:創建一個公用的連接通道,所有的讀寫請求都利用這個通道來完成,這樣的話,讀寫性能更快速,即時多線程調用也不會影響,內部有同步機制。如果服務器的端口僅僅支持單連接,那么這個端口就被占用了,比如三菱的端口機制,西門子的Modbus tcp端口機制也是這樣的。以下代碼默認使用長連接,性能更高,還支持多線程同步。
在短連接的模式下,每次請求都是單獨的訪問,所以沒有重連的困擾,在長連接的模式下,如果本次請求失敗了,在下次請求的時候,會自動重新連接服務器,直到請求成功為止。另外,盡量所有的讀寫都對結果的成功進行判斷。
關於日志記錄
不管是基恩士的,三菱的數據訪問類,還是西門子的,還是Modbus tcp訪問類,都有一個LogNet屬性用來記錄日志,該屬性是一個接口類,ILogNet,凡事繼承該接口的都可以用來記錄日志,該日志會在訪問失敗時,尤其是因為網絡的原因導致訪問失敗時會進行日志記錄(如果你為這個 LogNet 屬性配置了真實的日志記錄器的話):如果你想使用該記錄日志的功能,請參照如下的博客進行實例化:
http://www.cnblogs.com/dathlin/p/7691693.html
訪問測試項目
下面的一個項目是這個組件的訪問測試項目,您可以進行初步的訪問的測試,免去了您寫測試程序的麻煩,三菱的界面和西門子的界面幾乎是一致的。可以同時參考。該項目位於本篇文章開始處的Gitbub源代碼里面的
下載地址為:HslCommunicationDemo.zip
演示項目
下面的三篇演示了具體如何去訪問PLC的數據,我們在訪問完成后,通常需要進行處理,以下的示例項目就演示了后台從PLC讀取數據后,前台顯示並推送給所有在線客戶端的功能,客戶端並進行圖形化顯示,具有一定的參考意義,並且推送給網頁前端,項目地址為:
https://github.com/dathlin/RemoteMonitor
下面的圖片示例中的左邊程序就是服務器程序,它應該和PLC直接連接並接入局域網,然后把數據推送給客戶端顯示。注意:一個復雜高級的程序就應該把處理邏輯程序和界面程序分開,比如這里的服務器程序實現數據采集,推送,存儲。讓客戶端程序去實現數據的整理,分析,顯示,這樣即使客戶端程序因為BUG奔潰,服務器端仍然可以正常的工作。
安卓演示項目:
請加群下載,或是在華為,小米,應用寶等APP應用商店搜索HslCommunicaition 進行下載安裝!
代碼篇
具體的API文檔地址:http://api.hslcommunication.cn/html/31845cf4-eb9e-f801-f6b8-c2759f9b9a5b.htm
下面也做一些說明
關於支持的地址:
對於所有的數據讀寫,我們分為兩大類,讀寫Bool數據,讀寫字節數據。對應的方法分別是
OperateResult<bool[]> ReadBool( string address, ushort length ) OperateResult<bool> ReadBool( string address ) OperateResult Write( string address, bool[] value ) OperateResult Write( string address, bool value )
這類方法都是讀寫線圈的,針對的是X,Y,I,E,M,T,C,L線圈。
而其他的Read(string address, ushort length) 和寫入,讀取其他類型的都是寄存器的
好了。先從實例化開始
private YokogawaLinkTcp yokogawa = new YokogawaLinkTcp( "127.0.0.1", 12289 );
實例化之后就需要連接PLC了
OperateResult connect = yokogawa.ConnectServer( ); if (connect.IsSuccess) { MessageBox.Show( "連接成功" ); } else { MessageBox.Show( "連接失敗" ); }
連接的時候可能會失敗,因為網絡等等的原因,所以需要連接判斷。連接成功之后,就可以進行讀寫數據了。我們先來看看如何讀取一個X的點位信息
OperateResult<bool> read = yokogawa.ReadBool( "X0" ); if (read.IsSuccess) { bool value = read.Content; // true 表示 通, false 表示 斷 } else { Console.WriteLine( "Read failed: " + read.Message ); }
因為X的點位不能寫入操作,所以下面寫入Y信號。
OperateResult write = yokogawa.Write( "Y0", true ); if (write.IsSuccess) { Console.WriteLine( "Write success! " ); // 寫入成功 } else { Console.WriteLine( "Write failed: " + write.Message ); }
如果我要批量讀取點位信息呢?
OperateResult<bool[]> readArray = yokogawa.ReadBool( "X0", 20 ); if (readArray.IsSuccess) { bool[] value = readArray.Content; // 一個數組value[0] 就是X0, 按照索引依次往后對應 } else { Console.WriteLine( "Read failed: " + readArray.Message ); }
批量寫入數組也是類似的。
OperateResult writeArray = yokogawa.Write( "Y0", new bool[] { true, false, true, false, false } ); if (writeArray.IsSuccess) { Console.WriteLine( "Write success! " ); // 寫入成功 Y0=true, Y1=false, Y2=true, Y3=false, Y4=false } else { Console.WriteLine( "Write failed: " + writeArray.Message ); }
線圈的操作都是相似的,除了地址不一樣,其他的操作都是類似的。我們再來看看寄存器的操作。
OperateResult<short> read = yokogawa.ReadInt16( "D0" ); if (read.IsSuccess) { short value = read.Content; // value 就是D0的值 } else { Console.WriteLine( "Read failed: " + read.Message ); }
當然了,PLC在D0存儲的不一定是整數值,有可能是個浮點數
OperateResult<float> readfloat = yokogawa.ReadFloat( "D0" ); if (readfloat.IsSuccess) { float value = readfloat.Content; // value 就是D0的值 } else { Console.WriteLine( "Read failed: " + readfloat.Message ); }
如果是寫入,也是同理。
OperateResult write = yokogawa.Write( "D0", (short)123 ); if (write.IsSuccess) { Console.WriteLine( "write success" ); // 寫入成功 } else { Console.WriteLine( "write failed: " + write.Message ); }
寫入浮點數也是同理,這里就不贅述了:
yokogawa.Write( "D0", 123f )
讀取連續的short數組, float數組?
OperateResult<short[]> readArray = yokogawa.ReadInt16( "D0", 10 ); if (readArray.IsSuccess) { short[] value = readArray.Content; // value[0] 就是D0的值, value[1] 就是D1的值,以此類推 } else { Console.WriteLine( "Read failed: " + readArray.Message ); }
float數組的讀取也是類似的,也是加一個length。
yokogawa.ReadFloat( "D0", 10 );
批量的寫入也是類似的。
OperateResult writeArray = yokogawa.Write( "D0", new short[] { 123, 456, 789, 1234 } ); if (writeArray.IsSuccess) { Console.WriteLine( "write success" ); // 寫入成功 } else { Console.WriteLine( "write failed: " + writeArray.Message ); }
我們來看一個高級點的操作,我們要讀取不通的線圈的點位信息,怎么操作?
// 使用隨機讀取的方式讀取不同地址的數據信息 OperateResult<bool[]> read = yokogawa.ReadRandomBool( new string[] { "X0", "Y100", "M200", "M1000" } ); if (read.IsSuccess) { bool x_0 = read.Content[0]; bool y_100 = read.Content[1]; bool m_200 = read.Content[2]; bool m_1000 = read.Content[3]; } else { Console.WriteLine( "Read failed, reason: " + read.Message ); }
寫入也是類似的:
OperateResult write = yokogawa.WriteRandomBool( new string[] { "X0", "Y100", "M200", "M1000" }, new bool[] { true, false, false, true } ); if (write.IsSuccess) { Console.WriteLine( "write plc success!" ); } else { Console.WriteLine( "write failed:" + write.Message ); return; }
讀取特殊模塊的信息
// 讀取PLC的特殊模塊的地址數據 OperateResult<byte[]> read = yokogawa.ReadSpecialModule( 1, 2, 100, 2 ); if (read.IsSuccess) { // 我們讀取到了原始的數據內容 byte[] content = read.Content; } else { Console.WriteLine( "Read failed, reason: " + read.Message ); }
寫入也是類似
OperateResult<short> readInt16 = yokogawa.ReadInt16( "Special:unit=1;slot=2;100" ); if (readInt16.IsSuccess) { Console.WriteLine( "Read D100: " + readInt16.Content ); } else { Console.WriteLine( "Read failed, reason: " + readInt16.Message ); return; }
當然了,本組件支持讀PLC的基本信息,報警信息,更詳細的參考API文檔。
如果你沒有相關的PLC信息,卻又想進行相關測試的,可以使用HSL來構建虛擬PLC
具體參考類 YokogawaLinkServer
API說明地址為:http://api.hslcommunication.cn/html/ab5927f5-b6a1-d76a-7c06-10cbcca7ac37.htm