5.1 學(xué)習(xí)Modbus的快速方法
5.1.1 寄存器速記
作為初學(xué)者,你閱讀Modbus協(xié)議時(shí)會(huì)發(fā)現(xiàn)它的概念別扭、重復(fù)、不易區(qū)分,比如線圈狀態(tài)(Coil Status)、離散輸入狀態(tài)(Discrete Input Status)、保持寄存器(Holding Register)、輸入寄存器(Input Register)。
回到事情的本質(zhì),在工業(yè)控制PLC領(lǐng)域,涉及數(shù)字信號(hào)的輸入、輸出,模擬信號(hào)的輸入、輸出,如下圖所示:
對于軟件開發(fā)而言:
- 想得到按鍵輸入狀態(tài)時(shí),讀取到的是一位數(shù)據(jù);
- 想控制LED時(shí),需要輸出一位數(shù)據(jù),想讀取LED當(dāng)前狀態(tài)時(shí),也可以讀取到一位數(shù)據(jù)
- 想讀取模擬信號(hào)時(shí),讀取到的是多位數(shù)據(jù),比如16位數(shù)據(jù)
- 想輸出模擬信號(hào)時(shí),寫入的是多位數(shù)據(jù),比如16位數(shù)據(jù);也可以讀取“模擬量輸出”的當(dāng)前值。
在上圖中,“數(shù)字量輸入DI”是只讀的,“數(shù)字量輸出DO”是可讀可寫的,“模擬量輸入AI”是只讀的,“模擬量輸出AO”是可讀可寫的。
上圖里的“模擬量輸入AI”、“模擬量輸出AO”都表示“多位數(shù)值”,這些“多位數(shù)值”無需局限于只表示“模擬量”,也可以表示“多位數(shù)字量”。把AI、AO的含義擴(kuò)展后,如下圖所示:
對于軟件開發(fā)而言:
- 想得到按鍵輸入狀態(tài)時(shí),讀取到的是一位數(shù)據(jù);
- 想控制LED時(shí),需要輸出一位數(shù)據(jù),想讀取LED當(dāng)前狀態(tài)時(shí),也可以讀取到一位數(shù)據(jù)
- 想讀取參數(shù)時(shí),讀取到的“輸入寄存器”,得到多位數(shù)據(jù),比如16位數(shù)據(jù)
- 想設(shè)置參數(shù)時(shí),寫的是“保存寄存器”,寫入的是多位數(shù)據(jù),比如16位數(shù)據(jù);也可以讀“保存寄存器”
在電子系統(tǒng)里,無論是單bit的數(shù)值、多bit的數(shù)值,都是保存在寄存器里。根據(jù)上圖,這些寄存器可以分為4類:
寄存器種類 | 說明 | 與PLC類比 | 舉例說明 |
---|---|---|---|
線圈狀態(tài)(Coil Status) | 輸出端口??稍O(shè)定端口輸出狀態(tài),也可以讀取該位的輸出狀態(tài)??煞譃閮煞N不同的執(zhí)行狀態(tài),列如保持型或邊沿觸發(fā)型 | DO(數(shù)字量輸出) | 電磁閥輸出、MOSFEF輸出、LED顯示等 |
離散輸入狀態(tài)(Discrete Input Status) | 輸入端口。通過外部設(shè)定改變輸入狀態(tài),可讀但不可以寫 | DI(數(shù)字量輸入) | 撥碼開關(guān)、接近開關(guān)等 |
保持寄存器(Holding Register) | 輸出參數(shù)或保持參數(shù),控制器運(yùn)行時(shí)被設(shè)定的某些參數(shù),可讀可寫 | AO(模擬量輸出) | 模擬量輸出設(shè)定值,PID運(yùn)行參數(shù),變量閥輸出大小,傳感器報(bào)警上限下限 |
輸入寄存器(Input Register) | 輸入?yún)?shù)??刂破鬟\(yùn)行時(shí)從外部設(shè)備獲得的參數(shù),但可讀不可寫 | AI(模擬量輸入) | 模擬量輸入 |
在Modbus中,多位操作時(shí)都是16位(2bytes)的,總結(jié)如下:
- bit操作涉及的寄存器有2類:線圈狀態(tài)(可讀可寫)、離散輸入狀態(tài)(只讀)
- 16bit操作的寄存器有2類:保存寄存器(可讀可寫)、輸入寄存器(只讀)
一個(gè)設(shè)備里,可能有多個(gè)“線圈狀態(tài)”、多個(gè)“離散輸入狀態(tài)”、多個(gè)“保存寄存器”、多個(gè)“輸入寄存器”。怎么分辨某類寄存器中的某一個(gè)?它們有“寄存器地址”,如下圖所示:
寄存器種類 | PLC寄存器地址范圍 | Modbus寄存器地址范圍 | 簡稱 | 讀寫狀態(tài) |
---|---|---|---|---|
線圈狀態(tài) | 00001~09999 | 0000H~FFFFH | 0x | 可讀可寫 |
離散輸入狀態(tài) | 10001~19999 | 0000H~FFFFH | 1x | 只讀 |
保持寄存器 | 40001~49999 | 0000H~FFFFH | 4x | 可讀可寫 |
輸入寄存器 | 30001~39999 | 0000H~FFFFH | 3x | 只讀 |
在上表中,“線圈狀態(tài)”的寄存器N、“離散輸入狀態(tài)”的寄存器N,是兩個(gè)不同的寄存器。
簡單記憶方法:“
- 偶數(shù)類的寄存器”是可讀可寫的,比如“0x”和“4x”;
- “奇數(shù)類的寄存器”是只讀的,比如“1x”和“3x”;
- “0x”和“1x”是bit寄存器;
- “3x”和“4x”是16bit寄存器。
5.1.2 協(xié)議速記
Modbus是一主多從的協(xié)議,如下圖所示:
主控發(fā)出的數(shù)據(jù)里,必定含有如下信息:
- 設(shè)備地址:你要訪問從設(shè)備1,還是訪問從設(shè)備2
- 訪問哪類寄存器,是讀還是寫,只訪問1個(gè)寄存器,還是多個(gè)寄存器:這被稱為功能碼
- 起始寄存器地址、寄存器數(shù)量:這在數(shù)據(jù)里定義
- 為了保證數(shù)據(jù)傳輸?shù)目煽?,還附帶有CRC檢驗(yàn)碼
以Modbus RTU協(xié)議為例,主控發(fā)出的數(shù)據(jù)包格式如下:
功能代碼有哪些?常用的功能碼如下:
- 讀線圈狀態(tài)(01)
- 讀離散輸入狀態(tài)(02)
- 寫單個(gè)線圈(05)、寫多個(gè)線圈(15)
- 讀保持寄存器(03)
- 讀輸入寄存器(04)
- 寫單個(gè)保存寄存器(06)、寫多個(gè)保存寄存器(16)
數(shù)據(jù)的格式,由功能代碼確定。以“讀線圈狀態(tài)”為例,主控發(fā)出的請求、從設(shè)備返回的響應(yīng)包,或者從設(shè)備返回的錯(cuò)誤包,格式如下:
上圖中,寄存器起始地址(“Starting Address”)是16位的,先傳輸高字節(jié),再傳輸?shù)妥止?jié)。線圈數(shù)量(“Quantiti of coils”)也是16位的,先傳輸高字節(jié),再傳輸?shù)妥止?jié)。
響應(yīng)包回復(fù)多少個(gè)數(shù)據(jù)呢(上圖中N為多少)?N = Quantiti of coils / 8,如果余數(shù)不等于0,則N再加1。比如Quantiti of coils=9,則返回2個(gè)字節(jié)。
在《Modbus_Application_Protocol_V1_1b3.pdf》中,列出了如下功能表。根據(jù)次表,在結(jié)合《5.5 Moubus功能碼詳解》的示例,就可以對Modbus RTU協(xié)議有很好的理解了。
5.2 初識(shí)Modbus
5.2.1 背景
Modbus誕生于1979年莫迪康(Modicon)公司,后來被施耐德電氣公司收購。Modbus提供通用語言用于彼此通信的設(shè)備和設(shè)備,是全球第一個(gè)真正用于工業(yè)現(xiàn)場的總線協(xié)議。Modbus已經(jīng)成為工業(yè)領(lǐng)域通信協(xié)議的業(yè)界標(biāo)準(zhǔn),并且現(xiàn)在是工業(yè)電子設(shè)備之間常用的連接方式。Modbus作為目前工業(yè)領(lǐng)域應(yīng)用最廣泛的協(xié)議,之后為了更好地普及和推動(dòng)Modbus基于以太網(wǎng) (TCP/IP) 的分布式應(yīng)用,施耐德公司已將Modbus協(xié)議的所有權(quán)移交給IDA (Interface for Distributed Automation,分布式自動(dòng)化接口)組織,并成立了Modbus-IDA組織,此組織的成立和發(fā)展進(jìn)一步推動(dòng)了Modbus協(xié)議的廣泛應(yīng)用。
5.2.2 什么是Modbus?
1. Modbus簡介
Modbus協(xié)議是一種已廣泛應(yīng)用于當(dāng)今工業(yè)控制領(lǐng)域的通用通訊協(xié)議。通過此協(xié)議,控制器相互之間、或控制器經(jīng)由網(wǎng)絡(luò)(如以太網(wǎng))可以和其它設(shè)備之間進(jìn)行通信。Modbus協(xié)議使用的是主從通訊技術(shù),即由主設(shè)備主動(dòng)查詢和操作從設(shè)備。一般將主控設(shè)備方所使用的協(xié)議稱為Modbus Master,從設(shè)備方使用的協(xié)議稱為Modbus Slave。典型的主設(shè)備包括工控機(jī)和工業(yè)控制器等;典型的從設(shè)備如PLC可編程控制器等。有了它,不同廠商生產(chǎn)的控制設(shè)備就可以連接成工業(yè)網(wǎng)絡(luò),進(jìn)行集中監(jiān)控。Modbus協(xié)議定義了一個(gè)控制器能夠認(rèn)識(shí)和使用的消息結(jié)構(gòu),而不管它們是經(jīng)過何種網(wǎng)絡(luò)進(jìn)行通信的;而且描述了控制器請求訪問其他設(shè)備的過程,如何應(yīng)答來自其他設(shè)備的請求,以及怎樣偵測錯(cuò)誤并記錄,并制定了統(tǒng)一的消息域的結(jié)構(gòu)和內(nèi)容。 當(dāng)在Modbus網(wǎng)絡(luò)上通信時(shí),Modbus協(xié)議決定了每個(gè)控制器必須要知道它們的設(shè)備地址,識(shí)別按地址發(fā)來的消息決定要產(chǎn)生何種行為。如果需要回應(yīng),則控制器將生成反饋信息并通過Modbus協(xié)議發(fā)送。
Modbus通訊物理接口可以選用串口(包括RS232、RS485和RS422等),也可以選擇以太網(wǎng)口。其通信遵循以下的過程:
- 主設(shè)備向從設(shè)備發(fā)送請求
- 從設(shè)備分析并處理主設(shè)備的請求,然后向主設(shè)備發(fā)送結(jié)果
- 如果出現(xiàn)任何差錯(cuò),從設(shè)備將返回一個(gè)異常功能碼
此協(xié)議定義了一個(gè)控制器能認(rèn)識(shí)使用的消息結(jié)構(gòu),而不管它們是經(jīng)過何種網(wǎng)絡(luò)進(jìn)行通信的。它描述了一控制器請求訪問其它設(shè)備的過程,如何回應(yīng)來自其它設(shè)備的請求,以及怎樣偵測錯(cuò)誤并記錄。它制定了消息域格局和內(nèi)容的公共格式。
當(dāng)在Modbus網(wǎng)絡(luò)上通信時(shí),此協(xié)議決定了每個(gè)控制器須要知道它們的設(shè)備地址,識(shí)別按地址發(fā)來的消息,決定要產(chǎn)生何種行動(dòng)。如果需要回應(yīng),控制器將生成反饋信息并用Modbus協(xié)議發(fā)出。在其它網(wǎng)絡(luò)上,包含了Modbus協(xié)議的消息轉(zhuǎn)換為在此網(wǎng)絡(luò)上使用的幀或包結(jié)構(gòu)。這種轉(zhuǎn)換也擴(kuò)展了根據(jù)具體的網(wǎng)絡(luò)解決節(jié)地址、路由路徑及錯(cuò)誤檢測的方法。
Modbus的工作方式是請求/應(yīng)答,每次通訊都是主站先發(fā)送指令,可以是廣播,或是向特定從站的單播;從站響應(yīng)指令,并按要求應(yīng)答,或者報(bào)告異常。當(dāng)主站不發(fā)送請求時(shí),從站不會(huì)自己發(fā)出數(shù)據(jù),從站和從站之間不能直接通訊。
MODBUS 是一種應(yīng)用層消息傳遞協(xié)議,位于 OSI 模型的第 7 層。它提供連接在不同類型總線或網(wǎng)絡(luò)上的設(shè)備之間的客戶端/服務(wù)器通信。
Modbus通信棧如下:
2. Modbus特點(diǎn)
Modbus通信協(xié)議具有以下幾個(gè)特點(diǎn):
- Modbus協(xié)議標(biāo)準(zhǔn)開放、公開發(fā)表且無版稅要求。用戶可以免費(fèi)獲取并使用Modbus協(xié)議,不需要交納許可證費(fèi),也不會(huì)侵犯知識(shí)產(chǎn)權(quán)。
- Modbus協(xié)議支持多種電氣接口,如RS232、RS485、TCP/IP等,還可以在各種介質(zhì)上傳輸,如雙絞線、光纖、紅外、無線。
- Modbus協(xié)議消息幀格式簡單、緊湊、通俗易懂。用戶理解和使用簡單,廠商容易開發(fā)和集成,方便形成工業(yè)控制網(wǎng)絡(luò)。
- 可靠性: Modbus 是最古老的工業(yè)自動(dòng)化通信協(xié)議。它使用和編程簡單,因此學(xué)習(xí)曲線較低。
- 遺留基礎(chǔ)設(shè)施:許多制造商在早期自動(dòng)化方面投入了大量資金。Modbus 對于配置、DLR、節(jié)點(diǎn)、子站和其他基礎(chǔ)設(shè)施非常友好,這些基礎(chǔ)設(shè)施可能會(huì)被新的或更先進(jìn)的協(xié)議所淘汰。
- 快速部署: Modbus 可以輕松、立即集成到 SCADA和其他控制系統(tǒng)中
- 靈活性: Modbus 已適應(yīng)新興技術(shù)。例如,Modbus TCP 可以通過話配器進(jìn)行轉(zhuǎn)換,以與LAN 和遠(yuǎn)程控制系統(tǒng)集成。它還可以利用基于網(wǎng)絡(luò)和基于云的平臺(tái)。
- 簡單性:由于通信簡單,因此可以輕松擴(kuò)展到新技術(shù)。例如,Modbus TCP/P 由于指令集簡單,部署速度很快。它還可以與以太網(wǎng)配合使用,無需添加芯片或板。
3. Modbus常用術(shù)語
名詞 | 意義 |
---|---|
Master | 主(站) 設(shè)備 |
Slave | 從 (站) 設(shè)備 |
Client | 客戶端 |
Server | 服務(wù)器端 |
ADU | 應(yīng)用數(shù)據(jù)單元(Application Data Unit) |
PDU | 協(xié)議數(shù)據(jù)單元 (Protocol Data Unit) |
MSB | 最高有效位(Most Significant Bit) |
LSB | 最低有效位 (Least Significant Bit) |
MBAP | Modbus應(yīng)用協(xié)議(Modbus Application Protocol) |
PLC | 可編程邏輯控制器(Programmable Logic Controller) |
4. Modbus事務(wù)處理
Modbus協(xié)議允許在各種網(wǎng)終體系結(jié)構(gòu)內(nèi)進(jìn)行簡單通信,每種設(shè)備 (包括PLC、HMI、控制面板、驅(qū)動(dòng)程序、動(dòng)作控制、輸入/輸出設(shè)備) 都能使用Modbus協(xié)議啟動(dòng)遠(yuǎn)程操作。在基于串行鏈路和以太網(wǎng) (TCP/IP)的Modbus上可以進(jìn)行相互通信。一些網(wǎng)關(guān)允許在幾種使用MODBUS協(xié)議的總線或網(wǎng)絡(luò)之間進(jìn)行通訊。
MOUBUS網(wǎng)絡(luò)體系結(jié)構(gòu)的實(shí)例:
Modbus是一個(gè)請求、應(yīng)答協(xié)議,并且提供統(tǒng)一的功能碼用于數(shù)據(jù)傳輸服務(wù)。Modbus功能碼是Modbus請求/應(yīng)答PDU (Protocol Data Unit,協(xié)議數(shù)據(jù)單元)的元素之一,所謂的PDU其實(shí)就是Modbus協(xié)議定義的一個(gè)與基礎(chǔ)通信層無關(guān)的簡單協(xié)議數(shù)據(jù)單元。特定總線或網(wǎng)絡(luò)上的Modbus協(xié)議映射能夠在ADU (Application Data UInit ,應(yīng)用數(shù)據(jù)單元)上引入一些附加域,從而實(shí)現(xiàn)完整而準(zhǔn)確的數(shù)據(jù)傳輸。
為了尋求一種簡潔的通信格式,Modbus協(xié)議定義了PDU模型,即功能碼+數(shù)據(jù)的格式,而為了適應(yīng)多種傳輸模式,又在PDU的基礎(chǔ)上增加了必要的前綴 (如地址域)和后綴(如差錯(cuò)校驗(yàn)) ,形成了ADU模型(見下圖)。
通用MODBUS幀如下:
Modbus事務(wù)處理過程:
- 主機(jī)設(shè)備 (或客戶端)創(chuàng)建Modbus應(yīng)用數(shù)據(jù)單元形成查詢報(bào)文,其中功能碼標(biāo)識(shí)了向從機(jī)設(shè)備 (或服務(wù)器端)指示將要執(zhí)行的操作。其中功能碼占用1字節(jié),有效的碼字范圍是十進(jìn)制1 ~ 255 (其中128 ~255為異常響應(yīng)保留) 。查詢報(bào)文創(chuàng)建完畢,主機(jī)設(shè)備 (或客戶端) 向從機(jī)設(shè)備 (或服務(wù)器端)發(fā)送報(bào)文,從機(jī)設(shè)備 (或服務(wù)器端)接收報(bào)文后根據(jù)功能碼做出相應(yīng)的動(dòng)作,并將響應(yīng)報(bào)文返回給主機(jī)設(shè)備 (或客戶端),如圖下所示:
MouBus事務(wù)處理(無異常)
- 如果在一個(gè)正確接收的Modbus ADU中不出現(xiàn)與請求Modbus功能有關(guān)的差錯(cuò),那么從機(jī)設(shè)備 (或服務(wù)器端) 將返回正常的響應(yīng)報(bào)文。如果出現(xiàn)與請求Modbus功能有關(guān)的差錯(cuò),那么響應(yīng)報(bào)文的功能碼域?qū)ㄒ粋€(gè)異常碼,主機(jī)設(shè)備(或客戶端)能夠根據(jù)異常碼確定下一步執(zhí)行的操作;對于異常響應(yīng),服務(wù)器返回一個(gè)與原始功能碼等同的碼,設(shè)置該原始功能碼的最高有效位為邏輯1,用于通知主設(shè)備(客戶端)。如下圖所示:
MouBus事務(wù)處理(異常響應(yīng))
5.3 Modbus軟件與使用
5.3.1 Modbus軟件簡介
為了更好的學(xué)習(xí)和理解Modbus,這里推出三個(gè)軟件Modbus Poll(主站設(shè)備)、Modbus Slave(從站設(shè)備)和虛擬串口軟件,借助三款設(shè)備我們可以在PC上做一些基礎(chǔ)實(shí)驗(yàn),更加直觀地觀察通信數(shù)據(jù),加深我們的理解,我們將它稱為Modbus學(xué)習(xí)必備三件套,這是一個(gè)很好的入門方法。
5.3.2 Modbus Poll(主站設(shè)備)
1. Modbus Poll簡介
Modbus Poll是Modbus主站設(shè)備仿真器,用于測試和調(diào)試Modbus從設(shè)備便于觀察Modbus通信過程中的各種報(bào)文數(shù)據(jù)。該軟件支持ModbusRTU、ASCII、TCP/IP。用來幫助開發(fā)人員測試Modbus從設(shè)備,或者其它Modbus協(xié)議的測試和仿真。它支持多文檔接口,即,可以同時(shí)監(jiān)視多個(gè)從設(shè)備/數(shù)據(jù)域。每個(gè)窗口簡單地設(shè)定從設(shè)備ID,功能,地址,大小和輪詢間隔。你可以從任意一個(gè)窗口讀寫寄存器和線圈。如果你想改變一個(gè)單獨(dú)的寄存器,簡單地雙擊這個(gè)值即可?;蛘吣憧梢愿淖兌鄠€(gè)寄存器/線圈值。提供數(shù)據(jù)的多種格式方式,比如浮點(diǎn)、雙精度、長整型(可以字節(jié)序列交換)。該軟件支持Modbus RTU、ASCII、TCP/IP等協(xié)議模式。
Modbus Poll支持下列協(xié)議模式:
Modbus RTU | Modbus RTU Over TCP/IP |
---|---|
Modbus ASCII | Modbus ASCI Over TCP/IP |
Modbus TCP/IP | Modbus RTU Over UDP/IP |
Modbus UDP/IP | Modbus ASCII Over UDP/IP |
2. Modbus Poll 使用
點(diǎn)擊鏈接獲取軟件,按照提示安裝即可;鏈接:
https://pan.baidu.com/s/1SpTRz6Z1XlkoCZjDozwqog 提取碼:timc
下載完界面如下:
狀態(tài)欄:
- Tx = 0表示向主站發(fā)送數(shù)據(jù)幀次數(shù),圖中為0次;
- Err = 0表示通訊錯(cuò)誤次數(shù),圖中為0次;
- ID = 1表示模擬的Modbus子設(shè)備的設(shè)備地址,圖中地址為1;
- F = 03表示所使用的Modbus功能碼,圖中為03功能碼;
- SR = 1000ms表示發(fā)送周期,1S一次。
- 紅字部分,表示當(dāng)前的錯(cuò)誤狀態(tài),“No Connection”表示未連接狀態(tài)。
建立連接:
點(diǎn)擊Connection->Connect進(jìn)入配置頁面,選擇我們想要的連接,選擇我們虛擬出來的串口,選擇模式,例如:我們選擇串口的連接方式,選則RTU模式,對應(yīng)我們的Modbus RTU協(xié)議;接下來在設(shè)置波特率、比特位、校驗(yàn)位、停止位,如下圖所示:
設(shè)置參數(shù):點(diǎn)擊Setup->Read/Write Definition進(jìn)入配置頁面,配置從機(jī)地址、功能碼、地址類型、寄存器地址、訪問數(shù)量、輪詢時(shí)間,具體配置如下圖:
5.3.3 Modbus Slave(從站設(shè)備)
1. Modbus Slave簡介
Modbus從設(shè)備仿真器,可以仿真32個(gè)從設(shè)備/地址域。每個(gè)接口都提供了對EXCEL報(bào)表的OLE自動(dòng)化支持。主要用來模擬Modbus從站設(shè)備,接收主站的命令包,回送數(shù)據(jù)包。幫助Modbus通訊設(shè)備開發(fā)人員進(jìn)行Modbus通訊協(xié)議的模擬和測試,用于模擬、測試、調(diào)試Modbus通訊設(shè)備,便于觀察Modbus通信過程中的各種報(bào)文數(shù)據(jù);可以32個(gè)窗口中模擬多達(dá)32個(gè)Modbus子設(shè)備。與Modbus Poll的用戶界面相同,支持功能01, 02, 03, 04, 05, 06, 15, 16, 22和23,監(jiān)視串口數(shù)據(jù)。
Modbus Slave支持下列協(xié)議模式:
Modbus RTU | Modbus RTU Over TCP/IP |
---|---|
Modbus ASCII | Modbus ASCI Over TCP/IP |
Modbus TCP/IP | Modbus RTU Over UDP/IP |
Modbus UDP/IP | Modbus ASCII Over UDP/IP |
2. Modbus Slave使用
獲取軟件鏈接同上,下載完后主頁面如圖所示:
建立連接:
點(diǎn)擊Connection->Connect進(jìn)入配置頁面,選擇我們想要的連接,選擇我們虛擬出來的串口,選擇模式,接下來在設(shè)置波特率、比特位、校驗(yàn)位、停止位,如下圖所示:
設(shè)置參數(shù):點(diǎn)擊Setup->Read/Write Definition進(jìn)入配置頁面,配置從機(jī)地址、功能碼、地址類型、寄存器地址、訪問數(shù)量,具體配置如下圖:
這里有兩點(diǎn)需要我們注意一下:
- 一是:Function列表框選擇功能中的0x~4x,表示的是存儲(chǔ)區(qū)0區(qū)、1區(qū)、3區(qū)、4區(qū)
- 輸出線圈
- 輸入線圈
- 保持寄存器
- 輸入寄存器
Modbus協(xié)議規(guī)定了4個(gè)存儲(chǔ)區(qū) 分別是0、1、3、4區(qū) 其中0區(qū)和4區(qū)是可讀可寫,1區(qū)和3區(qū)是只讀。
區(qū)號(hào) | 名稱 | 讀寫 | 地址范圍 |
---|---|---|---|
0區(qū) | 輸出線圈 | 可讀可寫布爾量 | 00001-09999 |
1區(qū) | 輸入線圈 | 只讀布爾量 | 10001-19999 |
3區(qū) | 輸入寄存器 | 只讀寄存器 | 30001-39999 |
4區(qū) | 保持寄存器 | 可讀可寫寄存器 | 40001-49999 |
- 二是:Address項(xiàng),這里需要特別強(qiáng)調(diào)一下,Address表示Modbus寄存器地址,其取值范圍與設(shè)備寄存器地址存在映射關(guān)系,如下表所示:
Device address | Modbus address | Description | Function | R/W |
---|---|---|---|---|
1…10000 | address - 1 | Coils(outputs) | 01 | Read/Write |
10001…20000 | address - 10001 | Discrete Inputs | 02 | Read |
40001…50000 | address - 40001 | Holding Registers | 03 | Read/Write |
30001…40000 | address - 30001 | Input Registers | 04 | Read |
這里我們只簡單介紹下地址和存儲(chǔ)區(qū),下面我們會(huì)詳細(xì)展開。
5.3.4 虛擬串口軟件
1.軟件簡介
虛擬串口工具,可以創(chuàng)建2個(gè)互聯(lián)的串口,如下圖所示:
比如Modbus Poll工具使用COM1發(fā)送數(shù)據(jù)給COM2,Modbus Slave從COM2讀到數(shù)據(jù)。使用虛擬串口,就可以不使用開發(fā)板也可以體驗(yàn)Modbus Poll、Modbus Slave。
軟件在網(wǎng)盤里:
2.虛擬串口的使用
安裝后運(yùn)行虛擬串口程序“Virtual Serial Port Tools”,安裝下圖創(chuàng)建2個(gè)串口:
打開設(shè)備管理器,可以看到如下串口:
5.3.5 Modbus Poll 與 Modbus Slave互聯(lián)/通
下面我們進(jìn)行Modbus Poll 與 Modbus Slave互聯(lián)互通實(shí)驗(yàn),通過形象直觀的方式展示Modbus數(shù)據(jù)流,根據(jù)前面的設(shè)定我們已將知道了如何運(yùn)用Modbus學(xué)習(xí)必備三件套,下面我們就通過三件套來進(jìn)行實(shí)驗(yàn),首先打開VSPD虛擬串口軟件,設(shè)置虛擬串口,我這里就以上面設(shè)訂COM1,COM2為例,接下來我們再來配置我們的Modbus Poll 與 Modbus Slave;
我們首先打開Modbus Slave端,設(shè)置連接,連接方式我們選擇Serial Port串口連接,選擇我們設(shè)置的串口COM1,模式選擇RTU模式,如下圖所示:
- Modbus Slave連接設(shè)定
在設(shè)置參數(shù),從機(jī)地址我們設(shè)定1(你也可以自己隨意設(shè)定),F(xiàn)unction項(xiàng)我們選擇03 Holding Register(4x),地址類型我們選擇DEC(十進(jìn)制格式),Address首地址我們設(shè)置為0,訪問寄存器數(shù)量設(shè)置為10,如下圖所示:
- Modbus Slave參數(shù)設(shè)定
接下來我們再來設(shè)置Modbus Poll端,設(shè)置方法也是和Modbus Slave端一一對應(yīng)的,連接設(shè)定,參數(shù)設(shè)定,如下圖所示:
- Modbus Poll連接設(shè)定
注意這里串口要選擇我們設(shè)定的COM20,其它串口參數(shù)必須一一對應(yīng)。
- Modbus Poll參數(shù)設(shè)定
設(shè)置好后,我們主設(shè)備和從設(shè)備分別連接了我們設(shè)置的COM1,COM2,這樣我們便可觀察當(dāng)前寄存器的讀取情況。
我們雙擊Modbus Poll(主設(shè)備端)地址中的0值,便可打開值設(shè)置窗口如下圖所示:
修改值為66,點(diǎn)擊Send打開Modbus Slave(從設(shè)備端)便可發(fā)現(xiàn)也做出了改變,如下圖所示:
我們還可以打開Modbus Poll,點(diǎn)擊Display,選擇Commuaction,查看發(fā)送的報(bào)文:
TX是我們主站發(fā)送的報(bào)文,RX是從站返回的報(bào)文,報(bào)文我們下面會(huì)展開說明,帶領(lǐng)大家一起看報(bào)文;
5.4 Modbus協(xié)議細(xì)節(jié)
5.4.1 Modbus協(xié)議概述
簡而言之,Modbus 協(xié)議是一種單主/多從的通信協(xié)議,其特點(diǎn)是在同一時(shí)間總線上只能有一個(gè)主設(shè)備,但可以有一個(gè)或者多個(gè)(最多 247 個(gè))從設(shè)備。Modbus通信總是由主設(shè)備發(fā)起,當(dāng)從設(shè)備沒有收到來自主設(shè)備的請求時(shí),從設(shè)備不會(huì)主動(dòng)發(fā)送數(shù)據(jù)。從設(shè)備之間不能相互通信,主設(shè)備只能同時(shí)啟動(dòng)一個(gè) Modbus 訪回事務(wù)處理。 主設(shè)備可以采用兩種方式向從設(shè)備發(fā)送 Modbus 請求報(bào)文,即主設(shè)備可以對指定的單個(gè)從設(shè)備或者線路上所有的從設(shè)備發(fā)送請求報(bào)文,而從設(shè)備只能在被被動(dòng)接收請求報(bào)文后給出響應(yīng)報(bào)文,即應(yīng)答。這兩種模式分別如下圖所示:
Modbus請求應(yīng)答周期
單播模式。主設(shè)備僅僅尋址單個(gè)從設(shè)備,從設(shè)備接收并處理請求后,向主設(shè)備返回一個(gè)響應(yīng)報(bào)文,即應(yīng)答。在這種模式下,一個(gè) Modbus 事務(wù)處理包含兩個(gè)報(bào)文:一個(gè)是主設(shè)備的請求報(bào)文,另一個(gè)是從設(shè)備的響應(yīng)報(bào)文。
每個(gè)從設(shè)備必須有唯一的地址(地址范圍為 1~247),這樣才能區(qū)別于其它從設(shè)備,從而可以獨(dú)立被尋址,同時(shí)主設(shè)備不占用地址。
廣播模式。此種模式下,主設(shè)備可以向所有從設(shè)備發(fā)送請求指令,而從設(shè)備在接收到廣播指令后僅進(jìn)行相關(guān)指令的事務(wù)處理,而不要求返回應(yīng)答。因此廣播模式下,請求指令必須是 Modbus 標(biāo)準(zhǔn)功能中的寫指令。
根據(jù) Modbus 標(biāo)準(zhǔn)協(xié)議的要求,所有從設(shè)備必須接收廣播模式下的寫指令,且地址0被保留,用來識(shí)別廣播通信
- 請求:
主設(shè)備發(fā)送的請求報(bào)文主要包括從設(shè)備地址(或廣播地址0)、功能碼、傳輸?shù)臄?shù)據(jù)以及差錯(cuò)檢測字段。
查詢消息中的功能碼告訴我們被選中的從設(shè)備地址要執(zhí)行何種功能。數(shù)據(jù)段包含從設(shè)備要執(zhí)行功能的所有附加信息。例如,功能代碼 03 要求從設(shè)備讀取保持寄存器并返回其內(nèi)容。
數(shù)據(jù)段必須包含要告訴從設(shè)備的信息:從哪個(gè)寄存器開始讀取及要讀取的寄存器數(shù)量。差錯(cuò)檢測域?yàn)閺脑O(shè)備提供一種驗(yàn)證消息內(nèi)容是否正確的方法。
- 應(yīng)答:
從設(shè)備的應(yīng)答報(bào)文包括地址、功能碼、差錯(cuò)檢測域等; 如果從設(shè)備產(chǎn)生了一個(gè)正常的回應(yīng),則回應(yīng)消息中的功能碼是查詢消息中的功能碼的回應(yīng)。數(shù)據(jù)段包括從設(shè)備收集的數(shù)據(jù),如寄存器值或狀態(tài)。如果有錯(cuò)誤發(fā)生,則功能碼將被修改以用于指出回應(yīng)消息是錯(cuò)誤的,同時(shí)數(shù)據(jù)段包含描述此錯(cuò)誤信息的代碼。差錯(cuò)檢測域允許主設(shè)備確認(rèn)消息內(nèi)容是否可用。
對于串行鏈路來說,又存在兩種傳輸模式:ASCII(American StandardCode for Information Interchange,美國標(biāo)準(zhǔn)信息交換碼)模式和 RTU(RemoteTerminal Unit,遠(yuǎn)程終端單元)模式。但是,對于同一網(wǎng)絡(luò)或鏈路來說,所有設(shè)備必須保持統(tǒng)一,要么統(tǒng)一為 ASCII 模式,要么統(tǒng)一為 RTU 模式,不可共存。相對來說,RTU模式的傳輸效率更高,因此在當(dāng)前普遍的生產(chǎn)環(huán)境中,RTU 模式獲得了廣泛應(yīng)用,而 ASCII模式只能作為特殊情況下的可選項(xiàng)。
5.4.2 Modbus寄存器(存儲(chǔ)區(qū))
Modbus 協(xié)議中的一個(gè)重要概念是寄存器,所有數(shù)據(jù)均存放于寄存器。最初,Modbus 協(xié)議借鑒了 PLC 中寄存器的含義,但是隨著 Modbus 協(xié)議的廣泛應(yīng)用,寄存器的概念進(jìn)一步泛化,它不再是指具體的物理寄存器,也可能是指一塊內(nèi)存區(qū)域Modbus 寄存器根據(jù)存放的數(shù)據(jù)類型以及各自的讀寫特性將寄存器分為四部分,這四部分既可以連續(xù),也可以不連續(xù),由開發(fā)者決定。寄存器意義如下表所示:
Modbus寄存器(存儲(chǔ)區(qū))
寄存器種類 | 說明 | 與PLC類比 | 舉例說明 |
---|---|---|---|
線圈狀態(tài)(Coil Status) | 輸出端口??稍O(shè)定端口輸出狀態(tài),也可以讀取該位的輸出狀態(tài)??煞譃閮煞N不同的執(zhí)行狀態(tài),列如保持型或邊沿觸發(fā)型 | DO(數(shù)字量輸出) | 電磁閥輸出、MOSFEF輸出、LED顯示等 |
離散輸入狀態(tài)(Input Status) | 輸入端口。通過外部設(shè)定改變輸入狀態(tài),可讀但不可以寫 | DI(數(shù)字量輸入) | 撥碼開關(guān)、接近開關(guān)等 |
保持寄存器(Holding Register) | 輸出參數(shù)或保持參數(shù),控制器運(yùn)行時(shí)被設(shè)定的某些參數(shù),可讀可寫 | AO(模擬量輸出) | 模擬量輸出設(shè)定值,PID運(yùn)行參數(shù),變量閥輸出大小,傳感器報(bào)警上限下限 |
輸入寄存器 | 輸入?yún)?shù)??刂破鬟\(yùn)行時(shí)從外部設(shè)備獲得的參數(shù),但可讀不可寫 | AI(模擬量輸入) | 模擬量輸入 |
(PLC)數(shù)據(jù)的傳輸離不開存儲(chǔ)和讀寫操作,為了更好存儲(chǔ)不同的數(shù)據(jù)類型,我們可以理解Modbus 會(huì)將布爾和非布爾的數(shù)據(jù)分開存儲(chǔ)。
1. 存儲(chǔ)區(qū)類型
我們可以將存儲(chǔ)區(qū)類型分為布爾類型和非布爾類型,布爾類型我們用線圈(Coil)表示,非布爾用寄存器(Register)表示;
- 什么是布爾?
- 布爾類型只有兩個(gè)值,false 和 true。
- 通常用來判斷條件是否成立。
- C語言語法規(guī)定,如果變量值為 0 就是 false,否則為 true,布爾變量只有這兩個(gè)值。
因此,我們便有了線圈和寄存器的概念;
- 那線圈和寄存器又是什么?
- 線圈: 從電氣角度來看,在電氣控制回路中,一般都是靠接觸器或中間繼電器來實(shí)現(xiàn)控制,接觸器或中繼最終靠的是線圈的得電和失電來控制觸點(diǎn)閉合和斷開,因此用線圈表示布爾量;
- 寄存器: 用來暫時(shí)存放參與運(yùn)算的數(shù)據(jù)和運(yùn)算結(jié)果,具有接收數(shù)據(jù)、存放數(shù)據(jù)和輸出數(shù)據(jù)的功能。
- 而寄存器在計(jì)算機(jī)中,就是用來存儲(chǔ)數(shù)據(jù)的,因此非布爾的數(shù)據(jù)放在寄存器里。
回到存儲(chǔ)區(qū)分類,目的就是: 更好地存儲(chǔ)和區(qū)分不同的數(shù)據(jù)類型。
Modbus的線圈和寄存器應(yīng)該也按照只讀、讀寫來進(jìn)一步劃分,因此這就形成了Modbus的存儲(chǔ)區(qū),如下表所示:
- Modbus存儲(chǔ)區(qū)類型及名稱
序號(hào) | 讀寫 | 存儲(chǔ)類型 | 存儲(chǔ)區(qū)名稱 |
---|---|---|---|
1 | 只讀 | 線圈 | 輸入線圈 |
2 | 讀寫 | 線圈 | 輸出線圈 |
3 | 只讀 | 寄存器 | 輸入寄存器 |
4 | 讀寫 | 寄存器 | 保持寄存器 |
- 存儲(chǔ)區(qū)代號(hào):
為什么需要存儲(chǔ)區(qū)代號(hào)?上面表格里的存儲(chǔ)區(qū)名稱是一個(gè)全稱,開發(fā)和使用中使用全稱會(huì)比較麻煩,因此需要給他們?nèi)€(gè)別名。所以Modbus也要給這些存儲(chǔ)區(qū)取一個(gè)代號(hào),干脆直接用數(shù)字吧,于是,就有了下面的規(guī)定:
存儲(chǔ)區(qū)名稱 | 存儲(chǔ)區(qū)代號(hào) |
---|---|
輸入線圈 | 1區(qū) |
輸出線圈 | 0區(qū) |
輸入寄存器 | 3區(qū) |
保持寄存器 | 4區(qū) |
存儲(chǔ)區(qū)代號(hào)其實(shí)可以簡單理解為我們的名字,例如我們的名字有全名,和小名,全名呢是正式場合,外人叫的,小名呢是我們的親近的人,日常場合叫的。這么一說是不是就理解為什么有存儲(chǔ)區(qū)代號(hào)啦。
- 存儲(chǔ)區(qū)范圍:
- 無論是什么存儲(chǔ)區(qū),都會(huì)有一個(gè)范圍的限制;Modbus的每個(gè)存儲(chǔ)區(qū)也規(guī)定了一個(gè)范圍,不能無限制使用。
- Modbus規(guī)定每個(gè)存儲(chǔ)區(qū)的最大范圍是65536,也就是0~65535。
2. 協(xié)議地址模型
PLC地址是我們常見的,但它是怎么組成的的,它是由存儲(chǔ)區(qū)代號(hào) + 地址組成,我們把這樣的地址稱為絕對地址,把后面的地址成為相對地址;而我們的Modbus地址跟PLC地址也是類似的;
Modbus地址公式:存儲(chǔ)區(qū)代號(hào) + (地址 + 1)如下表所示:
- Modbus長地址模型
存儲(chǔ)區(qū)名稱 | 存儲(chǔ)區(qū)代號(hào) | 絕對地址范圍 | 相對地址范圍 |
---|---|---|---|
輸入線圈 | 1區(qū) | 100001~165536 | 0~65535 |
輸出線圈 | 0區(qū) | 000001~065536 | 0~65535 |
輸入寄存器 | 3區(qū) | 300001~365536 | 0~65535 |
保持寄存器 | 4區(qū) | 400001~465536 | 0~65535 |
Modbus地址分為長地址模型和短地址模型,上面Modbus長地址模型,但是在實(shí)際使用中,我們一般用不了這么多地址,一般情況下,10000以內(nèi)就已經(jīng)足夠使用了;因此,為了方便我們便有了另一種短的地址模型,如下圖所示:
- Modbus短地址模型
存儲(chǔ)區(qū)名稱 | 存儲(chǔ)區(qū)代號(hào) | 絕對地址范圍 | 相對地址范圍 |
---|---|---|---|
輸入線圈 | 1區(qū) | 10001~19999 | 0~9998 |
輸出線圈 | 0區(qū) | 00001~09999 | 0~9998 |
輸入寄存器 | 3區(qū) | 30001~39999 | 0~9998 |
保持寄存器 | 4區(qū) | 40001~49999 | 0~9998 |
5.4.3 Modbus常用功能碼
Modbus功能碼占用1字節(jié),取值范圍是1127。之所以127以上不能用,是因?yàn)镸odbus規(guī)定當(dāng)出現(xiàn)異常時(shí),功能碼+0x80(十進(jìn)制128)代表異常狀態(tài),因此129(1+128)255(127+128)的取值代表異常碼。
- Modbus常用功能碼
功能碼 | 描述 | 寄存器PLC地址 | 位/字操作 | 操作數(shù)量 |
---|---|---|---|---|
01H | 讀線圈寄存器(讀輸出線圈) | 00001~09999 | 位操作 | 單個(gè)或多個(gè) |
02H | 讀離散輸入寄存器(讀輸入線圈) | 10001~19999 | 位操作 | 單個(gè)或多個(gè) |
03H | 讀保持寄存器 | 40001~49999 | 字操作 | 單個(gè)或多個(gè) |
04H | 讀輸入寄存器 | 30001~39999 | 字操作 | 單個(gè)或多個(gè) |
05H | 寫單個(gè)線圈寄存器 | 00001~09999 | 位操作 | 單個(gè) |
06H | 寫單個(gè)保持寄存器 | 40001~49999 | 字操作 | 單個(gè) |
0FH(15) | 寫多個(gè)線圈寄存器 | 00001~09999 | 位操作 | 多個(gè) |
10H(16) | 寫多個(gè)保持寄存器 | 40001~49999 | 字操作 | 多個(gè) |
功能碼可以分為位操作和字操作兩類。位操作的最小為1位(bit),字操作的最小單位為2字節(jié)。
① 位操作指令:讀取線圈狀態(tài)的功能碼 01 ,讀(離散)輸入狀態(tài)功能碼 02 ,寫單個(gè)線圈功能碼 05 和寫多個(gè)線圈功能碼 15。
② 字操作指令:讀保持寄存器功能碼 03 ,讀輸入寄存器功能碼 04 ,寫單個(gè)保持寄存器功能碼 06 ,寫多個(gè)保持寄存器功能碼 16 。
5.4.4 Modbus協(xié)議類型
Modbus可以在各種介質(zhì)上傳輸,那么他的傳輸模式也分為三種。包括ASCII、RTU(遠(yuǎn)程終端控制系統(tǒng))、TCP三種報(bào)文類型
- 常用Modbus協(xié)議
Modbus協(xié)議 | Modbus協(xié)議 |
---|---|
Modbus RTU | Modbus RTU Over TCP/IP |
Modbus ASCII | Modbus ASCI Over TCP/IP |
Modbus TCP/IP | Modbus RTU Over UDP/IP |
Modbus UDP/IP | Modbus ASCII Over UDP/IP |
Modbus協(xié)議使用串口傳輸時(shí)可以選擇RTU或ASCII模式,并規(guī)定了消息、數(shù)據(jù)結(jié)構(gòu)、命令和應(yīng)答方式并需要對數(shù)據(jù)進(jìn)行校驗(yàn)。ASCII 模式采用LRC校驗(yàn),RTU模式采用16 位CRC校驗(yàn)。通過以太網(wǎng)傳輸時(shí)使用TCP,這種模式不使用校驗(yàn),因?yàn)門CP協(xié)議是一個(gè)面向連接的可靠協(xié)議。
5.4.5 Modbus報(bào)文幀
一個(gè)報(bào)文就是一幀數(shù)據(jù),一個(gè)數(shù)據(jù)幀就一個(gè)報(bào)文: 指的是一串完整的指令數(shù)據(jù),本質(zhì)就是一串?dāng)?shù)據(jù)。
Modbus報(bào)文是指主機(jī)發(fā)送給從機(jī)的一幀數(shù)據(jù),其中包含著從機(jī)的地址,主機(jī)想執(zhí)行的操作,校驗(yàn)碼等內(nèi)容
1. Modbus ASCII 模式
**當(dāng)控制器設(shè)為在Modbus網(wǎng)絡(luò)上以ASCII模式通信時(shí),在消息中每個(gè)8位(b)字節(jié)都將作為兩個(gè) ASCII字符發(fā)送。這種方式的主要優(yōu)點(diǎn)是字符發(fā)送的時(shí)間可隔可達(dá)到 1秒且不產(chǎn)生錯(cuò)誤。 **
**在ASCII模式下,消息以冒號(hào)(:)字符(ASCII碼為 0x3A)開始,以回車換行奇結(jié)束(ASCII碼為 0x0D、0x0A)。消息的其他字段(域)可以使用的傳輸字符是十六進(jìn)制的0···9、A···F。處于網(wǎng)絡(luò)上的 Modbus 設(shè)備不斷偵測“:”字符,當(dāng)接收到一個(gè)冒號(hào)時(shí),每個(gè)設(shè)備進(jìn)入解碼階段,并解碼下一個(gè)字段(地址域)以判斷是否是發(fā)給自己的。消息幀中的字符間發(fā)送的時(shí)間間隔最長不能超過 1秒,否則接收設(shè)備將認(rèn)為發(fā)生傳輸錯(cuò)誤。 **
下表是一個(gè)典型的ASCII報(bào)文格式:
開始字符 | 地址 | 功能碼 | 數(shù)據(jù) | LRC校驗(yàn) | 結(jié)束字符 |
---|---|---|---|---|---|
1byte (:) | 2byte | 2byte | Nbyte | 2byte | CR、LF |
2. Modbus RTU 模式
Modbus協(xié)議RTU報(bào)文格式如下所示:
從機(jī)地址 | 功能碼 | 數(shù)據(jù) | CRC校驗(yàn) |
---|---|---|---|
1byte | 1byte | Nbyte | 2byte |
- **幀結(jié)構(gòu) = 從機(jī)地址 + 功能碼 + 數(shù)據(jù) + 校驗(yàn) **
- 從機(jī)地址: 每個(gè)從機(jī)都有唯一地址,占用一個(gè)字節(jié),范圍0-255,其中有效范圍是1-247,其中255是廣播地址(廣播就是對所有從機(jī)發(fā)送應(yīng)答)
- 功能碼: 占用一個(gè)字節(jié),功能碼的意義就是,知道這個(gè)指令是干啥的,比如你可以查詢從機(jī)的數(shù)據(jù),也可以修改從機(jī)的數(shù)據(jù),所以不同功能碼對應(yīng)不同功能.
- 數(shù)據(jù): 根據(jù)功能碼不同,有不同功能,比方說功能碼是查詢從機(jī)的數(shù)據(jù),這里就是查詢數(shù)據(jù)的地址和查詢字節(jié)數(shù)等。
- 校驗(yàn): 在數(shù)據(jù)傳輸過程中可能數(shù)據(jù)會(huì)發(fā)生錯(cuò)誤,CRC檢驗(yàn)檢測接收的數(shù)據(jù)是否正確
3. 串行報(bào)文幀總結(jié):
ModbusASCII有開始字符(和結(jié)束字符(CR LF),可以作為一幀數(shù)據(jù)開始和結(jié)束的標(biāo)志,而ModbusRTU沒有這樣的標(biāo)志,需要用時(shí)間間隔來判斷一幀報(bào)文的開始和結(jié)束,協(xié)議規(guī)定的時(shí)間為3.5個(gè)字符周期,就是說一幀報(bào)文開始前,必須有大于3.5個(gè)字符周期的空閑時(shí)間,一幀報(bào)文結(jié)束后,也必須要有3.5個(gè)字符周期的空閑時(shí)間否則就會(huì)出現(xiàn)粘包的情況。
**注意:針對3.5個(gè)字符周期,其實(shí)是一個(gè)具體時(shí)間,但是這個(gè)時(shí)間跟波特率相關(guān)。 在串口通信中,1個(gè)字符包括1位起始位、8位數(shù)據(jù)位(一般情況)、1位校驗(yàn)位(或者沒有)、1位停止位(一般情況下),因此1個(gè)字符包括11個(gè)位,那么3.5個(gè)字符就是38.5個(gè)位,波特率表示的含義是每秒傳輸?shù)亩M(jìn)制位的個(gè)位,因此如果是9600波特率,3.5個(gè)字符周期=38.5/9600=0.00401s*1000=4.01ms**
5.4.6 Modbus 差錯(cuò)校驗(yàn)
在Modbus串行通信中,根據(jù)傳輸模式(ASCII或RTU)的不同,差錯(cuò)校驗(yàn)域?qū)⒉捎貌煌男r?yàn)方法。
- ASCII模式
在ASCII模式中,報(bào)文包含一個(gè)錯(cuò)誤校驗(yàn)字段,該字段由兩個(gè)字符組成,其基于對全部報(bào)文內(nèi)容執(zhí)行的縱向冗余校驗(yàn)(Longitudinal Redundancy ChedLRC)計(jì)算的結(jié)果而來,計(jì)算對象不包括起始的冒號(hào)(:)和回車換行符號(hào)(CR LF)。 - **RTU模式 **
在RTU模式中,報(bào)文同樣包含一個(gè)錯(cuò)誤校驗(yàn)字段。與ASCII模式不同的是該字段由 16 個(gè)比特位共2字節(jié)組成,其值基于對全部報(bào)文內(nèi)容執(zhí)行的循環(huán)冗余校驗(yàn)(Cyclical Redundancy Check,CRC)計(jì)算的結(jié)果而來,計(jì)算對象包括校驗(yàn)域之的所有字節(jié)。
1. LRC校驗(yàn)
在ASCII模式中,消息是由特定的字符作為幀頭和幀尾分隔的。
一條消息必須以“冒號(hào)”(:)字符(ASCII碼為0x3A)開始,以“回車換行(CRLF)(ASCII碼為 0x0D 和 0x0A)結(jié)束。LRC 校驗(yàn)算法的計(jì)算范圍為“:” “CRLF”之間的字符。
從算法本質(zhì)來說,LRC域自身為1字節(jié),即包含一個(gè) 8位二進(jìn)制數(shù)據(jù),由發(fā)送設(shè)備通過LRC算法把計(jì)算值附到信息末尾。接收設(shè)備在接收信息時(shí)通過 LRC法重新計(jì)算值,并把計(jì)算值與 LRC 字段中接收的實(shí)際值進(jìn)行比較。若兩者不同,則產(chǎn)生一個(gè)錯(cuò)誤,返回一個(gè)異常響應(yīng)幀,即對報(bào)文中的所有相鄰的兩個(gè) 8位字相加,丟棄任何進(jìn)位,然后對結(jié)果進(jìn)行二進(jìn)制補(bǔ)碼,計(jì)算出 LRC值。
必須注意的是,計(jì)算 LRC 校驗(yàn)碼的時(shí)機(jī)是在對報(bào)文中每個(gè)原始字節(jié)進(jìn)行ASCII碼編碼之前,對每個(gè)原始字節(jié)進(jìn)行LRC校驗(yàn)的計(jì)算操作。
- LRC校驗(yàn)流程:
- 將消息中的全部字節(jié)相加(不包括起始“:”和結(jié)束符(CRLF),并把結(jié)果送入8位數(shù)據(jù)區(qū),舍棄進(jìn)位。
- 由0xFF(即全 1)減去最終的數(shù)據(jù)值,產(chǎn)生1的補(bǔ)碼(即二進(jìn)制反碼)
- 加1產(chǎn)生二進(jìn)制補(bǔ)碼。
以上產(chǎn)生的LRC值占用1字節(jié),但實(shí)際上在通過串行鏈路由ASCII模式傳遞消息頓時(shí),LRC的結(jié)果(1字節(jié))被編碼為2字節(jié)的ASCII字符,并將其放置在ASCII模式報(bào)文幀的CRLF字段之前。
Modbus 標(biāo)準(zhǔn)協(xié)議的英文版提供了 LRC算法,其中的參數(shù)意義如下unsigned char*auchMsg:含有生成LRC所使用的二進(jìn)制數(shù)據(jù)的報(bào)文緩存區(qū)指針。 unsigned short usDataLen:報(bào)文緩存區(qū)中的字節(jié)數(shù)。
LCR的代碼如下:
/*函數(shù)返回unsigned char類型的 LRC值*/
?
static unsigned char LRC(unsigned char * auchMsg, unsigned short usDatalen)
?
{
?
unsigned char uchLRC=0; /*LRC字節(jié)初始化*/
?
?
while(usDataLen--) /*遍歷報(bào)文緩沖區(qū)*/
?
uchLRC+=*auchMsg++; /*緩沖區(qū)宇節(jié)相加,自動(dòng)舍棄進(jìn)位*/
?
?
return ((unsigned char)(-(( char)uchLRC))); /*返回二進(jìn)制補(bǔ)碼*/
?
}
下面舉一個(gè)簡單的例子。假設(shè)從設(shè)備地址為 1,要求讀取輸人寄存器地址30001的值,則具體的查詢消息幀如下:
":" , "0" , "1" , "0" , "4" , "0" ,"0" ,"0" ,"0" ,"0" ,"0" ,"0" , "1" , "F" , "A" ,CR/LF
其中,“F”, “A”即為LRC值在 ASCII模式下的形式,即0xFA.
2. CRC校驗(yàn)
在Modbus RTU傳輸模式下,通信報(bào)文(幀)包括一個(gè)基于循環(huán)冗余校驗(yàn)方法的差錯(cuò)校驗(yàn)字段。
Modbus協(xié)議采用了CRC-16標(biāo)準(zhǔn)校驗(yàn)方法。在RTU模式下,CRC自身由2字節(jié)組成,即CRC是一個(gè)16位的值。CRC字段校驗(yàn)整個(gè)報(bào)文的內(nèi)容,無論報(bào)文中的單個(gè)字節(jié)采用何種奇偶校驗(yàn)方式,整個(gè)通信報(bào)文均可使用CRC-16校驗(yàn)算法,CRC字段作為報(bào)文的最后字段添加在整個(gè)報(bào)文末尾。
需要注意的是,因?yàn)镃RC-16是由2字節(jié)組成,所以涉及哪個(gè)字節(jié)放在前面,哪個(gè)字節(jié)放在后面?zhèn)鬏數(shù)膯栴},即大小端模式的選擇問題。另外,由于Modbus協(xié)議規(guī)定寄存器為16位(即2字節(jié))長度,因此大小端問題的存在給很多初學(xué)者造成了困擾,下一章我們會(huì)重點(diǎn)講一下大小端的問題。
- CRC校驗(yàn)流程:
- 預(yù)置一個(gè)16位寄存器為0xFFFF(全1),稱之為CRC寄存器。
- 把數(shù)據(jù)幀中的第一個(gè)字節(jié)的8位與CRC寄存器中的低字節(jié)進(jìn)行異或運(yùn)算,結(jié)果存回CRC寄存器。
- 將CRC寄存器向右移一位,最高位填以0,最低位移出并檢測是0還是1。
- 如果最低位為0:重復(fù)第三步(再次右移一位);如果最低位為1:將CRC寄存器與一個(gè)預(yù)設(shè)的固定值(0xA001)進(jìn)行異或運(yùn)算。
- 重復(fù)第三步和第四步直到8次移位。這樣處理完了一個(gè)完整的八位。
- 重復(fù)第2步到第5步來處理下一個(gè)八位,直到所有的字節(jié)處理結(jié)束。
- 將該通信消息幀的所有字節(jié)按上述步驟計(jì)算完成后,再將得到的16位CRC寄存器的高、低位字節(jié)進(jìn)行交換,即發(fā)送時(shí)首先添加低位字節(jié),然后添加高位字節(jié)。
- 最終CRC寄存器的值就是CRC的校驗(yàn)碼。
需要注意的是,在進(jìn)行CRC計(jì)算時(shí)只有串行鏈路上的每個(gè)字符的8個(gè)數(shù)據(jù)位參與計(jì)算,從而起始位、停止位、奇偶校驗(yàn)位等都不參與CRC計(jì)算。
常用的CRC-16算法有查表法、計(jì)算法。
查表法:
CRC查表法是將位移異或的計(jì)算結(jié)果做成了一個(gè)表,即將0~256 放入一個(gè)度為16位的寄存器的低8位,高8位填充0,然后將該寄存器與多項(xiàng)式0xA001照上述步驟3、4直到8 位全部移出,最后寄存器中的值就是表格中的數(shù)據(jù),高8位、低 8 位分別單獨(dú)做成一個(gè)表。 實(shí)際上,Modbus 標(biāo)準(zhǔn)協(xié)議的英文版提供了CRC 查表算法 函數(shù)的輸入?yún)?shù)意義如下:
unsigned char * puchMsg; /*要進(jìn)行CRC校驗(yàn)的消息*/
?
unsigned short usDataLen; /*消息中的字節(jié)數(shù)*/
?
/*函數(shù)返回 unsigned short(即2個(gè)字節(jié))類型的 CRC值*/
?
unsigned short CRC16(unsigned char *puchMsg,unsigned short usDataLen)
?
{
?
unsigned charuchCRCHi=0xFF; /*高 CRC字節(jié)初始化* /
?
unsigned char uchCRCLo=0xFF; /*低 CRC字節(jié)初始化*/
?
unsigned short uIndex; /*CRC 循環(huán)表中的索引*/
?
?
while (usDataLen--) /* 循環(huán)處理傳輸緩沖區(qū)消息 */
?
{
?
uIndex=uchCRCHi ^ * puchMsg++; /*計(jì)算 CRC* /
?
uchCRCHi=uchCRCLo ^ auchCRCHi[uIndex];
?
uchCRCLo=auchCRCLo[uIndex];
?
}
?
return (uchCRCHi < 81uchCRCLo);
?
}
其中,auchCRCHi和auchCRCLo的定義分別如下:
static unsigned char auchcRCHi[] =
?
{
?
0x00,0xC1,0x81,0x48,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,
?
0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,
?
0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,
?
0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x01,
?
0x00,0xc1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,
?
0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,
?
0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,
?
0xc0,0x80,0x41,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
?
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,
?
0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x01,0xC0,
?
0x80,0x41,0x01,0xc0,0x80,0x41,0x00,0xCl,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,
?
0xc0,0x80,0x41,0x01,0xc0,0x80,0x41,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
?
0x00,0xc1,0x81,0x40,0x00,0xc1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,
?
0x40,0x01,0xc0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x01.0xC0,
?
0x80,0x41,0x00,0xc1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,
?
0xc0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
?
0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x01,0xc0,0x80,0x41,0x00,0xC1,0x81,
?
0x40
?
};
static char auchCRCLo[]=
?
{
?
0x00,0xc0,0xC1,0x01,0xC3,0x03,0x02,0xC2,0xC6,0x06,0x07,0xC7,0x05,0xC5,0xC4,
?
0x04,0xCC,0x0C,0x0D,0xCD,0x0F,0xCF,0xCE,0x0E,0x0A,0xCA,0xCB,0x0B,0xC9,0x09,
?
0x08,0xc8,0xDB,0x18,0x19,0xD9,0x1B,0xDB,0xDA,0x1A,0x1E,0XDE,0XDE,0x1F,0xDD,
?
0x1D,0x1C,0xDC,0x14,0xD4,0xD5,0x15,0xD7,0x17,0x16,0xD6,0xD2,0x12,0x13,0xD3,
?
0x11,0xD1,0xD0,0x10,0xF0,0x30,0x31,0xF1,0x33,0xE3,0xE2,0x32,0x36,0xF6,0xF7,
?
0x37,0xF5,0x35,0x34,0xF4,0x3C,0xFC,0xFD,0x3D,0xFF,0x3F,0x3E,0xFE,0xFA,0x3A,
?
0x3B,0xFB,0x39,0xF9,0xF8,0x38,0x28,0xE8,0xE9,0x29,0xEB,0x2B,0x2A,0xEA,0xEE,
?
0x2E,0x2F,0xEF,0x2D,0xED,0xEC,0x2C,0xE4,0x24,0x25,0xE5,0x27,0xE7,0xE6,0x26,
?
0x22,0xE2,0xE3,0x23,0xE1,0x21,0x20,0xE0,0xA0,0x60,0x61,0xA1,0x63,0xA3,0xA2,
?
0x62,0x66,0xA6,0xA7,0x67,0xA5,0x65,0x64,0xA4,0x6C,0xAC,0xAD,0x6D,0xAF,0x6F,
?
0x6E,0xAE,0xAA,0x6A,0x6B,0xAB,0x69,0xA9,0xAB,0x68,0x78,0xB8,0xB9,0x79,0xBB,
?
0x7B,0x7A,0xBA,0xBE,0x7E,0x7E,0xBE,0x7D,0xBD,0xBC,0x7C,0xB4,0x74,0x75,0xB5,
?
0x77,0xB7,0xB6,0x76,0x72,0xB2,0xB3,0x73,0xB1,0x71,0x70,0xB0,0x50,0x90,0x91,
?
0x51,0x93,0x53,0x52,0x92,0x96,0x56,0x57,0x97,0x55,0x95,0x94,0x54,0x9C,0x5C,
?
0x5D,0x9D,0x5F,0x9F,0x9E,0x5E,0x5A,0x9A,0x9B,0x5B,0x99,0x59,0x58,0x98,0x88,
?
0x48,0x49,0x89,0x4B,0x8B,0x8A,0x4A,0x4E,0x8E,0x8E,0x4F,0x8D,0x4D,0x4C,0x8C,
?
0x44,0x84,0x85,0x45,0x87,0x47,0x46,0x86,0x82,0x42,0x43,0x83,0x41,0x81,0x80,
?
0x40
?
};
注意:實(shí)際編程時(shí),auchcRCHi[]和auchCRCLo[]的定義應(yīng)該放在函數(shù)CRC-16()之前。
查表法可以進(jìn)一步化簡如下:
unsigned short CRC16(unsigned char * puchMsg,unsigned short usDataLen)
?
{
?
static const unsigned short usCRCTable[]=
?
{
?
0x0000,0xC0C1,0xC181,0x0140,0XC301,0X03C0,0X0280,0xc241,
?
0XC601,0X06C0,0x0780,0XC741,0X0500,0XC5C1,0XC481,0X0440,
?
0xCC01,0X0CC0,0X0D80,0XCD41,0X0F00,0XCEC1,0XCE81,0X0E40,
?
0X0A00,0XCAC1,0XCB81,0X0B40,0XC901,0X09C0,0X0880,0XC841,
?
0XD801,0x18c0,0X1980,0XD941,0X1B00,0XDBC1,0XDA81,0X1A40,
?
0X1E00,0XDEC1,0XDF81,0X1F40,0XDD01,0X1DC0,0X1C80,0XDC41,
?
0x1400,0XD4C1,0XD581,0X1540,0XD701,0X17C0,0X1680,0XD641,
?
0XD201,0X12c0,0X1380,0XD341,0X1100,0XD1C1,0XD081,0X1040,
?
0XF001,0X30C0,0X3180,0XE141,0X3300,0XE3C1,0XE281,0X3240,
?
0X3600,0XF6C1,0XE781,0X3740,0XE501,0X35C0,0X3480,0XE441,
?
0X3C00,0XFCC1,0XFD81,0X3D40,0XFF01,0X3FC0,0X3EB0,0XFE41,
?
0XFA01,0X3AC0,0X3B80,0XFB41,0X3900,0XE9C1,0XF881,0X3840,
?
0X2800,0XE8C1,0XE981,0X2940,0XEB01,0X2BC0,0X2A80,0XEA41,
?
0XEE01,0X2EC0,0X2F80,0XEF41,0X2D00,0XEDC1,0XEC81,0X2C40,
?
0XE401,0X24C0,0X2580,0XE541,0X2700,0XE7C1,0XE681,0X2640,
?
0x2200,0XE2C1,0XE381,0X2340,0XE101,0X21C0,0X2080,0XE041,
?
0XA001,0X60C0,0X6180,0XA141,0X6300,0XA3C1,0XA281,0X6240,
?
0X6600,0XA6c1,0XA781,0X6740,0XA501,0X65C0,0X6480,0XA441,
?
0X6C00,0XACC1,0XAD81,0X6D40,0XAF01,0X6EC0,0X6E80,0XAE41,
?
0XAA01,0X6AC0,0X6B80,0XAB41,0X6900,0XA9C1,0XA881,0X6840,
?
0X7800,0XB8C1,0XB981,0X7940,0XBB01,0X7BC0,0X7A80,0XBA41,
?
0XBE01,0X7EC0,0X7F80,0XBF41,0X7D00,0XBDC1,0XBC81,0X7C40,
?
0XB401,0X74C0,0X7580,0XB541,0X7700,0XB7C1,0XB681,0X7640,
?
0X7200,0XB2C1,0XB381,0X7340,0XB101,0X71C0,0X7080,0XB041,
?
0X5000,0X90c1,0X9181,0X5140,0X9301,0X53c0,0X5280,0X9241,
?
0X9601,0X56C0,0X5780,0X9741,0X5500,0X95c1,0X9481,0X5440,
?
0X9C01,0X5cc0,0X5D80,0X9D41,0X5E00,0X9FC1,0X9E81,0X5E40,
?
0X5A00,0X9AC1,0X9B81,0X5B40,0x9901,0x59c0,0x5880,0X9841,
?
0x8801,0X4BC0,0X4980,0X8941,0X4B00,0XBBC1,0X8AB1,0X4A40,
?
0X4E00,0X8EC1,0X8F81,0X4F40,0X8D01,0X4DC0,0X4C80,0X8C41,
?
0X4400,0X84c1,0x8581,0X4540,0X8701,0X47C0,0X4680,0X8641,
?
0x8201,0X42c0,0x4380,0X8341,0X4100,0XB1C1,0X8081,0X4040,
?
};
?
unsigned char nTemp;
?
unsigned short usRegCRC = 0xFFFF;
?
while (usDataLen--)
?
{
?
nTemp = * puchMsg ++ ^ usRegCRC;
?
usRegCRC > > = 8;
?
usRegCRC ^= usCRCTable[nTemp];
?
}
?
return usRegCRC;
?
}
查表法的特點(diǎn)是以字節(jié)為單位進(jìn)行計(jì)算,速度快,語句少,但表格會(huì)占用一定的程序空間。
- 計(jì)算法:
計(jì)算法按位計(jì)算,適用于所有長度的數(shù)據(jù)校驗(yàn),最為靈活;但由于是按位計(jì)算,其效率并不是最優(yōu)的,只適用于對速度不敏感的場合。計(jì)算法的基本算法如下; 輸入?yún)?shù)的意義:
unsigned char * puchMsg; /*要進(jìn)行 CRC校驗(yàn)的消息* /
?
unsigned short usDataLen; /*消息中的字節(jié)數(shù)*/
?
/*函數(shù)返回unsigned short(即 2個(gè)字節(jié))類型的CRC值*/
?
unsigned short CRC16(unsigned char *puchMsg,unsigned short usDataLen)
?
{
?
int i,j; /*循環(huán)變量*/
?
unsigned shortusRegCRC =0xFFFF; /*用于保存CRC值*/
?
?
for(i=0;i < usDataLen;i++) /*循環(huán)處理傳輸緩沖區(qū)消息*/
?
{
?
usRegCRC ^= * puchMsg++; /*異或算法得到CRC值*/
?
for(j=0;j< 8;j++) /*循環(huán)處理每個(gè) bit位*/
?
{
?
if (usRegCRC &0x0001)
?
usRegCRC =usRegCRC > >1^0xA001;
?
else
?
usRegCRC > >=1;
?
}
?
}
?
?
return usRegCRC;
?
}
下面舉一個(gè)簡單的例子。假設(shè)從設(shè)備地址為 1,要求讀取輸入寄存器地址30001的值,則RTU模式下的具體查詢消息幀如下:
0x01,0x04,0x00,0x00,0x00,0x01,0x31,0xCA
其中,0xCA31即為CRC值。因?yàn)镸odbus規(guī)定發(fā)送時(shí)CRC必須低字節(jié)在前、高字節(jié)在后,因此實(shí)際的消息幀的發(fā)送順序?yàn)?x31,0xCA。
5.4.7 字節(jié)序和大小端
Modbus中傳輸?shù)臄?shù)據(jù),按照“大字節(jié)序”來傳輸,比如:
寄存器數(shù)值是0x1234,先傳輸0x12,再傳輸0x34。
在 Modbus 寄存器中,對于一個(gè)由 2字節(jié)組成的16數(shù),在內(nèi)存中存儲(chǔ)這兩個(gè)字節(jié)有兩種方法:一種是將低序字節(jié)存儲(chǔ)在起始地址為小端(Little-Endian)字節(jié)序;另一種方法是將高序字節(jié)存儲(chǔ)在起始地稱為大端(Big-Endian)字節(jié)序。Modbus 通信協(xié)議中具體規(guī)定了字節(jié)高低位發(fā)送順序,這樣就自然引出了字節(jié)序和大小端的問題。
- 什么是大端:
所謂大端,是指數(shù)據(jù)的低位保存在內(nèi)存的高地址中,數(shù)據(jù)的高位保存在內(nèi)存的低地址中。 - 什么是小端:
所謂小端,是指數(shù)據(jù)的低位保存在內(nèi)存的低地址中,數(shù)據(jù)的高位保存在內(nèi)存的高地址中。 - 為什么會(huì)有大小端:
計(jì)算機(jī)系統(tǒng)是以字節(jié)為單位的,每個(gè)地址單元都對應(yīng)著1個(gè)字節(jié),一個(gè)字節(jié)為8bit。但在C語言中除了8bit的char類型,還有16bit的short類型和32bit的long類型,還有就是對于位數(shù)大于8位的處理器,如16位或32位的處理器,由于寄存器寬度大于一個(gè)字節(jié),那么必然存在一個(gè)如何將多個(gè)字節(jié)安排的問題。因此就導(dǎo)致了大端存儲(chǔ)模式和小端存儲(chǔ)模式的出現(xiàn)。
低位字節(jié)和高位字節(jié):好比如:123456 其中的1就是高位數(shù)字,6就是低位數(shù)字。
舉一個(gè)例子,在32位數(shù)字0x12345678在內(nèi)存中的表示形式為:
1)大端模式 :
低地址 | —— | —— | 高地址 |
---|---|---|---|
0x12 | 0x34 | 0x56 | 0x78 |
2)小端模式:
低地址 | —— | —— | 高地址 |
---|---|---|---|
0x78 | 0x56 | 0x34 | 0x12 |
5.4.8 Modbus報(bào)文分析
在第二章中我們已經(jīng)生成了一個(gè)報(bào)文,我們就拿此報(bào)文來逐步分析一下,報(bào)文如下:
我們可以看到上面報(bào)文都是循環(huán)發(fā)送的,這樣看起來不太容易分析,我摘抄下來其中一組來給大家分析
發(fā)送:
從機(jī)地址 | 功能碼 | 起始地址高位 | 起始地址低位 | 寄存器數(shù)量高位 | 寄存器數(shù)量低位 | CRC高位 | CRC低位 |
---|---|---|---|---|---|---|---|
01 | 03 | 00 | 00 | 00 | 0A | C5 | CD |
響應(yīng):
從機(jī)地址 | 功能碼 | 返回字節(jié)數(shù) | 數(shù)據(jù)位 | CRC高位 | CRC低位 |
---|---|---|---|---|---|
01 | 03 | 14 | 00 42… | CF | 10 |
這里我們就以03功能碼為例來分析一下報(bào)文;
- 03發(fā)送報(bào)文格式:從機(jī)地址+功能碼+加起始地址+寄存器數(shù)量+CRC校驗(yàn)
- 03接受報(bào)文格式:從機(jī)地址+功能碼+字節(jié)數(shù)+具體數(shù)據(jù)+CRC校驗(yàn)
首先我們看一下發(fā)送報(bào)文:
從機(jī)地址是01,功能碼03,起始地址00,寄存器數(shù)量是十六進(jìn)制0A也就是10,和門設(shè)置的是一樣的,我們來對對照一下我們設(shè)置的參數(shù):
我們再來看一下接收報(bào)文:
從機(jī)地址是01,功能碼03,返回字節(jié)數(shù)是十六進(jìn)制14也就是返回20給字節(jié),我們發(fā)送是個(gè)返回20個(gè)字節(jié)也是對的上的,第一個(gè)數(shù)據(jù)位是00 42 也是和我們發(fā)送的可以對上,十六機(jī)制42,也就66,我們來看一下我們之前設(shè)置的參數(shù):
5.4.9 Moubus TCP 消息幀格式
1.協(xié)議描述
在Modbus TCP/IP中,串行鏈路中的主/從設(shè)備分別演變?yōu)榭蛻舳?服務(wù)器端設(shè)備,即客戶端相當(dāng)于主站設(shè)備,服務(wù)器端設(shè)備相當(dāng)于從設(shè)備。基于TCP/IP網(wǎng)絡(luò)的傳輸特性,串行鏈路上一主多從的機(jī)構(gòu)也演變?yōu)槎嗫蛻舳?多服務(wù)器端的構(gòu)造模型。Modbus協(xié)議在TCP/IP上的實(shí)現(xiàn)是在TCP/IP層上的應(yīng)用,它需要一個(gè)完整的TCP/IP棧作為支撐,Modbus TCP/IP服務(wù)器端通常使用端口502作為接收報(bào)文的端口。
下圖為Moubus TCP的通訊結(jié)構(gòu):
ModbusTCP與ModbusUDP的報(bào)文格式是一樣的,它們之間的區(qū)別其實(shí)就是TCP與UDP的區(qū)別,因此下面就針對ModbusTCP的協(xié)議進(jìn)行分析,ModbusTCP與ModbusRtu(ModbusASCII)之間的區(qū)別如下圖:
從上圖可以看出,ModbusTCP在Modbus串行通信的基礎(chǔ)上,去除了校驗(yàn)(由于TCP本身就帶有校驗(yàn)和)和設(shè)備地址(ModbusTCP弱化了設(shè)備地址,用IP地址來取代),再加上MBAP報(bào)文頭(占7 bytes),下面針對MBAP進(jìn)行分析說明:
字段名 | 長度 | 描述 | 主站(客戶端) | 從站(服務(wù)器端) |
---|---|---|---|---|
事務(wù)處理標(biāo)識(shí)符(Transaction Identifier) | 2字節(jié) | Modbus 請求/應(yīng)答傳輸過程的事務(wù)處理的識(shí)別碼,可以設(shè)置為0,也可以設(shè)置為每次通訊時(shí)自動(dòng)+1 | 主站(客戶端)生成 | 應(yīng)答時(shí)從主站(客戶端)復(fù)制該值 |
協(xié)議標(biāo)識(shí)符(Protocol Identifier) | 2字節(jié) | 00表示是 Modbus協(xié)議,固定值 | 主站(客戶端)生成 | 應(yīng)答時(shí)從主站(客戶端)復(fù)制該值 |
長度(Lendgth) | 2字節(jié) | 從單元標(biāo)識(shí)符開始,整個(gè)PDU的數(shù)據(jù)長度,分為字節(jié)長度Hi和Lo | 請求時(shí)生成 | 應(yīng)答時(shí)重新生成 |
單元標(biāo)識(shí)符(Unit Identifier) | 1字節(jié) | 串行鏈路或其他總線上連接的遠(yuǎn)程從站的識(shí)別碼,可以設(shè)置為從機(jī)設(shè)備的地址 | 主站(客戶端)生成 | 應(yīng)答時(shí)從主站(客戶端)復(fù)制該值 |
事務(wù)處理標(biāo)識(shí)符:
事務(wù)處理標(biāo)識(shí)用于在查詢報(bào)文與未來響應(yīng)之間建立聯(lián)系。因此,對 TCP/IP 連接來說,在同一時(shí)刻這個(gè)標(biāo)識(shí)符必須是唯一的。有以下幾種使用此標(biāo)識(shí)符的方式。
例如,可以將傳輸標(biāo)識(shí)作為一個(gè)帶有計(jì)數(shù)器的簡單“TCP 發(fā)送順序號(hào)”,在每個(gè)請求發(fā)送時(shí)自動(dòng)+1;也可以用作智能索引或指針,用來識(shí)別事務(wù)處理的內(nèi)容,以便記憶當(dāng)前的遠(yuǎn)端服務(wù)器和未處理的請求。
服務(wù)器端可接收的請求數(shù)量取決于其容量,即服務(wù)器資源量和 TCP 窗口尺同樣,客戶端同時(shí)啟動(dòng)事務(wù)處理的數(shù)量也取決于客戶端的資源容量。
單元標(biāo)識(shí)符:
在對Modbus或 Modbus+等串行鏈路子網(wǎng)中的設(shè)備進(jìn)行尋址時(shí),這個(gè)域用于路由的目的。在這種情況下,單元標(biāo)識(shí)符(Unit Identifier) 攜帶一個(gè)遠(yuǎn)端設(shè)備的Modbus 從站地址。
如果 Modbus 服務(wù)器連接到 Modbus+或 Modbus 串行鏈路子網(wǎng),并通過一個(gè)網(wǎng)橋或網(wǎng)關(guān)配置這個(gè)服務(wù)器的IP 地址,則 Modbus 單元標(biāo)識(shí)符對識(shí)別連接到網(wǎng)橋或網(wǎng)關(guān)后的子網(wǎng)的從站設(shè)備是必需的。TCP 連接中的目的 IP 地址識(shí)別了網(wǎng)橋本身的地址,而網(wǎng)橋則使用 Modbus 單元標(biāo)識(shí)符將請求轉(zhuǎn)交給正確的從站設(shè)備。 分配給串行鏈路上的 Modbus 從站設(shè)備地址為 1~247(十進(jìn)制),地址0作為廣播地址。
對單純的 Modbus TCP/IP 設(shè)備來說用IP 地址即可尋址 Modbus 服務(wù)器端設(shè)備,此時(shí) Modbus 單元標(biāo)識(shí)符是無用的,必須使用值0xFF 填充。當(dāng)對直接連接到 TCP/IP 網(wǎng)絡(luò)上的 Modbus 服務(wù)器尋址時(shí),建議不要在“單元標(biāo)識(shí)符”域使用有效的Modbus從站地址。
以上是MBAP報(bào)文頭個(gè)字段含義的詳細(xì)說明。
實(shí)際上,在 Modbus TCP/IP傳輸過程中,服務(wù)端(從機(jī))返回的響應(yīng)報(bào)文中同樣包含 MBAP報(bào)頭,除了 Length 字段外,其他字段均與客戶端一致。Modbus消息由 TCP/IP 層提供,不需要像串行鏈路那樣自己判斷一幀是否結(jié)束,所有數(shù)據(jù)傳輸均由 TCP/IP層處理。因?yàn)榈讓拥?TCP/IP 確保了端到端的連接,而且 TCP/IP鏈路層已確保傳輸數(shù)據(jù)的準(zhǔn)確性,所以 Modbus TCP/IP 中已不再需要 LRC或CRC 等校驗(yàn)功能。
2. 查詢與響應(yīng)報(bào)文示例
對于Modbus TCP消息幀格式,下面舉例說明各部分的含義。
- 查詢報(bào)文:00 00 00 00 00 06 09 03 00 04 00 01。
- 0x06: 后續(xù)還有6字節(jié)。
- 0x09: 單元標(biāo)識(shí)符為9。
- 0x03: 功能碼 3,即讀保持寄存器的值。
- 0x00 0x04: Modbus起始地址4(即40005)。
- 0x00 0x01: 讀取寄存器個(gè)數(shù)為1。
- 響應(yīng)報(bào)文:00 00 00 00 00 05 09 03 02 00 05。
- 0x05:表示后續(xù)還有5字節(jié)。
- 0x09:同查詢報(bào)文,單元標(biāo)識(shí)符。
- 0x03:功能碼,同查詢報(bào)文。
- 0x02:返回?cái)?shù)據(jù)字節(jié)數(shù)。
- 0x00 0x05:寄存器的值。
可見,在Modbus TCP模式下,差錯(cuò)校驗(yàn)字段已不復(fù)存在。但在某些特殊場合,例如串行Modbus協(xié)議轉(zhuǎn)Modbus TCP的情況下,串行協(xié)議數(shù)據(jù)可以完整地裝載到Modbus TCP的數(shù)據(jù)字段,這時(shí)CRC或LRC差錯(cuò)校驗(yàn)字段仍然存在。例如,Modbus RTU Over TCP/IP 或 Modbus ASCII Over TCP/IP等。
5.5 Moubus功能碼詳解
本節(jié)大部分內(nèi)容參考《Modbus軟件開發(fā)實(shí)戰(zhàn)指南》。
5.5.1 功能碼概要
Modbus標(biāo)準(zhǔn)在協(xié)議中規(guī)定了以下3類Modbus功能碼。
- 公共功能碼:
- 被明確定義的功能碼;
- 保證唯一性;
- 由Modbus協(xié)會(huì)確認(rèn),并提供公開的文檔;
- 可進(jìn)行一致性測試;
- 包括協(xié)議定義的功能碼和保留將來使用的功能碼。
- 用戶自定義功能碼:
- 有兩個(gè)用戶自定義功能碼區(qū)域,分別是65
72和100110; - 用戶自定義,無法保證唯一性。
- 有兩個(gè)用戶自定義功能碼區(qū)域,分別是65
- 保留功能碼:
保留功能碼因?yàn)闅v史遺留原因,某些公司的傳統(tǒng)產(chǎn)品現(xiàn)行使用的功能碼不作為公共使用。
5.5.2 01(0x01)讀取線圈
1.功能說明
01功能碼用于讀取從設(shè)備的線圈或離散量輸出的狀態(tài),即各Do(Discrete Output,離散輸出)的ON/OFF狀態(tài)。消息幀中指定了需要讀取的線圈起始地址和線圈數(shù)目。需要注意的是,在Modbus協(xié)議規(guī)定的PDU中,所有線圈或寄存器地址都必須從0開始計(jì)算。
2. 查詢報(bào)文
如下表所示,查詢幀的消息中定義了從設(shè)備地址為3,并讀取從設(shè)備的Modbus地址0001900055(線圈地址0002000056)共計(jì)37個(gè)狀態(tài)值。起始線圈地址為0x13(即十進(jìn)制00019),因?yàn)榫€圈地址是從0開始計(jì)數(shù)的。
功能碼01查詢報(bào)文示例
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x03 | “0”,“3” | 0x03 |
功能碼 | 0x01 | “0”,“1” | 0x01 |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x13 | “1”,“3” | 0x13 |
寄存器數(shù)(高位) | 0x00 | “0”,“0” | 0x00 |
寄存器數(shù)(低位) | 0x25 | “2”,“5” | 0x25 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 17 | 8 |
Modbus協(xié)議規(guī)定,起始地址由2字節(jié)構(gòu)成,取值范圍為0x0000 ~ 0xFFFF: 線圈數(shù)量由2字節(jié)構(gòu)成,取值范圍為0x0001~ 0x07D0 (即+進(jìn)制1~2000)另外,注意觀察ASCII模式和RTU模式的區(qū)別,ASCII模式直接按每4位拆分成對應(yīng)的字符表示。
3. 響應(yīng)報(bào)文
**在響應(yīng)報(bào)文的數(shù)據(jù)字段中,每個(gè)線圈占用1位 (bit),狀態(tài)被表示為1=ON和O=OFF兩種類型。第1個(gè)數(shù)據(jù)字節(jié)的LSB(最低有效位)標(biāo)識(shí)查詢報(bào)文中的起始地址線圈的狀態(tài)值,其他線圈以此類推,一直到這個(gè)字節(jié)的MSB(最高有效位)為止,并在后續(xù)字節(jié)中按照同樣的方式(由低到高)排列。**
例如,下表中線圈20~27的狀態(tài)值分別是ON - ON - OFF OFF - ON - OFF - ON - OFF表示為二進(jìn)制則為01010011 (0x53),注意觀察對應(yīng)的順序。1字節(jié)可以表示8個(gè)線圈的狀態(tài)如果最后的數(shù)據(jù)字節(jié)中不能填滿8個(gè)線圈的狀態(tài),則用0填充。對應(yīng)于查詢報(bào)文中需要讀取37個(gè)線圈的狀態(tài),共需要5字節(jié)保存狀態(tài)值。
功能碼01響應(yīng)報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x03 | “0”,“3” | 0x03 |
功能碼 | 0x01 | “0”,“1” | 0x01 |
數(shù)據(jù)域字節(jié)數(shù) | 0x05 | “0”,“5” | 0x05 |
數(shù)據(jù)1 | 0x53 | “5”,“3” | 0x53 |
數(shù)據(jù)2 | 0x6B | “6”,“B” | 0x6B |
數(shù)據(jù)3 | 0x01 | “0”,“1” | 0x01 |
數(shù)據(jù)4 | 0xF4 | “F”,“B” | 0xF4 |
數(shù)據(jù)5 | 0x1B | “1”,“B” | 0x1B |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 21 | 10 |
5.5.3 02 (0x02) 讀取離散量輸入值
1. 功能說明
02功能碼用于讀取從設(shè)備的離散輸入,即DI (Discrete Input) 的ON/OFF狀態(tài)。消息頓中指定了需要讀取的離散輸入寄存器的起始地址和數(shù)目,可以讀取1 ~ 2000個(gè)連續(xù)的離散量輸入狀態(tài)如果從設(shè)備接受主設(shè)備的請求則回復(fù)功能碼02,并返回離散量且輸入各變量的當(dāng)前狀態(tài)。如果返回的離散輸入數(shù)量的個(gè)數(shù)不是8的整數(shù)倍,將用0填充最后的數(shù)據(jù)字節(jié)的剩余位。
2. 查詢報(bào)文
如下表所示,查詢頓的消息中定義了從設(shè)備的地址為3,并讀取從設(shè)備的離散輸入寄存器中地址1010110120 (Modbus地址表示為十進(jìn)制100119) 共計(jì)20個(gè)離散輸入狀態(tài)值。從下表中可以發(fā)現(xiàn),起始地址為0x64 (即十進(jìn)制100),因?yàn)橄DU中的Modbus地址從0開始計(jì)數(shù)。
功能碼02查詢報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x03 | “0”,“3” | 0x03 |
功能碼 | 0x02 | “0”,“2” | 0x02 |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x64 | “6”,“4” | 0x64 |
寄存器數(shù)(高位) | 0x00 | “0”,“0” | 0x00 |
寄存器數(shù)(低位) | 0x14 | “1”,“4” | 0x14 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 17 | 8 |
與5.4.2節(jié)中的功能碼 (01 (0x01) 讀取線圈/離散量輸出狀態(tài) (Read Coil status/DOs))一樣,本功能碼的起始地址由2字節(jié)構(gòu)成,取值范圍為0x0000 ~ 0xFFFF;離散量數(shù)量由2字節(jié)構(gòu)成,取值范圍為0x0001 0x07D0 (即十進(jìn)制1 2000),最多一次性可讀取2000人離散輸入狀態(tài)值。
3. 響應(yīng)報(bào)文
響應(yīng)報(bào)文的各項(xiàng)構(gòu)成和意義與5.4.2章節(jié)的功能碼(01(0x01)讀取線圈/離散量輸出狀態(tài)(Re-ad Coil Status/DOs))一樣,如下表所示:
功能碼02響應(yīng)報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x03 | “0”,“3” | 0x03 |
功能碼 | 0x02 | “0”,“2” | 0x02 |
數(shù)據(jù)域字節(jié)數(shù) | 0x03 | “0”,“3” | 0x03 |
數(shù)據(jù)1 | 0x53 | “5”,“3” | 0x53 |
數(shù)據(jù)2 | 0x6B | “6”,“B” | 0x6B |
數(shù)據(jù)3 | 0x01 | “0”,“1” | 0x01 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 21 | 10 |
5.5.4 03(0x03)讀取保持寄存器值
1. 功能說明
03功能碼用于讀取從設(shè)備保持寄存器的內(nèi)容,不支持廣播模式。消息頓中指定了需要讀取的保持寄存器的起始地址和數(shù)目。而保持寄存器中各地址的具體內(nèi)容和意義則由設(shè)備開發(fā)者自行規(guī)定。
2. 查詢報(bào)文
在查詢報(bào)文中,必須指定保持寄存器的開始地址和需要讀取的寄存器數(shù)量,例如,如下表所示,從設(shè)備地址為7 (0x07),需要讀取保持寄存器地址40201 ~ 40203共計(jì)3個(gè)寄存器的內(nèi)容即讀取Modbus協(xié)議地址200~ 202的內(nèi)容,在報(bào)文中表示如下。
起始地址: 0x00C8 (十進(jìn)制200)。
讀取數(shù)量: 0x0003 (十進(jìn)制3)。
功能碼03查詢報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x07 | “0”,“7” | 0x07 |
功能碼 | 0x03 | “0”,“3” | 0x03 |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0xC8 | “C”,“8” | 0xC8 |
寄存器數(shù)(高位) | 0x00 | “0”,“0” | 0x00 |
寄存器數(shù)(低位) | 0x03 | “0”,“3” | 0x03 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 17 | 8 |
本功能碼的起始地址由2字節(jié)構(gòu)成,取值范圍為0x00000xFFFF;寄存器數(shù)量由2字節(jié)構(gòu)成取值范圍為0x00010x007D (即十進(jìn)制1~125) ,即最多可以連續(xù)讀取125個(gè)寄存器。
需要特別注意的是,Modbus的保持寄存器和輸入寄存器是以字 (Word) 為基本單位的(1Word=2Byte),所以如果讀取保持寄存器地址為40001開始的一個(gè)16位 (bit) 的無符號(hào)數(shù),那么返回2字節(jié),并可以從40002開始讀取下一個(gè)16位的無符號(hào)數(shù)。如果需要讀取寄存器地址為40001開始的一個(gè)32位浮點(diǎn)數(shù),則需要返回4字節(jié),即必須連續(xù)讀取40001和40002的內(nèi)容,而且下一個(gè)32位的浮點(diǎn)數(shù)必須從40003開始讀取。對于浮點(diǎn)數(shù)(或者32位的整數(shù))而言,連續(xù)讀取的兩個(gè)寄存器之間存在字節(jié)序和大小端的問題,這一點(diǎn)在開發(fā)時(shí)必須引起注意。
3. 響應(yīng)報(bào)文
響應(yīng)報(bào)文的各項(xiàng)構(gòu)成和意義如下表所示。因?yàn)镸odbus的保持寄存器和輸入寄存器是以字為基本單位的,在上面的例子中,查詢報(bào)文連續(xù)讀取3個(gè)寄存器的內(nèi)容,將返回6字節(jié),參考表下表中數(shù)據(jù)1~3的高位和低位。
功能碼03響應(yīng)報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x07 | “0”,“7” | 0x07 |
功能碼 | 0x03 | “0”,“3” | 0x03 |
數(shù)據(jù)域字節(jié)數(shù) | 0x06 | “0”,“6” | 0x06 |
數(shù)據(jù)1(高位) | 0x03 | “0”,“3” | 0x03 |
數(shù)據(jù)1(低位) | 0x53 | “5”,“3” | 0x53 |
數(shù)據(jù)2(高位) | 0x01 | “0”,“1” | 0x01 |
數(shù)據(jù)2(低位) | 0xF3 | “F”,“3” | 0xF3 |
數(shù)據(jù)3(高位) | 0x01 | “0”,“1” | 0x01 |
數(shù)據(jù)3(低位) | 0x05 | “0”,“5” | 0x05 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 23 | 11 |
5.5.5 04 (0x04)讀取輸入寄存器值
1.功能說明
與功能碼03類似,04功能碼用于讀取從設(shè)備輸入寄存器的內(nèi)容,不支持廣播模式。消息頓中指定了需要讀取的輸入寄存器的起始地址和數(shù)目,而輸入寄存器中各地址的具體內(nèi)容和意義則由設(shè)備開發(fā)者自行規(guī)定。
2.查詢報(bào)文
在查詢報(bào)文中必須指定輸入寄存器的起始地址和需要讀取的寄存器數(shù)量。例如,如表4-9所示,從設(shè)備地址為7 (0x07),需要讀取輸入寄存器地址30301 ~ 30303共計(jì)3個(gè)寄存器的內(nèi)容即讀取Modbus協(xié)議地址300 ~302的內(nèi)容,在報(bào)文中表示如下。
起始地址: 0x012C (十進(jìn)制300) 。
讀取數(shù)量: 0x0003 (十進(jìn)制3)。
功能碼04查詢報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x07 | “0”,“7” | 0x07 |
功能碼 | 0x04 | “0”,“4” | 0x04 |
起始地址(高位) | 0x01 | “0”,“1” | 0x01 |
起始地址(低位) | 0x2C | “2”,“C” | 0x2C |
寄存器數(shù)(高位) | 0x00 | “0”,“0” | 0x00 |
寄存器數(shù)(低位) | 0x03 | “0”,“3” | 0x03 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 17 | 8 |
本功能碼中,起始地址由2字節(jié)構(gòu)成,取值范圍為0x0000 ~ 0xFFFF;寄存器數(shù)量由2字節(jié)構(gòu)成,取值范圍為0x0001 0x007D (即十進(jìn)制1125) ,即最多可以連續(xù)讀取125個(gè)寄存器同樣有一點(diǎn)需要注意,Modbus的保持寄存器和輸入寄存器是以字為基本單位的。所以對于浮點(diǎn)數(shù)(或者32位的整數(shù))而言,連續(xù)讀取的兩個(gè)寄存器之間存在字節(jié)序和大小端的問題,這一點(diǎn)在開發(fā)時(shí)必須引起注意。
3.響應(yīng)報(bào)文
響應(yīng)報(bào)文的各項(xiàng)構(gòu)成和意義如下表所示。因?yàn)镸odbus的保持寄存器和輸入寄存器是以字為基本單位的,上面的例子中,查詢報(bào)文連續(xù)讀取3個(gè)寄存器的內(nèi)容,那么將返回6字節(jié),參考下表中數(shù)據(jù)1~3的高位和低位。
功能碼04響應(yīng)報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x07 | “0”,“7” | 0x07 |
功能碼 | 0x04 | “0”,“4” | 0x04 |
數(shù)據(jù)域字節(jié)數(shù) | 0x06 | “0”,“6” | 0x06 |
數(shù)據(jù)1(高位) | 0x03 | “0”,“3” | 0x03 |
數(shù)據(jù)1(低位) | 0x53 | “5”,“3” | 0x53 |
數(shù)據(jù)2(高位) | 0x01 | “0”,“1” | 0x01 |
數(shù)據(jù)2(低位) | 0xF3 | “F”,“3” | 0xF3 |
數(shù)據(jù)3(高位) | 0x01 | “0”,“1” | 0x01 |
數(shù)據(jù)3(低位) | 0x05 | “0”,“5” | 0x05 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 23 | 11 |
5.5.6 05 (0x05)寫單個(gè)線圈
1. 功能說明
05功能碼用于將單個(gè)線圈寄存器 (或離散輸入)設(shè)置為ON或OFF,該功能碼支持廣播模式在廣播模式下,所有從站設(shè)備的同一地址的值將被統(tǒng)一修改。查詢報(bào)文中的ON/OFF狀態(tài)由報(bào)文數(shù)據(jù)字段的常數(shù)指定,0xFF00表示ON狀態(tài),0x0000表示OFF狀態(tài)。其他值均是非法的,并且對寄存器不起作用,將會(huì)返回異常響應(yīng)。
2. 查詢報(bào)文
查詢報(bào)文中需要指定從設(shè)備地址以及需要變更的線圈地址和設(shè)定的狀態(tài)值。需要注意的是,在查詢報(bào)文中,線圈地址從地址0開始計(jì)數(shù)。例如,如下表所示,從設(shè)備地址為3,設(shè)置線圈地址00150為ON狀態(tài),則查詢報(bào)文中的線圈地址設(shè)置為0x95 (149)。
功能碼05查詢報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x03 | “0”,“3” | 0x03 |
功能碼 | 0x05 | “0”,“5” | 0x05 |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x95 | “9”,“5” | 0x95 |
變更數(shù)據(jù)(高位) | 0xFF | “F”,“F” | 0xFF |
變更數(shù)據(jù)(低位) | 0x00 | “0”,“0” | 0x00 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 17 | 8 |
本功能碼中,起始地址由2字節(jié)構(gòu)成,取值范圍為0x0000~0xFFFF:變更目標(biāo)數(shù)據(jù)由2字節(jié)構(gòu)成,取值只能為0xFF00或0x0000。
3.響應(yīng)報(bào)文
響應(yīng)報(bào)文的各項(xiàng)構(gòu)成和意義如下表所示。對于從設(shè)備,在線圈或離散輸出寄存器正常變更的情況下會(huì)返回與查詢報(bào)文相同的響應(yīng)報(bào)文。如果修改失敗,則會(huì)返回一個(gè)異常響應(yīng),對于異常響應(yīng),后續(xù)章節(jié)會(huì)進(jìn)一步詳細(xì)介紹。
功能碼05響應(yīng)報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x03 | “0”,“3” | 0x03 |
功能碼 | 0x05 | “0”,“5” | 0x05 |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x95 | “9”,“5” | 0x95 |
變更數(shù)據(jù)(高位) | 0xFF | “F”,“F” | 0xFF |
變更數(shù)據(jù)(低位) | 0x00 | “0”,“0” | 0x00 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 17 | 8 |
5.5.7 06 (0x06) 寫單個(gè)保持寄存器
1.功能說明
06功能碼用于更新從設(shè)備的單個(gè)保持寄存器的值,該功能碼支持廣播模式,在廣播模式下所有從設(shè)備的同一地址的值將被統(tǒng)一修改。
2. 查詢報(bào)文
查詢報(bào)文中需要指定從設(shè)備地址以及需要變更的保持寄存器地址和設(shè)定的值。需要注意的是查詢報(bào)文中,寄存器地址從地址0開始計(jì)數(shù)。例如,如下表所示,從設(shè)備地址為3,設(shè)置寄存器地址40150為1200 (即0x04B0) ,則查詢報(bào)文中的地址字段設(shè)置為0x95 (149)。
功能碼06查詢報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x03 | “0”,“3” | 0x03 |
功能碼 | 0x06 | “0”,“6” | 0x06 |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x95 | “9”,“5” | 0x95 |
變更數(shù)據(jù)(高位) | 0x04 | “0”,“4” | 0x04 |
變更數(shù)據(jù)(低位) | 0xB0 | “B”,“0” | 0xB0 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 17 | 8 |
本功能碼中,起始地址由2字節(jié)構(gòu)成,取值范圍為0x00000xFFFF; 變更目標(biāo)數(shù)據(jù)由2字節(jié)構(gòu)成,取值范圍為0x00000xFFFF。
3.響應(yīng)報(bào)文
響應(yīng)報(bào)文的各項(xiàng)構(gòu)成和意義,如下表所示。對于從設(shè)備,在保持寄存器正常變更的情況下會(huì)返回與查詢報(bào)文相同的響應(yīng)報(bào)文。如果修改失敗,則返回個(gè)異常響應(yīng)。
功能碼06響應(yīng)報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x03 | “0”,“3” | 0x03 |
功能碼 | 0x06 | “0”,“6” | 0x06 |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x95 | “9”,“5” | 0x95 |
變更數(shù)據(jù)(高位) | 0x04 | “0”,“4” | 0x04 |
變更數(shù)據(jù)(低位) | 0xB0 | “B”,“0” | 0xB0 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 17 | 8 |
5.5.8 08 (0x08) 診斷功能
1.功能說明
08功能碼僅用于串行鏈路,主要用于檢測主設(shè)備和從設(shè)備之間的通信故障,或檢測從設(shè)備的各種內(nèi)部故障,該功能碼不支持廣播。為了區(qū)別各診斷類型,查詢報(bào)文中提供了2字節(jié)的子功能碼字段。
通常在正常的響應(yīng)報(bào)文中,從設(shè)備將原樣回復(fù)功能碼和子功能碼.
2. 查詢報(bào)文
查詢報(bào)文中需要指定從設(shè)備地址、功能碼以及子功能碼。
例如,下表中標(biāo)識(shí)了子功能碼“原樣返回查詢數(shù)據(jù)”的診斷功能,其中子功能碼為0(0x0000)。在子功能碼為0x0000的情況下,數(shù)據(jù)字段可以為任意值。各子功能碼的詳細(xì)意義可參考下表。
功能碼08查詢報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x05 | “0”,“5” | 0x05 |
功能碼 | 0x08 | “0”,“8” | 0x08 |
子功能碼(高位) | 0x00 | “0”,“0” | 0x00 |
子功能碼(低位) | 0x00 | “0”,“0” | 0x00 |
數(shù)據(jù)(高位) | 0x04 | “0”,“4” | 0x04 |
數(shù)據(jù)(低位) | 0xB0 | “B”,“0” | 0xB0 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 17 | 8 |
本功能碼中,子功能碼由2字節(jié)構(gòu)成,取值則根據(jù)意義而不同;數(shù)據(jù)字段由2字節(jié)構(gòu)成,其取值由子功能碼確定。
3.響應(yīng)報(bào)文
響應(yīng)報(bào)文的各項(xiàng)構(gòu)成和意義如下表所示。對于從設(shè)備,在保持寄存器正常變更的情況下會(huì)返回與查詢報(bào)文相同的響應(yīng)報(bào)文。如果修改失敗,則返回一個(gè)異常響應(yīng)。
功能碼08響應(yīng)報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x05 | “0”,“5” | 0x05 |
功能碼 | 0x08 | “0”,“8” | 0x08 |
子功能碼(高位) | 0x00 | “0”,“0” | 0x00 |
子功能碼(低位) | 0x00 | “0”,“0” | 0x00 |
數(shù)據(jù)(高位) | 0x04 | “0”,“4” | 0x04 |
數(shù)據(jù)(低位) | 0xB0 | “B”,“0” | 0xB0 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 17 | 8 |
4. 診斷子功能碼
各常用的診斷子功能碼的定義如下。
Return Query Data(00)
診斷內(nèi)容 | 原樣返回查詢報(bào)文 |
---|---|
子功能碼 | 0x00,0x00 |
查詢報(bào)文數(shù)據(jù)字段 | 任意16位數(shù)據(jù) |
響應(yīng)報(bào)文數(shù)據(jù)字段 | 同查詢報(bào)文 |
Restart Communication Option(01)
診斷內(nèi)容 | 重啟通信選項(xiàng); 用于初始化并重新啟動(dòng)從站設(shè)備,清楚所有通信事件計(jì)數(shù)器; 如果端口處于 Listen Only Mode,則不返回響應(yīng);否則在重啟之前返回響應(yīng) |
---|---|
子功能碼 | 0x00,0x01 |
查詢報(bào)文數(shù)據(jù)字段 | 0x00, 0x00 保持事件記錄; 0xFF,0x00 清除事件記錄 |
響應(yīng)報(bào)文數(shù)據(jù)字段 | 同查詢報(bào)文 |
Return Diagnostics Register(02)
診斷內(nèi)容 | 返回診斷寄存器 |
---|---|
子功能碼 | 0x00,0x04 |
查詢報(bào)文數(shù)據(jù)字段 | 0x00,0x00 |
響應(yīng)報(bào)文數(shù)據(jù)字段 | 診斷寄存器的內(nèi)容 |
Force Listen Only Mode
診斷內(nèi)容 | 強(qiáng)制只聽模式; 強(qiáng)制被尋址的從站設(shè)備進(jìn)入只聽模式,使得此設(shè)備與網(wǎng)絡(luò)中的其他設(shè)備斷開,不返回響應(yīng) |
---|---|
子功能碼 | 0x00,0x04 |
查詢報(bào)文數(shù)據(jù)字段 | 0x00,0x00 |
響應(yīng)報(bào)文數(shù)據(jù)字段 | 不返回響應(yīng) |
Clear Counters and Diagnostic Register
診斷內(nèi)容 | 清除計(jì)數(shù)器和診斷寄存器 |
---|---|
子功能碼 | 0x00,0x0A |
查詢報(bào)文數(shù)據(jù)字段 | 0x00,0x00 |
響應(yīng)報(bào)文數(shù)據(jù)字段 | 同查詢報(bào)文 |
Return Bus Message Count(11,0x0B)
診斷內(nèi)容 | 返回總線報(bào)文計(jì)數(shù) |
---|---|
子功能碼 | 0x00,0x0B |
查詢報(bào)文數(shù)據(jù)字段 | 0x00,0x00 |
響應(yīng)報(bào)文數(shù)據(jù)字段 | 返回報(bào)文的技數(shù)值 |
Return Bus Communication Error Count(12,0x0C)
診斷內(nèi)容 | 返回總線通信CRC差錯(cuò)計(jì)數(shù) |
---|---|
子功能碼 | 0x00,0x0C |
查詢報(bào)文數(shù)據(jù)字段 | 0x00,0x00 |
響應(yīng)報(bào)文數(shù)據(jù)字段 | 返回報(bào)文的CRC出錯(cuò)總數(shù) |
Return Bus Exception Error Count(13,0x0D)
診斷內(nèi)容 | 返回總線異常差錯(cuò)計(jì)數(shù) |
---|---|
子功能碼 | 0x00,0x0D |
查詢報(bào)文數(shù)據(jù)字段 | 0x00,0x00 |
響應(yīng)報(bào)文數(shù)據(jù)字段 | 返回異常響應(yīng)的總數(shù) |
Return Slave Message Count(14,0x0E)
診斷內(nèi)容 | 返回從站設(shè)備報(bào)文總數(shù) |
---|---|
子功能碼 | 0x00,0x0E |
查詢報(bào)文數(shù)據(jù)字段 | 0x00,0x00 |
響應(yīng)報(bào)文數(shù)據(jù)字段 | 返回從站設(shè)備接收報(bào)文總數(shù) |
Return Slave No Response Counrt(15,0x0F)
診斷內(nèi)容 | 返回從站設(shè)備無響應(yīng)計(jì)數(shù) |
---|---|
子功能碼 | 0x00,0x0F |
查詢報(bào)文數(shù)據(jù)字段 | 0x00,0x00 |
響應(yīng)報(bào)文數(shù)據(jù)字段 | 返回加電后沒有返回響應(yīng)的報(bào)文的保文數(shù)量 |
Return Slave Busy Count(17,0x11)
診斷內(nèi)容 | 返回從站設(shè)備忙計(jì)數(shù) |
---|---|
子功能碼 | 0x00,0x11 |
查詢報(bào)文數(shù)據(jù)字段 | 0x00,0x00 |
響應(yīng)報(bào)文數(shù)據(jù)字段 | 返回加電后異常響應(yīng)忙的報(bào)文數(shù)量 |
Return Bus Character Overrun Count(18,0x12)
診斷內(nèi)容 | 返回總線字符超限計(jì)數(shù) |
---|---|
子功能碼 | 0x00,0x12 |
查詢報(bào)文數(shù)據(jù)字段 | 0x00,0x00 |
響應(yīng)報(bào)文數(shù)據(jù)字段 | 返回超限的報(bào)文數(shù)量 |
5.5.9 11 (0x0B) 獲取通信事件計(jì)數(shù)器
1. 功能說明
11功能碼主要用于獲取從設(shè)備通信計(jì)數(shù)器中的狀態(tài)字和事件計(jì)數(shù)的值,本功能碼不支持廣播模式。通過在通信報(bào)文之前和之后讀取通信事件計(jì)數(shù)值,可以確定從設(shè)備是否正常處理報(bào)文。
對于正常完成報(bào)文處理和傳輸?shù)膱龊希录?jì)數(shù)器增加1;而對于異常響應(yīng)、輪詢命令或讀事件計(jì)數(shù)器(即Ox0B功能碼)的場合,則計(jì)數(shù)器不變。通過【0x08診斷功能】 中的子功能碼【Restart Communication Option ( 0x0001 )】 和 【Clear Counters and Diagnostic Register (0x000A) 】 可以復(fù)位事件寄存器。
2. 查詢報(bào)文
下表中的示例表示獲取通信事件計(jì)數(shù)器的查詢報(bào)文內(nèi)容,其中從站設(shè)備地址為5.
功能碼11查詢報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x05 | “0”,“5” | 0x05 |
功能碼 | 0x0B | “0”,“B” | 0x0B |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 9 | 4 |
3. 響應(yīng)報(bào)文
對于從設(shè)備,在正常情況下,響應(yīng)報(bào)文返回2字節(jié)的狀態(tài)字和2字節(jié)的事件計(jì)數(shù)。其中,如果從站設(shè)備處于忙狀態(tài),那么狀態(tài)字為0xFFFF,否則狀態(tài)字為0x0000。在表4-18的示例中,狀態(tài)字為0x0000,表示從站設(shè)備外于空閑狀態(tài)。事件計(jì)數(shù)的值為0x03E8,表示記錄了1000 (0x03E8)個(gè)事件。
功能碼11響應(yīng)報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x05 | “0”,“5” | 0x05 |
功能碼 | 0x0B | “0”,“B” | 0x0B |
子功能碼(高位) | 0x00 | “0”,“0” | 0x00 |
子功能碼(低位) | 0x00 | “0”,“0” | 0x00 |
數(shù)據(jù)(高位) | 0x03 | “0”,“3” | 0x03 |
數(shù)據(jù)(低位) | 0xE8 | “E”,“8” | 0xB8 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 17 | 8 |
5.5.10 12 (0x0C) 獲取通信事件記錄
1. 功能說明
12功能碼主要用于從從設(shè)備獲取狀態(tài)字、事件計(jì)數(shù)、報(bào)文計(jì)數(shù)以及事件字節(jié)字段。其中,狀態(tài)字和事件計(jì)數(shù)與功能碼11 (0x0B) 獲取的值一致。報(bào)文計(jì)數(shù)包含加電重啟、清除計(jì)數(shù)器之后的報(bào)文數(shù)量,報(bào)文計(jì)數(shù)與通過診斷功能碼08 (0x08)、子功能碼11 (0x0B) 獲取的值一致。事件字節(jié)字段包含0~64字節(jié),用來定義各種事件。
2. 查詢報(bào)文
下表中的示例表示獲取通信事件記錄的查詢報(bào)文內(nèi)容,其中從站地址位5。
功能碼12查詢報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x05 | “0”,“5” | 0x05 |
功能碼 | 0x0C | “0”,“C” | 0x0C |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 9 | 4 |
3. 響應(yīng)報(bào)文
對于從站設(shè)備,在正常情況下,響應(yīng)報(bào)文包括一個(gè)2字節(jié)的狀態(tài)字字段、一個(gè)2字節(jié)的事件計(jì)數(shù)字段、一個(gè)2字節(jié)的消息計(jì)數(shù)字段以及0~ 64字節(jié)的事件字段。因?yàn)槭录侄问亲冮L的,所以增加了一個(gè)1字節(jié)的數(shù)據(jù)長度字段,以方便讀取響應(yīng)數(shù)據(jù),如下表所示;
功能碼12響應(yīng)報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x05 | “0”,“5” | 0x05 |
功能碼 | 0x0C | “0”,“C” | 0x0C |
字節(jié)數(shù) | 0x08 | “0”,“8” | 0x08 |
狀態(tài)字(高位) | 0x00 | “0”,“0” | 0x00 |
狀態(tài)字(低位) | 0x00 | “0”,“0” | 0x00 |
事件計(jì)數(shù)(高位) | 0x03 | “0”,“3” | 0x03 |
事件計(jì)數(shù)(低位) | 0xE8 | “E”,“8” | 0xE8 |
消息計(jì)數(shù)(高位) | 0x01 | “0”,“1” | 0x01 |
消息計(jì)數(shù)(低位) | 0xF6 | ”F“,”6“ | 0xF6 |
事件0 | 0x20 | ”2“,”0“ | 0x20 |
事件1 | 0x00 | ”0“,”0“ | 0x00 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 17 | 8 |
5.5.11 15(0x0F)寫多個(gè)線圈
1.功能說明
15功能碼用于將連續(xù)的多個(gè)線圈或離散輸出設(shè)置為ON/OFF狀態(tài),支持廣播模式,在廣播模式下,所有從站設(shè)備的同一地址的值將被統(tǒng)一修改。15功能碼中,起始地址字段由2字節(jié)構(gòu)成,取值范圍為0x00000xFFFF:而寄存器數(shù)量字段由2字節(jié)構(gòu)成,取值范用為0x00010x07B0.
2. 查詢報(bào)文
查詢報(bào)文中包含請求數(shù)據(jù)字段,用于定義ON或OFF狀態(tài)。數(shù)據(jù)字段中為邏輯1的位對應(yīng)ON;邏輯0的位對應(yīng)OFF。其中,ON/OFF與數(shù)據(jù)字段的對應(yīng)關(guān)系可參考前面的童節(jié)“01 (0x01) 讀取線圈,離散量輸出狀態(tài) (Read Coil status/DOs)” 中的內(nèi)容舉例說明,假設(shè)從站設(shè)備地址為5,需要設(shè)置線圈地址20 ~30的狀態(tài)如下表所示。
線圈狀態(tài):
值 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
線圈 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | — | — | — | — | — | 30 | 29 | 28 |
那么,寫入的數(shù)據(jù)字段被劃分為2字節(jié),值分別為0xD1,對應(yīng)于27 ~ 20的線圈,值0x05對應(yīng)于30~28的線圈,注意細(xì)體會(huì)其中的高低位的對應(yīng)關(guān)系。需要注意的是,在查詢報(bào)文中,Modbus協(xié)議的起始地址為19 (0x13) ,即比線圈起始地址20少1。如下表所示,其中字節(jié)數(shù)字段表示需要變更數(shù)據(jù)的字節(jié)總數(shù)。
功能碼15查詢報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x05 | “0”,“5” | 0x05 |
功能碼 | 0x0F | “0”,“F” | 0x0F |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x13 | “1”,“3” | 0x13 |
寄存器數(shù)(高位) | 0x00 | “0”,“0” | 0x00 |
寄存器數(shù)(低位) | 0x0B | “0”,“B” | 0x08 |
字節(jié)數(shù) | 0x02 | “0”,“2” | 0x02 |
變更數(shù)據(jù)(高位) | 0xD1 | ”D“,”1“ | 0xD1 |
變更數(shù)據(jù)(低位) | 0x05 | ”0“,”5“ | 0x05 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 23 | 11 |
3. 響應(yīng)報(bào)文
對于從設(shè)備,在正常情況下,響應(yīng)報(bào)文包括功能碼、起始地址以及寫入的線圈數(shù)量,如下表所示。
功能碼15響應(yīng)報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x05 | “0”,“5” | 0x05 |
功能碼 | 0x0F | “0”,“F” | 0x0F |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x13 | “1”,“3” | 0x13 |
寄存器數(shù)(高位) | 0x00 | “0”,“0” | 0x00 |
寄存器數(shù)(低位) | 0x0B | “0”,“B” | 0x08 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 17 | 8 |
5.5.12 16 (0x10) 寫多個(gè)保持寄存器
1. 功能說明
16功能碼用于設(shè)置或?qū)懭霃脑O(shè)備保持寄存器的多個(gè)連續(xù)的地址塊 (1 ~ 123個(gè)寄存器),支持廣播模式,在廣播模式下,所有從站設(shè)備的同一地址的值將被統(tǒng)一修改。本功能碼中,起始地址字段由2字節(jié)構(gòu)成,取值范圍為0x0000 ~ 0xFFFF;而寄存器數(shù)量字段由2字節(jié)構(gòu)成,取值范圍為0x0001~0x007B。
2. 查詢報(bào)文
查詢報(bào)文包含請求數(shù)據(jù)字段。數(shù)據(jù)字段保存需要寫入的數(shù)值,各數(shù)據(jù)按每個(gè)寄存器2字節(jié)存放。舉例說明,從站設(shè)備地址為5,需要將保持寄存器地址40020 ~ 40022設(shè)置為如下表所示的數(shù)值。
寄存器的設(shè)置:
寄存器地址 | 設(shè)定值 | 寄存器地址 | 設(shè)定值 |
---|---|---|---|
40020 | 0x0155 | 40022 | 0x0157 |
40021 | 0x0156 |
對應(yīng)于40020~40022的寄存器,注意仔細(xì)體會(huì)其中的高低位的對應(yīng)關(guān)系。需要注意的是,在查詢報(bào)文中,Modbus協(xié)議的起始地址為19 (0x13),即比寄存器起始地址20少1。如下表所示,其中字節(jié)數(shù)字段表示需要變更數(shù)據(jù)的字節(jié)總數(shù)。
功能碼16查詢報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x05 | “0”,“5” | 0x05 |
功能碼 | 0x10 | “0”,“F” | 0x0F |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x13 | “1”,“3” | 0x13 |
寄存器數(shù)(高位) | 0x00 | “0”,“0” | 0x00 |
寄存器數(shù)(低位) | 0x03 | “0”,“B” | 0x08 |
字節(jié)數(shù) | 0x06 | ”0“,”6“ | 0x06 |
變更數(shù)據(jù)1(高位) | 0x01 | ”0“,”1“ | 0x01 |
變更數(shù)據(jù)1(低位) | 0x55 | ”5“,”5“ | 0x56 |
變更數(shù)據(jù)2(高位) | 0x01 | ”0“,”1“ | 0x01 |
變更數(shù)據(jù)2(低位) | 0x56 | ”5“,”6“ | 0x56 |
變更數(shù)據(jù)3(高位) | 0x01 | ”0“,”1“ | 0x01 |
變更數(shù)據(jù)3(低位) | 0x57 | ”5“,”7“ | 0x57 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 31 | 15 |
3. 響應(yīng)報(bào)文
對于從設(shè)備,在正常情況下,響應(yīng)報(bào)文包括功能碼、起始地址及寫入的寄存器數(shù)量,如下表所示。
功能碼16響應(yīng)報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x05 | “0”,“5” | 0x05 |
功能碼 | 0x10 | “1”,“0” | 0x10 |
起始地址(高位) | 0x00 | “0”,“0” | 0x00 |
起始地址(低位) | 0x13 | “1”,“3” | 0x13 |
寄存器數(shù)(高位) | 0x00 | “0”,“0” | 0x00 |
寄存器數(shù)(低位) | 0x03 | “0”,“3” | 0x03 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 17 | 8 |
在實(shí)際開發(fā)過程中,功能碼“16 (0x10) 寫多個(gè)寄存器 (Preset Multiple Registers) ”通常用于方便用戶寫入多字節(jié)類型的數(shù)據(jù)。
例如,假設(shè)從站設(shè)備地址為5,需要向保持寄存器寫入一個(gè)32位 (4字節(jié)) 的浮點(diǎn)數(shù),那么此浮點(diǎn)數(shù)將占用2個(gè)寄存器地址。假設(shè)浮點(diǎn)數(shù)將存放在40001和40002寄存器中,設(shè)定值為1.235(即0x3F9E 147A)實(shí)際的查詢和響應(yīng)報(bào)文如下(其中標(biāo)記部分為設(shè)定的浮點(diǎn)數(shù)值,假設(shè)字節(jié)序?yàn)锳B-CD,參考第5.3.7章字節(jié)序和大小端的內(nèi)容)。
查詢報(bào)文: 05 10 00 00 00 02 04 3F 9E 14 7A 05 86
響應(yīng)報(bào)文: 05 10 00 00 00 02 40 4C
對于64位(8字節(jié))的雙精度浮點(diǎn)數(shù),同理將占用4個(gè)寄存器地址共8字節(jié)的空間。特別需要注意的是字節(jié)序及大小端的問題,前面討論過多字節(jié)存在大小端問題,因此主站設(shè)備和從站設(shè)備必須保持一致的規(guī)則處理,約定Modbus傳輸中的數(shù)據(jù)字段的字節(jié)序,否則會(huì)因?yàn)榇笮《瞬灰恢露a(chǎn)生數(shù)據(jù)處理錯(cuò)誤。
5.5.13 17 (0x11) 報(bào)告從站ID (僅用于串行鏈路)
1. 功能說明
17功能碼用于讀取從站設(shè)備的ID、類型描述、當(dāng)前狀態(tài)以及其他信息,不支持廣播模式。響應(yīng)消息的構(gòu)成依賴于設(shè)備而不盡相同。
2. 查詢報(bào)文
查詢報(bào)文中不包含請求數(shù)據(jù)字段。舉例說明,從站設(shè)備地址為5,獲取相關(guān)信息,如下表所示。
功能碼17查詢報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x05 | “0”,“5” | 0x05 |
功能碼 | 0x11 | “1”,“1” | 0x11 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 9 | 4 |
3. 響應(yīng)報(bào)文
**對于從設(shè)備,在正常情況下,響應(yīng)報(bào)文包括從站ID、運(yùn)行狀態(tài)以及其他附加信息,如下表所示。運(yùn)行狀態(tài)字段占用1字節(jié),且0x00=OFF,0xFF=ON,而響應(yīng)報(bào)文的組成則由開發(fā)者決定。**
功能碼17響應(yīng)報(bào)文示例:
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x05 | “0”,“5” | 0x05 |
功能碼 | 0x11 | “1”,“1” | 0x11 |
字節(jié)數(shù) | 設(shè)備相關(guān) | 設(shè)備相關(guān) | 設(shè)備相關(guān) |
從設(shè)備ID | 設(shè)備相關(guān) | 設(shè)備相關(guān) | 設(shè)備相關(guān) |
運(yùn)行狀態(tài) | 0xFF | “F”,“F” | 0xFF |
附加情報(bào)1 | 設(shè)備相關(guān) | 設(shè)備相關(guān) | 設(shè)備相關(guān) |
…… | 設(shè)備相關(guān) | 設(shè)備相關(guān) | 設(shè)備相關(guān) |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 17 | 8 |
5.5.14 Modbus異常響應(yīng)
以上介紹了一些常見的公共功能碼的報(bào)文 (消息頓)構(gòu)成,廣播模式以外的查詢報(bào)文都希望能夠獲取一個(gè)正常的響應(yīng)報(bào)文。在通常情況下,從站設(shè)備將返回一個(gè)正常響應(yīng)報(bào)文,但是在某些特殊情況下將返回異常響應(yīng)報(bào)文。
對于查詢報(bào)文,存在以下4種處理反饋:
- 正常接收,正常處理,返回正常響應(yīng)報(bào)文;
- 因?yàn)橥ㄐ佩e(cuò)誤等原因造成從站設(shè)備沒有接收到查詢報(bào)文,主站設(shè)備將按超時(shí)處理:從站設(shè)備接收到的查詢報(bào)文存在通信錯(cuò)誤 (如LRC、CRC錯(cuò)誤等),此時(shí)從站設(shè)備將丟棄報(bào)文不響應(yīng),主站設(shè)備將按超時(shí)處理;
- 從站設(shè)備接收到正確的報(bào)文,但是超過處理范圍(如不存在的功能碼或者寄存器等),此時(shí)從站設(shè)備將返回包含異常碼 (Exception Code) 的響應(yīng)報(bào)文。
- 異常響應(yīng)報(bào)文由從站地址、功能碼以及異常碼構(gòu)成。其中,功能碼與正常響應(yīng)報(bào)文不同,在異常響應(yīng)報(bào)文中,功能碼最高位 (即MSB) 被設(shè)置為1。因?yàn)镸odbus協(xié)議中的功能碼占用1字節(jié)故用表達(dá)式描述為:
異常功能碼=正常功能碼+0x80
舉例說明,如下表所示,查詢報(bào)文的起始地址為0x012C (十進(jìn)制300) ,即需要讀取寄存器地址為30301開始的值。若從站設(shè)備中不存在輸入寄存器30301,則從站設(shè)備將返回一個(gè)異常響應(yīng)報(bào)文,參見下表的功能碼和異常碼。
異常響應(yīng)示例(功能碼04查詢報(bào)文 ):
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x07 | “0”,“7” | 0x07 |
功能碼 | 0x04 | “0”,“4” | 0x04 |
起始地址(高位) | 0x01 | “0”,“1” | 0x01 |
起始地址(低位) | 0x2C | “2”,“C” | 0x2C |
寄存器數(shù)(高位) | 0x00 | “0”,“0” | 0x00 |
寄存器數(shù)(低位) | 0x03 | “0”,“3” | 0x03 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 17 | 8 |
異常響應(yīng)示例(功能碼04響應(yīng)報(bào)文 ) :
字段 | 例(Hex) | ASCII模式字符型 | RTU模式8位(Hex) |
---|---|---|---|
幀頭 | “:” | ||
從設(shè)備地址 | 0x07 | “0”,“7” | 0x07 |
功能碼 | 0x84 | “8”,“4” | 0x84 |
異常碼 | 0x02 | “0”,“2” | 0x02 |
差錯(cuò)校驗(yàn) | LRC(2字符) | CRC(2字節(jié)) | |
幀尾 | CR/LF | ||
合計(jì)字節(jié)數(shù) | 11 | 5 |
常見的異常碼如下表所示:
常見異常碼說明:
異常碼 | 名稱 | 說明 |
---|---|---|
01 | 非法功能碼 | 從站設(shè)備不支持此功能碼 |
02 | 非法數(shù)據(jù)地址 | 指定的數(shù)據(jù)地址在從站設(shè)備中不存在 |
03 | 非法數(shù)據(jù)值 | 指定的數(shù)據(jù)超過范圍或者不允許使用 |
04 | 從站設(shè)備故障 | 從站設(shè)備處理響應(yīng)的過程中出現(xiàn)未知錯(cuò)誤等 |
-
寄存器
+關(guān)注
關(guān)注
31文章
5250瀏覽量
119195 -
MODBUS
+關(guān)注
關(guān)注
28文章
1718瀏覽量
76415 -
通訊協(xié)議
+關(guān)注
關(guān)注
10文章
263瀏覽量
20271
發(fā)布評論請先 登錄
相關(guān)推薦
評論