java 讀寫三菱PLC 使用TCP/IP 協議

來源:互聯網
上載者:User

標籤:java版本   結果   bsp   add   項目   adf   api   開源   ascii   

本文將使用一個Github開源的組件庫技術來讀寫三菱PLC和西門子plc資料,使用的是基於乙太網路的TCP/IP實現,不需要額外的組件,讀取操作只要放到後台線程就不會卡死線程,本組件支援超級方便的高效能讀寫操作

 github地址:https://github.com/dathlin/HslCommunication 如果喜歡可以star或是fork,還可以打賞支援,打賞請認準原始碼項目。

本項目目前支援C#語言和java語言,C#語言的功能比較齊全,java版本的庫還在開發及完善中。

 

 

點擊下載本組件的jar包。HslCommunication.jar

代碼使用支援的例子可以參照C#版本的,兩者幾乎是一模一樣的,支援的資料類型也是一致的。

 

 

支援人員QQ群:592132877  (組件的版本更新細節也將第一時間在群裡發布)最後編輯日期:2018年6月13日 08:28:34

裡面各種小夥伴,為您解答資料互動,編程技巧,如果對本介面提供的API有任何疑問,都可以加群諮詢,如果有更好的建議,歡迎提出。

 

組件的完整資訊和API介紹參照:http://www.cnblogs.com/dathlin/p/7703805.html   組件的使用限制,更新日誌,都在該頁面裡面。

 

 

本文將展示如何配置網路參數及怎樣使用代碼來訪問PLC資料,希望給有需要的人解決一些實際問題。主要對三菱Q系列PLC的X,Y,M,L,B,V,F,S,D,W,R地區的資料讀寫,對西門子PLC的M,Q,I,DB塊的資料讀寫,親測有效。

此處使用了網線直接的方式,如果PLC接進了區域網路,就可以進行遠程讀寫了^_^

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

import HslCommunication.Core.Types.OperateResultExOne;
import HslCommunication.Profinet.Melsec.MelsecMcNet;

 

隨便聊聊

當我們一個上位機需要讀取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連接埠機制也是這樣的。以下代碼預設使用長串連,效能更高,還支援多線程同步。

在短串連的模式下,每次請求都是單獨的訪問,所以沒有重連的困擾,在長串連的模式下,如果本次請求失敗了,在下次請求的時候,會自動重新串連伺服器,直到請求成功為止。另外,盡量所有的讀寫都對結果的成功進行判斷。

 

關於日誌記錄

暫時不支援

 

PLC的配置

 

環境1:此處以GX Works3為樣本,fx5u的配置如下:(感謝 山楂 提供的圖片)

 

環境2:此處以GX Works2為樣本,測試PLC為L02CPU,內建了乙太網路協議

 


環境3:此處以GX Works2為樣本,添加乙太網路模組,型號為QJ71E71-100,組態裡添加完成後進行乙太網路的參數配置,此處需要注意的是:參數的配置對接下來的代碼中配置參數要一一對應




注意:在PLC的乙太網路模組的配置中,無法設定網路號為0,也無法設定站號為0, 所以此處均設定為1,在C#程式中也使用上述的配置,在代碼中均配置為0,如果您自訂設定為網路2, 站號8,那麼在代碼中就要寫對應的資料。如果仍然通訊失敗,重新測試0,0。

開啟設定:在中的開啟設定選項,進行其他參數的配置,只是舉了一個例子,開通了4個連接埠來支援讀寫操作:

 

 

 



連接埠號碼設定規則:

  • 為了不與原先存在的系統發生衝突,您在添加自己的連接埠時盡量使用您自己的連接埠。
  • 如果讀寫都需要,儘可能的將讀取連接埠和寫入連接埠區分開來,這樣做比較高效能。
  • 如果您的網路狀態不是特別穩定,讀取連接埠使用2個,一個受阻切換另一個讀取可以提升系統的穩定性。


本文檔僅作組件的測試,所以只用了一個連接埠作為讀寫。如果你的程式也使用了一個連接埠,那麼你在讀取資料時候, 剛好也在寫入(非同步作業可能發生這樣的情況),那麼寫入會失敗!)(在長串連模式下沒有這個問題)

三菱PLC的資料主要由兩類資料群組成,位元據和字資料,在位元據中,例如X,Y,M,L都是位元據,字資料例如D,W。 兩類的資料在讀取解碼上存在一點小差別。(事實上也可以先將16個M先賦值給一個D,讀取D資料再進行解析, 在讀取M的數量比較多的時候,這樣操作效率更高)

初始化訪問PLC對象

如果想使用本組件的資料讀取功能,必須先初始化Data Access Objects,根據實際情況進行資料的填入。 下面僅僅是測試中的資料:

MelsecMcNet melsec_net = new MelsecMcNet("192.168.1.192",6001);

  

 

然後你可以指定一些參數,網路號,網路站號之類的,通常的情況都是不需要指定的

        melsec_net.setNetworkNumber((byte) 0x00);        melsec_net.setNetworkStationNumber((byte) 0x00);        melsec_net.setConnectTimeOut(1000);

  

  

開啟串連

melsec_net.ConnectServer();

如果想知道有沒有串連上去

        OperateResult connectResult = melsec_net.ConnectServer();        if(connectResult.IsSuccess){            System.out.print("串連成功");        }        else {            System.out.print("串連失敗:"+connectResult.Message);        }

  

  

關於地址的表示方式

使用字串表示,這個組件裡所有的讀寫操作提供字串表示的重載方法,所有的支援訪問的類型對應如下,字串的表示方式存在十進位和十六進位的區別:

  • 輸入繼電器:"X100","X1A0"            // 字串為十六進位機制
  • 輸出繼電器:"Y100" ,"Y1A0"           // 字串為十六進位機制
  • 內部繼電器:"M100","M200"           // 字串為十進位
  • 鎖存繼電器:"L100"  ,"L200"           // 字串為十進位
  • 通報器:       "F100", "F200"            // 字串為十進位
  • 邊沿繼電器:"V100" , "V200"          // 字串為十進位
  • 連結繼電器:"B100" , "B1A0"          // 字串為十六進位
  • 步進繼電器:"S100" , "S200"          // 字串為十進位
  • 資料寄存器:"D100", "D200"           // 字串為十進位
  • 連結寄存器:"W100" ,"W1A0"         // 字串為十六進位
  • 檔案寄存器:"R100","R200"            // 字串為十進位
關於資料分類

以上地址的資料是分為位元據和字資料的,位元據只能調用ReadBool,字資料用Read及其擴充的方法

 

簡單讀寫的樣本
        boolean[] M100 = melsec_net.ReadBool("M100",(short) 1).Content;            // 讀取M100是否通,十進位地址        boolean[] X1A0 = melsec_net.ReadBool("X1A0",(short) 1).Content;            // 讀取X1A0是否通,十六進位地址        boolean[] Y1A0 = melsec_net.ReadBool("Y1A0",(short) 1).Content;            // 讀取Y1A0是否通,十六進位地址        boolean[] B1A0 = melsec_net.ReadBool("B1A0",(short) 1).Content;            // 讀取B1A0是否通,十六進位地址        short short_D1000 = melsec_net.ReadInt16("D1000").Content;                 // 讀取D1000的short值  ,W3C0,R3C0 效果是一樣的        int int_D1000 = melsec_net.ReadInt32("D1000").Content;                     // 讀取D1000-D1001組成的int資料        float float_D1000 = melsec_net.ReadFloat("D1000").Content;                 // 讀取D1000-D1001組成的float資料        long long_D1000 = melsec_net.ReadInt64("D1000").Content;                   // 讀取D1000-D1003組成的long資料        double double_D1000 = melsec_net.ReadDouble("D1000").Content;              // 讀取D1000-D1003組成的double資料        String str_D1000 = melsec_net.ReadString("D1000", (short) 10).Content;     // 讀取D1000-D1009組成的條碼資料        melsec_net.Write("M100", new boolean[] { true} );                          // 寫入M100為通        melsec_net.Write( "Y1A0", new boolean[] { true } );                        // 寫入Y1A0為通        melsec_net.Write( "X1A0", new boolean[] { true } );                        // 寫入X1A0為通        melsec_net.Write( "B1A0", new boolean[] { true } );                        // 寫入B1A0為通        melsec_net.Write( "D1000", (short)1234);                                   // 寫入D1000  short值  ,W3C0,R3C0 效果是一樣的        melsec_net.Write( "D1000", 1234566);                                // 寫入D1000  int值        melsec_net.Write( "D1000", 123.456f);                               // 寫入D1000  float值        melsec_net.Write( "D1000", 123.456d);                               // 寫入D1000  double值        melsec_net.Write( "D1000", 123456661235123534L);                    // 寫入D1000  long值        melsec_net.Write( "D1000", "K123456789");                           // 寫入D1000  string值

  

X,Y,M,L,F,V,B,S位元據的讀寫說明

  • X 輸入繼電器
  • Y 輸出繼電器
  • M 內部繼電器
  • L 鎖存繼電器
  • F 通報器
  • V 邊沿繼電器
  • B 連結繼電器
  • S 步進繼電器

 

本小節將展示八種位元據的讀取,雖然更多的時候只是讀取D資料即可,或者是將位元據批量挪到D資料中, 但是在此處仍然進行介紹單獨的讀取X,Y,M,L,F,V,B,S,由於這八種讀取手法一致,故針對M資料進行介紹,其他的您可以自己測試。

如下方法示範讀取了M200-M209這10個M的值,注意:讀取長度必須為偶數,即時寫了奇數,也會補齊至偶數,讀取和寫入的最大長度為7168,否則報錯。如需實際需求確實大於7168的,請分批次讀取。
傳回值解析:如果讀取正常則共返回10個位元組的資料,以下樣本資料進行批量化的讀取

 OperateResultExOne<boolean[]> read = melsec_net.ReadBool("M100",(short)10);        if(read.IsSuccess){            boolean m100 = read.Content[0];            boolean m101 = read.Content[1];            boolean m102 = read.Content[2];            boolean m103 = read.Content[3];            boolean m104 = read.Content[4];            boolean m105 = read.Content[5];            boolean m106 = read.Content[6];            boolean m107 = read.Content[7];            boolean m108 = read.Content[8];            boolean m109 = read.Content[9];        }        else {            System.out.print("讀取失敗:"+read.Message);        }

  

        // 寫入測試,M100-M104 寫入測試 此處寫入後M100:通 M101:斷 M102:斷 M103:通 M104:通        boolean[] values = new boolean[]{true,false,false,true,true};        OperateResult write = melsec_net.Write("M100",values);        if(write.IsSuccess){            System.out.print("寫入成功");        }        else {            System.out.print("寫入失敗:"+write.Message);        }

  

 

D,W,R字資料的讀寫操作

此處讀取針對中間存在整數資料的情況,因為兩者讀取方式相同,故而只示範一種資料讀取, 使用該組件讀取資料,一次最多讀取或寫入960個字,超出則失敗。 如果讀取的長度確實超過限制,請考慮分批讀取。

 

        OperateResultExOne<byte[]> read1 = melsec_net.Read("D100",(short)5);        if(read1.IsSuccess){            short D100 = melsec_net.getByteTransform().TransByte(read1.Content,0);            short D101 = melsec_net.getByteTransform().TransByte(read1.Content,2);            short D102 = melsec_net.getByteTransform().TransByte(read1.Content,4);            short D103 = melsec_net.getByteTransform().TransByte(read1.Content,6);            short D104 = melsec_net.getByteTransform().TransByte(read1.Content,8);        }        else {            System.out.print("讀取失敗:"+read1.Message);        }

  

        // D100為1234,D101為8765,D102為1234,D103為4567,D104為-2563        short[] values2 = new short[]{1335, 8765, 1234, 4567, -2563 };        OperateResult write = melsec_net.Write("M100",values2);        if(write.IsSuccess){            System.out.print("寫入成功");        }        else {            System.out.print("寫入失敗:"+write.Message);        }

 

一個實際中複雜的例子示範

實際中可能碰到的情況會很複雜,一台裝置中需要上傳的資料包含了溫度,壓力,產量,規格等等資訊,在一串資料中 會包含各種各樣的不同的資料,上述的讀取D,讀取M,讀取條碼的方式不太好用,所以此處做一個完整樣本的示範,假設我們需要讀取 D4000-D4009的資料,假設D4000存放了溫度資料,55.1℃在D中為551,D4001存放了壓力資料,1.23MPa在D中存放為123,D4002存放了 裝置狀態,0為停止,1為運行,D4003存放了產量,1000就是指1000個,D4004備用,D4005-D4009存放了規格,以下代碼示範如何去解析資料:

 

        //解析複雜資料        OperateResultExOne<byte[]> read3 = melsec_net.Read("D4000", (short) 10);        if (read3.IsSuccess)        {            double 溫度 = melsec_net.getByteTransform().TransInt16(read3.Content, 0) / 10d;//索引很重要            double 壓力 = melsec_net.getByteTransform().TransInt16(read3.Content, 2) / 100d;            boolean IsRun = melsec_net.getByteTransform().TransInt16(read3.Content, 4) == 1;            int 產量 =melsec_net.getByteTransform().TransInt32(read3.Content, 6);            String 規格 = melsec_net.getByteTransform().TransString(read3.Content, 10, 10,"ascii");        }        else        {            System.out.print("讀取失敗:"+read3.Message);        }

  

更詳細的資訊,可以參照原始碼裡面的測試專案。

 

 

java 讀寫三菱PLC 使用TCP/IP 協議

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.