Modbus協議(一)
Modbus協議
概述
Modbus誕生于1979年,莫迪康Modicon公司(傳聞是發明了第一臺PLC的公司,后被施耐德電氣公司收購),目前是工業領域應用最廣泛的通信協議。
Modbus之所以使用廣泛,主要原因是:
Modbus協議標準開放、無專利保護,任何廠商都可以用
Modbus協議支持多種電氣接口,包括RS232、RS485、TCP/IP等,還可以在各種介質上傳輸,如雙絞線、光纖、紅外、無線等
Modbus協議消息幀格式簡單、緊湊、通俗易懂。用戶理解和使用簡單,廠商容易開發和集成,方便形成工業控制網絡
Modbus協議數據模型統一,通過預定義寄存器地址讀寫數據
Modbus協議是一種應用層報文傳輸協議,協議本身并沒有定義物理層,而是定義了控制器能夠認識和使用的消息結構,這就使得它可以在不同的物理層上實現設備和設備之間的通信。下表是Modbus協議在不同物理層應用舉例。
| Modbus 協議類型 | 通信方式 | 物理層標準 | 線纜類型 | 接口/接頭 | 最大傳輸距離 | 設備示例 | 應用場景舉例 |
|---|---|---|---|---|---|---|---|
| Modbus RTU | 串行通信 | RS-485 | 雙絞屏蔽電纜(如:RVSP) | DB9、RJ45、端子排 | 1200 米(RS-485) | PLC、變頻器、傳感器、儀表等 | 工廠自動化、樓宇控制、產線設備 |
| Modbus ASCII | 串行通信 | RS-232 / RS-485 | 普通雙絞線或屏蔽線 | DB9、RJ45、端子排 | RS-232: 15米 RS-485: 1200米 |
調試工具、老式設備 | 調試、低速通信、簡單人機交互 |
| Modbus TCP | 以太網通信 | TCP/IP over Ethernet | 標準網線(Cat5e / Cat6) | RJ45 | 100 米(單段) 可擴展 |
HMI、SCADA、服務器、工業交換機 | 工業以太網、遠程監控、數據采集系統 |
| Modbus UDP | 以太網通信 | UDP/IP | 標準網線(Cat5e / Cat6) | RJ45 | 同TCP/IP | 實時控制系統、運動控制設備 | 對實時性要求高、容忍少量丟包的控制系統 |
其中在工業上最常見的就是ModbusRTU和ModbusTCP,一個是使用雙絞線走RS485協議標準,一個是使用標準網線走TCP/IP協議標準。
數據模型
Modbus 定義了四種主要的數據區(寄存器類型),具體根據不同的通信對象(設備),會對應到PLC、變頻器、智能儀表等內部的存儲區,具體需要查看PLC、變頻器、智能儀表的對應說明:
| 類型 | 可讀/可寫 | 描述 |
|---|---|---|
| 線圈(Coils) | 讀/寫 | 開關量輸出(0x 寄存器) |
| 離散輸入(Discrete Inputs) | 只讀 | 開關量輸入(1x 寄存器) |
| 輸入寄存器(Input Registers) | 只讀 | 模擬量輸入(3x 寄存器) |
| 保持寄存器(Holding Registers) | 讀/寫 | 模擬量輸出(4x 寄存器) |
功能碼
協議通過功能碼結合設備地址+數據區地址實現對設備存儲信息的讀寫。功能碼如下表所示:
| 功能碼(十進制) | 功能碼(十六進制) | 名稱 | 操作類型 | 操作對象 | Modbus地址范圍 | 數據類型 | 最大支持數量 |
|---|---|---|---|---|---|---|---|
| 1 | 0x01 | 讀線圈狀態 | 讀 | 線圈(Coils) | 00001-09999 | 位(Bit) | 2000 |
| 2 | 0x02 | 讀離散輸入 | 讀 | 離散輸入(Discrete Inputs) | 10001-19999 | 位(Bit) | 2000 |
| 3 | 0x03 | 讀保持寄存器 | 讀 | 保持寄存器(Holding Registers) | 40001-49999 | 字(Word) | 125 |
| 4 | 0x04 | 讀輸入寄存器 | 讀 | 輸入寄存器(Input Registers) | 30001-39999 | 字(Word) | 125 |
| 5 | 0x05 | 寫單線圈 | 寫 | 單個線圈 | 00001-09999 | 位(Bit) | 1 |
| 6 | 0x06 | 寫單個寄存器 | 寫 | 單個保持寄存器 | 40001-49999 | 字(Word) | 1 |
| 15 | 0x0F | 寫多個線圈 | 寫 | 多個線圈 | 00001-09999 | 位(Bit) | 1968 |
| 16 | 0x10 | 寫多個寄存器 | 寫 | 多個保持寄存器 | 40001-49999 | 字(Word) | 123 |
| 22 | 0x16 | 屏蔽寫寄存器 | 寫 | 保持寄存器(位操作) | 40001-49999 | 字(位掩碼) | 1 |
| 23 | 0x17 | 讀/寫多個寄存器 | 讀寫混合 | 保持寄存器 | 40001-49999 | 字(Word) | 121/121 |
異常功能碼
所有異常響應 = 功能碼 + 0x80(如 0x03 → 0x83)
| 異常碼 | 名稱 | 說明 |
|---|---|---|
| 0x01 | 非法功能碼 | 設備不支持該功能 |
| 0x02 | 非法數據地址 | 請求地址超出設備范圍 |
| 0x03 | 非法數據值 | 數據域值無效 |
| 0x04 | 從站設備故障 | 設備執行失敗 |
| 0x05 | 確認 | 設備已接收但需長時間處理 |
| 0x06 | 從站設備忙 | 設備暫時無法響應 |
| 0x07 | 存儲奇偶錯誤 | 設備存儲器校驗失敗 |
| 0x08 | 不可用網關路徑 | 網關無法分配請求路徑 |
| 0x0A | 網關目標設備無響應 | 網關無法獲取從站響應 |
關鍵說明
-
地址映射規則:
- 所有Modbus地址在協議中轉換為0-based地址(如40001 → 0x0000)
- 部分設備需要偏移(如40001 → 0x0001)
-
數據打包規則:
- 位操作:8位/字節(LSB優先)
- 字操作:大端序(高位在前)
-
數量限制:
- 讀操作最大數量受協議限制(位操作2000,字操作125)
- 寫操作數量受設備內存限制
-
混合操作:
- FC23(0x17)可同時讀寫寄存器,提升通信效率
ModbusRTU
01ModbusRTU讀取線圈狀態(多個位)
樣例1
ModbusRTU協議按照下列模式發送報文
| 地址 | 功能碼 | 起始地址高位 | 起始地址低位 | 讀取線圈數量高位 | 讀取線圈數量低位 | CRC16 校驗碼 |
|---|---|---|---|---|---|---|
| 0x01 | 0x01 | 0x00 | 0x00 | 0x00 | 0x05 | 0xFC 0x09 |
代表讀取從站地址1的設備,地址從0開始的5個線圈的狀態。
使用串口調試軟件以Hex格式發送
010100000005FC09
收到反饋
01 01 01 0A D1 8F
代表
| 字段 | 地址 | 功能碼 | 接下來的數據部分字節數 | 十六進制的線圈狀態 | CRC16校驗 |
|---|---|---|---|---|---|
| 值 | 01 | 01 | 01 | 0A | D1 8F |
| 含義 | 從站1 | 讀線圈 | 接下來的數據有1字節 | 0A=00001010:線圈2``4為ON |
CRC校驗 |

樣例2
再試一次,讀取多一點線圈數據。
發送
01 01 00 00 00 20 3D D2
收到響應
01 01 04 8A 10 02 00 D1 6C
分別代表,發送
| 地址 | 功能碼 | 起始地址高位 起始地址低位 | 讀取線圈數量高位 讀取線圈數量低位 | CRC16 校驗碼 |
|---|---|---|---|---|
| 0x01 | 0x01 | 0x00 0x00 | 0x00 0x20 | 0x3D 0xD2 |
| 從站1 | 讀多個線圈 | 從0號線圈開始 | 讀十六進制的20個=16*2=30個線圈的值 | CRC16校驗 |
收到響應解釋
| 字段 | 從站地址 | 功能碼 | 字節數 | 數據1 | 數據2 | 數據3 | 數據4 | CRC 校驗 |
|---|---|---|---|---|---|---|---|---|
| 值 | 01 | 01 | 04 | 8A | 10 | 02 | 00 | D16C |
| 含義(高位在前) | 從站地址為 1 | 讀線圈(Read Coils) | 接下來的數據有 4 個字節(共 32 位) | 8A:10001010 |
10:00010000 |
02:00000010 |
00:00000000 |
CRC16 校驗碼(兩個字節) |
線圈狀態解析(按順序)
| 線圈地址 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|---|
| 狀態 | OFF | ON | OFF | ON | OFF | OFF | OFF | ON |
| 線圈地址 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 狀態 | OFF | OFF | OFF | OFF | ON | OFF | OFF | OFF |
| 線圈地址 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
| 狀態 | OFF | OFF | OFF | OFF | OFF | OFF | ON | OFF |
| 線圈地址 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
| 狀態 | OFF | OFF | OFF | OFF | OFF | OFF | OFF | OFF |
串口調試軟件截圖

ModSim43截圖

02ModbusRTU讀取離散輸入狀態
報文格式與01讀線圈類似
樣例
| 地址 | 功能碼 | 起始地址高位 起始地址低位 | 讀取輸入點數量高位 讀取輸入點數量低位 | CRC16 校驗碼 |
|---|---|---|---|---|
| 0x01 | 0x02 | 0x00 0x00 | 0x00 0x05 | 0xB8 0x09 |
| 從站1 | 讀輸入 | 起始輸入地址0 | 讀取5個 | CRC16校驗 |
使用串口調試助手發送
010200000005B809
收到響應
``·bash
01 02 01 09 61 8E
···
收到響應解釋
| 字段 | 從站地址 | 功能碼 | 字節數 | 數據 | CRC 校驗 |
|---|---|---|---|---|---|
| 值 | 01 | 02 | 01 | 09 | 61 8E |
| 含義(高位在前) | 從站地址為 1 | 讀離散輸入( Discrete Inputs ) | 接下來的數據有 41個字節(共8位) | 09:00001001 |
CRC16 校驗碼(兩個字節) |
| 輸入地址 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|---|
| 狀態 | ON | OFF | OFF | ON | OFF | OFF | OFF | OFF |
串口調試軟件截圖

ModSim截圖

由于發送的讀取輸入報文是讀5個輸入點的信號,所以可以看到,即使ModSim的輸入6、7位都是ON,但收到的代表輸入狀態的值仍是09也就是00001001(LSB first 最低有效位在前)。
這里有一點需要注意,ModSim的寄存器或線圈的地址都是從1開始計數,而使用ModbusRTU讀寫命令的地址是從0開始,這一點需要進行匹配。也就是Modbus命令寄存器地址n對應Modsim的寄存器地址n+1。

浙公網安備 33010602011771號