Modbus由MODICON公司于1979年開發,是一種工業現場總線協議標準,1996年施耐德公司推出基于以太網TCP/IP的Modbus協議,ModbusTCP,
Modbus通信的設備分為主站(mater)和從站(slave),主站為主動方,從站為被動方,
通信程序
通信的程序為:
- 主站設備主動向從站設備發送請求
- 從站設備處理主站的請求后,向主站回傳結果,
- 如果從站設備處理請求出現例外,則向主站設備回傳例外功能碼,
資料傳輸方式
modbus的資料傳輸被定義為對以下4個存盤塊的讀寫:
- 線圈(coils) 操作單位為1位字的開關量,PLC的輸出位,在Modbus中可讀可寫
- 離散量(discreteinputs) 操作單位為1位字的開關量,PLC的輸入位,在Modbus中只讀
- 輸入暫存器(inputregisters) 操作單位為16位字(兩個位元組)資料,PLC中只能從模擬量輸入端改變的暫存器,在Modbus中只讀
- 保持暫存器(holdingregisters) 操作單位為16位字(兩個位元組)資料,PLC中用于輸出模擬量信號的暫存器,在Modbus中可讀可寫
MODBUS-TCP報文結構
modbus-tcp報文結構:

如上圖所示:modbus-tcp的報文由MBAP+PDU組成,
MBAP報文頭
其中MBAP報文頭的組成為:
| 域 | 長度 | 描述 |
|---|---|---|
| 事務元識別符號 | 2 個位元組 | MODBUS 請求/回應事務處理的識別碼,主要用于在主站設備在接收到回應時能知道是哪個請求的回應 |
| 協議識別符號 | 2 個位元組 | 對于MODBUS 協議來說,這里恒為0 |
| 長度 | 2 個位元組 | 以下位元組的數量,也就是完整報文的位元組數減去6 |
| 單元識別符號 | 1 個位元組 | 串行鏈路或其它總線上連接的遠程從站的識別碼,也就是要訪問的從站的標識號,因為只有一個位元組,所以一個主站最多只能訪問256個從站設備 |
由上表可知,報文頭為 7 個位元組長,
PDU報文體
PDU的組成為功能碼(一個位元組)和資料(n個位元組)
其中功能碼為一個位元組,modbus定義的功能碼有:
- 01 讀線圈(coils)狀態,讀取單個或多個
- 02 讀離散輸入(discreteinputs)狀態,讀取單個或多個
- 03 讀保持暫存器(holdingregisters),讀取單個或多個
- 04 讀輸入暫存器(inputregisters),讀取單個或多個
- 05 寫單個線圈(coils)狀態,單個寫入
- 06 寫單個保持暫存器(holdingregisters),單個寫入
- 15 寫多個線圈(coils),多個寫入
- 16 寫多個保持暫存器(holdingregisters),多個寫入
另外,當回應報文的功能碼最高位為1時(即:(function & 0x80) != 0),表示為例外回應,這時資料為一個位元組的例外碼,具體的例外碼定義有:
- 01 功能碼不能被從機識別
- 02 從機的單元識別符號不正確
- 03 值不被從機接受
- 04 當從機試圖執行請求的操作時,發生了不可恢復的錯誤,
- 05 從機已接受請求并正在處理,但需要很長時間,回傳此回應是為了防止在主機中發生超時錯誤,主站可以在下一個輪詢程式中發出一個完整的訊息,以確定處理是否完成,
- 06 從站正在處理長時間命令,Master應該稍后重試,
- 07 從站不能執行程式功能,主站應該向從站請求診斷或錯誤資訊,
- 08 從站在記憶體中檢測到奇偶校驗錯誤,主設備可以重試請求,但從設備上可能需要服務,
- 10 專門用于Modbus網關,表示配置錯誤的網關,
- 11 專用于Modbus網關的回應,當從站無法回應時發送,
PDU報文詳情
1、讀線圈
請求報文:
| 功能碼:01,一個位元組 | 偏移量offset(讀取資料的開始位置),兩個位元組 | 讀取數量,兩個位元組 |
|---|
正常回應報文:
| 功能碼:01,一個位元組 | 資料長度(位元組數),一個位元組 | 線圈狀態資料,n個位元組(由于網路傳輸的資料都是以整位元組為單位的,所以收到的資料可能比請求中要讀的位數要多,這時按位將資料轉換為開關量,只需決議請求中讀取數量欄位設定的位數就可以了) |
|---|
例外回應報文:
| 功能碼:129(0x81),一個位元組 | 例外碼,一個位元組 |
|---|
2、讀離散輸入
請求報文:
| 功能碼:02,一個位元組 | 偏移量offset(讀取資料的開始位置),兩個位元組 | 讀取數量,兩個位元組 |
|---|
正常回應報文:
| 功能碼:02,一個位元組 | 資料長度(位元組數),一個位元組 | 離散輸入狀態資料,n個位元組(由于網路傳輸的資料都是以整位元組為單位的,所以收到的資料可能比請求中要讀的位數要多,這時按位將資料轉換為開關量,只需決議請求中讀取數量欄位設定的位數就可以了) |
|---|
例外回應報文:
| 功能碼:130(0x82),一個位元組 | 例外碼,一個位元組 |
|---|
3、讀保持暫存器
請求報文:
| 功能碼:03,一個位元組 | 偏移量offset(讀取資料的開始位置),兩個位元組 | 讀取數量,兩個位元組 |
|---|
正常回應報文:
| 功能碼:03,一個位元組 | 資料長度(位元組數,這里應該是請求報文中的讀取數量的2倍),一個位元組 | 保持暫存器資料,n個位元組(資料的位元組數應該是請求報文中的讀取數量的2倍) |
|---|
例外回應報文:
| 功能碼:131(0x83),一個位元組 | 例外碼,一個位元組 |
|---|
4、讀輸入暫存器
請求報文:
| 功能碼:04,一個位元組 | 偏移量offset(讀取資料的開始位置),兩個位元組 | 讀取數量,兩個位元組 |
|---|
正常回應報文:
| 功能碼:04,一個位元組 | 資料長度(位元組數,這里應該是請求報文中的讀取數量的2倍),一個位元組 | 輸入暫存器資料,n個位元組(資料的位元組數應該是請求報文中的讀取數量的2倍) |
|---|
例外回應報文:
| 功能碼:132(0x84),一個位元組 | 例外碼,一個位元組 |
|---|
5、寫單個線圈
請求報文:
| 功能碼:05,一個位元組 | 偏移量offset(寫入資料的開始位置),兩個位元組 | 要寫入的線圈狀態值(只關注0和非0),兩個位元組 |
|---|
正常回應報文:
| 功能碼:05,一個位元組 | 偏移量offset(寫入資料的開始位置),兩個位元組 | 要寫入的線圈狀態值(只關注0和非0),兩個位元組 |
|---|
例外回應報文:
| 功能碼:133(0x85),一個位元組 | 例外碼,一個位元組 |
|---|
6、寫單個保持暫存器
請求報文:
| 功能碼:06,一個位元組 | 偏移量offset(寫入資料的開始位置),兩個位元組 | 要寫入的保持暫存器資料,兩個位元組 |
|---|
正常回應報文:
| 功能碼:06,一個位元組 | 偏移量offset(寫入資料的開始位置),兩個位元組 | 要寫入的保持暫存器資料,兩個位元組 |
|---|
例外回應報文:
| 功能碼:134(0x86),一個位元組 | 例外碼,一個位元組 |
|---|
7、寫多個線圈
請求報文:
| 功能碼:15,一個位元組 | 偏移量offset(寫入資料的開始位置),兩個位元組 | 要寫入的數量,兩個位元組 | 資料長度(位元組數),一個位元組 | 線圈狀態資料,n個位元組 |
|---|
正常回應報文:
| 功能碼:15,一個位元組 | 偏移量offset(寫入資料的開始位置),兩個位元組 | 要寫入的數量,兩個位元組 |
|---|
例外回應報文:
| 功能碼:143(0x8f),一個位元組 | 例外碼,一個位元組 |
|---|
8、寫多個保持暫存器
請求報文:
| 功能碼:16,一個位元組 | 偏移量offset(寫入資料的開始位置),兩個位元組 | 要寫入的數量,兩個位元組 | 資料長度(位元組數),一個位元組 | 保持暫存器資料,n個位元組 |
|---|
正常回應報文:
| 功能碼:16,一個位元組 | 偏移量offset(寫入資料的開始位置),兩個位元組 | 要寫入的數量,兩個位元組 |
|---|
例外回應報文:
| 功能碼:144(0x90),一個位元組 | 例外碼,一個位元組 |
|---|
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/252202.html
標籤:其他
下一篇:嵌入式的一點回憶
