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