開放、平等、協(xié)作、快速、分享
Modbus是一種工業(yè)協(xié)議,于1979年開發(fā),旨在實現(xiàn)自動化設備之間的通信。 Modbus最初是作為通過串行層傳輸數(shù)據(jù)的應用級協(xié)議實現(xiàn)的,現(xiàn)已擴展到包括通過串行、TCP/IP和用戶數(shù)據(jù)報協(xié)議(UDP)的實現(xiàn)。 本文檔提供了協(xié)議實現(xiàn)的深入講解。
Modbus是使用主從關系實現(xiàn)的請求 - 響應協(xié)議。 在主從關系中,通信總是成對發(fā)生 - 一個設備必須發(fā)起請求,然后等待響應 - 并且發(fā)起設備(主設備)負責發(fā)起每次交互。 通常,主設備是人機界面(HMI)或監(jiān)控和數(shù)據(jù)采集(SCADA)系統(tǒng),從設備是傳感器、可編程邏輯控制器(PLC)或可編程自動化控制器(PAC)。 這些請求和響應的內(nèi)容以及發(fā)送這些消息的網(wǎng)絡層由協(xié)議的不同層來定義。
![]() |
圖1. 主從網(wǎng)絡關系 |
Modbus協(xié)議層
在最初的做法中,Modbus是建立在串行端口之上的單一協(xié)議,因此它不能被分成多個層。 隨著時間的推移,該協(xié)議引入了不同的應用程序數(shù)據(jù)單元來更改串行通信使用的數(shù)據(jù)包格式,或允許使用TCP/IP和用戶數(shù)據(jù)報協(xié)議(UDP)網(wǎng)絡。 這實現(xiàn)了定義協(xié)議數(shù)據(jù)單元(PDU)的核心協(xié)議和定義應用數(shù)據(jù)單元(ADU)的網(wǎng)絡層的分離。
PDU及其處理代碼構(gòu)成了Modbus應用協(xié)議規(guī)范的核心。 該規(guī)范定義了PDU的格式、協(xié)議使用的各種數(shù)據(jù)概念、如何使用功能代碼訪問數(shù)據(jù),以及每個功能代碼的具體實現(xiàn)和限制。
Modbus PDU格式被定義為一個功能代碼,后面跟著一組關聯(lián)的數(shù)據(jù)。 該數(shù)據(jù)的大小和內(nèi)容由功能代碼定義,整個PDU(功能代碼和數(shù)據(jù))的大小不能超過253個字節(jié)。 每個功能代碼都有一個特定的行為,從設備可以根據(jù)所需的應用程序行為靈活地實現(xiàn)這些行為。 PDU規(guī)范定義了數(shù)據(jù)訪問和操作的核心概念;但是,從設備可能會以規(guī)范中未明確定義的方式處理數(shù)據(jù)。
通常,Modbus可訪問的數(shù)據(jù)存儲在四個數(shù)據(jù)庫或地址范圍的其中一個: 線圈狀態(tài)、離散量輸入、保持寄存器和輸入寄存器。 與許多規(guī)范一樣,名稱可能因行業(yè)或應用而異。 例如,保持寄存器也可以稱為輸出寄存器,線圈狀態(tài)可能稱為數(shù)字或離散量輸出。 這些數(shù)據(jù)庫定義了所包含數(shù)據(jù)的類型和訪問權(quán)限。 從設備可以直接訪問這些數(shù)據(jù),因為這些數(shù)據(jù)由設備本地托管。 Modbus可訪問的數(shù)據(jù)通常是設備主存的一個子集。 相反,Modbus主設備必須通過各種功能代碼請求訪問這些數(shù)據(jù)。 表1中描述了每個區(qū)塊的行為。
內(nèi)存區(qū)塊 | 數(shù)據(jù)類型 | 主設備訪問 | 從設備訪問 |
線圈狀態(tài) | 布爾 | 讀/寫 | 讀/寫 |
離散輸入 | 布爾 | 只讀 | 讀/寫 |
保持寄存器 | 無符號雙字節(jié)整型 | 讀/寫 | 讀/寫 |
輸入寄存器 | 無符號雙字節(jié)整型 | 只讀 | 讀/寫 |
表1. Modbus數(shù)據(jù)模型區(qū)塊
這些區(qū)塊允許您限制或允許訪問不同的數(shù)據(jù)元素,并且為應用層提供簡化的機制來訪問不同的數(shù)據(jù)類型。
這些區(qū)塊是完全概念性的。 它們可能作為獨立的內(nèi)存地址存在于給定的系統(tǒng)中,但也可能重疊。 例如,線圈狀態(tài)1可能存在于與保持寄存器1所代表的字的第一位相同的內(nèi)存中。 尋址方案完全由從設備定義,其對每個內(nèi)存區(qū)的解釋是設備數(shù)據(jù)模型的重要組成部分。
該規(guī)范將每個區(qū)塊定義為包含多達65,536(216)個元素的地址空間。 在PDU的定義中,Modbus定義了每個數(shù)據(jù)元素的地址,范圍從0到65,535。但是,每個數(shù)據(jù)元素的編號從1到n,其中n的最大值為65,536。也就是說,線圈狀態(tài)1位于地址0的線圈狀態(tài)區(qū)塊中,而保持寄存器54位于從機被定義為保持寄存器的內(nèi)存部分中的地址53。
規(guī)范允許的全部范圍不需要給定設備實現(xiàn)。 例如,設備可能會選擇不執(zhí)行線圈、離散輸入或輸入寄存器,而只使用保持寄存器150至175和200至225。這是完全可以接受的,并且通過例外來處理無效的訪問嘗試。
雖然規(guī)范將不同的數(shù)據(jù)類型定義為存在于不同的區(qū)塊中,并為每種類型分配一個本地地址范圍,但這并不一定會轉(zhuǎn)化為用于記錄或理解給定設備的Modbus可訪問內(nèi)存的直觀編址方案。 為了簡化對內(nèi)存區(qū)塊位置的理解,引入了一種編號方案,其將前綴添加到所討論的數(shù)據(jù)的地址中。
例如,設備手冊不會引用地址13寄存器14的數(shù)據(jù)項,而是引用地址4,014,40,014或400,014的數(shù)據(jù)項。在任何情況下,第一個數(shù)字都是4,表示保持寄存器,剩余數(shù)字則表示指定地址。 4XXX、4XXXX和4XXXXX的區(qū)別取決于設備使用的地址空間。 如果所有65,536個寄存器都在使用中,應該使用4XXXXX符號,因為其允許范圍為400,001~465,536。如果只使用幾個寄存器,通常的做法是使用范圍4,001到4,999。
在這種尋址方案中,每種數(shù)據(jù)類型都被分配了一個前綴,如表2所示。
數(shù)據(jù)區(qū)塊 | 前綴 |
線圈狀態(tài) | 0 |
離散輸入 | 1 |
輸入寄存器 | 3 |
保持寄存器 | 4 |
表2. 數(shù)據(jù)范圍前綴
線圈狀態(tài)存在前綴為0的情況。這意味著4001的引用可能指的是保持寄存器1或線圈4001。因此,建議所有新尋址方案都采用帶前導零的6位尋址,并在文檔中進行標注。 因此,保持寄存器1的地址為400,001,而線圈4001的地址則為004,001。
內(nèi)存地址和參考數(shù)字之間的差異會由給定應用程序選擇的索引進一步復雜化。 如前所述,保存寄存器1位于地址零。 通常,參考號碼是1索引,這意味著給定范圍的起始值為1。 因此,400,001就表示為地址0的保持寄存器00001。一些做法選擇以零開始其范圍,這意味著400,000轉(zhuǎn)換為地址零的保持寄存器。 表3展示了這個概念。
地址 | 寄存器編號 | 編號1(1索引,標準) | 編號(0索引,替換) |
0 | 1 | 400001 | 400000 |
1 | 2 | 400002 | 400001 |
2 | 3 | 400003 | 400002 |
表3.寄存器索引方案
1索引范圍應用較為廣泛,強烈建議采用。 無論哪種情況,每個范圍的起始值都應在文檔中注明。
Modbus標準提供了一個相對簡單的數(shù)據(jù)模型,它不包含無符號字和位值之外的其他數(shù)據(jù)類型。 如果系統(tǒng)的位值對應于螺線管和繼電器,并且字值對應于未縮放的ADC值,這是足夠的,但對于更高級的系統(tǒng)則可能不足。 因此,許多Modbus實現(xiàn)都包含跨寄存器邊界的數(shù)據(jù)類型。 NI LabVIEW數(shù)據(jù)記錄和監(jiān)控(DSC)模塊和KEPServerEX都定義了許多參考類型。 例如,存儲在保持寄存器中的字符串遵循標準格式(400,001),但后跟一個十進制數(shù)、長度和字符串的字節(jié)順序(400,001.2H是指保持寄存器1中的兩個字符串,其中高位字節(jié)對應到字符串的第一個字符)。 這是必需的,因為每個請求的大小都是有限的,所以Modbus主機必須知道字符串的確切范圍,而不是像NULL那樣搜索長度或分隔符。
除了允許訪問跨寄存器邊界的數(shù)據(jù)之外,一些Modbus主設備還支持對寄存器中各個位的引用。 這是有好處的,因為它允許設備將相同內(nèi)存范圍內(nèi)的每種類型的數(shù)據(jù)組合在一起,而不必將二進制數(shù)據(jù)分成線圈整體和離散量輸入范圍。 這通常使用小數(shù)點和位索引或數(shù)字進行索引,具體取決于如何實現(xiàn)。 也就是說,第一個寄存器的第一位可能是400,001.00或400,001.01。 建議任何文檔都要說明所使用的索引方案。
多寄存器數(shù)據(jù)(單精度浮點值),可以通過將數(shù)據(jù)拆分到兩個寄存器,輕松地在Modbus中傳輸。 由于這不是由標準定義的,因此分割的字節(jié)順序沒有規(guī)定。 盡管每個無符號字必須以網(wǎng)絡(big-endian)字節(jié)順序發(fā)送以滿足標準,但許多設備會顛倒多字節(jié)數(shù)據(jù)的字節(jié)順序。 圖2所示的是一個不常見但有效的例子。
![]() |
圖2.多字數(shù)據(jù)的字節(jié)順序交換 |
請務必理解設備如何將信息存儲在內(nèi)存中并對其進行正確解碼。 建議文檔寫明系統(tǒng)所使用的字順序。 如果需要靈活性,也可以將Endian添加為系統(tǒng)配置選項,提供基礎的編碼和解碼功能。
字符串可以很容易地存儲在Modbus寄存器中。 為了簡單起見,一些方法要求字符串長度為2的倍數(shù),并使用控制來填充額外的空間。 字節(jié)順序也是字符串交互中的一個變量。 字符串格式可能包含也可能不包含NULL作為最終值。 舉個例子,一些設備的數(shù)據(jù)存儲方法可能如圖3所示。
![]() |
圖3. Modbus字符串中的字節(jié)順序反轉(zhuǎn) |
了解功能代碼
與數(shù)據(jù)模型可能因設備而異不同,功能代碼及其數(shù)據(jù)由標準明確定義。 每個功能都遵循一種模式。 首先,從設備會驗證功能代碼、數(shù)據(jù)地址和數(shù)據(jù)范圍等輸入。 然后執(zhí)行所請求的操作并發(fā)送與代碼相符的響應。 如果此過程中的任何步驟失敗,則會向請求程序返回異常。 這些請求的數(shù)據(jù)傳輸就稱為PDU。
PDU由一個單字節(jié)的功能代碼組成,后面跟著多達252字節(jié)的針對特定函數(shù)的數(shù)據(jù)。
![]() |
圖4. Modbus PDU |
功能代碼是第一個需要驗證的項。 如果功能代碼沒有被接收到請求的設備識別,則會回應一個異常。 如果功能代碼被接受,則從設備根據(jù)功能定義開始分解數(shù)據(jù)。
由于數(shù)據(jù)包大小限制為253字節(jié),設備可傳輸?shù)臄?shù)據(jù)量有限。 最常見的功能代碼可以240到250字節(jié)的從設備數(shù)據(jù)模型數(shù)據(jù),具體取決于代碼。
不同的函數(shù)由數(shù)據(jù)模型定義訪問不同的概念數(shù)據(jù)塊。 一個常見的做法是讓代碼訪問靜態(tài)內(nèi)存位置,但其他行為是可用的。 例如,功能代碼1(讀取線圈狀態(tài))和3(讀取保持寄存器)可以訪問內(nèi)存中相同的物理位置。 而功能代碼3(讀取保持寄存器)和16(寫入保持寄存器)可以訪問內(nèi)存中完全不同的位置。 因此,建議在定義從數(shù)據(jù)模型時同時考慮每個功能代碼的執(zhí)行。
無論執(zhí)行的是何種實際行為,所有的從設備都應該遵循每個請求的簡單狀態(tài)流程圖。 圖5是代碼1讀取線圈狀態(tài)的一個例子。
![]() |
圖5.Modbus協(xié)議規(guī)范定義的讀取線圈狀態(tài)流程圖 |
每個從設備必須驗證功能代碼、輸入數(shù)量、起始地址、總范圍以及實際進行讀取行為的從屬定義函數(shù)(slave-defined function)的執(zhí)行。
盡管上面的狀態(tài)圖包含了靜態(tài)地址范圍,但真實系統(tǒng)的需求可能會使靜態(tài)地址范圍與定義的數(shù)字有所不同。 在某些情況下,從設備無法傳輸協(xié)議定義的最大字節(jié)數(shù)。 也就是說,如果主設備請求0x07D0輸入,從設備只能用0x0400進行響應。 如果主設備從地址0開始請求125,則這是正確的,但是如果主設備從地址400開始發(fā)出相同的請求,最后一個線圈狀態(tài)將位于地址525,超出了該設備的范圍,會導致出現(xiàn)狀態(tài)圖定義的異常02。
每個標準功能代碼的定義都包含在說明書中。 即使對于最常見的功能代碼,在主設備上啟用的功能與從設備可以處理的功能之間也存在不可避免的不匹配。 為了解決這個問題,Modbus TCP規(guī)范的早期版本定義了三個一致性類。 官方的Modbus一致性測試規(guī)范沒有引用這些類,而是在每個功能的基礎上定義一致性;但是,這些仍然很容易理解。 建議任何文檔都遵循測試規(guī)范,并根據(jù)其支持的代碼而不是傳統(tǒng)分類來定義它們的一致性。
0類代碼通常被認為是有用Modbus設備的最低配置,因為它們使主設備能夠讀取或?qū)懭霐?shù)據(jù)模型。
代碼 | 說明 |
3 | 讀多寄存器 |
16 | 寫多寄存器 |
表4.0類一致性代碼
1類功能代碼由訪問所有類型的數(shù)據(jù)模型所需的其他代碼組成。 在原始定義中,這個列表包含功能代碼7(讀取異常)。 但是,此代碼由當前規(guī)范定義為僅限于串行的代碼。
代碼 | 說明 |
1 | 讀線圈 |
2 | 讀離散輸入 |
4 | 讀輸入寄存器 |
5 | 寫單線圈 |
6 | 寫單寄存器 |
7 | 讀取異常狀態(tài)(僅限串行) |
表5. 1類一致性代碼
2類功能代碼用于更為專業(yè)化的功能,不太常用。 例如,讀/寫多個寄存器可能有助于減少請求/響應周期的總數(shù),但該行為仍可以用0類代碼實現(xiàn)。
代碼 | 說明 |
15 | 寫多線圈 |
20 | 讀文件記錄 |
21 | 寫文件記錄 |
22 | 屏蔽寫寄存器 |
23 | 讀/寫多寄存器 |
24 | 讀取FIFO |
表6. 2類一致性代碼
Modbus封裝接口(MEI)代碼功能43用于封裝Modbus數(shù)據(jù)包內(nèi)的其他數(shù)據(jù)。 目前,有兩個MEI號碼可用,13(CANopen)和14(設備識別)。
功能43/14(設備識別)非常有用,因為它允許傳送多達256個唯一的對象。 其中一些對象已預定義且預留好,例如供應商名稱和產(chǎn)品代碼,但應用程序可以將其他對象定義為通用數(shù)據(jù)集。
此代碼并不常用。
從設備使用異常來指示各種不良狀況,比如錯誤請求或不正確輸入。 但是,異常也可以作為對無效請求的應用程序級響應。 從設備不響應發(fā)出異常的請求。 相反,從設備忽略不完整或損壞的請求,并開始等待新的消息傳入。
異常以定義好的數(shù)據(jù)包格式報告給用戶。 首先將一個功能代碼返回給等同于與原始功能代碼的請求主設備,除了設置了最高有效位。 這等同于為原始功能代碼的值加上0x80。 異常響應包括一個異常代碼來代替與給定函數(shù)響應相關的正常數(shù)據(jù)。
在標準內(nèi),四種最常見的異常代碼是01,02,03和04。表7介紹了這些代碼以及每種功能的標準含義。
異常代碼 | 含義 |
01 | 不支持接收到功能代碼。 要確認原始功能代碼,請從返回值中減去0x80。 |
02 | 嘗試訪問的請求是一個無效地址。 在標準中,只有起始地址和請求的數(shù)值超過216時才會發(fā)生這種情況。 但是,有些設備可能會限制其數(shù)據(jù)模型中的地址空間。 |
03 | 請求包含不正確的數(shù)據(jù)。 在某些情況下,這意味著參數(shù)不匹配,例如發(fā)送的寄存器的數(shù)量與“字節(jié)數(shù)”字段之間的參數(shù)不匹配。 更常見的情況是,主機請求的數(shù)據(jù)比從機或協(xié)議允許的要多。 例如,主設備一次只能讀取125個保持寄存器,而資源受限的設備可能會將此值限制為更少的寄存器。 例如,主設備一次只能讀取125個保持寄存器,而資源受限的設備可能會將此值限制為更少的寄存器。 |
04 | 嘗試處理請求時發(fā)生不可恢復的錯誤。 這是一個異常的代碼,表示請求有效,但從設備無法執(zhí)行該請求。 |
表7.常見的Modbus異常代碼
每個功能代碼的狀態(tài)圖至少應包含異常代碼01,通常包含異常代碼04,02,03,并且任何其他定義的異常代碼都是可選的。
除了Modbus協(xié)議的PDU核心定義的功能外,您還可以使用多種網(wǎng)絡協(xié)議。 最常見的協(xié)議是串行和TCP/IP,但也可以使用其他協(xié)議,如UDP。 為了在這些層之間傳輸Modbus所需的數(shù)據(jù),Modbus包含一組適用于每種網(wǎng)絡協(xié)議的ADU。
Modbus需要某些功能來提供可靠的通信。 單元ID或地址用在每個ADU格式中,為應用層提供路由信息。 每個ADU都帶有一個完整的PDU,其中包含給定請求的功能代碼和相關數(shù)據(jù)。 為了可靠性,每條消息都包含錯誤檢查信息。 最后,所有的ADU都提供了一種機制來確定請求幀的開始和結(jié)束,但實現(xiàn)這些機制的方式各不相同。
ADU的三種標準格式是TCP、遠程終端單元(RTU)和ASCII。 RTU和ASCII ADU通常用于串行線路,而TCP則用于現(xiàn)代TCP/IP或UDP/IP網(wǎng)絡。
TCP ADU由Modbus應用協(xié)議(MBAP)報文頭和Modbus PDU組成。 MBAP是一個通用的報文頭,依賴于可靠的網(wǎng)絡層。 此ADU的格式(包括報文頭)如圖6所示。
![]() |
圖6.TCP/IP ADU |
報文頭的數(shù)據(jù)字段代表其用途。 首先,它包含一個事務處理標識符。 這有助于網(wǎng)絡允許同時發(fā)生多個未處理的請求。 也就是說,主設備可以發(fā)送請求1、2和3。在稍后的時間點,從設備可以以2、1、3的順序進行響應,并且主設備可以將請求匹配到響應并準確解析數(shù)據(jù)。 這對以太網(wǎng)網(wǎng)絡很有用。
協(xié)議標識符通常為零,但您可以使用它來擴展協(xié)議的行為。 協(xié)議使用長度字段來描述數(shù)據(jù)包其余部分的長度。 這個元素的位置也表明了這個報文頭格式在可靠的網(wǎng)絡層上的依賴關系。 由于TCP數(shù)據(jù)包具有內(nèi)置的錯誤檢查功能,可確保數(shù)據(jù)一致性和傳送,因此數(shù)據(jù)包長度可位于報文頭的任何位置。 在可靠性較差的網(wǎng)絡上(比如串行網(wǎng)絡),數(shù)據(jù)包可能會丟失,其影響是即使應用程序讀取的數(shù)據(jù)流包含有效的事務處理和協(xié)議信息,長度信息的損壞也會使報文頭無效。 TCP為這種情況提供了適當?shù)谋Wo。
TCP/IP設備通常不適用單元ID。 但是,Modbus是一種常見的協(xié)議,因此通常會開發(fā)一些網(wǎng)關來將Modbus協(xié)議轉(zhuǎn)換為另一種協(xié)議。 在最初的預期應用中, Modbus TCP/IP轉(zhuǎn)串行網(wǎng)關用于連接新的TCP/IP網(wǎng)絡和舊的串行網(wǎng)絡。 這時,單元ID用于確定PDU對應的從設備的地址。
最后,ADU包含一個PDU。 對于標準協(xié)議,PDU的長度仍限制為253字節(jié)。
RTU ADU看起來要簡單得多,如圖7所示。
![]() |
圖7. RTU ADU |
與較為復雜的TCP/IP ADU不同的是,除了核心PDU之外,該ADU僅包含兩條信息。 首先,地址用于定義PDU對應的從設備。 在大多數(shù)網(wǎng)絡中,地址0定義的是“廣播”地址。 也就是說,主設備可以發(fā)送輸出命令到地址0,而所有從設備應處理該請求,但是不做出任何響應。 除了這個地址外,CRC還用于確保數(shù)據(jù)的完整性。
然而,現(xiàn)在的實現(xiàn)機制遠沒有那么簡單。 數(shù)據(jù)包的首尾一對沉默時間(silent time),即總線上沒有通信的時段。對于9,600的波特率,這個速率大約是4ms。該標準定義了一個最小沉默長度,不論波特率如何,都低于2 ms。
首先,這存在性能缺陷,因為在處理數(shù)據(jù)包之前設備必須等待空閑時間結(jié)束。 然而,更危險的是串行傳輸引入了不同技術,并且波特率比標準更快。 例如,使用USB/串口轉(zhuǎn)換器電纜,您無法控制數(shù)據(jù)的數(shù)據(jù)包和數(shù)據(jù)傳輸。 測試表明,結(jié)合NI-VISA驅(qū)動程序使用USB轉(zhuǎn)串口電纜會在數(shù)據(jù)流中引入了尺寸可變的大間隙,而這些間隙 – 沉默期 – 會“誘騙”符合規(guī)范的代碼相信消息是完整的。 由于消息不完整,通常會導致CRC無效,并導致設備將ADU解釋為損壞。
除了傳輸問題之外,現(xiàn)代驅(qū)動程序技術還大量提取串行通信,并且通常需要應用程序代碼中的輪詢機制。 例如,除非通過輪詢端口上的字節(jié),.NET Framework 4.5 SerialPort Class和NI-VISA驅(qū)動程序都不提供檢測串行線路上的沉默的機制。 這會導致性能降低(如果輪詢執(zhí)行過慢)或CPU使用率過高(如果輪詢執(zhí)行過快)。
解決這些問題的常用方法是打破Modbus PDU和網(wǎng)絡層之間的抽象層。 也就是說,串行代碼詢問Modbus PDU數(shù)據(jù)包以確定功能代碼。 結(jié)合數(shù)據(jù)包中的其他數(shù)據(jù),可以發(fā)現(xiàn)剩余數(shù)據(jù)包的長度,從而確定數(shù)據(jù)包的結(jié)尾。 利用這些信息,可以使用更長的超時時間,以允許傳輸間隙,并且應用程序級的輪詢速度可能更慢。 這種機制推薦用于新的開發(fā)。 不采用此方法可能會遇到大于預期數(shù)量的“損壞”數(shù)據(jù)包。
如圖8所示,ASCII ADU比RTU更復雜,但也避免了RTU數(shù)據(jù)包的許多問題。 然而,它自身也有一些缺點。
![]() |
圖 8. ASCII ADU |
為了解決確定數(shù)據(jù)包大小的問題,ASCII ADU為每個數(shù)據(jù)包定義了一個明確且唯一的開始和結(jié)束。 也就是說,每個數(shù)據(jù)包以“:”開始 并以回車(CR)和換行符(LF)結(jié)束。 另外,像NI-VISA和.NET Framework SerialPort Class這樣的串行API可以輕松讀取緩沖區(qū)中的數(shù)據(jù),直到收到特定字符的CR/LF為止。 這些特性有助于在現(xiàn)代應用程序代碼中有效地處理串行線路上的數(shù)據(jù)流。
ASCII ADU的缺點是所有數(shù)據(jù)都以ASCII編碼的十六進制字符進行傳輸。 也就是說,針對功能代碼3(0x03)發(fā)送的不是單個字節(jié),而是發(fā)送ASCII字符“0”和“3”或0x30/0x33。 這使協(xié)議更具可讀性,但也意味著必須通過串行網(wǎng)絡傳輸兩倍的數(shù)據(jù),并且發(fā)送和接收應用程序必須能夠解析ASCII值。
Modbus是一種相對簡單和開放的標準,可以進行修改以適應給定應用的需求。 這常用于HMI和PLC或PAC之間的通信,因為在這種情況下組織可以控制協(xié)議的首尾。 例如,傳感器的開發(fā)人員更可能遵守書面標準,因為他們通常只控制其從設備的實現(xiàn),互通性也是可能實現(xiàn)的。
一般來說,不建議修改協(xié)議。 本節(jié)僅作為對其他人用來調(diào)整協(xié)議行為的機制的確認。
Modbus標準定義了一些功能代碼,但也可允許您開發(fā)更多的功能代碼。 具體而言,功能代碼1至64,73至99以及111至127是預留的并保證唯一的公共代碼。 其余代碼65至72和100至110可由用戶自定義。 使用這些用戶定義的代碼時,您可以使用任何數(shù)據(jù)結(jié)構(gòu)。 數(shù)據(jù)甚至可能超過Modbus PDU的標準253字節(jié)限制,但應驗證整個應用程序以確保其他層在PDU超過標準限制時按預期工作。 高于127的功能代碼預留作異常響應。
除了串行和TCP之外,Modbus還可以在許多網(wǎng)絡層上運行。 一個可能的實現(xiàn)是UDP,因為它適合于Modbus通信風格。 Modbus本質(zhì)上是基于消息的協(xié)議,因此UDP能夠發(fā)送明確定義的信息包,而不需要任何額外的應用程序級信息,如起始字符或長度,這使得Modbus非常易于實現(xiàn)。 Modbus PDU數(shù)據(jù)包可以使用標準的UDP API發(fā)送,不需要額外的ADU或重新使用現(xiàn)有的ADU,并由另一端完全接收。 雖然由于其內(nèi)置確認系統(tǒng),TCP對某些協(xié)議有利,但Modbus是在應用層執(zhí)行確認。 因此,以這種方式使用UDP會消除TCP ADU中的事務處理標識符字段,從而消除了存在多個同時發(fā)生的未完成事務的可能性。 因此,主設備必須是同步主設備,或者UDP數(shù)據(jù)包必須有一個標識符以幫助主設備組織請求和響應。 建議的做法是在UDP網(wǎng)絡層上使用TCP/IP ADU。
最后,應用程序可以選擇修改ADU,或使用現(xiàn)有ADU的未使用部分(如TCP)。 例如,TCP定義了一個16位長度字段、一個16位協(xié)議和一個8位單元ID。鑒于最大的Modbus PDU是253字節(jié),長度字段的高字節(jié)始終為零。 對于Modbus/TCP,協(xié)議字段和單元ID始終為零。 協(xié)議的簡單擴展可以通過將協(xié)議字段更改為非零數(shù)字并使用兩個未使用的字節(jié)(單元ID和長度字段的高字節(jié))來發(fā)送兩個附加PDU的長度,從而同時發(fā)送三個數(shù)據(jù)包(請參閱圖9)。
![]() |
圖9. TCP ADU修改示例 |