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