1. 程式人生 > >三菱Q協議PLC TCP/IP通訊協議解析簡述

三菱Q協議PLC TCP/IP通訊協議解析簡述

市場上那麼多PLC ; 
其實國內用的最多的就是  西門子,和三菱 ;

因為西門子之前一直用OPC,雖然之前偶然間破譯了ISO ON TCP 這個最常用乙太網協議的一部分,但是距離正在明白還有一段距離;
仍需要繼續測試和驗證; 
德國的東西雖然質量好,就是討厭不公開;那個倍福plc也是的,官方提供的方法是dll,最不喜歡dll,誰知道里面有什麼漏洞;
西門子也有一個prodave的dll; 有個德國愛好者做的開源的libnodave的dll,專門針對它的;

反正德國佬的東西,用起來就是不爽;
英國的圖靈在二戰期間破解德國的“謎”式密碼機,讓二戰提前3年結束都不為過;
所以有的時候破解的收益也是不小的;可以砍掉軟體開發的成本,提高效能,能隨心所欲的做更優化的控制方法和手段;


還是日本的東西更open一些,輕便一些,就像二戰風靡一時的零式戰機;
三菱PLC市場上最常用的就是FX系列和Q系列;
FX系列用的少,協議研究的不透,僅僅會簡單的D點的讀寫;等以後用到,再細化;
Q系列,稍微大一些的專案裡,主流用這個;
到三菱的辦事處,也質詢過,廠商也不是太懂通訊,他們建議給客戶的方法,還是最通用的中介軟體方法:OPC ;
  他們自己的號稱賣幾十萬的組態軟體工具也是基於OPC的;
如果實在不想用opc,也可以呼叫他們的MXComponent的元件,類似dll或ocx之類的;
當然老朽肯定不想他們現成的這兩樣東西;就像孫大聖除了定海神針,看不上東海龍王的普通兵器一樣;
要弄就要用深入骨髓的本質的東西,這樣才能靈活的做72變;




網上可以下載到《Q  系列 MELSEC 參考手冊》官方協議說明;
裡面東西很多,其實未必都用到;
看手冊太麻煩,沒經驗的朋友,上來可能就被嚇住了;
根據2-8原理,專案中能用到20%就不做了,所以不用全看;

最好有真實的plc做實驗,驗證;
條件再好一些,可以安裝一個opc server,在opc client裡監控和更改plc記憶體值,用 抓包工具smartsniff 等監控資料變化;
就能更快的搞清楚協議的互動的具體特點;

一般專案裡,我們常常用D點做通訊;
  其實PLC裡的所有型別的點,都可以通過socket通訊的方法任意讀寫;  比如:輸入 X,輸出Y,輔助暫存器M,擴充套件卡記憶體ZR;
  如果輸入X點是常開,又沒有接入裝置;那麼寫入就會保持不被覆蓋;


下面舉例子說明讀寫方法:
      1.讀D100開始的連續的20個數據塊,也就是讀D100~D119的資料;
電腦讀命令:  50 00 00 FF FF 03 00 0C 00 10 00 01 04 00 00 64 00 00 A8 14 00 (23:19:46:937)
PLC反饋:  D0 00 00 FF FF 03 00 2A 00 00 00 86 F1 00 00 C9 01 00 00 D6 02 00 00 68 02 00 00 2E 02 00 00 00 00 00 00 C3 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (23:19:46:937)


下面解析一下:
電腦讀命令: 50 00(命令)  :表示發起指令,固定50 00;


         00(網路編號) :上位訪問下位,固定00;
         FF(PLC編號) : 上位訪問下位,固定FF;
         FF 03(請求目標模組IO編號) : 值要從小到大看,也就是反過來看,三菱所有的協值都是這樣,所以這裡是03FF,十進位制是1023; 也是固定的;
         00(請求目標模組站編號) :上位訪問下位,固定00;
         0C 00 (應答資料物理長度): 也要反過來,值是000C,也就是12;表示後面的報文內容的長度是12(手工數一下,後面報文長度真的是12)
         10 00 (cpu監視定時器)  : 表示等待PLC響應的timeout時間;這裡 值是0010,十進位制是16 ;相當與最大等待時間
250ms*16=4秒;實際上PLC一般2,3個毫秒內就響應了;
         01 04 (命令)  :   值是0401(所有值都要反過來看,再說就囉嗦了,後面不說了);表示批量讀取;如果是1401就是隨機讀取;
         00 00 (子命令) : 值是0表示按字讀取(1個字=16位),如果值是1就按位讀取;
         64 00 00(首地址):地址因為跨度比較大,所以用了3個位元組;這裡的值是000064,十進位制就是100
         A8 (軟元件)         : 表示讀取PLC暫存器的型別:  這裡的A8表示D點;其他常見的有: 90-M點;9C-X點;9D-Y點;B0-ZR外部儲存卡
         14 00(讀取長度)  :值是0014,十進位制就是20;



PLC反饋: D0 00 (響應) :表示反饋資訊,固定D0 00;
               00  (網路編號 ): 與上同
               FF  (PLC編號) : 與上同
               FF 03 (請求目標模組IO編號) : 與上同
              00 (請求目標模組站編號): 與上同
              2A 00 (應答資料物理長度):值是002A; 十進位制是 42;也就是說後面的:結束程式碼(2個位元組)+值=42;所以值是40個位元組;2個位元組=1個字;所以值是20個字;
              00 00(結束程式碼) :可以理解成異常程式碼,如果正常的話,就是0000
               86 F1 00 00 C9 01 00 00 D6 02 00 00 68 02 00 00 2E 02 00 00 00 00 00 00 C3 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (反饋的值);這裡正好40個位元組;
               再囉嗦一下,值要反過來看,所以地址D100=F186;D101=0000,D102=01C9......


    2.寫D100這一個點的值為13,D101這個點的值為14,D102這個點的值為15;


        電腦寫命令: 50 00 00 FF FF 03 00 12 00 10 00 01 14 00 00 64 00 00 A8 03 00 0C 00 0D 00 0E 00 (00:14:55:188)
        PLC反饋D0 00 00 FF FF 03 00 02 00 00 00 (00:14:55:188)


下面解析一下:
     電腦寫命令:
                50 00 (命令)  :意義和讀一樣
                00(網路編號 ) :意義和讀一樣
                FF(PLC編號)    :意義和讀一樣
                FF 03 (請求目標模組IO編號) :意義和讀一樣
                00(請求目標模組站編號) :意義和讀一樣
               12 00(請求資料物理長度) :
                           值是0012,也就是十進位制18;表示後面的報文內容的長度是20;
                        也就是後面的:cpu監視定時器+命令+子命令+首地址+軟元件+長度+值=18;前面有12個位元組;所以值是6個位元組;也就是3個字;
               10 00(cpu監視定時器):同上
               01 14(命令):跟讀的差別是:讀是0104,寫是0114 ;就是04和14的差別;
              0000(子命令):值是0表示按字讀寫入1個字=16位),如果值是1就按位寫入;
              640000(首地址) :意義和讀一樣,10進位制100;表示從D100這個首地址寫入;
              A8(軟元件)  :意義和讀一樣  
              0300(長度): 值是0003 表示連續寫入3個長度;
              0C00 0D00  0E00(寫入的值): D100=13 ,D101=14,D102=15;



    PLC反饋(所有正常的寫入,反饋的資訊都固定為這個):
          D0 00(響應) :表示反饋資訊,與讀取反饋一樣,固定D0 00;
          00(網路編號 ):同上
          FF(PLC編號)  :同上
          FF 03 (請求目標模組IO編號) :同上
          00(請求目標模組站編號) :同上
          02 00(應答資料物理長度): 就是後面的 00 00 正好兩個位元組,所以這裡值=2;
          00 00(結束程式碼)  :可以理解成異常程式碼,如果正常的話,就是0000





  還有其他常見的 X,Y ,M 點讀寫方法,就懶得再舉例子了;
  道理一樣,區別是: X,Y,M 讀取和寫入不但可以用字,也可以用位;而且這樣更容易分析;
   不過我的用法是:讀取的時候,按字讀取,這樣效能高; 寫入的時候按位,因為寫入一般不會16個相鄰的點同時寫入;


  上面介紹的是連續讀寫的例子;
  其實還支援隨機讀寫,也就是在一個指令裡讀寫不連續的資料塊;
   這個功能,以前一直猶豫要不要在框架里加上;隨著專案逐漸複雜,資料點跨度也比較大;有的時候還是需要的;
   這樣同一個功能點,可以一個指令寫入,確保了類似資料庫事務一致性的處理;


  上面只是簡單的介紹了最常見的讀寫說明;


我們再做專案的時候,很多細節要琢磨;
比如在高速讀寫的時候,有的時候可能會產生“髒資料”;特別做非阻塞非同步通訊的時候,或者多埠併發通訊的時候;
比如剛剛寫入的值之後1個毫秒,前一個週期讀取的舊值響應了,這樣你認為寫入的是3,可能1毫秒後得到了舊的讀取的2,
但是第二次讀取,就肯定為3了; 不做非同步的多埠讀寫不需要考慮這個; 因為老朽過於計較效能;
所以所有的通訊都是多埠非阻塞非同步進行的;處理辦法是:寫入後,第一次接受的值如果和剛剛寫入的不一樣,不做更新覆蓋,仍然認為寫入的是正確的;
當第二次讀取的時候,如果再發現和之前的寫入值不一致,才覆蓋;