2008年12月8日 星期一

充電一下 -- MODBUS 通訊格式

剛剛完成機械手臂的基本雛形

要銜接下一個進度的空檔

來談談通訊中最常被使用的格式 -- MODBUS



MODBUS是一種通訊碼的標準

有別於硬體的RS232, RS485, USB...等規範

它純粹是定義軟體的碼

如果你告訴別人MODBUS就是9600,n,8,1

那觀念上就差了十萬八千里囉!!



到底什麼是MODBUS??

簡單說

就是兩台機器彼此用來溝通的語言

標準格式如下



1. 站號 --  2. 指令 -- 3. 資料位址 -- 4. 資料長度 -- 5. 檢查碼





底下分別說明各個部分



1.  站號 (0~255)



其實就是我們常說的ID(身份證號碼)

用來表示您所正在溝通的對象硬體

因為絕大多數的通訊

都是並接很多台設備同時進行連線的

如果不能明確告知要跟哪一台溝通

很可能機器跟機器之間會溝通不良而罷工或暴動





2. 指令



這就是您對硬體所要求執行的動作

常見的指令如下

0x01 : Read digital (ON/OFF) parameter (讀取一個數位參數) 

0x03 : Read analog parameter (讀取一組類比參數)

0x05 : Write digital parameter (寫入一個數位參數)

0x06 : Write analog parameter(寫入一組類比參數)




標示藍色的指令(digital)

就是一次只能存取一個 bit 的資料

標示紅色的指令(analog)

就是一次能存取一組 16 bits 的資料





3. 資料位址



固定格式為2 Bytes

如果是數位的位址

代表的意思就是第幾個bit的位置

假設我寫位址是0000

那麼就代表第一個bit

位址是0013

就代表第20個bit  (0x0013=19)



同樣的

類比所代表的位址

就是代表第幾組資料的位址(一組是16bits)





4. 資料長度 (或寫入資料)



當指令為讀取時

這兩個Bytes的功能就是告訴對方我要讀取幾個Bytes

當指令為寫入時

就是把前一組位址寫入現在這裡所填的資料





5. 檢查碼



MODBUS的檢查碼分兩種

第一種是給ASCII(文字形)通訊用的

叫做LRC

它簡單來說就是checksum的功能

把前面所有的通訊碼的值累加起來

再用0去減掉這個總合

得到一個8 bits的運算值之後

再把這個值拆成兩個 ASCII文字

最後補上結束碼(CRLF)



第二種是給RTU(二進位形)通訊用的

叫做CRC16(簡稱CRC)

它比較複雜

是透過一連串的互斥運算所得到的值

不過現下絕大多數的CRC

是用查表比對出來的



在這種檢查碼的格式下

有一個很重要的參數

我把它稱做"啟始種子"

一般來說

這個種子應該是0xffff開始的

也就是互斥運算的一開始

必須是0xffff

然而隨著通訊碼的諜對諜

這個種子可能會變成是0x0000或是0x8000

小弟在實際的應用場合

就看到這兩個異類種子出現過

然而這是否算是違反MODBUS格式呢?

那就見人見智囉!!





在什麼地方看得到MODBUS呢?

大多數的PLC通訊

應該是用MODBUS平台來架構的

某一些大型的加工機台

或是機械手臂

也會用MODBUS來進行通訊

大致來說

MODBUS就像機器界的中英文一樣

是最多人使用的語言

所以想要玩通訊的人

要稍微熟悉一下這個格式唷~~~





以上是一點小分享

詳細的資料可以參考一下這篇文章

http://www.eecs.umich.edu/~modbus/documents/PI_MBUS_300.pdf

38 則留言:

  1. 不好意思,請教個問題。

    在目前您所有PO上來的實作中,有無已經使用到MODBUS的部分呢?



    或者林老師的那本書籍中的章節有這個部分,我想翻閱看看。

    麻煩您囉!

    回覆刪除
    回覆
    1. 大大您好
      目前PO的文章中
      還沒有MODBUS相關的應用實例唷~~~
      林老師的串列書也還沒出哩~~~
      ^+++++^


      如果您有這方面的需求
      可以請您先提一下您所要學習的方向
      我可以整理一些相關的訊息供您參考

      MODBUS通訊除了傳送的資料外
      回應的資料也是一門學問
      而在這篇文章中尚未介紹回應的部分
      因為要談到的內容太多
      要分好幾次才寫得完

      感謝您的支持唷~~

      ps.
      如果您有很急迫的需要
      建議您可以直接上網搜索MODBUS與CRC16的關鍵字
      應該能找到很多說明文件與範例
      只是"族繁不及備載"的缺憾
      還請多多包涵

      刪除
  2. PLC也有用vb的com port來傳送資料啊?

    只是通訊是n,7唷。fx2(n)其它的沒試過啦。

    回覆刪除
    回覆
    1. 大大您好~~
      您所說的是JIS的7bits格式嗎?
      那是屬於硬體的部分唷!!
      modbus也是可以用VB的COM PORT來傳的唷~~~
      應該說不管是RS232, RS485, UART....
      通通都可以送MODBUS的碼
      因為傳輸資料進到硬體後
      它還是必須轉成格式碼
      才能進行指令分析
      而MODBUS就是這個指令集的代稱

      所以說MODBUS只是一個軟體編碼的標準制定
      跟n,o,e; 7,8 ; 1,1.5,2;....之類的硬體設定無關唷~~~

      不過我知道您所要提的意思
      因為有一些PLC會有自訂格式
      是有別於MODBUS規範的
      在某些不希望和別人相容的系統中
      就會使用這類不屬於MODBUS標準的PLC
      它可以對系統的盜烤有一定的防範效果
      但原則上應該還是可以接受MODBUS設定的唷~~
      只要在硬體部分切換就好

      不過隨著時代的需求
      很難說是不是有PLC已經完全放棄使用這個標準
      至少在常見的大廠牌
      應該都還是會用的

      感謝大大提供的資訊唷~~~
      我再稍微修正一下原文好了~~~
      ^+++++^

      刪除
  3. Nichal大大,謝謝您的資訊,您解釋得很好啦,

    只是有用過三菱的plc,

    他的通訊也有用過vb來做圖控,所以有此推論,畢竟這方面還是不熟,

    謝謝您的資訊啦。

    回覆刪除
  4. CRC-16 循環多餘檢查碼 使用除法 實作的一種檢查





    MODBUS也有使用到嗎??



    我記的這用在網路傳輸資料比較常見!!!?

    回覆刪除
    回覆
    1. 是呀~~~
      看一下PDF的附錄
      就是在交待這個檢查碼怎麼用唷~~~

      ^^

      刪除
  5. 大大,想請問一下

    while (usDataLen––)

    {

    uIndex = uchCRCHi ^ *puchMsgg++ ;

    uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex} ;

    uchCRCLo = auchCRCLo[uIndex] ;

    }

    此行uIndex = uchCRCHi ^ *puchMsgg++ ;的意思不知道大大是如何翻譯的

    回覆刪除
  6. 抱歉抱歉

    沒看清楚unsigned char *puchMsg ;這行

    想說奇怪互斥完再*一次暫存器的值就超過256了

    這樣是要怎麼寫>"<

    原來是小弟眼殘XD

    回覆刪除
  7. 請問版主大大

    目前市面上有介紹modbus的中文書目嗎??

    因為最近要做報告

    臨時看英文的資料可能來不及

    還是說哪裡有中文的相關資料可以參考??

    回覆刪除
    回覆
    1. 大大您好
      我都是看英文跟日文的資料耶!!
      中文的話
      不妨上大陸網站上找看看
      說不定會有電子書

      英文的paper單字不會很多
      大多是數據表跟時序圖
      日文也差不多
      不要害怕看外文書啦~~~

      刪除
  8. 恩恩^^"

    好吧...看來也只好巴結一點了XD



    謝謝版主大大囉!!

    回覆刪除
    回覆
    1. 加油囉~~~
      祝您順利!!

      有需要協助的地方可以在這裡詢問唷
      幫得上忙的話會儘量回覆

      刪除
  9. 網路上找NODBUS資料

    剛好找到貴BLOG.

    多謝大大的分享

    很清楚

    回覆刪除
  10. 版主大大, 想請指點一下:

    目前我手邊已經有寫好了RS232通訊程式, 但是我想連接RS485裝置.

    目前我的規劃如下:

    [(PC端)RS232<->轉RS485卡]<-雙絞線路->[(裝置端)RS485]



    目前我的疑惑如下:

    1.PC端RS232程式我需要做修改嗎?232轉485IC可以幫我把訊號轉出去是這樣說嘛?

    2.線路上的終端電阻該怎摸計算呢?



    謝謝版主大大 指點

    回覆刪除
    回覆
    1. RS232跟RS485差別在硬體架構
      軟體上應該是一樣的
      但還是有那麼一點點不一樣....
      RS232是全雙工
      所以傳送與接收理論上是可以同時進行的
      而且不會有資料碰撞的問題(因為收rx跟送tx是兩條不同的線)
      但是RS485就要注意收跟送的時間間隔
      不然要是發生資料碰撞就收不到正確的訊號了!!

      終端電阻原則上並聯後控制在100~120歐姆左右(以9600bps當標準的話)
      這樣信號就不會收不到了
      比方說有一台裝置要連線
      那麼終端電阻就用120歐姆
      如果有10台要連線
      那每台就都用1.2K歐姆
      不過這只是參考值
      實際上連傳輸線的線阻也要算進去
      祝您順利囉!!

      刪除
  11. 感謝 板主的指點^^

    回覆刪除
  12. 請問一下大大,我用03讀取,回傳值都正常,但用10寫入時,有寫入成

    功,監看回傳陣列也都是對得值,但pc端收到的值前面總會多出一些1,

    寫入幾bit會多出幾bit1,這是什麼情形?

    回覆刪除
    回覆
    1. 請檢查一下鮑率的設定
      有可能是7bit或8bit的設定有誤
      也可能是停止位元1bit或2bit設錯
      如果都不是
      那就是裝置本身不支援您所調整的鮑率
      或是PC本身接收指令需要等待的時間
      換一台不同廠牌的PC試一下說不定就OK了

      再試試看吧~~
      有任何結果也請讓我知道
      祝您順利

      刪除
  13. 版主你好
    我想用matlab 與plc 溝通 這個是可行的嗎?
    不過我對modbus 跟 matlab不熟 對裡面的指令有點不了解 版主能推薦一下書嗎?

    回覆刪除
    回覆
    1. 您好, 不好意思這麼晚才回覆, Modbus建議要用datasheet去看才容易理解唷! 而datasheet在文章內有連結, 您可以點進去看看, 這邊提供的是協助您理解datasheet內容的一些關鍵點, 有問題隨時歡迎在這裡留言~~~

      刪除
    2. 另外, matlab是軟體, PLC是硬體, 並不互相衝突! 只要matlab可以透過硬體將指令碼輸出給PLC, 那就可以通訊了, 當然您要先對信號組成有一定程度的瞭解才行~~

      刪除
  14. 板主您好
    有疑問想請教您
    1.
    現在客戶有一個儀器(具備 Modbus通訊功能)
    他的 PLC 要與儀器通訊 (已接好儀器端 與 PLC端 的接線)
    但他是第一次使用Modbus 通訊

    而客戶PLC 要如何與儀器 建立通訊?
    是否將
    Half-duplex
    Baud rate: 9600/19200/38400bps
    Date bits: 8 bits
    Parity: Odd parity
    Stop bit: 1 bit
    以及
    指令表: Details of Function and Address

    交給他PLC 電控

    然後客戶的電控 要自己寫程式去抓內容是嗎?

    還是儀器廠商需提供程式給客戶PLC?

    非常感謝您

    回覆刪除
    回覆
    1. 您好

      第一個要確認的是PLC支援的modbus版本
      是否與您所使用的儀器相容(定址範圍, 通訊格式)
      如果PLC所支援的格式剛好與您的儀器不同
      那就通不起來了

      如果確認通訊的格式有相容
      一般來說
      PLC是要自己寫程式去抓儀器的資料
      因為儀器是終端裝置
      並不曉得要跟他接的系統是哪一類
      所以儀器只會開放通訊格式
      並不一定有附程式碼
      不過您還是可以問看看儀器商是否有範例程式
      有的話就會比較省時了

      刪除
  15. 版主您好
    我現在工作上有需要用modbus做一套監控軟體
    目前是考慮用vb來做
    VB的話應該是使用mscomm控件來進行modbus的通訊
    在網站上找了很多資料
    但都沒有比較完整的說明,關於資料發送及接收的程式碼
    發送的寫法大概是如下
    dim btsend(8) as byte
    btsend(0)=XXX
    ...
    btsend(7)=XXX
    mscomm1.output=btsend
    有幾個問題想請教版主大大
    1.modbus發送接收的格式都是固定的嗎?
    2..net關於modbus寫法有比較完整的資料可以參考嗎?
    感謝您了

    回覆刪除
    回覆
    1. 六月風笛您好
      不好意思這麼晚才看到您的留言

      在VB6以前的版本
      確實要以mscomm物件來進行modbus通訊
      但在.net以後
      就要改用SerialPort物件會比較好
      建議您多參考一下.net在通訊物件上有介紹的書
      或是直接參考MSDN的說明

      modbus是一種指令格式的定義
      而且有很大的彈性
      除了基本運算架構是固定的
      其他很多都可以自定義
      因此很多新的指令在較新版本的modbus白皮書中
      會被不斷延伸引用

      至於modbus在.net上有沒有比較完整的參考資料
      我其實不是很清楚
      因為也沒認真去找過這一段的資料
      只要理解SerialPort的物件用法
      可以直接從mscomm的概念將程式改寫成serial的寫法
      如果是ASCII模式
      就是一般read_line及write_line的寫法(帶CRLF)
      如果是RTU模式
      就是read(byte[],) 及write(byte[],)的寫法
      搭配含有modbus的機器實機操作
      應該很快就可以試出來
      不要把他想難了

      希望這樣的回覆有解答到您的疑問
      祝您實作順利!!

      刪除
  16. 請問一下 modbus 命令端的RTU和TCP我會寫 但我們公司寫韌體的不會寫回應modbus的標準格式 要怎麼做?

    回覆刪除
    回覆
    1. 建議您先從一個指令的回應寫起
      再慢慢追加指令

      回應跟詢問是一樣的概念
      受到指令後要先確認是不是自己的站號
      不然千萬不要回應
      再依本文最後附上的PDF格式書去設計回應碼
      包括錯誤判斷以及正確的狀態回復
      最後不要忘了檢查碼的計算也要滿足CRC或LRC

      只要一個指令可以完整規劃成功
      接下來就將這段程式模組化
      變更一下指令內容及回應碼的對應陣列就可以了

      希望這樣的回覆有解答您的疑問
      或是您也可以更詳細把您現在遇到的困難描述一下
      祝您順利

      刪除
  17. 版主您好
    有問題要請教您
    小弟目前要整合一台儀器
    它的說明文件內有提到以下資訊 ,
    Register 14000-18999: AME names

    Register 14000-14001: Number of AME compounds

    Register >= 14002: Names

    maximum length per name: 32 characters (= 16 registers).
    So from register 14002 to 14017: Name of AME1 ("Acetone"), reg. 14018 to 14033: "Isoprene"

    摸了好久下了很多指令(0,1,2,3,4,6)都撈不出來東西 ,
    不知道可否幫忙解惑一下.

    回覆刪除
    回覆
    1. 您好
      請問您的大名是?

      如果單純根據您所提供的線索來看
      您可能正在使用一台化學儀器
      而化合物的名稱目前存放在14002~14033這段記憶體內
      名稱為 "Acetone Isoprene"
      化合物的編號則存放在14000~14001這個word(register)裡
      這台儀器可以存放化合物名稱的位置是從14000-18999這段記憶體
      也就是您可以嘗試修改這台儀器裡化合物的名稱

      不過
      有一個您必須先確認的訊息是
      14000這個位址的真正定位在哪?
      其次
      他每一個英文字都用一個word(register)的方式存取
      是全形字?還是半形字?是低位在先?還是高位在先?
      基本上
      他應該只適用03或06的功能碼來存取
      但您必須先確認14000這個位址
      是應該真的輸入14000
      或是只要4000
      或根本就是從0開始

      如果有原廠的範例可以參考
      請先看一下設定記憶體該注意的事項

      刪除
  18. 也希望可邀請站長,實際現場指導本人,
    不知有無這機會。
    在新北市樹林區。
    指導費用可。

    回覆刪除
    回覆
    1. 我人在高雄
      不曉得您的需求是甚麼?
      應用在哪一個環境上?

      modbus只是一個協定
      搭配在不同的硬體上就會產生不同的功能
      方便告知您所應用的領域嗎?
      看看有沒有我可以幫上忙的地方

      刪除
  19. 忘了自我介紹,我是何先生。
    我公司是以modbus及modssan做協定

    回覆刪除
    回覆
    1. 不好意思回覆得比較晚了
      如果不方便公開透露信息
      也可以Email給我
      nichal.lee@gmail.com

      刪除