一、簡介
ModBus是Modicon公司為(wei) 其PLC通訊而開發的一種通訊協議。如今Modicon公司已經被施耐德收購成為(wei) 了施耐德旗下品牌。從(cong) 1979年問世至今,已經成為(wei) 工業(ye) 通訊領域的業(ye) 界標準。
ModBus具有兩(liang) 種串行傳(chuan) 輸模式,ASCII 和 RTU。它們(men) 定義(yi) 了數據如何打包、解碼的不同方式。支持 Modbus 協議的設備一般都支持 RTU 格式。通信雙方必須同時支持上述模式中的一種。
二、寄存器類型
MODBUS寄存器分類
寄存器種類 | 讀寫狀態 | 數據類型 | 功能碼 | PLC地址 |
---|---|---|---|---|
線圈寄存器 | 讀/寫 | 位(bit) | 01H(讀單/多個位); 05H(寫單個位); 0FH(寫多個位) | 00001-09999 |
離散輸入寄存器 | 隻讀 | 位(bit) | 02H (讀單/多個位) | 10001-19999 |
保持寄存器 | 讀/寫 | 字(byte) | 03H(讀); 06H(寫單個字節); 0FH(寫多個字節) | 30001-39999 |
輸入寄存器 | 隻讀 | 字(byte) | 04H (讀單/多個字) | 40001-49999 |
線圈寄存器:實際上可以表示一個(ge) 開關(guan) 量,線圈操作位(bit)一個(ge) bit對應一個(ge) 開關(guan) 信號,即(0/false,1/true),每個(ge) byte字節就能代表8個(ge) 的位的開關(guan) 信號,線圈寄存器支持讀和寫(xie) ,Modbus的功能碼又能對線圈的單個(ge) 或多個(ge) 進行一個(ge) 讀取寫(xie) 入操作,其實就是在操作字節的位。實對應上麵的功能碼也就是:0x01 0x05 0x0f
離散輸入寄存器:離散輸入寄存器就相當於(yu) 線圈寄存器的隻讀模式,功能跟上麵基本一致,除了不能寫(xie) 入。所以功能碼也簡單就一個(ge) 讀的 0x02
保持寄存器:保持寄存器是對字節進行的操作,每兩(liang) 個(ge) 字節對應一個(ge) 寄存器,支持讀取和寫(xie) 入。功能碼有對應的三個(ge) :0x03 0x06 0x10
輸入寄存器:,這個(ge) 和保持寄存器類似,但是也是隻支持讀而不能寫(xie) 。一個(ge) 寄存器地址是占據兩(liang) 個(ge) byte的空間,也就是16個(ge) 位。對應的功能碼也就一個(ge) 0x04
言外之話:
當需要對保持寄存器操作時,不同的數據類型占據的字節長度其實是不一致的,一個(ge) 寄存器地址占兩(liang) 個(ge) 字節16位代表的隻是一個(ge) 單精度的數據。如C#的數據類型占據的長度如下
C# 數據類型和字節長度
所以在讀取寫(xie) 入保持寄存器的時候不同類型需要讀取不同長度的字節才能拿到對應類型的值,寫(xie) 入的時候同理。如(int類型讀取2個(ge) 數量為(wei) int的時候需要乘以2,也就是讀取4個(ge) 寄存器才能拿到兩(liang) 個(ge) int類型的數據)
三、MODBUS常用功能碼
功能碼 | 名稱 | 操作數據類型 | 作用描述 | PLC地址 |
---|---|---|---|---|
01H | 讀線圈寄存器 | 位(bit) | 獲得一組開關線圈的當前狀態(ON/OFF ) | 00001-09999 |
02H | 讀離散輸入寄存器 | 位(bit) | 獲得一組開關線圈的當前狀態(ON/OFF ) | 10001-19999 |
03H | 讀保持寄存器 | 字(byte) | 在一個或多個保持寄存器中取得當前的二進製值 | 30001-39999 |
04H | 讀輸入寄存器 | 字(byte) | 在一個或多個輸入寄存器中取得當前的二進製值 | 40001-49999 |
05H | 寫單個線圈寄存器 | 位(bit) | 設置一個單獨的線圈狀態(ON/OFF ) | 00001-09999 |
06H | 寫單個保持寄存器 | 字(byte) | 寫單個保持寄存器,將兩個字節寫入到寄存器 | 40001-49999 |
0FH | 寫多個線圈寄存器 | 位(bit) | 寫多個線圈寄存器,可以設置多個bit開關狀態 | 00001-09999 |
10H | 寫多個保持寄存器 | 字(byte) | 寫多個保持寄存器,將多個字節寫入到寄存器 | 40001-49999 |
MODBUS通訊協議格式
讀線圈寄存器——01H
從(cong) 站發送讀取格式:
從站地址 | 功能碼 | 起始地址高位 | 起始地址低位 | 讀取數量高位 | 讀取數量低位 | CRC高位 | CRC低位 |
---|---|---|---|---|---|---|---|
0x01 | 0x01 | 0x00 | 0x00 | 0x00 | 0x02 | BD | CB |
主站返回讀取格式:
從站地址 | 功能碼 | 返回字節數 | data1 | CRC高位 | CRC低位 |
---|---|---|---|---|---|
0x01 | 0x01 | 0x01 | 0x00 | 51 | 88 |
解讀:
發送格式:
從(cong) 站地址:01
功能碼:01
起始地址: 00 00
讀取數量: 00 02
CRC校驗:BD CB
接收格式:
從(cong) 站地址:01
功能碼:01
返回字節數: 01
Data數據: 00(一個(ge) byte有8個(ge) bit,讀取兩(liang) 個(ge) bit返回會(hui) 補成字節用一個(ge) byte返回讀取兩(liang) 個(ge) bit就行)
CRC校驗:BD CB
讀離散輸入狀態——02H
從(cong) 站發送讀取格式:
從站地址 | 功能碼 | 起始地址高位 | 起始地址低位 | 讀取數量高位 | 讀取數量低位 | CRC高位 | CRC低位 |
---|---|---|---|---|---|---|---|
0x01 | 0x02 | 0x00 | 0x00 | 0x00 | 0x02 | F9 | CB |
主站返回讀取格式:
從站地址 | 功能碼 | 返回字節數 | data1 | CRC高位 | CRC低位 |
---|---|---|---|---|---|
0x01 | 0x02 | 0x01 | 0x00 | A1 | 88 |
讀保持寄存器——03H
從(cong) 站發送讀取格式:
從站地址 | 功能碼 | 起始地址高位 | 起始地址低位 | 讀取數量高位 | 讀取數量低位 | CRC高位 | CRC低位 |
---|---|---|---|---|---|---|---|
0x01 | 0x03 | 0x00 | 0x00 | 0x00 | 0x02 | C4 | CB |
主站返回讀取格式:
從站地址 | 功能碼 | 返回字節數 | data1 | data2 | data3 | data4 | CRC高位 | CRC低位 |
---|---|---|---|---|---|---|---|---|
0x01 | 0x03 | 0x04 | 0x00 | 0x0A | 0x00 | 0x00 | 0A | 31 |
解析讀取返回:
為(wei) 啥讀取是讀取兩(liang) 個(ge) 地址數量會(hui) 返回四個(ge) byte字節?因為(wei) 在保持寄存器裏麵兩(liang) 個(ge) 字節才對應一個(ge) 寄存器,你讀取兩(liang) 個(ge) 寄存器地址數量就需要四個(ge) 字節來表示。
注意:在解析字節的時候數據的高低位順序倒序後才能表示一個(ge) 數據
讀輸入寄存器——04H
同讀取保存寄存器一樣的格式,同上
寫(xie) 單個(ge) 線圈——05H
從(cong) 站地址 | 功能碼 | 起始地址高位 | 起始地址低位 | data1 | data2 | CRC高位 | CRC低位 |
---|---|---|---|---|---|---|---|
0x01 | 0x05 | 0x00 | 0x00 | 0xFF | 0x00 | 8C | 3A |
主站返回讀取格式:
從站地址 | 功能碼 | 起始地址高位 | 起始地址低位 | 寫入數據高位 | 寫入數據低位 | CRC高位 | CRC低位 |
---|---|---|---|---|---|---|---|
0x01 | 0x05 | 0x00 | 0x00 | 0xFF | 0x00 | 8C | 3A |
解析:
寫(xie) 入無誤的話返回同發送指令一樣;通斷標誌為(wei) FF00H表示寫(xie) ON,0000H表示寫(xie) OFF,
寫單個保持寄存器——06H
將地址0的保存寄存器的數據設置為(wei) 10(單精度)
從(cong) 站地址 | 功能碼 | 起始地址高位 | 起始地址低位 | data1 | data2 | CRC高位 | CRC低位 |
---|---|---|---|---|---|---|---|
0x01 | 0x06 | 0x00 | 0x00 | 0x00 | 0x0A | 09 | CD |
主站返回讀取格式:
響應:同發送指令;
寫多個線圈——0FH
從站地址 | 功能碼 | 起始地址高位 | 起始地址低位 | 寫入數量高位 | 寫入數據低位 | 字節長度 | data1 | CRC高位 | CRC低位 |
---|---|---|---|---|---|---|---|---|---|
0x01 | 0x0F | 0x00 | 0x00 | 0x00 | 0x02 | 0x01 | 0x03 | 9E | 96 |
主站返回讀取格式:
響應:
從站地址 | 功能碼 | 起始地址高位 | 起始地址低位 | 寫入數量高位 | 寫入數據低位 | CRC高位 | CRC低位 |
---|---|---|---|---|---|---|---|
0x01 | 0x0F | 0x00 | 0x00 | 0x00 | 0x02 | 9E | 96 |
返回數據格式不返回Data數據
詳情:寫(xie) 入數量為(wei) 2的線圈,其中data1數據0x03代表0000 0011 將連續兩(liang) 個(ge) 線圈置為(wei) ON
寫多個保持寄存器——10H
從站地址 | 功能碼 | 起始地址高位 | 起始地址低位 | 寫入數量高位 | 寫入數據低位 | 字節長度 | data1 | data2 | data3 | data4 | CRC高位 | CRC低位 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0x01 | 0x10 | 0x00 | 0x00 | 0x00 | 0x02 | 0x04 | 0x0C | 0x02 | 0x12 | 0x45 | 9C | 6C |
主站返回讀取格式:
響應:
從站地址 | 功能碼 | 起始地址高位 | 起始地址低位 | 寫入數量高位 | 寫入數據低位 | CRC高位 | CRC低位 |
---|---|---|---|---|---|---|---|
0x01 | 0x10 | 0x00 | 0x00 | 0x00 | 0x02 | 41 | CB |
返回數據格式不返回Data數據
詳情:寫(xie) 入數量為(wei) 2的線圈,其中data1,data2,data3,data4數據兩(liang) 個(ge) 代表一個(ge) 單精度數據
0C 02表示一個(ge) 3074 ,12 45代表一個(ge) 4677
MODBUS TCP通訊協議格式
ModbusTCP的數據幀可分為(wei) 兩(liang) 部分:MBAP+PDU。
| 事務處理標識| 協議標識 | 字節長度 | 單元標識符 | 功能碼 |起始地址H | 起始地址L |數量H | 數量L
事務處理標識 | 協議標識 | 字節長度 | 單元標識符 | 功能碼 | 起始地址H | 起始地址L | 數量H | 數量L |
---|---|---|---|---|---|---|---|---|
2字節 | 2字節 | 2字節 | 1字節 | 1字節 | 1字節 | 1字節 | 1字節 | 1字節 |
事務處理標識: 可以理解為(wei) 報文的序列號,一般每次通信之後就要加1以區別不同的通信數據報文。
協議標識符: 00 00表示ModbusTCP協議。
字節長度: 表示接下來的數據長度,單位為(wei) 字節
單元標識符: 可以理解為(wei) 設備地址。
TCP跟RTU的協議格式其實基本上是一致的,隻是TCP增加了報文頭MBAP,取消了RTU的從(cong) 站地址跟CRC校驗