C# 讀寫西門子PLC數據,包含S7協議和Fetch/Write協議,s7支持200smart,300PLC,1200PLC,1500PLC

本文將使用一個gitHub開源的組件技術來讀寫西門子plc數據,使用的是基於以太網的TCP/IP實現,不須要額外的組件,讀取操做只要放到後臺線程就不會卡死線程,本組件支持超級方便的高性能讀寫操做css

官方地址:http://www.hslcommunication.cn/ 打賞請認準官網。html

nuget地址:https://www.nuget.org/packages/HslCommunication/       nuget     下載git

github地址:https://github.com/dathlin/HslCommunication      fork      star                 若是喜歡能夠star或是fork,還能夠打賞支持。github

聯繫做者及加羣方式(激活碼在羣裏發放):http://www.hslcommunication.cn/Cooperation
web

 

在Visual Studio 中的NuGet管理器中能夠下載安裝,也能夠直接在NuGet控制檯輸入下面的指令安裝編程

Install-Package HslCommunication

 若是須要教程:Nuget安裝教程:http://www.cnblogs.com/dathlin/p/7705014.htmlc#

 

組件的完整信息和其餘API介紹參照:http://www.cnblogs.com/dathlin/p/7703805.html   組件的受權協議,更新日誌,都在該頁面裏面。安全

 

本文將展現如何配置網絡參數及怎樣使用代碼來訪問PLC數據,但願給有須要的人解決一些實際問題。主要對西門子PLC的M,Q,I,DB塊的數據讀寫,親測有效。服務器

此處使用了網線直接的方式,若是PLC接進了局域網,就能夠進行遠程讀寫了^_^網絡

此處使用到了2個命名空間:

using HslCommunication;
using HslCommunication.Profinet.Siemens;

 

隨便聊聊


當咱們一個上位機須要讀取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

 

關於兩種模式


本組件所提供的全部客戶端類,包括三菱,西門子,歐姆龍,modbus-tcp,以及SimplifyNet都是繼承自雙模式基類,雙模式包含了短鏈接和長鏈接,下面就具體介紹下兩個模式的區別

短鏈接:每次讀寫都是一個單獨的請求,請求完畢也就關閉了,若是服務器的端口僅僅支持單鏈接,那麼關閉後這個端口能夠被其餘鏈接複用,可是在頻繁的網絡請求下,容易發生異常,會有其餘的請求不成功,尤爲是多線程的狀況下。

長鏈接:建立一個公用的鏈接通道,全部的讀寫請求都利用這個通道來完成,這樣的話,讀寫性能更快速,即時多線程調用也不會影響,內部有同步機制。若是服務器的端口僅僅支持單鏈接,那麼這個端口就被佔用了,好比三菱的端口機制,西門子的Modbus tcp端口機制也是這樣的。如下代碼默認使用長鏈接,性能更高,還支持多線程同步。

在短鏈接的模式下,每次請求都是單獨的訪問,因此沒有重連的困擾,在長鏈接的模式下,若是本次請求失敗了,在下次請求的時候,會自動從新鏈接服務器,直到請求成功爲止。另外,儘可能全部的讀寫都對結果的成功進行判斷。

 

關於日誌記錄


不論是三菱的數據訪問類,仍是西門子的,仍是Modbus tcp訪問類,都有一個LogNet屬性用來記錄日誌,該屬性是一個接口類,ILogNet,凡事繼承該接口的均可以用來記錄日誌,該日誌會在訪問失敗時,尤爲是由於網絡的緣由致使訪問失敗時會進行日誌記錄(若是你爲這個 LogNet 屬性配置了真實的日誌記錄器的話):若是你想使用該記錄日誌的功能,請參照以下的博客進行實例化:

http://www.cnblogs.com/dathlin/p/7691693.html

舉個例子:

siemensTcpNet.LogNet = new HslCommunication.LogNet.LogNetSingle( "log.txt" );

 

 

關於兩種協議


本組件支持的西門子通訊有兩種協議,一種是S7協議,在PLC側幾乎不須要配置參數,另外一個協議Fetch/Write協議,相對比較麻煩一點,若是S7不方便讀取的話,能夠選擇Fetch/Write,相對而言,S7更加方便點。

這兩個協議除了實例化的類型不一致,讀寫PLC的代碼和鏈接機制都是一致的,因此FW協議的具體代碼就不粘貼了,詳細參照下面的Demo項目。

 

訪問測試項目


在上述的github源代碼裏有個測試項目,HslCommunicationDemo,裏面包含了各類客戶端的Demo項目,不須要編寫任何的代碼就能夠測試數據的訪問了。

下載地址爲:HslCommunicationDemo.zip

 

演示項目


下面的三篇演示了具體如何去訪問PLC的數據,咱們在訪問完成後,一般須要進行處理,如下的示例項目就演示了後臺從PLC讀取數據後,前臺顯示並推送給全部在線客戶端的功能,客戶端並進行圖形化顯示,具備必定的參考意義,項目地址爲:

https://github.com/dathlin/RemoteMonitor

下面的圖片示例中的左邊程序就是服務器程序,它應該和PLC直接鏈接並接入局域網,而後把數據推送給客戶端顯示。注意:一個複雜高級的程序就應該把處理邏輯程序和界面程序分開,好比這裏的服務器程序實現數據採集,推送,存儲。讓客戶端程序去實現數據的整理,分析,顯示,這樣即便客戶端程序由於BUG奔潰,服務器端仍然能夠正常的工做。

 

 

S7協議下的tcp直接通信,配置簡單,通常PLC都支持


 

測試經過的PLC:1200系列 本人親測

                          200smart  感謝 無名①終止^^ 的測試

                          300系列  感謝 懂PLC不懂c# 的測試

                          1500系列 感謝 ∮溪風-⊙_⌒ 的測試

 

 報文的格式參考了以下的兩篇文章

http://www.itpub.net/thread-2052649-1-1.html

https://wenku.baidu.com/view/d93b88b06394dd88d0d233d4b14e852459fb3912.html

若是你擅長於網絡通訊和組件開發,能夠經過報文格式開發出本身的西門子通訊庫,我所作的就是基於報文格式進行了二次封裝,隱藏了socket通訊的細節,還包含了異常處理,提供了簡單方便的API來讀寫數據。提供了整數數據的讀寫,字符串讀寫,來豐富各類需求,從事實上來講,只要能夠讀寫字節,至關於任何數據了。

準備:在西門子PLC上配置好IP地址,就只有一個IP地址就夠了,而後打開電腦的cmd指令,只要能ping通西門子PLC便可。

還須要在PLC側配置打開  GET/SET通信容許:(感謝網友 OLIFE 提供的圖片) (若是碰到讀取數據時出現長度驗證失敗的信息,請務必檢查下面的勾是否打上)

 

 

實例化:

siemensTcpNet = new SiemensS7Net( SiemensPLCS.S1200, "192.168.0.100" ) {
                ConnectTimeOut = 5000
            };

若是你的PLC是其餘系列的,就修改上面的枚舉值,本組件支持的西門子型號都在裏面。

 

 

鏈接服務器,也能夠放在窗口的Load方法中,通常建議使用長鏈接,速度更快,又是線程安全的(調用下面的方法就是使用了長鏈接,若是不鏈接直接讀取數據,那就是短鏈接):

                OperateResult connect = siemensTcpNet.ConnectServer( );
                if (connect.IsSuccess)
                {
                    MessageBox.Show( "鏈接成功!" );
                }
                else
                {
                    MessageBox.Show( "鏈接失敗!" );
                }

 

斷開鏈接,也就是關閉了長鏈接,若是再去請求數據,就變成了短鏈接

siemensTcpNet.ConnectClose( );

 

下面就演示一些簡單的數據操做,省去了對結果是否成功的驗證,全部的讀寫結果都是OperateResult類型及派生類型,都有一個IsSuccess屬性來判斷成功與否

            // 讀取操做,這裏的M100能夠替換成I100,Q100,DB20.100效果時同樣的
            bool M100_7 = siemensTcpNet.ReadBool( "M100.7" ).Content;  // 讀取M100.7是否通斷,注意M100.0等同於M100
            byte byte_M100 = siemensTcpNet.ReadByte( "M100" ).Content; // 讀取M100的值
            short short_M100 = siemensTcpNet.ReadInt16( "M100" ).Content; // 讀取M100-M101組成的字
            ushort ushort_M100 = siemensTcpNet.ReadUInt16( "M100" ).Content; // 讀取M100-M101組成的無符號的值
            int int_M100 = siemensTcpNet.ReadInt32( "M100" ).Content;         // 讀取M100-M103組成的有符號的數據
            uint uint_M100 = siemensTcpNet.ReadUInt32( "M100" ).Content;      // 讀取M100-M103組成的無符號的值
            float float_M100 = siemensTcpNet.ReadFloat( "M100" ).Content;   // 讀取M100-M103組成的單精度值
            long long_M100 = siemensTcpNet.ReadInt64( "M100" ).Content;      // 讀取M100-M107組成的大數據值
            ulong ulong_M100 = siemensTcpNet.ReadUInt64( "M100" ).Content;   // 讀取M100-M107組成的無符號大數據
            double double_M100 = siemensTcpNet.ReadDouble( "M100" ).Content; // 讀取M100-M107組成的雙精度值
            string str_M100 = siemensTcpNet.ReadString( "M100", 10 ).Content;// 讀取M100-M109組成的ASCII字符串數據

            // 寫入操做,這裏的M100能夠替換成I100,Q100,DB20.100效果時同樣的
            siemensTcpNet.Write( "M100.7", true );                // 寫位,注意M100.0等同於M100
            siemensTcpNet.Write( "M100", (byte)0x33 );            // 寫單個字節
            siemensTcpNet.Write( "M100", (short)12345 );          // 寫雙字節有符號
            siemensTcpNet.Write( "M100", (ushort)45678 );         // 寫雙字節無符號
            siemensTcpNet.Write( "M100", 123456789 );             // 寫雙字有符號
            siemensTcpNet.Write( "M100", (uint)3456789123 );      // 寫雙字無符號
            siemensTcpNet.Write( "M100", 123.456f );              // 寫單精度
            siemensTcpNet.Write( "M100", 1234556434534545L );     // 寫大整數有符號
            siemensTcpNet.Write( "M100", 523434234234343UL );     // 寫大整數無符號
            siemensTcpNet.Write( "M100", 123.456d );              // 寫雙精度
            siemensTcpNet.Write( "M100", "K123456789" );// 寫ASCII字符串

 

下面說明覆雜的數據操做,以及批量化的數據操做,例如讀取M100-M109

            OperateResult<byte[]> read = siemensTcpNet.Read( "M100", 10 );
            {
                if(read.IsSuccess)
                {
                    byte m100 = read.Content[0];
                    byte m101 = read.Content[1];
                    byte m102 = read.Content[2];
                    byte m103 = read.Content[3];
                    byte m104 = read.Content[4];
                    byte m105 = read.Content[5];
                    byte m106 = read.Content[6];
                    byte m107 = read.Content[7];
                    byte m108 = read.Content[8];
                    byte m109 = read.Content[9];
                }
                else
                {
                    // 發生了異常
                }
            }

這樣就把全部的字節數據都提取上來了,若是數據比較複雜,還能夠根據實際狀況處理。固然也支持批量的寫入數據信息

若是想實現自定義的數據類型,須要繼承一個接口

public class UserType : HslCommunication.IDataTransfer
{
    #region IDataTransfer

    private HslCommunication.Core.IByteTransform ByteTransform = new HslCommunication.Core.ReverseBytesTransform( );


    public ushort ReadCount => 20;

    public void ParseSource( byte[] Content )
    {
        int count = ByteTransform.TransInt32( Content, 0 );
        float temp = ByteTransform.TransSingle( Content, 4 );
        short name1 = ByteTransform.TransInt16( Content, 8 );
        string barcode = Encoding.ASCII.GetString( Content, 10, 10 );
    }

    public byte[] ToSource( )
    {
        byte[] buffer = new byte[20];
        ByteTransform.TransByte( count ).CopyTo( buffer, 0 );
        ByteTransform.TransByte( temp ).CopyTo( buffer, 4 );
        ByteTransform.TransByte( name1 ).CopyTo( buffer, 8 );
        Encoding.ASCII.GetBytes( barcode ).CopyTo( buffer, 10 );
        return buffer;
    }


    #endregion


    #region Public Data

    public int count { get; set; }

    public float temp { get; set; }

    public short name1 { get; set; }

    public string barcode { get; set; }

    #endregion
}

  這樣咱們就是能夠實現特殊數據的讀寫了

OperateResult<UserType> read = siemensTcpNet.ReadCustomer<UserType>( "M100" );
if (read.IsSuccess)
{
    UserType value = read.Content;
}
// write value
siemensTcpNet.WriteCustomer( "M100", new UserType( ) );

  

支持M,I,Q,DB,T,C數據的讀寫操做

 

究極數據的讀取:

此處提供一個核心的報文讀取機制,你能夠本身傳入本身的報文,而後接收服務器的報文,再本身解析操做,能夠根據報文格式實現任意的操做,固然,前提是須要報文支持。假設我要實現寫入M100,爲0x3B,那麼最終的報文爲

03 00 00 24 02 F0 80 32 01 00 00 00 01 00 0E 00 05 05 01 12 0A 10 02 00 01 00 00 83 00 03 20 00 04 00 08 3B

        private void userButton23_Click_1(object sender, EventArgs e)
        {
            byte[] buffer = HslCommunication.BasicFramework.SoftBasic.HexStringToBytes(
                "03 00 00 24 02 F0 80 32 01 00 00 00 01 00 0E 00 05 05 01 12 0A 10 02 00 01 00 00 83 00 03 20 00 04 00 08 3B");
            OperateResult<byte[]> operate = siemensTcpNet.ReadFromServerCore(buffer);
            if (operate.IsSuccess)
            {
                // 顯示服務器返回的報文
                TextBoxAppendStringLine(HslCommunication.BasicFramework.SoftBasic.ByteToHexString(operate.Content));
            }
            else
            {
                // 顯示網絡錯誤
                MessageBox.Show(operate.ToMessageShowString());
            }
        }

 

更詳細的信息,能夠參照源代碼裏面的測試項目。

 

若是使用Fetch/Write協議進行讀寫操做,PLC端的配置不一致,實例化的類不一致,其餘都是同樣的,再也不贅述了,就重點說明下PLC網絡模塊的配置


 

環境:此處使用了STEP 7V5.5 sp4編程軟件做爲示例,在添加以太網模塊(6GK7 343-1EX30-0E0 CP343-1)到組態中時,能夠設置IP地址及子網掩碼, 此處測試使用,因此不使用路由器,若是您的西門子須要鏈接到內網中的話,須要配置路由器。目前只支持M,I,Q數據的讀寫。 而後點擊新建,建立一個Ethernet(1)網絡。以太網參數配置以下圖:



將以太網的模塊添加到機架中之後,如今打開網絡組態 ,打開後點擊組態上的PLC模塊。會出現以下界面,在箭頭出進行雙擊操做,能夠彈出對話框,並進行一系列操做:

 

 

 



按照上面一套操做下來,建立了一個讀取的端口,端口號爲2000,後面有用,須要記住, 按照上述的步驟再建立一個寫入的端口,只有最後一步不一致,以下:



配置完以後的效果圖以下,新建了兩個端口,一個用於讀取數據,一個用於寫入數據。 <strong>注意:設置完成後必定要寫入到PLC纔算真的完成。</strong>



如上圖所示,上圖配置錯誤,應該配置一個同時支持讀寫的操做的端口

 

 

實例化的類的時候

private SiemensFetchWriteNet siemensFWNet = null;

  

siemensFWNet = new SiemensFetchWriteNet( )
            {
                IpAddress = "192.168.0.100",
                Port = 2000,
                ConnectTimeOut = 5000,
            };
相關文章
相關標籤/搜索