banner
yono

yono

哈喽~欢迎光临
follow
github

modbus 協議介紹

參考資料#

各博客網站都是缺章少句,排版混亂,偶有錯誤,不建議參考。

這裡有 modbus 中文網的資料

MODBUS 協議中文版 / 英文版預覽及下載 | Modbus 物聯網雲平台

更權威的是官方文檔

MODBUS Application Protocol 1 1 b

以及官方其他文檔,在這裡尋找

Modbus 規格和實施指南

當然官方文檔我也不是很滿意,為了保持他們的遠古設計架構,各個幀段的介紹不直觀了,同時還有少量筆誤。

image

下面有自己重寫的有效信息。

另外有我自己實現的庫

stbanana/modbusX: modbus protocol support (github.com)

協議特性#

整體幀結構#

報文頭地址域功能碼數據域校驗域
RTU1 字節 (從機 ID)1 字節n 字節不定2 字節 (對其他所有內容 CRC-MB16)
TCP6 字節
(2 字節事務號 +
2 字節協議標識 - 就是全 0+
2 字節後續字節總長 - 包括從機 ID)
1 字節 (從機 ID)1 字節n 字節不定

關於報文頭,在官方文檔的總體模型中劃分到地址域的,但實際上的字節總長又包括從機 ID。大概是早期只有串口協議時,整體模型已經定下了,新加的 modbusTCP 只能為了兼容亂搞,

我這裡直接重新歸類好了,不標準,但我樂意。

寄存器屬性#

RW 屬性bit 位數
線圈 (0x01)可讀寫1 位 bit
離散輸入寄存器 (0x02)只讀1 位 bit
保持寄存器 (0x03)可讀寫16 位 bit
輸入寄存器 (0x04)只讀16 位 bit

整體模型#

使用軟件抽象一個內存結構,每個地址存有不同意義的數據,和 FPGA 模擬 SRAM 是一個道理。不過每個寄存器地址不都是 16 位,也可以是 1 位。屬性是 RO\RW。

RTU 系列#

(0x01) 讀線圈#

主機請求#

地址域功能碼起始地址線圈數量校驗域
1 字節1 字節2 字節2 字節2 字節 (CRC-MB16)

從機響應#

地址域功能碼字節數線圈狀態校驗域
1 字節1 字節1 字節 (計算線圈狀態部分的字節數)n 字節2 字節 (CRC-MB16)

示例#

請求讀 20~38 地址的線圈數據,總之回覆地址是由低到高,最終字節不齊在高位填 0。

[!NOTE]

最終的輸出狀態 38-36 回覆字節,用零填充 5 個剩餘 bit(一直到高位端)。

請求響應
地址域 (從機 ID)0x01地址域 (從機 ID)0x01
功能碼0x01功能碼0x01
起始地址高 8 位0x00字節數0x03
起始地址低 8 位0x13輸出狀態 27-200xCD
輸出數量高 8 位0x00輸出狀態 35-280x6B
輸出數量低 8 位0x13輸出狀態 38-360x05
校驗 CRC 低 8 位0xA9校驗 CRC 低 8 位0x42
校驗 CRC 高 8 位0xC8校驗 CRC 高 8 位0x82

(0x02) 讀離散輸入寄存器#

主機請求#

地址域功能碼起始地址離散輸入數量校驗域
1 字節1 字節2 字節2 字節2 字節 (CRC-MB16)

從機響應#

地址域功能碼字節數離散輸入狀態校驗域
1 字節1 字節1 字節 (計算離散輸入狀態部分的字節數)n 字節2 字節 (CRC-MB16)

示例#

請求讀 197~218 地址的離散輸入寄存器數據,總之回覆地址是由低到高,最終字節不齊在高位填 0。

[!NOTE]

最終的輸入狀態 218-213 回覆字節,用零填充 2 個剩餘 bit(一直到高位端)。

請求響應
地址域 (從機 ID)0x01地址域 (從機 ID)0x01
功能碼0x02功能碼0x02
起始地址高 8 位0x00字節數0x03
起始地址低 8 位0xC4輸入狀態 204-1970xAC
輸出數量高 8 位0x00輸入狀態 212-2050xDB
輸出數量低 8 位0x16輸入狀態 218-2130x35
校驗 CRC 低 8 位0xB8校驗 CRC 低 8 位0x22
校驗 CRC 高 8 位0x39校驗 CRC 高 8 位0x88

(0x03) 讀保持寄存器#

主機請求#

地址域功能碼起始地址保持寄存器數量校驗域
1 字節1 字節2 字節2 字節2 字節 (CRC-MB16)

從機響應#

地址域功能碼字節數保持寄存器狀態校驗域
1 字節1 字節1 字節 (計算保持寄存器狀態部分的字節數)n 字節2 字節 (CRC-MB16)

示例#

請求讀 108~110 地址的保持寄存器數據

請求響應
地址域 (從機 ID)0x01地址域 (從機 ID)0x01
功能碼0x03功能碼0x03
起始地址高 8 位0x00字節數0x06
起始地址低 8 位0x6B寄存器值高八位(108)0x02
寄存器數量高 8 位0x00寄存器值低八位(108)0x2B
寄存器數量低 8 位0x03寄存器值高八位(109)0x00
校驗 CRC 低 8 位0x74寄存器值低八位(109)0x00
校驗 CRC 高 8 位0x17寄存器值高八位(110)0x00
寄存器值低八位(110)0x64
校驗 CRC 低 8 位0x05
校驗 CRC 高 8 位0x7A

(0x04) 讀輸入寄存器#

主機請求#

地址域功能碼起始地址輸入寄存器數量校驗域
1 字節1 字節2 字節2 字節2 字節 (CRC-MB16)

從機響應#

地址域功能碼字節數輸入寄存器狀態校驗域
1 字節1 字節1 字節 (計算輸入寄存器狀態部分的字節數)n 字節2 字節 (CRC-MB16)

示例#

請求讀 9~10 地址的保持寄存器數據

請求響應
地址域 (從機 ID)0x01地址域 (從機 ID)0x01
功能碼0x04功能碼0x04
起始地址高 8 位0x00字節數0x06
起始地址低 8 位0x6B寄存器值高八位(9)0x02
寄存器地址高 8 位0x00寄存器值低八位(9)0x2B
寄存器地址低 8 位0x03寄存器值高八位(10)0x00
校驗 CRC 低 8 位0xC1寄存器值低八位(10)0x00
校驗 CRC 高 8 位0xD7校驗 CRC 低 8 位0xF3
校驗 CRC 高 8 位0xF4

(0x05) 寫單個線圈#

[!NOTE]

寫單個線圈,輸出值部分僅允許 FF 00 表示 ON、00 00 表示 OFF,其他值都不合法

主機請求#

地址域功能碼輸出地址輸出值校驗域
1 字節1 字節2 字節2 字節2 字節 (CRC-MB16)

從機響應#

地址域功能碼地址輸出值校驗域
1 字節1 字節2 字節2 字節2 字節 (CRC-MB16)

示例#

請求寫 173 地址的線圈數據為 ON

請求響應
地址域 (從機 ID)0x01地址域 (從機 ID)0x01
功能碼0x05功能碼0x05
寄存器地址高 8 位0x00寄存器地址高 8 位0x00
寄存器地址低 8 位0xAC寄存器地址低 8 位0xAC
寄存器值高 8 位0xFF寄存器值高 8 位0xFF
寄存器值低 8 位0x00寄存器值低 8 位0x00
校驗 CRC 低 8 位0x4C校驗 CRC 低 8 位0x4C
校驗 CRC 高 8 位0x1B校驗 CRC 高 8 位0x1B

(0x06) 寫單個保持寄存器#

主機請求#

地址域功能碼保持寄存器地址寄存器值校驗域
1 字節1 字節2 字節2 字節2 字節 (CRC-MB16)

從機響應#

地址域功能碼保持寄存器地址寄存器值校驗域
1 字節1 字節2 字節2 字節2 字節 (CRC-MB16)

示例#

請求寫 2 地址的保持寄存器數據為 0x0003

請求響應
地址域 (從機 ID)0x01地址域 (從機 ID)0x01
功能碼0x06功能碼0x06
寄存器地址高 8 位0x00寄存器地址高 8 位0x00
寄存器地址低 8 位0x02寄存器地址低 8 位0x02
寄存器值高 8 位0x00寄存器值高 8 位0x00
寄存器值低 8 位0x03寄存器值低八位0x03
校驗 CRC 低 8 位0x2C校驗 CRC 低 8 位0x2C
校驗 CRC 高 8 位0x0B校驗 CRC 高 8 位0x0B

(0x0F) 寫多個線圈#

主機請求#

地址域功能碼起始地址設置數量字節數設置值校驗域
1 字節1 字節2 字節2 字節1 字節 (計算設置值部分的字節數)n 字節2 字節 (CRC-MB16)

從機響應#

地址域功能碼起始地址設置數量校驗域
1 字節1 字節2 字節2 字節2 字節 (CRC-MB16)

示例#

請求寫 20 地址開始的 10 個線圈

[!NOTE]

共需寫入 2 字節 (16bit),用零填充 6 個剩餘 bit(一直到高位端)。

線圈地址27262524232221202928
對應值1100110100000001

依據規範填充後,實際設置值段應當是 0xCD 0x01

請求響應
地址域 (從機 ID)0x01地址域 (從機 ID)0x01
功能碼0x0F功能碼0x0F
起始地址高 8 位0x00起始地址高 8 位0x00
起始地址低 8 位0x13起始地址低 8 位0x13
設置數量高 8 位0x00設置數量高 8 位0x00
設置數量低 8 位0x0A設置數量低 8 位0x0A
字節數0x02校驗 CRC 低 8 位0x24
設置值 (27~20 地址)0xCD校驗 CRC 高 8 位0x09
設置值 (29~28 地址)0x01
校驗 CRC 低 8 位0x72
校驗 CRC 高 8 位0xCB

(0x10) 寫多個保持寄存器#

主機請求#

地址域功能碼起始地址設置數量字節數設置值校驗域
1 字節1 字節2 字節2 字節1 字節 (計算設置值部分的字節數)n 字節2 字節 (CRC-MB16)

從機響應#

地址域功能碼起始地址設置數量校驗域
1 字節1 字節2 字節2 字節2 字節 (CRC-MB16)

示例#

請求寫 34 地址開始的 4 個保持寄存器

請求響應
地址域 (從機 ID)0x01地址域 (從機 ID)0x01
功能碼0x10功能碼0x10
起始地址高 8 位0x00起始地址高 8 位0x00
起始地址低 8 位0x22起始地址低 8 位0x22
設置數量高 8 位0x00設置數量高 8 位0x00
設置數量低 8 位0x04設置數量低 8 位0x04
字節數0x08校驗 CRC 低 8 位0x61
設置值高 8 位 (34 地址)0x00校驗 CRC 高 8 位0xC0
設置值低 8 位 (34 地址)0x40
設置值高 8 位 (35 地址)0x00
設置值低 8 位 (35 地址)0x24
設置值高 8 位 (36 地址)0x00
設置值低 8 位 (36 地址)0x01
設置值高 8 位 (37 地址)0xBF
設置值低 8 位 (37 地址)0x52
校驗 CRC 低 8 位0x5F
校驗 CRC 高 8 位0xCC

異常響應幀#

地址域功能碼異常碼校驗域
1 字節1 字節 (功能碼 + 0x80)1 字節2 字節 (CRC-MB16)
異常碼名稱含義
0x01非法功能碼接收到的請求指令功能碼是不可允許的操作。可能是功能碼在其中不被支持,也可能是其正處於錯誤狀態中處理請求。
0x02非法數據地址詢問中接收到的數據地址是不可允許的地址。特別是,起始地址和傳輸長度的組合是無效的。對於帶有 100 個寄存器的控制器來說,帶有起始地址 96 和長度 4 的請求會成功,帶有起始地址 96 和長度 5 的請求將產生異常碼 0x02。
0x03非法數據值實際上是數據段非法的意思。例如非法數據段長度,或者寫入或者讀取的寄存器數量和數據段不匹配。注意的是,這並不代表寄存器被寫入一個期望範圍以外的值、實際寫入失敗 (這種情況是 0x04)。
0x04從站設備故障當伺服器 (或從站),對寄存器執行請求的操作時出現差錯,例如寄存器被寫入一個期望範圍以外的值等。
0x05確認其實並非錯誤,而是收到長耗時指令,表明已收到並開始處理.
0x06從屬設備忙正在處理耗時命令在忙。(當從機空閒後,應當重發引起此錯誤的請求)
0x08存儲奇偶性差錯設法讀取記錄文件,但是在存儲器中發現一個奇偶校驗錯誤。
0x0A不可用網關路徑與網關一起使用,指示網關不能為處理請求分配輸入端口至輸出端口的內部通信路徑。通常意味著網關是錯誤配置的或過載的。
0x0B網關目標設備響應失敗與網關一起使用,指示沒有從目標設備中獲得響應。通常意味著設備未在網絡中。

TCP 系列#

總之 modbusTCP 相比於 RTU 只是包裝了前面的報文頭,同時去除了 CRC 校驗👍。== 因為 TCP 管理層的鏈路傳輸已經很穩健了,而串口傳輸是不穩健的 ==

報文頭中的事務號會在主機 (TCP 客戶端) 發起請求時不斷累加,從機 (TCP 伺服器端) 響應請求會回覆相同的事務號表示處理的是什麼請求。所以 modbusTCP 是天生支持多幀連發的,主機不會因此誤解回覆👍。

個人是更喜歡這樣流暢的通信協議的。|| 信息準確性什麼的交給物理鏈路層就好了,大霧大霧,校驗還是有必要的 ||

(0x01) 讀線圈#

主機請求#

事務號協議標識字節總長地址域功能碼起始地址線圈數量
2 字節2 字節 (全 0)2 字節 (後續字節總長)1 字節1 字節2 字節2 字節

從機響應#

事務號協議標識字節總長地址域功能碼字節數線圈狀態
2 字節2 字節 (全 0)2 字節 (後續字節總長)1 字節1 字節1 字節 (計算線圈狀態部分的字節數)n 字節

示例#

請求讀 20~38 地址的線圈數據,總之回覆地址是由低到高,最終字節不齊在高位填 0。

[!NOTE]

最終的輸出狀態 38-36 回覆字節,用零填充 5 個剩餘 bit(一直到高位端)。

請求響應
事務號高 8 位0x00事務號高 8 位0x00
事務號低 8 位0x01事務號低 8 位0x01
協議標識 16 位 (全 0)0x00 0x00協議標識 16 位 (全 0)0x00 0x00
字節總長高 8 位0x00字節總長高 8 位0x00
字節總長低 8 位0x06字節總長低 8 位0x06
地址域 (從機 ID)0x01地址域 (從機 ID)0x01
功能碼0x01功能碼0x01
起始地址高 8 位0x00字節數0x03
起始地址低 8 位0x13輸出狀態 27-200xCD
輸出數量高 8 位0x00輸出狀態 35-280x6B
輸出數量低 8 位0x13輸出狀態 38-360x05

其他協議不贅述了

其他協議不贅述了

總之 modbusTCP 相比於 RTU 只是包裝了前面的報文頭,同時去除了 CRC 校驗👍。

此文由 Mix Space 同步更新至 xLog
原始鏈接為 https://www.yono233.cn/posts/shoot/24_7_26_modbus


載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。