91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

第5章_Modbus通訊協(xié)議

嵌入式Linux那些事 ? 來源:嵌入式Linux那些事 ? 作者:嵌入式Linux那些事 ? 2024-06-29 14:35 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

5.1 學習Modbus的快速方法

5.1.1 寄存器速記

作為初學者,你閱讀Modbus協(xié)議時會發(fā)現(xiàn)它的概念別扭、重復、不易區(qū)分,比如線圈狀態(tài)(Coil Status)、離散輸入狀態(tài)(Discrete Input Status)、保持寄存器(Holding Register)、輸入寄存器(Input Register)。

回到事情的本質(zhì),在工業(yè)控制PLC領(lǐng)域,涉及數(shù)字信號的輸入、輸出,模擬信號的輸入、輸出,如下圖所示:

img

對于軟件開發(fā)而言:

  • 想得到按鍵輸入狀態(tài)時,讀取到的是一位數(shù)據(jù);
  • 想控制LED時,需要輸出一位數(shù)據(jù),想讀取LED當前狀態(tài)時,也可以讀取到一位數(shù)據(jù)
  • 想讀取模擬信號時,讀取到的是多位數(shù)據(jù),比如16位數(shù)據(jù)
  • 想輸出模擬信號時,寫入的是多位數(shù)據(jù),比如16位數(shù)據(jù);也可以讀取“模擬量輸出”的當前值。

在上圖中,“數(shù)字量輸入DI”是只讀的,“數(shù)字量輸出DO”是可讀可寫的,“模擬量輸入AI”是只讀的,“模擬量輸出AO”是可讀可寫的。

上圖里的“模擬量輸入AI”、“模擬量輸出AO”都表示“多位數(shù)值”,這些“多位數(shù)值”無需局限于只表示“模擬量”,也可以表示“多位數(shù)字量”。把AI、AO的含義擴展后,如下圖所示:

img

對于軟件開發(fā)而言:

  • 想得到按鍵輸入狀態(tài)時,讀取到的是一位數(shù)據(jù);
  • 想控制LED時,需要輸出一位數(shù)據(jù),想讀取LED當前狀態(tài)時,也可以讀取到一位數(shù)據(jù)
  • 想讀取參數(shù)時,讀取到的“輸入寄存器”,得到多位數(shù)據(jù),比如16位數(shù)據(jù)
  • 想設(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)。可分為兩種不同的執(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ù),控制器運行時被設(shè)定的某些參數(shù),可讀可寫AO(模擬量輸出)模擬量輸出設(shè)定值,PID運行參數(shù),變量閥輸出大小,傳感器報警上限下限
輸入寄存器(Input Register)輸入?yún)?shù)。控制器運行時從外部設(shè)備獲得的參數(shù),但可讀不可寫AI(模擬量輸入)模擬量輸入

在Modbus中,多位操作時都是16位(2bytes)的,總結(jié)如下:

  • bit操作涉及的寄存器有2類:線圈狀態(tài)(可讀可寫)、離散輸入狀態(tài)(只讀)
  • 16bit操作的寄存器有2類:保存寄存器(可讀可寫)、輸入寄存器(只讀)

一個設(shè)備里,可能有多個“線圈狀態(tài)”、多個“離散輸入狀態(tài)”、多個“保存寄存器”、多個“輸入寄存器”。怎么分辨某類寄存器中的某一個?它們有“寄存器地址”,如下圖所示:

寄存器種類PLC寄存器地址范圍Modbus寄存器地址范圍簡稱讀寫狀態(tài)
線圈狀態(tài)00001~099990000H~FFFFH0x可讀可寫
離散輸入狀態(tài)10001~199990000H~FFFFH1x只讀
保持寄存器40001~499990000H~FFFFH4x可讀可寫
輸入寄存器30001~399990000H~FFFFH3x只讀

在上表中,“線圈狀態(tài)”的寄存器N、“離散輸入狀態(tài)”的寄存器N,是兩個不同的寄存器。

簡單記憶方法:“

  • 偶數(shù)類的寄存器”是可讀可寫的,比如“0x”和“4x”;
  • “奇數(shù)類的寄存器”是只讀的,比如“1x”和“3x”;
  • “0x”和“1x”是bit寄存器;
  • “3x”和“4x”是16bit寄存器。

5.1.2 協(xié)議速記

Modbus是一主多從的協(xié)議,如下圖所示:

img

主控發(fā)出的數(shù)據(jù)里,必定含有如下信息:

  • 設(shè)備地址:你要訪問從設(shè)備1,還是訪問從設(shè)備2
  • 訪問哪類寄存器,是讀還是寫,只訪問1個寄存器,還是多個寄存器:這被稱為功能碼
  • 起始寄存器地址、寄存器數(shù)量:這在數(shù)據(jù)里定義
  • 為了保證數(shù)據(jù)傳輸?shù)目煽?,還附帶有CRC檢驗碼

以Modbus RTU協(xié)議為例,主控發(fā)出的數(shù)據(jù)包格式如下:

img

功能代碼有哪些?常用的功能碼如下:

  • 讀線圈狀態(tài)(01)
  • 讀離散輸入狀態(tài)(02)
  • 寫單個線圈(05)、寫多個線圈(15)
  • 讀保持寄存器(03)
  • 讀輸入寄存器(04)
  • 寫單個保存寄存器(06)、寫多個保存寄存器(16)

數(shù)據(jù)的格式,由功能代碼確定。以“讀線圈狀態(tài)”為例,主控發(fā)出的請求、從設(shè)備返回的響應包,或者從設(shè)備返回的錯誤包,格式如下:

img

上圖中,寄存器起始地址(“Starting Address”)是16位的,先傳輸高字節(jié),再傳輸?shù)妥止?jié)。線圈數(shù)量(“Quantiti of coils”)也是16位的,先傳輸高字節(jié),再傳輸?shù)妥止?jié)。

響應包回復多少個數(shù)據(jù)呢(上圖中N為多少)?N = Quantiti of coils / 8,如果余數(shù)不等于0,則N再加1。比如Quantiti of coils=9,則返回2個字節(jié)。

在《Modbus_Application_Protocol_V1_1b3.pdf》中,列出了如下功能表。根據(jù)次表,在結(jié)合《5.5 Moubus功能碼詳解》的示例,就可以對Modbus RTU協(xié)議有很好的理解了。

img

5.2 初識Modbus

5.2.1 背景

Modbus誕生于1979年莫迪康(Modicon)公司,后來被施耐德電氣公司收購。Modbus提供通用語言用于彼此通信的設(shè)備和設(shè)備,是全球第一個真正用于工業(yè)現(xiàn)場的總線協(xié)議。Modbus已經(jīng)成為工業(yè)領(lǐng)域通信協(xié)議的業(yè)界標準,并且現(xiàn)在是工業(yè)電子設(shè)備之間常用的連接方式。Modbus作為目前工業(yè)領(lǐng)域應用最廣泛的協(xié)議,之后為了更好地普及和推動Modbus基于以太網(wǎng) (TCP/IP) 的分布式應用,施耐德公司已將Modbus協(xié)議的所有權(quán)移交給IDA (Interface for Distributed Automation,分布式自動化接口)組織,并成立了Modbus-IDA組織,此組織的成立和發(fā)展進一步推動了Modbus協(xié)議的廣泛應用。

img

5.2.2 什么是Modbus?

1. Modbus簡介

Modbus協(xié)議是一種已廣泛應用于當今工業(yè)控制領(lǐng)域的通用通訊協(xié)議。通過此協(xié)議,控制器相互之間、或控制器經(jīng)由網(wǎng)絡(如以太網(wǎng))可以和其它設(shè)備之間進行通信。Modbus協(xié)議使用的是主從通訊技術(shù),即由主設(shè)備主動查詢和操作從設(shè)備。一般將主控設(shè)備方所使用的協(xié)議稱為Modbus Master,從設(shè)備方使用的協(xié)議稱為Modbus Slave。典型的主設(shè)備包括工控機和工業(yè)控制器等;典型的從設(shè)備如PLC可編程控制器等。有了它,不同廠商生產(chǎn)的控制設(shè)備就可以連接成工業(yè)網(wǎng)絡,進行集中監(jiān)控。Modbus協(xié)議定義了一個控制器能夠認識和使用的消息結(jié)構(gòu),而不管它們是經(jīng)過何種網(wǎng)絡進行通信的;而且描述了控制器請求訪問其他設(shè)備的過程,如何應答來自其他設(shè)備的請求,以及怎樣偵測錯誤并記錄,并制定了統(tǒng)一的消息域的結(jié)構(gòu)和內(nèi)容。 當在Modbus網(wǎng)絡上通信時,Modbus協(xié)議決定了每個控制器必須要知道它們的設(shè)備地址,識別按地址發(fā)來的消息決定要產(chǎn)生何種行為。如果需要回應,則控制器將生成反饋信息并通過Modbus協(xié)議發(fā)送。

Modbus通訊物理接口可以選用串口(包括RS232RS485RS422等),也可以選擇以太網(wǎng)口。其通信遵循以下的過程:

  • 主設(shè)備向從設(shè)備發(fā)送請求
  • 從設(shè)備分析并處理主設(shè)備的請求,然后向主設(shè)備發(fā)送結(jié)果
  • 如果出現(xiàn)任何差錯,從設(shè)備將返回一個異常功能碼

此協(xié)議定義了一個控制器能認識使用的消息結(jié)構(gòu),而不管它們是經(jīng)過何種網(wǎng)絡進行通信的。它描述了一控制器請求訪問其它設(shè)備的過程,如何回應來自其它設(shè)備的請求,以及怎樣偵測錯誤并記錄。它制定了消息域格局和內(nèi)容的公共格式。

當在Modbus網(wǎng)絡上通信時,此協(xié)議決定了每個控制器須要知道它們的設(shè)備地址,識別按地址發(fā)來的消息,決定要產(chǎn)生何種行動。如果需要回應,控制器將生成反饋信息并用Modbus協(xié)議發(fā)出。在其它網(wǎng)絡上,包含了Modbus協(xié)議的消息轉(zhuǎn)換為在此網(wǎng)絡上使用的幀或包結(jié)構(gòu)。這種轉(zhuǎn)換也擴展了根據(jù)具體的網(wǎng)絡解決節(jié)地址、路由路徑及錯誤檢測的方法。

Modbus的工作方式是請求/應答,每次通訊都是主站先發(fā)送指令,可以是廣播,或是向特定從站的單播;從站響應指令,并按要求應答,或者報告異常。當主站不發(fā)送請求時,從站不會自己發(fā)出數(shù)據(jù),從站和從站之間不能直接通訊。

MODBUS 是一種應用層消息傳遞協(xié)議,位于 OSI 模型的第 7 層。它提供連接在不同類型總線或網(wǎng)絡上的設(shè)備之間的客戶端/服務器通信。

Modbus通信棧如下:

img

2. Modbus特點

Modbus通信協(xié)議具有以下幾個特點:

  • Modbus協(xié)議標準開放、公開發(fā)表且無版稅要求。用戶可以免費獲取并使用Modbus協(xié)議,不需要交納許可證費,也不會侵犯知識產(chǎn)權(quán)。
  • Modbus協(xié)議支持多種電氣接口,如RS232、RS485、TCP/IP等,還可以在各種介質(zhì)上傳輸,如雙絞線、光纖、紅外、無線。
  • Modbus協(xié)議消息幀格式簡單、緊湊、通俗易懂。用戶理解和使用簡單,廠商容易開發(fā)和集成,方便形成工業(yè)控制網(wǎng)絡。
  • 可靠性: Modbus 是最古老的工業(yè)自動化通信協(xié)議。它使用和編程簡單,因此學習曲線較低。
  • 遺留基礎(chǔ)設(shè)施:許多制造商在早期自動化方面投入了大量資金。Modbus 對于配置、DLR、節(jié)點、子站和其他基礎(chǔ)設(shè)施非常友好,這些基礎(chǔ)設(shè)施可能會被新的或更先進的協(xié)議所淘汰。
  • 快速部署: Modbus 可以輕松、立即集成到 SCADA和其他控制系統(tǒng)
  • 靈活性: Modbus 已適應新興技術(shù)。例如,Modbus TCP 可以通過話配器進行轉(zhuǎn)換,以與LAN 和遠程控制系統(tǒng)集成。它還可以利用基于網(wǎng)絡和基于云的平臺。
  • 簡單性:由于通信簡單,因此可以輕松擴展到新技術(shù)。例如,Modbus TCP/P 由于指令集簡單,部署速度很快。它還可以與以太網(wǎng)配合使用,無需添加芯片或板。

3. Modbus常用術(shù)語

名詞意義
Master主(站) 設(shè)備
Slave從 (站) 設(shè)備
Client客戶端
Server服務器端
ADU應用數(shù)據(jù)單元(Application Data Unit)
PDU協(xié)議數(shù)據(jù)單元 (Protocol Data Unit)
MSB最高有效位(Most Significant Bit)
LSB最低有效位 (Least Significant Bit)
MBAPModbus應用協(xié)議(Modbus Application Protocol)
PLC可編程邏輯控制器(Programmable Logic Controller)

4. Modbus事務處理

Modbus協(xié)議允許在各種網(wǎng)終體系結(jié)構(gòu)內(nèi)進行簡單通信,每種設(shè)備 (包括PLC、HMI、控制面板、驅(qū)動程序、動作控制、輸入/輸出設(shè)備) 都能使用Modbus協(xié)議啟動遠程操作。在基于串行鏈路和以太網(wǎng) (TCP/IP)的Modbus上可以進行相互通信。一些網(wǎng)關(guān)允許在幾種使用MODBUS協(xié)議的總線或網(wǎng)絡之間進行通訊。

MOUBUS網(wǎng)絡體系結(jié)構(gòu)的實例:

img

Modbus是一個請求、應答協(xié)議,并且提供統(tǒng)一的功能碼用于數(shù)據(jù)傳輸服務。Modbus功能碼是Modbus請求/應答PDU (Protocol Data Unit,協(xié)議數(shù)據(jù)單元)的元素之一,所謂的PDU其實就是Modbus協(xié)議定義的一個與基礎(chǔ)通信層無關(guān)的簡單協(xié)議數(shù)據(jù)單元。特定總線或網(wǎng)絡上的Modbus協(xié)議映射能夠在ADU (Application Data UInit ,應用數(shù)據(jù)單元)上引入一些附加域,從而實現(xiàn)完整而準確的數(shù)據(jù)傳輸。

為了尋求一種簡潔的通信格式,Modbus協(xié)議定義了PDU模型,即功能碼+數(shù)據(jù)的格式,而為了適應多種傳輸模式,又在PDU的基礎(chǔ)上增加了必要的前綴 (如地址域)和后綴(如差錯校驗) ,形成了ADU模型(見下圖)。

通用MODBUS幀如下:

img

Modbus事務處理過程:

  • 主機設(shè)備 (或客戶端)創(chuàng)建Modbus應用數(shù)據(jù)單元形成查詢報文,其中功能碼標識了向從機設(shè)備 (或服務器端)指示將要執(zhí)行的操作。其中功能碼占用1字節(jié),有效的碼字范圍是十進制1 ~ 255 (其中128 ~255為異常響應保留) 。查詢報文創(chuàng)建完畢,主機設(shè)備 (或客戶端) 向從機設(shè)備 (或服務器端)發(fā)送報文,從機設(shè)備 (或服務器端)接收報文后根據(jù)功能碼做出相應的動作,并將響應報文返回給主機設(shè)備 (或客戶端),如圖下所示:
    MouBus事務處理(無異常)

img

  • 如果在一個正確接收的Modbus ADU中不出現(xiàn)與請求Modbus功能有關(guān)的差錯,那么從機設(shè)備 (或服務器端) 將返回正常的響應報文。如果出現(xiàn)與請求Modbus功能有關(guān)的差錯,那么響應報文的功能碼域?qū)ㄒ粋€異常碼,主機設(shè)備(或客戶端)能夠根據(jù)異常碼確定下一步執(zhí)行的操作;對于異常響應,服務器返回一個與原始功能碼等同的碼,設(shè)置該原始功能碼的最高有效位為邏輯1,用于通知主設(shè)備(客戶端)。如下圖所示:
    MouBus事務處理(異常響應)

img

5.3 Modbus軟件與使用

5.3.1 Modbus軟件簡介

為了更好的學習和理解Modbus,這里推出三個軟件Modbus Poll(主站設(shè)備)、Modbus Slave(從站設(shè)備)和虛擬串口軟件,借助三款設(shè)備我們可以在PC上做一些基礎(chǔ)實驗,更加直觀地觀察通信數(shù)據(jù),加深我們的理解,我們將它稱為Modbus學習必備三件套,這是一個很好的入門方法。

5.3.2 Modbus Poll(主站設(shè)備)

1. Modbus Poll簡介

Modbus Poll是Modbus主站設(shè)備仿真器,用于測試和調(diào)試Modbus從設(shè)備便于觀察Modbus通信過程中的各種報文數(shù)據(jù)。該軟件支持ModbusRTU、ASCII、TCP/IP。用來幫助開發(fā)人員測試Modbus從設(shè)備,或者其它Modbus協(xié)議的測試和仿真。它支持多文檔接口,即,可以同時監(jiān)視多個從設(shè)備/數(shù)據(jù)域。每個窗口簡單地設(shè)定從設(shè)備ID,功能,地址,大小和輪詢間隔。你可以從任意一個窗口讀寫寄存器和線圈。如果你想改變一個單獨的寄存器,簡單地雙擊這個值即可?;蛘吣憧梢愿淖兌鄠€寄存器/線圈值。提供數(shù)據(jù)的多種格式方式,比如浮點、雙精度、長整型(可以字節(jié)序列交換)。該軟件支持Modbus RTU、ASCII、TCP/IP等協(xié)議模式。

Modbus Poll支持下列協(xié)議模式:

Modbus RTUModbus RTU Over TCP/IP
Modbus ASCIIModbus ASCI Over TCP/IP
Modbus TCP/IPModbus RTU Over UDP/IP
Modbus UDP/IPModbus ASCII Over UDP/IP

2. Modbus Poll 使用

點擊鏈接獲取軟件,按照提示安裝即可;鏈接:

https://pan.baidu.com/s/1SpTRz6Z1XlkoCZjDozwqog 提取碼:timc

下載完界面如下:

img

狀態(tài)欄:

  • Tx = 0表示向主站發(fā)送數(shù)據(jù)幀次數(shù),圖中為0次;
  • Err = 0表示通訊錯誤次數(shù),圖中為0次;
  • ID = 1表示模擬的Modbus子設(shè)備的設(shè)備地址,圖中地址為1;
  • F = 03表示所使用的Modbus功能碼,圖中為03功能碼;
  • SR = 1000ms表示發(fā)送周期,1S一次。
  • 紅字部分,表示當前的錯誤狀態(tài),“No Connection”表示未連接狀態(tài)。

建立連接:

點擊Connection->Connect進入配置頁面,選擇我們想要的連接,選擇我們虛擬出來的串口,選擇模式,例如:我們選擇串口的連接方式,選則RTU模式,對應我們的Modbus RTU協(xié)議;接下來在設(shè)置波特率、比特位、校驗位、停止位,如下圖所示:

img

設(shè)置參數(shù):點擊Setup->Read/Write Definition進入配置頁面,配置從機地址、功能碼、地址類型、寄存器地址、訪問數(shù)量、輪詢時間,具體配置如下圖:

img

5.3.3 Modbus Slave(從站設(shè)備)

1. Modbus Slave簡介

Modbus從設(shè)備仿真器,可以仿真32個從設(shè)備/地址域。每個接口都提供了對EXCEL報表的OLE自動化支持。主要用來模擬Modbus從站設(shè)備,接收主站的命令包,回送數(shù)據(jù)包。幫助Modbus通訊設(shè)備開發(fā)人員進行Modbus通訊協(xié)議的模擬和測試,用于模擬、測試、調(diào)試Modbus通訊設(shè)備,便于觀察Modbus通信過程中的各種報文數(shù)據(jù);可以32個窗口中模擬多達32個Modbus子設(shè)備。與Modbus Poll的用戶界面相同,支持功能01, 02, 03, 04, 05, 06, 15, 16, 22和23,監(jiān)視串口數(shù)據(jù)。

Modbus Slave支持下列協(xié)議模式:

Modbus RTUModbus RTU Over TCP/IP
Modbus ASCIIModbus ASCI Over TCP/IP
Modbus TCP/IPModbus RTU Over UDP/IP
Modbus UDP/IPModbus ASCII Over UDP/IP

2. Modbus Slave使用

獲取軟件鏈接同上,下載完后主頁面如圖所示:

img

建立連接:

點擊Connection->Connect進入配置頁面,選擇我們想要的連接,選擇我們虛擬出來的串口,選擇模式,接下來在設(shè)置波特率、比特位、校驗位、停止位,如下圖所示:

img

設(shè)置參數(shù):點擊Setup->Read/Write Definition進入配置頁面,配置從機地址、功能碼、地址類型、寄存器地址、訪問數(shù)量,具體配置如下圖:

img

這里有兩點需要我們注意一下:

  • 一是:Function列表框選擇功能中的0x~4x,表示的是存儲區(qū)0區(qū)、1區(qū)、3區(qū)、4區(qū)
    • 輸出線圈
    • 輸入線圈
    • 保持寄存器
    • 輸入寄存器

img

Modbus協(xié)議規(guī)定了4個存儲區(qū) 分別是0、1、3、4區(qū) 其中0區(qū)和4區(qū)是可讀可寫,1區(qū)和3區(qū)是只讀。

區(qū)號名稱讀寫地址范圍
0區(qū)輸出線圈可讀可寫布爾量00001-09999
1區(qū)輸入線圈只讀布爾量10001-19999
3區(qū)輸入寄存器只讀寄存器30001-39999
4區(qū)保持寄存器可讀可寫寄存器40001-49999
  • 二是:Address項,這里需要特別強調(diào)一下,Address表示Modbus寄存器地址,其取值范圍與設(shè)備寄存器地址存在映射關(guān)系,如下表所示:
Device addressModbus addressDescriptionFunctionR/W
1…10000address - 1Coils(outputs)01Read/Write
10001…20000address - 10001Discrete Inputs02Read
40001…50000address - 40001Holding Registers03Read/Write
30001…40000address - 30001Input Registers04Read

這里我們只簡單介紹下地址和存儲區(qū),下面我們會詳細展開。

5.3.4 虛擬串口軟件

1.軟件簡介

虛擬串口工具,可以創(chuàng)建2個互聯(lián)的串口,如下圖所示:

img

比如Modbus Poll工具使用COM1發(fā)送數(shù)據(jù)給COM2,Modbus Slave從COM2讀到數(shù)據(jù)。使用虛擬串口,就可以不使用開發(fā)板也可以體驗Modbus Poll、Modbus Slave。

軟件在網(wǎng)盤里:

img

2.虛擬串口的使用

安裝后運行虛擬串口程序“Virtual Serial Port Tools”,安裝下圖創(chuàng)建2個串口:

img

打開設(shè)備管理器,可以看到如下串口:

img

5.3.5 Modbus Poll 與 Modbus Slave互聯(lián)/通

下面我們進行Modbus Poll 與 Modbus Slave互聯(lián)互通實驗,通過形象直觀的方式展示Modbus數(shù)據(jù)流,根據(jù)前面的設(shè)定我們已將知道了如何運用Modbus學習必備三件套,下面我們就通過三件套來進行實驗,首先打開VSPD虛擬串口軟件,設(shè)置虛擬串口,我這里就以上面設(shè)訂COM1,COM2為例,接下來我們再來配置我們的Modbus Poll 與 Modbus Slave;

我們首先打開Modbus Slave端,設(shè)置連接,連接方式我們選擇Serial Port串口連接,選擇我們設(shè)置的串口COM1,模式選擇RTU模式,如下圖所示:

  • Modbus Slave連接設(shè)定

img

在設(shè)置參數(shù),從機地址我們設(shè)定1(你也可以自己隨意設(shè)定),F(xiàn)unction項我們選擇03 Holding Register(4x),地址類型我們選擇DEC(十進制格式),Address首地址我們設(shè)置為0,訪問寄存器數(shù)量設(shè)置為10,如下圖所示:

  • Modbus Slave參數(shù)設(shè)定

img

接下來我們再來設(shè)置Modbus Poll端,設(shè)置方法也是和Modbus Slave端一一對應的,連接設(shè)定,參數(shù)設(shè)定,如下圖所示:

  • Modbus Poll連接設(shè)定

img

注意這里串口要選擇我們設(shè)定的COM20,其它串口參數(shù)必須一一對應。

  • Modbus Poll參數(shù)設(shè)定

img

設(shè)置好后,我們主設(shè)備和從設(shè)備分別連接了我們設(shè)置的COM1,COM2,這樣我們便可觀察當前寄存器的讀取情況。

我們雙擊Modbus Poll(主設(shè)備端)地址中的0值,便可打開值設(shè)置窗口如下圖所示:

img

修改值為66,點擊Send打開Modbus Slave(從設(shè)備端)便可發(fā)現(xiàn)也做出了改變,如下圖所示:

img

我們還可以打開Modbus Poll,點擊Display,選擇Commuaction,查看發(fā)送的報文:

img

TX是我們主站發(fā)送的報文,RX是從站返回的報文,報文我們下面會展開說明,帶領(lǐng)大家一起看報文;

5.4 Modbus協(xié)議細節(jié)

5.4.1 Modbus協(xié)議概述

簡而言之,Modbus 協(xié)議是一種單主/多從的通信協(xié)議,其特點是在同一時間總線上只能有一個主設(shè)備,但可以有一個或者多個(最多 247 個)從設(shè)備。Modbus通信總是由主設(shè)備發(fā)起,當從設(shè)備沒有收到來自主設(shè)備的請求時,從設(shè)備不會主動發(fā)送數(shù)據(jù)。從設(shè)備之間不能相互通信,主設(shè)備只能同時啟動一個 Modbus 訪回事務處理。 主設(shè)備可以采用兩種方式向從設(shè)備發(fā)送 Modbus 請求報文,即主設(shè)備可以對指定的單個從設(shè)備或者線路上所有的從設(shè)備發(fā)送請求報文,而從設(shè)備只能在被被動接收請求報文后給出響應報文,即應答。這兩種模式分別如下圖所示:

Modbus請求應答周期

img

單播模式。主設(shè)備僅僅尋址單個從設(shè)備,從設(shè)備接收并處理請求后,向主設(shè)備返回一個響應報文,即應答。在這種模式下,一個 Modbus 事務處理包含兩個報文:一個是主設(shè)備的請求報文,另一個是從設(shè)備的響應報文。

每個從設(shè)備必須有唯一的地址(地址范圍為 1~247),這樣才能區(qū)別于其它從設(shè)備,從而可以獨立被尋址,同時主設(shè)備不占用地址。

img

廣播模式。此種模式下,主設(shè)備可以向所有從設(shè)備發(fā)送請求指令,而從設(shè)備在接收到廣播指令后僅進行相關(guān)指令的事務處理,而不要求返回應答。因此廣播模式下,請求指令必須是 Modbus 標準功能中的寫指令。

根據(jù) Modbus 標準協(xié)議的要求,所有從設(shè)備必須接收廣播模式下的寫指令,且地址0被保留,用來識別廣播通信

img

  • 請求:
    主設(shè)備發(fā)送的請求報文主要包括從設(shè)備地址(或廣播地址0)、功能碼、傳輸?shù)臄?shù)據(jù)以及差錯檢測字段。
    查詢消息中的功能碼告訴我們被選中的從設(shè)備地址要執(zhí)行何種功能。數(shù)據(jù)段包含從設(shè)備要執(zhí)行功能的所有附加信息。例如,功能代碼 03 要求從設(shè)備讀取保持寄存器并返回其內(nèi)容。

數(shù)據(jù)段必須包含要告訴從設(shè)備的信息:從哪個寄存器開始讀取及要讀取的寄存器數(shù)量。差錯檢測域為從設(shè)備提供一種驗證消息內(nèi)容是否正確的方法。

  • 應答:
    從設(shè)備的應答報文包括地址、功能碼、差錯檢測域等; 如果從設(shè)備產(chǎn)生了一個正常的回應,則回應消息中的功能碼是查詢消息中的功能碼的回應。數(shù)據(jù)段包括從設(shè)備收集的數(shù)據(jù),如寄存器值或狀態(tài)。如果有錯誤發(fā)生,則功能碼將被修改以用于指出回應消息是錯誤的,同時數(shù)據(jù)段包含描述此錯誤信息的代碼。差錯檢測域允許主設(shè)備確認消息內(nèi)容是否可用。

對于串行鏈路來說,又存在兩種傳輸模式:ASCII(American StandardCode for Information Interchange,美國標準信息交換碼)模式和 RTU(RemoteTerminal Unit,遠程終端單元)模式。但是,對于同一網(wǎng)絡或鏈路來說,所有設(shè)備必須保持統(tǒng)一,要么統(tǒng)一為 ASCII 模式,要么統(tǒng)一為 RTU 模式,不可共存。相對來說,RTU模式的傳輸效率更高,因此在當前普遍的生產(chǎn)環(huán)境中,RTU 模式獲得了廣泛應用,而 ASCII模式只能作為特殊情況下的可選項。

5.4.2 Modbus寄存器(存儲區(qū))

Modbus 協(xié)議中的一個重要概念是寄存器,所有數(shù)據(jù)均存放于寄存器。最初,Modbus 協(xié)議借鑒了 PLC 中寄存器的含義,但是隨著 Modbus 協(xié)議的廣泛應用,寄存器的概念進一步泛化,它不再是指具體的物理寄存器,也可能是指一塊內(nèi)存區(qū)域Modbus 寄存器根據(jù)存放的數(shù)據(jù)類型以及各自的讀寫特性將寄存器分為四部分,這四部分既可以連續(xù),也可以不連續(xù),由開發(fā)者決定。寄存器意義如下表所示:

Modbus寄存器(存儲區(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ù),控制器運行時被設(shè)定的某些參數(shù),可讀可寫AO(模擬量輸出)模擬量輸出設(shè)定值,PID運行參數(shù),變量閥輸出大小,傳感器報警上限下限
輸入寄存器輸入?yún)?shù)??刂破鬟\行時從外部設(shè)備獲得的參數(shù),但可讀不可寫AI(模擬量輸入)模擬量輸入

(PLC)數(shù)據(jù)的傳輸離不開存儲和讀寫操作,為了更好存儲不同的數(shù)據(jù)類型,我們可以理解Modbus 會將布爾和非布爾的數(shù)據(jù)分開存儲。

1. 存儲區(qū)類型

我們可以將存儲區(qū)類型分為布爾類型和非布爾類型,布爾類型我們用線圈(Coil)表示,非布爾用寄存器(Register)表示;

  • 什么是布爾?
    • 布爾類型只有兩個值,false 和 true。
    • 通常用來判斷條件是否成立。
    • C語言語法規(guī)定,如果變量值為 0 就是 false,否則為 true,布爾變量只有這兩個值。

因此,我們便有了線圈和寄存器的概念;

  • 那線圈和寄存器又是什么?
  • 線圈: 從電氣角度來看,在電氣控制回路中,一般都是靠接觸器或中間繼電器來實現(xiàn)控制,接觸器或中繼最終靠的是線圈的得電和失電來控制觸點閉合和斷開,因此用線圈表示布爾量;
    • 寄存器: 用來暫時存放參與運算的數(shù)據(jù)和運算結(jié)果,具有接收數(shù)據(jù)、存放數(shù)據(jù)和輸出數(shù)據(jù)的功能。
    • 而寄存器在計算機中,就是用來存儲數(shù)據(jù)的,因此非布爾的數(shù)據(jù)放在寄存器里。

回到存儲區(qū)分類,目的就是: 更好地存儲和區(qū)分不同的數(shù)據(jù)類型。

Modbus的線圈和寄存器應該也按照只讀、讀寫來進一步劃分,因此這就形成了Modbus的存儲區(qū),如下表所示:

  • Modbus存儲區(qū)類型及名稱
序號讀寫存儲類型存儲區(qū)名稱
1只讀線圈輸入線圈
2讀寫線圈輸出線圈
3只讀寄存器輸入寄存器
4讀寫寄存器保持寄存器
  • 存儲區(qū)代號:

為什么需要存儲區(qū)代號?上面表格里的存儲區(qū)名稱是一個全稱,開發(fā)和使用中使用全稱會比較麻煩,因此需要給他們?nèi)€別名。所以Modbus也要給這些存儲區(qū)取一個代號,干脆直接用數(shù)字吧,于是,就有了下面的規(guī)定:

存儲區(qū)名稱存儲區(qū)代號
輸入線圈1區(qū)
輸出線圈0區(qū)
輸入寄存器3區(qū)
保持寄存器4區(qū)

存儲區(qū)代號其實可以簡單理解為我們的名字,例如我們的名字有全名,和小名,全名呢是正式場合,外人叫的,小名呢是我們的親近的人,日常場合叫的。這么一說是不是就理解為什么有存儲區(qū)代號啦。

  • 存儲區(qū)范圍:
    • 無論是什么存儲區(qū),都會有一個范圍的限制;Modbus的每個存儲區(qū)也規(guī)定了一個范圍,不能無限制使用。
    • Modbus規(guī)定每個存儲區(qū)的最大范圍是65536,也就是0~65535。

2. 協(xié)議地址模型

PLC地址是我們常見的,但它是怎么組成的的,它是由存儲區(qū)代號 + 地址組成,我們把這樣的地址稱為絕對地址,把后面的地址成為相對地址;而我們的Modbus地址跟PLC地址也是類似的;

Modbus地址公式:存儲區(qū)代號 + (地址 + 1)如下表所示:

  • Modbus長地址模型
存儲區(qū)名稱存儲區(qū)代號絕對地址范圍相對地址范圍
輸入線圈1區(qū)100001~1655360~65535
輸出線圈0區(qū)000001~0655360~65535
輸入寄存器3區(qū)300001~3655360~65535
保持寄存器4區(qū)400001~4655360~65535

Modbus地址分為長地址模型和短地址模型,上面Modbus長地址模型,但是在實際使用中,我們一般用不了這么多地址,一般情況下,10000以內(nèi)就已經(jīng)足夠使用了;因此,為了方便我們便有了另一種短的地址模型,如下圖所示:

  • Modbus短地址模型
存儲區(qū)名稱存儲區(qū)代號絕對地址范圍相對地址范圍
輸入線圈1區(qū)10001~199990~9998
輸出線圈0區(qū)00001~099990~9998
輸入寄存器3區(qū)30001~399990~9998
保持寄存器4區(qū)40001~499990~9998

5.4.3 Modbus常用功能碼

Modbus功能碼占用1字節(jié),取值范圍是1127。之所以127以上不能用,是因為Modbus規(guī)定當出現(xiàn)異常時,功能碼+0x80(十進制128)代表異常狀態(tài),因此129(1+128)255(127+128)的取值代表異常碼。

  • Modbus常用功能碼
功能碼描述寄存器PLC地址位/字操作操作數(shù)量
01H讀線圈寄存器(讀輸出線圈)00001~09999位操作單個或多個
02H讀離散輸入寄存器(讀輸入線圈)10001~19999位操作單個或多個
03H讀保持寄存器40001~49999字操作單個或多個
04H讀輸入寄存器30001~39999字操作單個或多個
05H寫單個線圈寄存器00001~09999位操作單個
06H寫單個保持寄存器40001~49999字操作單個
0FH(15)寫多個線圈寄存器00001~09999位操作多個
10H(16)寫多個保持寄存器40001~49999字操作多個

功能碼可以分為位操作和字操作兩類。位操作的最小為1位(bit),字操作的最小單位為2字節(jié)。

① 位操作指令:讀取線圈狀態(tài)的功能碼 01 ,讀(離散)輸入狀態(tài)功能碼 02 ,寫單個線圈功能碼 05 和寫多個線圈功能碼 15。
② 字操作指令:讀保持寄存器功能碼 03 ,讀輸入寄存器功能碼 04 ,寫單個保持寄存器功能碼 06 ,寫多個保持寄存器功能碼 16 。

5.4.4 Modbus協(xié)議類型

Modbus可以在各種介質(zhì)上傳輸,那么他的傳輸模式也分為三種。包括ASCII、RTU(遠程終端控制系統(tǒng))、TCP三種報文類型

  • 常用Modbus協(xié)議
Modbus協(xié)議Modbus協(xié)議
Modbus RTUModbus RTU Over TCP/IP
Modbus ASCIIModbus ASCI Over TCP/IP
Modbus TCP/IPModbus RTU Over UDP/IP
Modbus UDP/IPModbus ASCII Over UDP/IP

Modbus協(xié)議使用串口傳輸時可以選擇RTU或ASCII模式,并規(guī)定了消息、數(shù)據(jù)結(jié)構(gòu)、命令和應答方式并需要對數(shù)據(jù)進行校驗。ASCII 模式采用LRC校驗,RTU模式采用16 位CRC校驗。通過以太網(wǎng)傳輸時使用TCP,這種模式不使用校驗,因為TCP協(xié)議是一個面向連接的可靠協(xié)議。

5.4.5 Modbus報文幀

一個報文就是一幀數(shù)據(jù),一個數(shù)據(jù)幀就一個報文: 指的是一串完整的指令數(shù)據(jù),本質(zhì)就是一串數(shù)據(jù)。

Modbus報文是指主機發(fā)送給從機的一幀數(shù)據(jù),其中包含著從機的地址,主機想執(zhí)行的操作,校驗碼等內(nèi)容

1. Modbus ASCII 模式

**當控制器設(shè)為在Modbus網(wǎng)絡上以ASCII模式通信時,在消息中每個8位(b)字節(jié)都將作為兩個 ASCII字符發(fā)送。這種方式的主要優(yōu)點是字符發(fā)送的時間可隔可達到 1秒且不產(chǎn)生錯誤。 **

**在ASCII模式下,消息以冒號(:)字符(ASCII碼為 0x3A)開始,以回車換行奇結(jié)束(ASCII碼為 0x0D、0x0A)。消息的其他字段(域)可以使用的傳輸字符是十六進制的0···9、A···F。處于網(wǎng)絡上的 Modbus 設(shè)備不斷偵測“:”字符,當接收到一個冒號時,每個設(shè)備進入解碼階段,并解碼下一個字段(地址域)以判斷是否是發(fā)給自己的。消息幀中的字符間發(fā)送的時間間隔最長不能超過 1秒,否則接收設(shè)備將認為發(fā)生傳輸錯誤。 **

下表是一個典型的ASCII報文格式:

開始字符地址功能碼數(shù)據(jù)LRC校驗結(jié)束字符
1byte (:)2byte2byteNbyte2byteCR、LF

2. Modbus RTU 模式

Modbus協(xié)議RTU報文格式如下所示:

從機地址功能碼數(shù)據(jù)CRC校驗
1byte1byteNbyte2byte
  • **幀結(jié)構(gòu) = 從機地址 + 功能碼 + 數(shù)據(jù) + 校驗 **
    • 從機地址: 每個從機都有唯一地址,占用一個字節(jié),范圍0-255,其中有效范圍是1-247,其中255是廣播地址(廣播就是對所有從機發(fā)送應答)
    • 功能碼: 占用一個字節(jié),功能碼的意義就是,知道這個指令是干啥的,比如你可以查詢從機的數(shù)據(jù),也可以修改從機的數(shù)據(jù),所以不同功能碼對應不同功能.
    • 數(shù)據(jù): 根據(jù)功能碼不同,有不同功能,比方說功能碼是查詢從機的數(shù)據(jù),這里就是查詢數(shù)據(jù)的地址和查詢字節(jié)數(shù)等。
    • 校驗: 在數(shù)據(jù)傳輸過程中可能數(shù)據(jù)會發(fā)生錯誤,CRC檢驗檢測接收的數(shù)據(jù)是否正確

3. 串行報文幀總結(jié):

ModbusASCII有開始字符(和結(jié)束字符(CR LF),可以作為一幀數(shù)據(jù)開始和結(jié)束的標志,而ModbusRTU沒有這樣的標志,需要用時間間隔來判斷一幀報文的開始和結(jié)束,協(xié)議規(guī)定的時間為3.5個字符周期,就是說一幀報文開始前,必須有大于3.5個字符周期的空閑時間,一幀報文結(jié)束后,也必須要有3.5個字符周期的空閑時間否則就會出現(xiàn)粘包的情況。

**注意:針對3.5個字符周期,其實是一個具體時間,但是這個時間跟波特率相關(guān)。 在串口通信中,1個字符包括1位起始位、8位數(shù)據(jù)位(一般情況)、1位校驗位(或者沒有)、1位停止位(一般情況下),因此1個字符包括11個位,那么3.5個字符就是38.5個位,波特率表示的含義是每秒傳輸?shù)亩M制位的個位,因此如果是9600波特率,3.5個字符周期=38.5/9600=0.00401s*1000=4.01ms**

5.4.6 Modbus 差錯校驗

在Modbus串行通信中,根據(jù)傳輸模式(ASCII或RTU)的不同,差錯校驗域?qū)⒉捎貌煌男r灧椒ā?/strong>

  • ASCII模式
    在ASCII模式中,報文包含一個錯誤校驗字段,該字段由兩個字符組成,其基于對全部報文內(nèi)容執(zhí)行的縱向冗余校驗(Longitudinal Redundancy ChedLRC)計算的結(jié)果而來,計算對象不包括起始的冒號(:)和回車換行符號(CR LF)。
  • **RTU模式 **
    在RTU模式中,報文同樣包含一個錯誤校驗字段。與ASCII模式不同的是該字段由 16 個比特位共2字節(jié)組成,其值基于對全部報文內(nèi)容執(zhí)行的循環(huán)冗余校驗(Cyclical Redundancy Check,CRC)計算的結(jié)果而來,計算對象包括校驗域之的所有字節(jié)。

1. LRC校驗

在ASCII模式中,消息是由特定的字符作為幀頭和幀尾分隔的。

一條消息必須以“冒號”(:)字符(ASCII碼為0x3A)開始,以“回車換行(CRLF)(ASCII碼為 0x0D 和 0x0A)結(jié)束。LRC 校驗算法的計算范圍為“:” “CRLF”之間的字符。

從算法本質(zhì)來說,LRC域自身為1字節(jié),即包含一個 8位二進制數(shù)據(jù),由發(fā)送設(shè)備通過LRC算法把計算值附到信息末尾。接收設(shè)備在接收信息時通過 LRC法重新計算值,并把計算值與 LRC 字段中接收的實際值進行比較。若兩者不同,則產(chǎn)生一個錯誤,返回一個異常響應幀,即對報文中的所有相鄰的兩個 8位字相加,丟棄任何進位,然后對結(jié)果進行二進制補碼,計算出 LRC值。

必須注意的是,計算 LRC 校驗碼的時機是在對報文中每個原始字節(jié)進行ASCII碼編碼之前,對每個原始字節(jié)進行LRC校驗的計算操作。

  • LRC校驗流程:
    • 將消息中的全部字節(jié)相加(不包括起始“:”和結(jié)束符(CRLF),并把結(jié)果送入8位數(shù)據(jù)區(qū),舍棄進位。
    • 由0xFF(即全 1)減去最終的數(shù)據(jù)值,產(chǎn)生1的補碼(即二進制反碼)
    • 加1產(chǎn)生二進制補碼。

以上產(chǎn)生的LRC值占用1字節(jié),但實際上在通過串行鏈路由ASCII模式傳遞消息頓時,LRC的結(jié)果(1字節(jié))被編碼為2字節(jié)的ASCII字符,并將其放置在ASCII模式報文幀的CRLF字段之前。

Modbus 標準協(xié)議的英文版提供了 LRC算法,其中的參數(shù)意義如下unsigned char*auchMsg:含有生成LRC所使用的二進制數(shù)據(jù)的報文緩存區(qū)指針。 unsigned short usDataLen:報文緩存區(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--)          /*遍歷報文緩沖區(qū)*/
?
    uchLRC+=*auchMsg++;       /*緩沖區(qū)宇節(jié)相加,自動舍棄進位*/
?
  
?
return ((unsigned char)(-(( char)uchLRC))); /*返回二進制補碼*/
?
}

下面舉一個簡單的例子。假設(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校驗

在Modbus RTU傳輸模式下,通信報文(幀)包括一個基于循環(huán)冗余校驗方法的差錯校驗字段。

Modbus協(xié)議采用了CRC-16標準校驗方法。在RTU模式下,CRC自身由2字節(jié)組成,即CRC是一個16位的值。CRC字段校驗整個報文的內(nèi)容,無論報文中的單個字節(jié)采用何種奇偶校驗方式,整個通信報文均可使用CRC-16校驗算法,CRC字段作為報文的最后字段添加在整個報文末尾。

需要注意的是,因為CRC-16是由2字節(jié)組成,所以涉及哪個字節(jié)放在前面,哪個字節(jié)放在后面?zhèn)鬏數(shù)膯栴},即大小端模式的選擇問題。另外,由于Modbus協(xié)議規(guī)定寄存器為16位(即2字節(jié))長度,因此大小端問題的存在給很多初學者造成了困擾,下一章我們會重點講一下大小端的問題。

  • CRC校驗流程:
    • 預置一個16位寄存器為0xFFFF(全1),稱之為CRC寄存器。
    • 把數(shù)據(jù)幀中的第一個字節(jié)的8位與CRC寄存器中的低字節(jié)進行異或運算,結(jié)果存回CRC寄存器。
    • 將CRC寄存器向右移一位,最高位填以0,最低位移出并檢測是0還是1。
    • 如果最低位為0:重復第三步(再次右移一位);如果最低位為1:將CRC寄存器與一個預設(shè)的固定值(0xA001)進行異或運算。
    • 重復第三步和第四步直到8次移位。這樣處理完了一個完整的八位。
    • 重復第2步到第5步來處理下一個八位,直到所有的字節(jié)處理結(jié)束。
    • 將該通信消息幀的所有字節(jié)按上述步驟計算完成后,再將得到的16位CRC寄存器的高、低位字節(jié)進行交換,即發(fā)送時首先添加低位字節(jié),然后添加高位字節(jié)。
    • 最終CRC寄存器的值就是CRC的校驗碼。

需要注意的是,在進行CRC計算時只有串行鏈路上的每個字符的8個數(shù)據(jù)位參與計算,從而起始位、停止位、奇偶校驗位等都不參與CRC計算。

常用的CRC-16算法有查表法、計算法。

查表法:

CRC查表法是將位移異或的計算結(jié)果做成了一個表,即將0~256 放入一個度為16位的寄存器的低8位,高8位填充0,然后將該寄存器與多項式0xA001照上述步驟3、4直到8 位全部移出,最后寄存器中的值就是表格中的數(shù)據(jù),高8位、低 8 位分別單獨做成一個表。 實際上,Modbus 標準協(xié)議的英文版提供了CRC 查表算法 函數(shù)的輸入?yún)?shù)意義如下:

unsigned char * puchMsg;         /*要進行CRC校驗的消息*/
?
unsigned short usDataLen;      /*消息中的字節(jié)數(shù)*/
?
/*函數(shù)返回 unsigned short(即2個字節(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++;        /*計算 CRC* /
?
    uchCRCHi=uchCRCLo ^ auchCRCHi[uIndex];
?
    uchCRCLo=auchCRCLo[uIndex];
?
  }
?
  return (uchCRCHi < 

其中,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
?
};

注意:實際編程時,auchcRCHi[]和auchCRCLo[]的定義應該放在函數(shù)CRC-16()之前。

查表法可以進一步化簡如下:

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;
?
}

查表法的特點是以字節(jié)為單位進行計算,速度快,語句少,但表格會占用一定的程序空間。

  • 計算法:

計算法按位計算,適用于所有長度的數(shù)據(jù)校驗,最為靈活;但由于是按位計算,其效率并不是最優(yōu)的,只適用于對速度不敏感的場合。計算法的基本算法如下; 輸入?yún)?shù)的意義:

unsigned char * puchMsg;       /*要進行 CRC校驗的消息* /
?
unsigned short usDataLen;      /*消息中的字節(jié)數(shù)*/
?
/*函數(shù)返回unsigned short(即 2個字節(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)處理每個 bit位*/
?
    {
?
      if (usRegCRC &0x0001)
?
        usRegCRC =usRegCRC > >1^0xA001;
?
      else
?
        usRegCRC > >=1;
?
    }
?
  }
?
  
?
  return usRegCRC;
?
}

下面舉一個簡單的例子。假設(shè)從設(shè)備地址為 1,要求讀取輸入寄存器地址30001的值,則RTU模式下的具體查詢消息幀如下:

0x01,0x04,0x00,0x00,0x00,0x01,0x31,0xCA

其中,0xCA31即為CRC值。因為Modbus規(guī)定發(fā)送時CRC必須低字節(jié)在前、高字節(jié)在后,因此實際的消息幀的發(fā)送順序為0x31,0xCA。

5.4.7 字節(jié)序和大小端

Modbus中傳輸?shù)臄?shù)據(jù),按照“大字節(jié)序”來傳輸,比如:

img

寄存器數(shù)值是0x1234,先傳輸0x12,再傳輸0x34。

在 Modbus 寄存器中,對于一個由 2字節(jié)組成的16數(shù),在內(nèi)存中存儲這兩個字節(jié)有兩種方法:一種是將低序字節(jié)存儲在起始地址為小端(Little-Endian)字節(jié)序;另一種方法是將高序字節(jié)存儲在起始地稱為大端(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)存的高地址中。
  • 為什么會有大小端:
    計算機系統(tǒng)是以字節(jié)為單位的,每個地址單元都對應著1個字節(jié),一個字節(jié)為8bit。但在C語言中除了8bit的char類型,還有16bit的short類型和32bit的long類型,還有就是對于位數(shù)大于8位的處理器,如16位或32位的處理器,由于寄存器寬度大于一個字節(jié),那么必然存在一個如何將多個字節(jié)安排的問題。因此就導致了大端存儲模式和小端存儲模式的出現(xiàn)。

低位字節(jié)和高位字節(jié):好比如:123456 其中的1就是高位數(shù)字,6就是低位數(shù)字。

舉一個例子,在32位數(shù)字0x12345678在內(nèi)存中的表示形式為:

1)大端模式

低地址————高地址
0x120x340x560x78

2)小端模式:

低地址————高地址
0x780x560x340x12

5.4.8 Modbus報文分析

在第二章中我們已經(jīng)生成了一個報文,我們就拿此報文來逐步分析一下,報文如下:

img

我們可以看到上面報文都是循環(huán)發(fā)送的,這樣看起來不太容易分析,我摘抄下來其中一組來給大家分析

發(fā)送:

從機地址功能碼起始地址高位起始地址低位寄存器數(shù)量高位寄存器數(shù)量低位CRC高位CRC低位
01030000000AC5CD

響應:

從機地址功能碼返回字節(jié)數(shù)數(shù)據(jù)位CRC高位CRC低位
01031400 42…CF10

這里我們就以03功能碼為例來分析一下報文;

  • 03發(fā)送報文格式:從機地址+功能碼+加起始地址+寄存器數(shù)量+CRC校驗
  • 03接受報文格式:從機地址+功能碼+字節(jié)數(shù)+具體數(shù)據(jù)+CRC校驗

首先我們看一下發(fā)送報文:

從機地址是01,功能碼03,起始地址00,寄存器數(shù)量是十六進制0A也就是10,和門設(shè)置的是一樣的,我們來對對照一下我們設(shè)置的參數(shù):

img

我們再來看一下接收報文:

從機地址是01,功能碼03,返回字節(jié)數(shù)是十六進制14也就是返回20給字節(jié),我們發(fā)送是個返回20個字節(jié)也是對的上的,第一個數(shù)據(jù)位是00 42 也是和我們發(fā)送的可以對上,十六機制42,也就66,我們來看一下我們之前設(shè)置的參數(shù):

img

5.4.9 Moubus TCP 消息幀格式

1.協(xié)議描述

在Modbus TCP/IP中,串行鏈路中的主/從設(shè)備分別演變?yōu)榭蛻舳?服務器端設(shè)備,即客戶端相當于主站設(shè)備,服務器端設(shè)備相當于從設(shè)備。基于TCP/IP網(wǎng)絡的傳輸特性,串行鏈路上一主多從的機構(gòu)也演變?yōu)槎嗫蛻舳?多服務器端的構(gòu)造模型。Modbus協(xié)議在TCP/IP上的實現(xiàn)是在TCP/IP層上的應用,它需要一個完整的TCP/IP棧作為支撐,Modbus TCP/IP服務器端通常使用端口502作為接收報文的端口。

下圖為Moubus TCP的通訊結(jié)構(gòu):

img

ModbusTCP與ModbusUDP的報文格式是一樣的,它們之間的區(qū)別其實就是TCP與UDP的區(qū)別,因此下面就針對ModbusTCP的協(xié)議進行分析,ModbusTCP與ModbusRtu(ModbusASCII)之間的區(qū)別如下圖:

img

從上圖可以看出,ModbusTCP在Modbus串行通信的基礎(chǔ)上,去除了校驗(由于TCP本身就帶有校驗和)和設(shè)備地址(ModbusTCP弱化了設(shè)備地址,用IP地址來取代),再加上MBAP報文頭(占7 bytes),下面針對MBAP進行分析說明:

字段名長度描述主站(客戶端)從站(服務器端)
事務處理標識符(Transaction Identifier)2字節(jié)Modbus 請求/應答傳輸過程的事務處理的識別碼,可以設(shè)置為0,也可以設(shè)置為每次通訊時自動+1主站(客戶端)生成應答時從主站(客戶端)復制該值
協(xié)議標識符(Protocol Identifier)2字節(jié)00表示是 Modbus協(xié)議,固定值主站(客戶端)生成應答時從主站(客戶端)復制該值
長度(Lendgth)2字節(jié)從單元標識符開始,整個PDU的數(shù)據(jù)長度,分為字節(jié)長度Hi和Lo請求時生成應答時重新生成
單元標識符(Unit Identifier)1字節(jié)串行鏈路或其他總線上連接的遠程從站的識別碼,可以設(shè)置為從機設(shè)備的地址主站(客戶端)生成應答時從主站(客戶端)復制該值

事務處理標識符:

事務處理標識用于在查詢報文與未來響應之間建立聯(lián)系。因此,對 TCP/IP 連接來說,在同一時刻這個標識符必須是唯一的。有以下幾種使用此標識符的方式。

例如,可以將傳輸標識作為一個帶有計數(shù)器的簡單“TCP 發(fā)送順序號”,在每個請求發(fā)送時自動+1;也可以用作智能索引或指針,用來識別事務處理的內(nèi)容,以便記憶當前的遠端服務器和未處理的請求。

服務器端可接收的請求數(shù)量取決于其容量,即服務器資源量和 TCP 窗口尺同樣,客戶端同時啟動事務處理的數(shù)量也取決于客戶端的資源容量。

單元標識符:

在對Modbus或 Modbus+等串行鏈路子網(wǎng)中的設(shè)備進行尋址時,這個域用于路由的目的。在這種情況下,單元標識符(Unit Identifier) 攜帶一個遠端設(shè)備的Modbus 從站地址。

如果 Modbus 服務器連接到 Modbus+或 Modbus 串行鏈路子網(wǎng),并通過一個網(wǎng)橋或網(wǎng)關(guān)配置這個服務器的IP 地址,則 Modbus 單元標識符對識別連接到網(wǎng)橋或網(wǎng)關(guān)后的子網(wǎng)的從站設(shè)備是必需的。TCP 連接中的目的 IP 地址識別了網(wǎng)橋本身的地址,而網(wǎng)橋則使用 Modbus 單元標識符將請求轉(zhuǎn)交給正確的從站設(shè)備。 分配給串行鏈路上的 Modbus 從站設(shè)備地址為 1~247(十進制),地址0作為廣播地址。

對單純的 Modbus TCP/IP 設(shè)備來說用IP 地址即可尋址 Modbus 服務器端設(shè)備,此時 Modbus 單元標識符是無用的,必須使用值0xFF 填充。當對直接連接到 TCP/IP 網(wǎng)絡上的 Modbus 服務器尋址時,建議不要在“單元標識符”域使用有效的Modbus從站地址。

以上是MBAP報文頭個字段含義的詳細說明。

實際上,在 Modbus TCP/IP傳輸過程中,服務端(從機)返回的響應報文中同樣包含 MBAP報頭,除了 Length 字段外,其他字段均與客戶端一致。Modbus消息由 TCP/IP 層提供,不需要像串行鏈路那樣自己判斷一幀是否結(jié)束,所有數(shù)據(jù)傳輸均由 TCP/IP層處理。因為底層的 TCP/IP 確保了端到端的連接,而且 TCP/IP鏈路層已確保傳輸數(shù)據(jù)的準確性,所以 Modbus TCP/IP 中已不再需要 LRC或CRC 等校驗功能。

2. 查詢與響應報文示例

對于Modbus TCP消息幀格式,下面舉例說明各部分的含義。

  • 查詢報文:00 00 00 00 00 06 09 03 00 04 00 01。
    • 0x06: 后續(xù)還有6字節(jié)。
    • 0x09: 單元標識符為9。
    • 0x03: 功能碼 3,即讀保持寄存器的值。
    • 0x00 0x04: Modbus起始地址4(即40005)。
    • 0x00 0x01: 讀取寄存器個數(shù)為1。
  • 響應報文:00 00 00 00 00 05 09 03 02 00 05。
    • 0x05:表示后續(xù)還有5字節(jié)。
    • 0x09:同查詢報文,單元標識符。
    • 0x03:功能碼,同查詢報文。
    • 0x02:返回數(shù)據(jù)字節(jié)數(shù)。
    • 0x00 0x05:寄存器的值。

可見,在Modbus TCP模式下,差錯校驗字段已不復存在。但在某些特殊場合,例如串行Modbus協(xié)議轉(zhuǎn)Modbus TCP的情況下,串行協(xié)議數(shù)據(jù)可以完整地裝載到Modbus TCP的數(shù)據(jù)字段,這時CRC或LRC差錯校驗字段仍然存在。例如,Modbus RTU Over TCP/IP 或 Modbus ASCII Over TCP/IP等。

5.5 Moubus功能碼詳解

本節(jié)大部分內(nèi)容參考《Modbus軟件開發(fā)實戰(zhàn)指南》。

5.5.1 功能碼概要

Modbus標準在協(xié)議中規(guī)定了以下3類Modbus功能碼。

  • 公共功能碼:
    • 被明確定義的功能碼;
    • 保證唯一性;
    • 由Modbus協(xié)會確認,并提供公開的文檔;
    • 可進行一致性測試;
    • 包括協(xié)議定義的功能碼和保留將來使用的功能碼。
  • 用戶自定義功能碼:
    • 有兩個用戶自定義功能碼區(qū)域,分別是6572和100110;
    • 用戶自定義,無法保證唯一性。
  • 保留功能碼:
    保留功能碼因為歷史遺留原因,某些公司的傳統(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開始計算。

2. 查詢報文

如下表所示,查詢幀的消息中定義了從設(shè)備地址為3,并讀取從設(shè)備的Modbus地址0001900055(線圈地址0002000056)共計37個狀態(tài)值。起始線圈地址為0x13(即十進制00019),因為線圈地址是從0開始計數(shù)的。

功能碼01查詢報文示例

字段例(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
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)178

Modbus協(xié)議規(guī)定,起始地址由2字節(jié)構(gòu)成,取值范圍為0x0000 ~ 0xFFFF: 線圈數(shù)量由2字節(jié)構(gòu)成,取值范圍為0x0001~ 0x07D0 (即+進制1~2000)另外,注意觀察ASCII模式和RTU模式的區(qū)別,ASCII模式直接按每4位拆分成對應的字符表示。

3. 響應報文

**在響應報文的數(shù)據(jù)字段中,每個線圈占用1位 (bit),狀態(tài)被表示為1=ON和O=OFF兩種類型。第1個數(shù)據(jù)字節(jié)的LSB(最低有效位)標識查詢報文中的起始地址線圈的狀態(tài)值,其他線圈以此類推,一直到這個字節(jié)的MSB(最高有效位)為止,并在后續(xù)字節(jié)中按照同樣的方式(由低到高)排列。**

例如,下表中線圈20~27的狀態(tài)值分別是ON - ON - OFF OFF - ON - OFF - ON - OFF表示為二進制則為01010011 (0x53),注意觀察對應的順序。1字節(jié)可以表示8個線圈的狀態(tài)如果最后的數(shù)據(jù)字節(jié)中不能填滿8個線圈的狀態(tài),則用0填充。對應于查詢報文中需要讀取37個線圈的狀態(tài),共需要5字節(jié)保存狀態(tài)值。

功能碼01響應報文示例:

字段例(Hex)ASCII模式字符型RTU模式8位(Hex)
幀頭“:”
從設(shè)備地址0x03“0”,“3”0x03
功能碼0x01“0”,“1”0x01
數(shù)據(jù)域字節(jié)數(shù)0x05“0”,“5”0x05
數(shù)據(jù)10x53“5”,“3”0x53
數(shù)據(jù)20x6B“6”,“B”0x6B
數(shù)據(jù)30x01“0”,“1”0x01
數(shù)據(jù)40xF4“F”,“B”0xF4
數(shù)據(jù)50x1B“1”,“B”0x1B
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)2110

5.5.3 02 (0x02) 讀取離散量輸入值

1. 功能說明

02功能碼用于讀取從設(shè)備的離散輸入,即DI (Discrete Input) 的ON/OFF狀態(tài)。消息頓中指定了需要讀取的離散輸入寄存器的起始地址和數(shù)目,可以讀取1 ~ 2000個連續(xù)的離散量輸入狀態(tài)如果從設(shè)備接受主設(shè)備的請求則回復功能碼02,并返回離散量且輸入各變量的當前狀態(tài)。如果返回的離散輸入數(shù)量的個數(shù)不是8的整數(shù)倍,將用0填充最后的數(shù)據(jù)字節(jié)的剩余位。

2. 查詢報文

如下表所示,查詢頓的消息中定義了從設(shè)備的地址為3,并讀取從設(shè)備的離散輸入寄存器中地址1010110120 (Modbus地址表示為十進制100119) 共計20個離散輸入狀態(tài)值。從下表中可以發(fā)現(xiàn),起始地址為0x64 (即十進制100),因為消息PDU中的Modbus地址從0開始計數(shù)。

功能碼02查詢報文示例:

字段例(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
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)178

與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 (即十進制1 2000),最多一次性可讀取2000人離散輸入狀態(tài)值。

3. 響應報文

響應報文的各項構(gòu)成和意義與5.4.2章節(jié)的功能碼(01(0x01)讀取線圈/離散量輸出狀態(tài)(Re-ad Coil Status/DOs))一樣,如下表所示:

功能碼02響應報文示例:

字段例(Hex)ASCII模式字符型RTU模式8位(Hex)
幀頭“:”
從設(shè)備地址0x03“0”,“3”0x03
功能碼0x02“0”,“2”0x02
數(shù)據(jù)域字節(jié)數(shù)0x03“0”,“3”0x03
數(shù)據(jù)10x53“5”,“3”0x53
數(shù)據(jù)20x6B“6”,“B”0x6B
數(shù)據(jù)30x01“0”,“1”0x01
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)2110

5.5.4 03(0x03)讀取保持寄存器值

1. 功能說明

03功能碼用于讀取從設(shè)備保持寄存器的內(nèi)容,不支持廣播模式。消息頓中指定了需要讀取的保持寄存器的起始地址和數(shù)目。而保持寄存器中各地址的具體內(nèi)容和意義則由設(shè)備開發(fā)者自行規(guī)定。

2. 查詢報文

在查詢報文中,必須指定保持寄存器的開始地址和需要讀取的寄存器數(shù)量,例如,如下表所示,從設(shè)備地址為7 (0x07),需要讀取保持寄存器地址40201 ~ 40203共計3個寄存器的內(nèi)容即讀取Modbus協(xié)議地址200~ 202的內(nèi)容,在報文中表示如下。

起始地址: 0x00C8 (十進制200)。
讀取數(shù)量: 0x0003 (十進制3)。

功能碼03查詢報文示例:

字段例(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
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)178

本功能碼的起始地址由2字節(jié)構(gòu)成,取值范圍為0x00000xFFFF;寄存器數(shù)量由2字節(jié)構(gòu)成取值范圍為0x00010x007D (即十進制1~125) ,即最多可以連續(xù)讀取125個寄存器。

需要特別注意的是,Modbus的保持寄存器和輸入寄存器是以字 (Word) 為基本單位的(1Word=2Byte),所以如果讀取保持寄存器地址為40001開始的一個16位 (bit) 的無符號數(shù),那么返回2字節(jié),并可以從40002開始讀取下一個16位的無符號數(shù)。如果需要讀取寄存器地址為40001開始的一個32位浮點數(shù),則需要返回4字節(jié),即必須連續(xù)讀取40001和40002的內(nèi)容,而且下一個32位的浮點數(shù)必須從40003開始讀取。對于浮點數(shù)(或者32位的整數(shù))而言,連續(xù)讀取的兩個寄存器之間存在字節(jié)序和大小端的問題,這一點在開發(fā)時必須引起注意。

3. 響應報文

響應報文的各項構(gòu)成和意義如下表所示。因為Modbus的保持寄存器和輸入寄存器是以字為基本單位的,在上面的例子中,查詢報文連續(xù)讀取3個寄存器的內(nèi)容,將返回6字節(jié),參考表下表中數(shù)據(jù)1~3的高位和低位。

功能碼03響應報文示例:

字段例(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
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)2311

5.5.5 04 (0x04)讀取輸入寄存器值

1.功能說明

與功能碼03類似,04功能碼用于讀取從設(shè)備輸入寄存器的內(nèi)容,不支持廣播模式。消息頓中指定了需要讀取的輸入寄存器的起始地址和數(shù)目,而輸入寄存器中各地址的具體內(nèi)容和意義則由設(shè)備開發(fā)者自行規(guī)定。

2.查詢報文

在查詢報文中必須指定輸入寄存器的起始地址和需要讀取的寄存器數(shù)量。例如,如表4-9所示,從設(shè)備地址為7 (0x07),需要讀取輸入寄存器地址30301 ~ 30303共計3個寄存器的內(nèi)容即讀取Modbus協(xié)議地址300 ~302的內(nèi)容,在報文中表示如下。

起始地址: 0x012C (十進制300) 。
讀取數(shù)量: 0x0003 (十進制3)。

功能碼04查詢報文示例:

字段例(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
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)178

本功能碼中,起始地址由2字節(jié)構(gòu)成,取值范圍為0x0000 ~ 0xFFFF;寄存器數(shù)量由2字節(jié)構(gòu)成,取值范圍為0x0001 0x007D (即十進制1125) ,即最多可以連續(xù)讀取125個寄存器同樣有一點需要注意,Modbus的保持寄存器和輸入寄存器是以字為基本單位的。所以對于浮點數(shù)(或者32位的整數(shù))而言,連續(xù)讀取的兩個寄存器之間存在字節(jié)序和大小端的問題,這一點在開發(fā)時必須引起注意。

3.響應報文

響應報文的各項構(gòu)成和意義如下表所示。因為Modbus的保持寄存器和輸入寄存器是以字為基本單位的,上面的例子中,查詢報文連續(xù)讀取3個寄存器的內(nèi)容,那么將返回6字節(jié),參考下表中數(shù)據(jù)1~3的高位和低位。

功能碼04響應報文示例:

字段例(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
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)2311

5.5.6 05 (0x05)寫單個線圈

1. 功能說明

05功能碼用于將單個線圈寄存器 (或離散輸入)設(shè)置為ON或OFF,該功能碼支持廣播模式在廣播模式下,所有從站設(shè)備的同一地址的值將被統(tǒng)一修改。查詢報文中的ON/OFF狀態(tài)由報文數(shù)據(jù)字段的常數(shù)指定,0xFF00表示ON狀態(tài),0x0000表示OFF狀態(tài)。其他值均是非法的,并且對寄存器不起作用,將會返回異常響應。

2. 查詢報文

查詢報文中需要指定從設(shè)備地址以及需要變更的線圈地址和設(shè)定的狀態(tài)值。需要注意的是,在查詢報文中,線圈地址從地址0開始計數(shù)。例如,如下表所示,從設(shè)備地址為3,設(shè)置線圈地址00150為ON狀態(tài),則查詢報文中的線圈地址設(shè)置為0x95 (149)。

功能碼05查詢報文示例:

字段例(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
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)178

本功能碼中,起始地址由2字節(jié)構(gòu)成,取值范圍為0x0000~0xFFFF:變更目標數(shù)據(jù)由2字節(jié)構(gòu)成,取值只能為0xFF00或0x0000。

3.響應報文

響應報文的各項構(gòu)成和意義如下表所示。對于從設(shè)備,在線圈或離散輸出寄存器正常變更的情況下會返回與查詢報文相同的響應報文。如果修改失敗,則會返回一個異常響應,對于異常響應,后續(xù)章節(jié)會進一步詳細介紹。

功能碼05響應報文示例:

字段例(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
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)178

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

1.功能說明

06功能碼用于更新從設(shè)備的單個保持寄存器的值,該功能碼支持廣播模式,在廣播模式下所有從設(shè)備的同一地址的值將被統(tǒng)一修改。

2. 查詢報文

查詢報文中需要指定從設(shè)備地址以及需要變更的保持寄存器地址和設(shè)定的值。需要注意的是查詢報文中,寄存器地址從地址0開始計數(shù)。例如,如下表所示,從設(shè)備地址為3,設(shè)置寄存器地址40150為1200 (即0x04B0) ,則查詢報文中的地址字段設(shè)置為0x95 (149)。

功能碼06查詢報文示例:

字段例(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
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)178

本功能碼中,起始地址由2字節(jié)構(gòu)成,取值范圍為0x00000xFFFF; 變更目標數(shù)據(jù)由2字節(jié)構(gòu)成,取值范圍為0x00000xFFFF。

3.響應報文

響應報文的各項構(gòu)成和意義,如下表所示。對于從設(shè)備,在保持寄存器正常變更的情況下會返回與查詢報文相同的響應報文。如果修改失敗,則返回個異常響應。

功能碼06響應報文示例:

字段例(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
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)178

5.5.8 08 (0x08) 診斷功能

1.功能說明

08功能碼僅用于串行鏈路,主要用于檢測主設(shè)備和從設(shè)備之間的通信故障,或檢測從設(shè)備的各種內(nèi)部故障,該功能碼不支持廣播。為了區(qū)別各診斷類型,查詢報文中提供了2字節(jié)的子功能碼字段。

通常在正常的響應報文中,從設(shè)備將原樣回復功能碼和子功能碼.

2. 查詢報文

查詢報文中需要指定從設(shè)備地址、功能碼以及子功能碼。

例如,下表中標識了子功能碼“原樣返回查詢數(shù)據(jù)”的診斷功能,其中子功能碼為0(0x0000)。在子功能碼為0x0000的情況下,數(shù)據(jù)字段可以為任意值。各子功能碼的詳細意義可參考下表。

功能碼08查詢報文示例:

字段例(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
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)178

本功能碼中,子功能碼由2字節(jié)構(gòu)成,取值則根據(jù)意義而不同;數(shù)據(jù)字段由2字節(jié)構(gòu)成,其取值由子功能碼確定。

3.響應報文

響應報文的各項構(gòu)成和意義如下表所示。對于從設(shè)備,在保持寄存器正常變更的情況下會返回與查詢報文相同的響應報文。如果修改失敗,則返回一個異常響應。

功能碼08響應報文示例:

字段例(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
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)178

4. 診斷子功能碼

各常用的診斷子功能碼的定義如下。

Return Query Data(00)

診斷內(nèi)容原樣返回查詢報文
子功能碼0x00,0x00
查詢報文數(shù)據(jù)字段任意16位數(shù)據(jù)
響應報文數(shù)據(jù)字段同查詢報文

Restart Communication Option(01)

診斷內(nèi)容重啟通信選項; 用于初始化并重新啟動從站設(shè)備,清楚所有通信事件計數(shù)器; 如果端口處于 Listen Only Mode,則不返回響應;否則在重啟之前返回響應
子功能碼0x00,0x01
查詢報文數(shù)據(jù)字段0x00, 0x00 保持事件記錄; 0xFF,0x00 清除事件記錄
響應報文數(shù)據(jù)字段同查詢報文

Return Diagnostics Register(02)

診斷內(nèi)容返回診斷寄存器
子功能碼0x00,0x04
查詢報文數(shù)據(jù)字段0x00,0x00
響應報文數(shù)據(jù)字段診斷寄存器的內(nèi)容

Force Listen Only Mode

診斷內(nèi)容強制只聽模式; 強制被尋址的從站設(shè)備進入只聽模式,使得此設(shè)備與網(wǎng)絡中的其他設(shè)備斷開,不返回響應
子功能碼0x00,0x04
查詢報文數(shù)據(jù)字段0x00,0x00
響應報文數(shù)據(jù)字段不返回響應

Clear Counters and Diagnostic Register

診斷內(nèi)容清除計數(shù)器和診斷寄存器
子功能碼0x00,0x0A
查詢報文數(shù)據(jù)字段0x00,0x00
響應報文數(shù)據(jù)字段同查詢報文

Return Bus Message Count(11,0x0B)

診斷內(nèi)容返回總線報文計數(shù)
子功能碼0x00,0x0B
查詢報文數(shù)據(jù)字段0x00,0x00
響應報文數(shù)據(jù)字段返回報文的技數(shù)值

Return Bus Communication Error Count(12,0x0C)

診斷內(nèi)容返回總線通信CRC差錯計數(shù)
子功能碼0x00,0x0C
查詢報文數(shù)據(jù)字段0x00,0x00
響應報文數(shù)據(jù)字段返回報文的CRC出錯總數(shù)

Return Bus Exception Error Count(13,0x0D)

診斷內(nèi)容返回總線異常差錯計數(shù)
子功能碼0x00,0x0D
查詢報文數(shù)據(jù)字段0x00,0x00
響應報文數(shù)據(jù)字段返回異常響應的總數(shù)

Return Slave Message Count(14,0x0E)

診斷內(nèi)容返回從站設(shè)備報文總數(shù)
子功能碼0x00,0x0E
查詢報文數(shù)據(jù)字段0x00,0x00
響應報文數(shù)據(jù)字段返回從站設(shè)備接收報文總數(shù)

Return Slave No Response Counrt(15,0x0F)

診斷內(nèi)容返回從站設(shè)備無響應計數(shù)
子功能碼0x00,0x0F
查詢報文數(shù)據(jù)字段0x00,0x00
響應報文數(shù)據(jù)字段返回加電后沒有返回響應的報文的保文數(shù)量

Return Slave Busy Count(17,0x11)

診斷內(nèi)容返回從站設(shè)備忙計數(shù)
子功能碼0x00,0x11
查詢報文數(shù)據(jù)字段0x00,0x00
響應報文數(shù)據(jù)字段返回加電后異常響應忙的報文數(shù)量

Return Bus Character Overrun Count(18,0x12)

診斷內(nèi)容返回總線字符超限計數(shù)
子功能碼0x00,0x12
查詢報文數(shù)據(jù)字段0x00,0x00
響應報文數(shù)據(jù)字段返回超限的報文數(shù)量

5.5.9 11 (0x0B) 獲取通信事件計數(shù)器

1. 功能說明

11功能碼主要用于獲取從設(shè)備通信計數(shù)器中的狀態(tài)字和事件計數(shù)的值,本功能碼不支持廣播模式。通過在通信報文之前和之后讀取通信事件計數(shù)值,可以確定從設(shè)備是否正常處理報文。

對于正常完成報文處理和傳輸?shù)膱龊?,事件計?shù)器增加1;而對于異常響應、輪詢命令或讀事件計數(shù)器(即Ox0B功能碼)的場合,則計數(shù)器不變。通過【0x08診斷功能】 中的子功能碼【Restart Communication Option ( 0x0001 )】 和 【Clear Counters and Diagnostic Register (0x000A) 】 可以復位事件寄存器。

2. 查詢報文

下表中的示例表示獲取通信事件計數(shù)器的查詢報文內(nèi)容,其中從站設(shè)備地址為5.

功能碼11查詢報文示例:

字段例(Hex)ASCII模式字符型RTU模式8位(Hex)
幀頭“:”
從設(shè)備地址0x05“0”,“5”0x05
功能碼0x0B“0”,“B”0x0B
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)94

3. 響應報文

對于從設(shè)備,在正常情況下,響應報文返回2字節(jié)的狀態(tài)字和2字節(jié)的事件計數(shù)。其中,如果從站設(shè)備處于忙狀態(tài),那么狀態(tài)字為0xFFFF,否則狀態(tài)字為0x0000。在表4-18的示例中,狀態(tài)字為0x0000,表示從站設(shè)備外于空閑狀態(tài)。事件計數(shù)的值為0x03E8,表示記錄了1000 (0x03E8)個事件。

功能碼11響應報文示例:

字段例(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
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)178

5.5.10 12 (0x0C) 獲取通信事件記錄

1. 功能說明

12功能碼主要用于從從設(shè)備獲取狀態(tài)字、事件計數(shù)、報文計數(shù)以及事件字節(jié)字段。其中,狀態(tài)字和事件計數(shù)與功能碼11 (0x0B) 獲取的值一致。報文計數(shù)包含加電重啟、清除計數(shù)器之后的報文數(shù)量,報文計數(shù)與通過診斷功能碼08 (0x08)、子功能碼11 (0x0B) 獲取的值一致。事件字節(jié)字段包含0~64字節(jié),用來定義各種事件。

2. 查詢報文

下表中的示例表示獲取通信事件記錄的查詢報文內(nèi)容,其中從站地址位5。

功能碼12查詢報文示例:

字段例(Hex)ASCII模式字符型RTU模式8位(Hex)
幀頭“:”
從設(shè)備地址0x05“0”,“5”0x05
功能碼0x0C“0”,“C”0x0C
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)94

3. 響應報文

對于從站設(shè)備,在正常情況下,響應報文包括一個2字節(jié)的狀態(tài)字字段、一個2字節(jié)的事件計數(shù)字段、一個2字節(jié)的消息計數(shù)字段以及0~ 64字節(jié)的事件字段。因為事件字段是變長的,所以增加了一個1字節(jié)的數(shù)據(jù)長度字段,以方便讀取響應數(shù)據(jù),如下表所示;

功能碼12響應報文示例:

字段例(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
事件計數(shù)(高位)0x03“0”,“3”0x03
事件計數(shù)(低位)0xE8“E”,“8”0xE8
消息計數(shù)(高位)0x01“0”,“1”0x01
消息計數(shù)(低位)0xF6”F“,”6“0xF6
事件00x20”2“,”0“0x20
事件10x00”0“,”0“0x00
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)178

5.5.11 15(0x0F)寫多個線圈

1.功能說明

15功能碼用于將連續(xù)的多個線圈或離散輸出設(shè)置為ON/OFF狀態(tài),支持廣播模式,在廣播模式下,所有從站設(shè)備的同一地址的值將被統(tǒng)一修改。15功能碼中,起始地址字段由2字節(jié)構(gòu)成,取值范圍為0x00000xFFFF:而寄存器數(shù)量字段由2字節(jié)構(gòu)成,取值范用為0x00010x07B0.

2. 查詢報文

查詢報文中包含請求數(shù)據(jù)字段,用于定義ON或OFF狀態(tài)。數(shù)據(jù)字段中為邏輯1的位對應ON;邏輯0的位對應OFF。其中,ON/OFF與數(shù)據(jù)字段的對應關(guān)系可參考前面的童節(jié)“01 (0x01) 讀取線圈,離散量輸出狀態(tài) (Read Coil status/DOs)” 中的內(nèi)容舉例說明,假設(shè)從站設(shè)備地址為5,需要設(shè)置線圈地址20 ~30的狀態(tài)如下表所示。

線圈狀態(tài):

1101000100000101
線圈2726252423222120302928

那么,寫入的數(shù)據(jù)字段被劃分為2字節(jié),值分別為0xD1,對應于27 ~ 20的線圈,值0x05對應于30~28的線圈,注意細體會其中的高低位的對應關(guān)系。需要注意的是,在查詢報文中,Modbus協(xié)議的起始地址為19 (0x13) ,即比線圈起始地址20少1。如下表所示,其中字節(jié)數(shù)字段表示需要變更數(shù)據(jù)的字節(jié)總數(shù)。

功能碼15查詢報文示例:

字段例(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
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)2311

3. 響應報文

對于從設(shè)備,在正常情況下,響應報文包括功能碼、起始地址以及寫入的線圈數(shù)量,如下表所示。

功能碼15響應報文示例:

字段例(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
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)178

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

1. 功能說明

16功能碼用于設(shè)置或?qū)懭霃脑O(shè)備保持寄存器的多個連續(xù)的地址塊 (1 ~ 123個寄存器),支持廣播模式,在廣播模式下,所有從站設(shè)備的同一地址的值將被統(tǒng)一修改。本功能碼中,起始地址字段由2字節(jié)構(gòu)成,取值范圍為0x0000 ~ 0xFFFF;而寄存器數(shù)量字段由2字節(jié)構(gòu)成,取值范圍為0x0001~0x007B。

2. 查詢報文

查詢報文包含請求數(shù)據(jù)字段。數(shù)據(jù)字段保存需要寫入的數(shù)值,各數(shù)據(jù)按每個寄存器2字節(jié)存放。舉例說明,從站設(shè)備地址為5,需要將保持寄存器地址40020 ~ 40022設(shè)置為如下表所示的數(shù)值。

寄存器的設(shè)置:

寄存器地址設(shè)定值寄存器地址設(shè)定值
400200x0155400220x0157
400210x0156

對應于40020~40022的寄存器,注意仔細體會其中的高低位的對應關(guān)系。需要注意的是,在查詢報文中,Modbus協(xié)議的起始地址為19 (0x13),即比寄存器起始地址20少1。如下表所示,其中字節(jié)數(shù)字段表示需要變更數(shù)據(jù)的字節(jié)總數(shù)。

功能碼16查詢報文示例:

字段例(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
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)3115

3. 響應報文

對于從設(shè)備,在正常情況下,響應報文包括功能碼、起始地址及寫入的寄存器數(shù)量,如下表所示。

功能碼16響應報文示例:

字段例(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
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)178

在實際開發(fā)過程中,功能碼“16 (0x10) 寫多個寄存器 (Preset Multiple Registers) ”通常用于方便用戶寫入多字節(jié)類型的數(shù)據(jù)。

例如,假設(shè)從站設(shè)備地址為5,需要向保持寄存器寫入一個32位 (4字節(jié)) 的浮點數(shù),那么此浮點數(shù)將占用2個寄存器地址。假設(shè)浮點數(shù)將存放在40001和40002寄存器中,設(shè)定值為1.235(即0x3F9E 147A)實際的查詢和響應報文如下(其中標記部分為設(shè)定的浮點數(shù)值,假設(shè)字節(jié)序為AB-CD,參考第5.3.7章字節(jié)序和大小端的內(nèi)容)。

查詢報文: 05 10 00 00 00 02 04 3F 9E 14 7A 05 86
響應報文: 05 10 00 00 00 02 40 4C

對于64位(8字節(jié))的雙精度浮點數(shù),同理將占用4個寄存器地址共8字節(jié)的空間。特別需要注意的是字節(jié)序及大小端的問題,前面討論過多字節(jié)存在大小端問題,因此主站設(shè)備和從站設(shè)備必須保持一致的規(guī)則處理,約定Modbus傳輸中的數(shù)據(jù)字段的字節(jié)序,否則會因為大小端不一致而產(chǎn)生數(shù)據(jù)處理錯誤。

5.5.13 17 (0x11) 報告從站ID (僅用于串行鏈路)

1. 功能說明

17功能碼用于讀取從站設(shè)備的ID、類型描述、當前狀態(tài)以及其他信息,不支持廣播模式。響應消息的構(gòu)成依賴于設(shè)備而不盡相同。

2. 查詢報文

查詢報文中不包含請求數(shù)據(jù)字段。舉例說明,從站設(shè)備地址為5,獲取相關(guān)信息,如下表所示。

功能碼17查詢報文示例:

字段例(Hex)ASCII模式字符型RTU模式8位(Hex)
幀頭“:”
從設(shè)備地址0x05“0”,“5”0x05
功能碼0x11“1”,“1”0x11
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)94

3. 響應報文

**對于從設(shè)備,在正常情況下,響應報文包括從站ID、運行狀態(tài)以及其他附加信息,如下表所示。運行狀態(tài)字段占用1字節(jié),且0x00=OFF,0xFF=ON,而響應報文的組成則由開發(fā)者決定。**

功能碼17響應報文示例:

字段例(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)
運行狀態(tài)0xFF“F”,“F”0xFF
附加情報1設(shè)備相關(guān)設(shè)備相關(guān)設(shè)備相關(guān)
……設(shè)備相關(guān)設(shè)備相關(guān)設(shè)備相關(guān)
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)178

5.5.14 Modbus異常響應

以上介紹了一些常見的公共功能碼的報文 (消息頓)構(gòu)成,廣播模式以外的查詢報文都希望能夠獲取一個正常的響應報文。在通常情況下,從站設(shè)備將返回一個正常響應報文,但是在某些特殊情況下將返回異常響應報文。

對于查詢報文,存在以下4種處理反饋:

  • 正常接收,正常處理,返回正常響應報文;
  • 因為通信錯誤等原因造成從站設(shè)備沒有接收到查詢報文,主站設(shè)備將按超時處理:從站設(shè)備接收到的查詢報文存在通信錯誤 (如LRC、CRC錯誤等),此時從站設(shè)備將丟棄報文不響應,主站設(shè)備將按超時處理;
  • 從站設(shè)備接收到正確的報文,但是超過處理范圍(如不存在的功能碼或者寄存器等),此時從站設(shè)備將返回包含異常碼 (Exception Code) 的響應報文。
  • 異常響應報文由從站地址、功能碼以及異常碼構(gòu)成。其中,功能碼與正常響應報文不同,在異常響應報文中,功能碼最高位 (即MSB) 被設(shè)置為1。因為Modbus協(xié)議中的功能碼占用1字節(jié)故用表達式描述為:
異常功能碼=正常功能碼+0x80

舉例說明,如下表所示,查詢報文的起始地址為0x012C (十進制300) ,即需要讀取寄存器地址為30301開始的值。若從站設(shè)備中不存在輸入寄存器30301,則從站設(shè)備將返回一個異常響應報文,參見下表的功能碼和異常碼。

異常響應示例(功能碼04查詢報文 ):

字段例(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
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)178

異常響應示例(功能碼04響應報文 )

字段例(Hex)ASCII模式字符型RTU模式8位(Hex)
幀頭“:”
從設(shè)備地址0x07“0”,“7”0x07
功能碼0x84“8”,“4”0x84
異常碼0x02“0”,“2”0x02
差錯校驗LRC(2字符)CRC(2字節(jié))
幀尾CR/LF
合計字節(jié)數(shù)115

常見的異常碼如下表所示:

常見異常碼說明:

異常碼名稱說明
01非法功能碼從站設(shè)備不支持此功能碼
02非法數(shù)據(jù)地址指定的數(shù)據(jù)地址在從站設(shè)備中不存在
03非法數(shù)據(jù)值指定的數(shù)據(jù)超過范圍或者不允許使用
04從站設(shè)備故障從站設(shè)備處理響應的過程中出現(xiàn)未知錯誤等
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5608

    瀏覽量

    129951
  • MODBUS
    +關(guān)注

    關(guān)注

    28

    文章

    2456

    瀏覽量

    83177
  • 通訊協(xié)議
    +關(guān)注

    關(guān)注

    10

    文章

    298

    瀏覽量

    21480
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    什么是Modbus通訊協(xié)議?Modbus通訊協(xié)議有什么特點?

    什么是Modbus通訊協(xié)議:  Modbus是由Modicon(現(xiàn)為施耐德電氣公司的一個品牌)在1979年發(fā)明的,是全球第一個真正用于工業(yè)現(xiàn)場的總線
    發(fā)表于 11-11 10:35

    MODBUS通訊協(xié)議---多機通訊

    本帖最后由 eehome 于 2013-1-5 09:48 編輯 要搞個MODBUS協(xié)議,這幾天剛好有空,所以就把它寫了出來,里面還是有點問題,但是總體上問題不大,如果有的話應該是在某些細節(jié)上
    發(fā)表于 11-11 17:25

    基于LabVIEW的Modbus串口通訊協(xié)議的實現(xiàn)

    基于LabVIEW 的Modbus 串口通訊協(xié)議的實現(xiàn)附件基于LabVIEW 的Modbus 串口通訊協(xié)
    發(fā)表于 10-16 10:50

    ModBus通訊協(xié)議簡介

    ModBus通訊協(xié)議通訊協(xié)議又稱通信規(guī)程,是指通信雙方對數(shù)據(jù)傳送控制的一種約定。約定中包括對數(shù)據(jù)格式,同步方式,傳送速度,傳送步驟,檢糾錯方
    發(fā)表于 08-23 09:19

    如何通過VISA編寫Modbus通訊協(xié)議

    什么是Modbus通訊協(xié)議?如何通過VISA編寫Modbus通訊協(xié)議呢?
    發(fā)表于 09-29 07:44

    Modbus通訊協(xié)議的幾種實現(xiàn)方式

    RTU和TCP兩種協(xié)議中轉(zhuǎn)換,根據(jù)需要選擇不同協(xié)議。這是LabVIEW多態(tài)的一個非常好的示例。程序見下圖。   5.LabVIEW 采用TCP模塊實現(xiàn)Modbus
    發(fā)表于 05-05 16:19

    MODBUS通訊協(xié)議及編程

    ModBus通訊協(xié)議分為RTU協(xié)議和ASCII協(xié)議,下面就ModBus?RTU
    發(fā)表于 07-17 11:58 ?1.5w次閱讀

    Modbus_通訊協(xié)議詳解

    Modbus_通訊協(xié)議詳解,Modbus_通訊協(xié)議詳解
    發(fā)表于 12-08 14:13 ?0次下載

    MODBUS通訊協(xié)議及編程

    MODBUS通訊協(xié)議及編程標準通訊協(xié)議格式,工業(yè)通信的標準格式。
    發(fā)表于 03-10 11:45 ?68次下載

    MODBUS通訊協(xié)議詳細介紹

    MODBUS通訊協(xié)議詳細介紹標準通訊協(xié)議格式,工業(yè)通信的標準格式。
    發(fā)表于 03-10 11:42 ?38次下載

    MODBUS通訊協(xié)議中文版

    介紹了MODBUS通訊協(xié)議的架構(gòu),和應用,分享給大家,歡迎下載。
    發(fā)表于 08-09 17:33 ?0次下載

    Modbus通訊協(xié)議的原理和標準

    Modbus通訊協(xié)議分為RTU和ASCLL兩種傳輸模式,已經(jīng)成為一種標準工業(yè)控制協(xié)議。
    發(fā)表于 11-02 18:31 ?13次下載

    解讀Modbus通訊協(xié)議

    作為工控人,Modbus 通訊協(xié)議想必都不陌生,Modbus 通訊協(xié)議可以說是工業(yè)自動化領(lǐng)域應用
    的頭像 發(fā)表于 11-09 16:39 ?3493次閱讀

    Modbus通訊協(xié)議的詳細資料講解

    作為工控人,Modbus 通訊協(xié)議想必都不陌生,Modbus 通訊協(xié)議可以說是工業(yè)自動化領(lǐng)域應用
    發(fā)表于 11-27 02:01 ?54次下載
    <b class='flag-5'>Modbus</b><b class='flag-5'>通訊</b><b class='flag-5'>協(xié)議</b>的詳細資料講解

    Modbus TCP通訊協(xié)議概述

    1? Modbus TCP通訊概述 MODBUS/TCP是簡單的、中立廠商的用于管理和控制自動化設(shè)備的MODBUS系列訊協(xié)議的派生產(chǎn)品,顯而
    的頭像 發(fā)表于 01-04 17:51 ?3.3w次閱讀
    <b class='flag-5'>Modbus</b> TCP<b class='flag-5'>通訊</b><b class='flag-5'>協(xié)議</b>概述