第一部分 Modbus
1.Modbus相關術語
ADU(Application Data Unit) 應用數據單元
PDU(Protocol Data Unit) 協議數據單元
LSB(Least Significant Bit) 最低有效位
MSB(Most Significant Bit) 最高有效位
MB(Modbus Protocol) Modbus協議
2.Modbus協議簡介
Modbus是一個請求/應答協議,并且提供功能碼規定的服務。Modbus功能碼是Modbus請求/應答PDU的元素。【PDU表示協議數據單元】
Modbus是應用層報文傳輸協議,它在通過不同類型的總線或網絡連接的設備之間的客戶機/服務器通信。
目前,通過下列方式實現Modbus通信:
——以太網上的TCP/IP
——各種介質(有線;EIA/TIA-232-E、EIA-422、EIA/TIA-485-A;光纖、無線等等)上的異步串行傳輸。【我們要使用和介紹的就是這種方式】
——Modbus+,一種高速令牌傳輸網絡
Modbus協議定義了一個與基礎通信層無關的簡單協議數據單元(PDU)。特定總線或網絡上的Modbus協議映射能夠在應用數據單元(ADU)上引用一些附加域。
啟動Modbus事務處理的客戶機創建Modbus應用數據單元。功能碼向服務器指示將執行哪種操作。Modbus協議建立了客戶機啟動的請求格式。
用一個字節編碼Modbus數據單元的功能碼域。有效的碼字范圍是十進制1~255(128~255為異常響應保留)。當從客戶機向服務器設備發送報文時,功能碼域通知服務器執行哪種操作。
從客戶機向服務器設備發送的報文數據域包括附加信息,服務器使用這個信息執行功能碼定義的操作。這個域還包括離散量和寄存器地址、處理的項目數量以及字段中的實際數據字節數。
在某種請求中,數據字段可以是不存在的(0長度),在此情況下服務器不需要任何附加信息。功能碼僅說明操作。
如果在一個正確接收的Modbus ADU中,不出現與所請求的Modbus功能有關的差錯,那么服務器至客戶機的響應數據字段包含所請求的數據。如果出現與所請求的Modbus功能有關的差錯,那么該域包含一個異常碼,服務器應用能夠使用這個字段確定下一個執行的操作。
當服務器對客戶機響應時,它使用功能碼字段來指示正常(無差錯)響應(見圖2)或者出現某種差錯(稱為異常響應),見圖3。對于一個正常響應來說,服務器僅復制原始功能碼。
3.數據編碼
Modbus使用最高有效字節在低地址存儲的方式表示地址和數據項。這意味著當發送多個字節時,首先發送最高有效字節。例如:
寄存器大小值
16位0x1234 發送的第一字節為:0x12 然后是0x34
4.Modbus 數據模型
Modbus 的數據模型是以一組具有不同特征的表為基礎建立的。4個基本表見表1:
基本表 |
對象類型 |
訪問類型 |
注釋 |
離散量輸入 |
單個位 |
只讀 |
I/O系統可提供這種類型數據 |
線圈 |
單個位 |
讀寫 |
通過應用程序可改變這種類型數據 |
輸入寄存器 |
16位字 |
只讀 |
I/O系統可提供這種類型數據 |
保持寄存器 |
16位字 |
讀寫 |
通過應用程序可改變這種類型數據 |
輸入與輸出之間以及位尋址的和字尋址的數據項之間的區別并不意味著應用特性的差別。如果所有4個表相互覆蓋是對該目標機器最自然的解釋,也是完全可接收的,而且很普遍。
對于每個基本表,協議都允許單個的選擇65536個數據項,而且其讀寫操作被設計為可以越過多個連續數據項直到數據大小規格限制,這個數據大小規格限制與事務處理功能碼有關。
很顯然,必須將Modbus處理的所有數據(位,寄存器)放置在設備應用寄存器中,但是,存儲器的物理地址不應該與數據引用混淆。僅要求將數據引用與物理地址鏈接。
Modbus功能碼中使用的Modbus寄存器邏輯編號是以0開始的無符號整數。
——Modbus模型實現的實例
下列實例表示了兩種在設備中組織數據的方法。有多種組織數據的方法,在本部分中沒有被全部描述。每個設備根據其應用都有它自己的組織數據的方法。
實例1:有4個獨立塊的設備
圖4表示了含有數字量和模擬量、輸入量和輸出量的設備中的數據組織。由于不同
塊中的數據不相關,每個塊是獨立的。可通過不同Modbus功能碼訪問每個塊。
5.公共功能碼定義
5.1.01(0x01)讀線圈
見表2~表4。
使用該功能碼從一個遠程設備中讀1~2000個連續的線圈狀態。請求PDU指定了起始地址,即指定了第一個線圈地址和線圈數目。在PDU中,從17(十六進制11)返回從站忙計數。
響應報文中的線圈按數據域的每位一個線圈進行打包。狀態被表示成1=ON和0=OFF。第一個數據字節的LSB(最低有效位)包含詢問中所尋址的輸出。其他線圈依次類推,一直到這個字節的高位端為止,并在后續字節中按照從低位到高位的順序排列。
如果返回的輸出數量不是8的倍數,將用零填充最后數據字節中的剩余位(一直到字節的最高位端)。字節數量域說明了數據的全部字節數。
表2
請求
功能碼 |
1字節 |
0x01 |
起始地址 |
2字節 |
0x0000~0xFFFF |
線圈數量 |
2字節 |
1~2000(0x07D0) |
表3
響應
功能碼 |
1字節 |
0x01 |
字節計數 |
1字節 |
N* |
線圈狀態 |
n字節 |
n=N或N+1 |
*N=輸出數量/8,如果余數不等于0,那么N=N+1。 |
表4
錯誤
功能碼 |
1字節 |
功能碼+0x80 |
異常碼 |
1字節 |
01或02或03或04 |
5.2.02(0x02)讀離散量輸入
見表5~表7。
使用該功能從一個遠程設備中讀1~2000個連續的離散量輸入狀態。請求PDU指定了起始地址,即指定了第一個離散量輸入地址和離散量輸入數目。在PDU中,從零開始尋址離散量輸入。因此標號1~16的離散量輸入尋址為0~15。
響應報文中的離散量輸入按數據域的每位一個離散量輸入進行打包。狀態被表示成1=ON和0=OFF。第一個數據字節的LSB(最低有效位)包含訊問中所尋址的輸入。其他離散量輸入依次類推,一直到這個字節的高位端為止,并在后續字節中按照從低位到高位的順序排列。
如果返回的輸出數量不是8的倍數,將用零填充最后數據字節中的剩余位(一直到字節的最高位端)。字節數量域說明了數據的全部字節數。
表5
請求
功能碼 |
1字節 |
0x02 |
起始地址 |
2字節 |
0x0000~0xFFFF |
線圈數量 |
2字節 |
1~2000(0x07D0) |
表6
響應
功能碼 |
1字節 |
0x02 |
字節計數 |
1字節 |
N* |
線圈狀態 |
N*×1個字節 |
… |
*N=輸出數量/8,如果余數不等于0,那么N=N+1 |
表7
錯誤
差錯碼 |
1字節 |
0x82 |
異常碼 |
1字節 |
01或02或03或04 |
5.3.03(0x03)讀保持寄存器
見表8~表10。
使用該功能碼從遠程設備中讀保持寄存器連續塊的內容。請求PDU說明了起始寄存器地址和寄存器數量。在PDU中,從零開始尋址寄存器。因此編號1~16的寄存器尋址為0~15。
將響應報文中的寄存器數據打包成每個寄存器有兩字節。
對于每個寄存器,第一個字節為高位字節,第二個字節為低位字節。
表8
請求
功能碼 |
1字節 |
0x03 |
起始地址 |
2字節 |
0x0000~0xFFFF |
寄存器數量 |
2字節 |
1~125(0x007D) |
表9
響應
功能碼 |
1字節 |
0x03 |
字節數 |
1字節 |
2×N* |
寄存器值 |
N*×2個字節 |
… |
*N=寄存器的數量 |
表10
錯誤
差錯碼 |
1字節 |
0x83 |
異常碼 |
1字節 |
01或02或03或04 |
5.4.04(0x04)讀輸入寄存器
見表11~表13。
使用該功能碼從一個遠程設備中讀1~125個連續輸入寄存器。請求PDU說明了起始地址和寄存器數量。在PDU中,從零開始尋址寄存器。因此,標號為1~16的輸入寄存器尋址為0~15。
將響應報文中的寄存器數據打包成每個寄存器為兩字節。
對于每個寄存器,第一個字節包括高位位,第二個字節包括低位位。
表11
請求
功能碼 |
1字節 |
0x04 |
起始地址 |
2字節 |
0x0000~0xFFFF |
輸入寄存器數量 |
2字節 |
0x0001~0x007D |
表12
響應
功能碼 |
1字節 |
0x04 |
字節計數 |
1字節 |
2×N* |
輸入寄存器 |
N*×2個字節 |
… |
*N=輸入寄存器的數量。 |
表13
錯誤
差錯碼 |
1字節 |
0x84 |
異常碼 |
1字節 |
01或02或03或04 |
5.5.05(0x05)寫單個線圈
見表14~表16。
使用該功能碼將一個遠程設備中的一個輸出寫ON或OFF。
請求數據域中的常數指定所請求的ON/OFF狀態。十六進制值FF00請求輸出為ON。十六進制值0000請求輸出為OFF。其他所有值均是非法的,并且對輸出不起作用。
請求PDU說明了被強制的線圈地址。從零開始尋址線圈。因此,編號為1的線圈被尋址為0。線圈值域的常數指定所請求的ON/OFF狀態。十六進制值0xFF00請求線圈為ON。十六進制值0x0000請求線圈為OFF。其他所有值均為非法的,并且對線圈不起作用。
正常的響應是請求的復制,在寫入線圈狀態后被返回。
表14
請求
功能碼 |
1字節 |
0x05 |
輸出地址 |
2字節 |
0x0000~0xFFFF |
輸出值 |
2字節 |
0x0000或0xFF00 |
表15
響應
功能碼 |
1字節 |
0x05 |
輸出地址 |
2字節 |
0x0000~0xFFFF |
輸出值 |
2字節 |
0x0000或0xFF00 |
表16
錯誤
差錯碼 |
1字節 |
0x85 |
異常碼 |
1字節 |
01或02或03或04 |
5.6.06(0x06)寫單個寄存器
見表17~19。
使用該功能碼在一個遠程設備中寫一個保持寄存器。
請求PDU指定了被寫入寄存器的地址。從零開始尋址寄存器。因此,編號為1的寄存器被尋址為0。
正常的響應是請求的復制,在寫入寄存器內容之后被返回。
表17
請求
功能碼 |
1字節 |
0x06 |
寄存器地址 |
2字節 |
0x0000~0xFFFF |
寄存器值 |
2字節 |
0x0000~0xFFFF |
表18
響應
功能碼 |
1字節 |
0x06 |
寄存器地址 |
2字節 |
0x0000~0xFFFF |
寄存器值 |
2字節 |
0x0000~0xFFFF |
表19
錯誤
差錯碼 |
1字節 |
0x86 |
異常碼 |
1字節 |
01或02或03或04 |
5.7.07(0x07)讀異常狀態
見表20~22。
使用這個功能碼從一個遠程設備中讀8個異常狀態輸出的內容。
因為異常碼輸出參量是已知的(在這個功能中不需要輸出參量),該功能提供一種簡單的訪問這種信息的方法。
正常的響應包括8個異常狀態輸出的內容。將這些輸出打包成一個字節,每個輸出一個位。在該字節的最低有效位中包含最低位輸出參量的狀態。
表20
請求
表21
響應
功能碼 |
1字節 |
0x07 |
輸出數據 |
1字節 |
0x00~0xFF |
表22
錯誤
差錯碼 |
1字節 |
0x87 |
異常碼 |
1字節 |
01或04 |
5.8.08(0x08)診斷
公司產品通訊協議中不使用該功能碼,不進行描述。
5.9.11(0x0B)獲得通信事件計數器
公司產品通訊協議中不使用該功能碼,不進行描述。
5.10.12(0x0C)獲得通信事件記錄
公司產品通訊協議中不使用該功能碼,不進行描述。
5.11.15(0x0F)寫多個線圈
見表23~25。
該功能碼將一個遠程設備中的一個線圈序列的每個線圈強制為ON或OFF。請求PDU指定了被強制的線圈編號。從零開始尋址線圈。因此,編號為1的線圈被尋址為0。
請求數據域的內容指定了被請求的ON/OFF狀態。數據域中為邏輯“1”的位請求相應輸出為ON。為邏輯“0”的位請求相應輸出為OFF。
正常的響應返回功能碼、起始地址和被強制的線圈數量。
表23
請求
功能碼 |
1字節 |
0x0F |
起始地址 |
2字節 |
0x0000~0xFFFF |
輸出數量 |
2字節 |
0x0001~0x07B0 |
字節計數 |
1字節 |
N* |
輸出值 |
N*×1字節 |
… |
*N=輸出數量/8,如果余數不等于0,那么,N=N+1。 |
表24
響應
功能碼 |
1字節 |
0x0F |
起始地址 |
2字節 |
0x0000~0xFFFF |
輸出數量 |
2字節 |
0x0001~0x07B0 |
表25
錯誤
差錯碼 |
1字節 |
0x8F |
異常碼 |
1字節 |
01或02或03或04 |
5.12.16(0x10)寫多個寄存器
見表26~28。
使用該功能碼在一個遠程設備中寫連續寄存器塊(1~123個寄存器)。
在請求數據域中指定了請求寫入的值。將數據打包成每個寄存器兩字節。
正常的響應返回功能碼、起始地址和被寫入寄存器的數量。
表26
請求
功能碼 |
1字節 |
0x10 |
起始地址 |
2字節 |
0x0000~0xFFFF |
寄存器數量 |
2字節 |
0x0001~0x007B |
字節計數 |
1字節 |
2×N* |
寄存器值 |
N*×2字節 |
值 |
*N=寄存器數量 |
表27
響應
功能碼 |
1字節 |
0x10 |
起始地址 |
2字節 |
0x0000~0xFFFF |
寄存器數量 |
2字節 |
1~123(0x007B) |
表28
錯誤
差錯碼 |
1字節 |
0x90 |
異常碼 |
1字節 |
01或02或03或04 |
5.13.17(0x11)報告從站ID
公司產品通訊協議中不使用該功能碼,不進行描述。
5.14.20/6(0x14/0x06)讀文件記錄
公司產品通訊協議中不使用該功能碼,不進行描述。
5.15.21/6(0x15/0x06)寫文件記錄
公司產品通訊協議中不使用該功能碼,不進行描述。
5.16.22(0x16)屏蔽寫寄存器
公司產品通訊協議中不使用該功能碼,不進行描述。
5.17.23(0x17)讀/寫多個寄存器
公司產品通訊協議中不使用該功能碼,不進行描述。
5.18.24(0x18)讀FIFO隊列
公司產品通訊協議中不使用該功能碼,不進行描述。
5.19.43(0x2B)封裝接口傳輸
公司產品通訊協議中不使用該功能碼,不進行描述。
5.20.43/14(0x2B/0x0E)讀設備標識
見表29~32。
這個功能碼允許讀取與遠程設備的物理和功能描述相關的標識和附加信息。
讀設備識別接口由包含一組可尋址數據元素組成的地址空間構成。數據元素被稱作對象,由對象Id識別它們。
接口由3類對象組成:
——基本設備識別。所有此類對象都是必備的:廠商名稱、產品代碼和修訂版本號。
——常規設備識別。除基本數據對象以外,設備提供了附加的和可選擇的識別以及數據
對象描述。本標準定義了所有類別的對象,但是它們的實現是可選的。
——擴展設備識別。除常規數據對象以外,設備提供了附加的和可選的識別以及專用數
據描述。所有這些數據都是與設備有關的。
表29
對象Id |
對象名稱/描述 |
類型 |
M/O |
類別 |
0x00 |
廠商名稱 |
ASCII字符串 |
強制的 |
基本 |
0x01 |
產品代碼 |
ASCII字符串 |
強制的 |
基本 |
0x02 |
主要修訂本 |
ASCII字符串 |
強制的 |
基本 |
0x03 |
廠商網址 |
ASCII字符串 |
可選的 |
常規 |
0x04 |
產品名稱 |
ASCII字符串 |
可選的 |
常規 |
0x05 |
模式名稱 |
ASCII字符串 |
可選的 |
常規 |
0x06 |
用戶應用名稱 |
ASCII字符串 |
可選的 |
常規 |
0x07
…
0x7F |
保留 |
— |
可選的 |
常規 |
0x80
…
0xFF |
可選擇的定義專用對象
范圍(0x80~0xFF)與產品有關 |
ASCII字符串 |
可選的 |
擴展 |
表30
請求
功能碼 |
1字節 |
0x2B |
MEI類型 |
1字節 |
0x0E |
ReadDevId碼 |
1字節 |
01/02/03/04 |
對象Id |
1字節 |
0x00~0xFF |
表31
響應
功能碼 |
1字節 |
0x2B |
MEI類型 |
1字節 |
0x0E |
ReadDevId碼 |
1字節 |
01/02/03/04 |
一致性等級 |
1字節 |
… |
接續標識 |
1字節 |
0x00/0xFF |
下一個對象Id |
1字節 |
對象ID號 |
對象數量 |
1字節 |
… |
列表 |
|
|
對象ID |
1字節 |
… |
對象長度 |
1字節 |
… |
對象值 |
對象長度 |
與對象ID有關 |
表32
錯誤
功能碼 |
1字節 |
0xAB:Fc 0x2B+0x80 |
MEI類型 |
1字節 |
0x0E |
異常碼 |
1字節 |
01或02或03或04 |
第二部分 Modbus協議在電力儀表中的應用
Modbus協議定義了兩種串行傳輸模式:RTU模式和ASCII模式。這兩種模式定義了串行鏈路上傳送報文域的位內容,確定了信息如何打包為報文域和如何解碼。
Modbus要求每個設備必須實現RTU模式,ASCII模式作為可選模式。我公司目前主要采用Modbus RTU模式。暫時不考慮使用Modbus ASCII模式。
2.1. RTU傳輸模式
在Modbus串行鏈路上通信時,報文中每個8位字節含有兩個4位十六進制字符。
RTU模式中每個字節(10位)的格式為:
編碼系統: 每個8位字節含有兩個4位十六進制字符(0~9、A~F)
每個字節的位: 1個起始位
8個數據位
無校驗位
1個停止位
注:幀校驗域: 循環冗余校驗(CRC)。
通訊波特率:可選范圍為2400bps、4800bps、9600bps、19200bps。
2.2. Modbus報文RTU幀
在RTU模式中,時長至少為3.5個字符的間隔時間將報文幀區分開。這個時間稱為
t3.5。
圖7表示了一個典型的報文幀。
起始 |
地址 |
功能碼 |
數據 |
CRC |
結束 |
≥3.5字符 |
8位 |
8位 |
N×8位 |
16位 |
≥3.5字符 |
圖7
必須以連續的字符流發送整個報文幀。
如果字符之間的空閑間隔大于1.5個字符時間,那么認為報文幀不完整,并且接收站應該丟棄這個報文幀。
字符間間隔
所謂1個字符的時間t,是指發送完每個10位所用的時間,計算方法為“1÷波特率×10”。但是,實現RTU的定時會對系統帶來大量中斷管理。在較高的通訊波特率下,這將導致CPU負擔加重。因此,當波特率等于或低于19200 bit/s時,必須嚴格遵守這兩個定時;波特率大于19200 bit/s時,兩個定時器應該使用固定值:建議字符間隔超時時間(t1.5)為750μs,幀間的超時時間(t3.5)為1.750ms。
2.3. CRC校驗
RTU模式包含一個差錯校驗域,該域是基于冗余循環校驗(CRC)方法對全部報文內容執行的。
CRC域校驗整個報文的內容。無論單個字符報文使用何種奇偶校驗,均應用這種CRC校驗。
CRC包括兩個8位字節組成的一個16位值。
CRC域作為報文的最后域附加到報文上。當進行這種附加時,首先附加域的低位字節,然后附加域的高位字節。CRC高位字節是報文中發送的最后字節。
2.4. Mosbus功能碼簡介
儀表中使用了Modbus中的部分功能碼,分別是:
功能碼 |
Modbus中定義 |
儀表中定義 |
操作說明 |
0x02 |
讀離散量輸入 |
讀開關量輸入DI |
讀取一路或多路開關量狀態輸入數(遙信) |
0x 01 |
讀線圈 |
讀狀態量輸出OUT |
讀取一路或多路開關量輸出狀態數據 |
0x 03 |
讀多個保持寄存器 |
讀寄存器數據 |
讀取一個或多個寄存器的數據 |
0x 05 |
寫單個線圈 |
寫開關量輸出OUT |
控制一路繼電器“合/分”輸出(遙控) |
0x 06 |
寫單個保持寄存器 |
寫單路寄存器 |
把一組數據寫入單個寄存器 |
0x 10 |
寫多個保持寄存器 |
寫多路寄存器 |
把多組數據寫入多個寄存器 |
2.4.1. 功能碼“0x02”
功能碼0x02的意思是:讀1路或多路開關量輸入狀態DI
例如:主機要讀取儀表地址為0x01的開關量(DI1—DI4)的輸入狀態。
從機(儀表)中保存開關量輸入狀態的寄存器地址和數據為:
起始DI地址 |
DI寄存器數據 |
備注 |
0x0000 |
0x0B |
DI1/DI2/DI4的狀態為“1”,DI3狀態為“0” |
主機發送的報文格式:
主機發送 |
字節數 |
發送的信息 |
備注 |
從機地址 |
1 |
01 |
發送至地址為01的從機 |
功能碼 |
1 |
02 |
讀開關量輸入狀態 |
起始BIT位 |
2 |
0000 |
起始BIT位的地址為0000 |
讀數據長度 |
2 |
0004 |
讀取4路開關量輸入狀態位 |
CRC碼 |
2 |
79C9 |
由主機計算得到CRC碼 |
從機(儀表)響應返回的報文格式:
從機響應 |
字節數 |
返回的信息 |
備注 |
從機地址 |
1 |
01 |
來自地址為01的從機 |
功能碼 |
1 |
02 |
讀開關量輸入狀態 |
數據長度 |
1 |
01 |
1個字節(8個bit位) |
DI狀態數據 |
1 |
0B |
DI寄存器內容(bit0對應DI1)
DI1/DI2/DI4狀態為“1”,DI3狀態為“0” |
CRC碼 |
2 |
E04F |
由儀表計算得到CRC碼 |
2.4.2. 功能碼“0x01”
功能碼0x01的意思是:讀1路或多路開關量輸出狀態
例如:主機要讀取儀表地址為0x01的輸出狀態量(OUT1、OUT2)的輸出狀態。
從機(儀表)數據寄存器的地址和數據為:
起始位地址 |
DO寄存器數據 |
備注 |
0x0000 |
0x02 |
DO2輸出狀態為“1”,DO1輸出狀態為“0” |
主機發送的報文格式:
主機發送 |
字節數 |
發送的信息 |
備注 |
從機地址 |
1 |
01 |
發送至地址為01的從機 |
功能碼 |
1 |
01 |
讀開關量輸出狀態 |
起始BIT位 |
2 |
0000 |
起始BIT位的地址為0000 |
讀數據長度 |
2 |
0002 |
讀取2路繼電器輸出狀態位 |
CRC碼 |
2 |
BDCB |
由主機計算得到CRC碼 |
從機(儀表)響應返回的報文格式:
從機響應 |
字節數 |
返回的信息 |
備注 |
從機地址 |
1 |
01 |
來自地址為01的從機 |
功能碼 |
1 |
01 |
讀開關量輸出狀態 |
數據長度 |
1 |
01 |
1個字節(8個bit位) |
OUT狀態數據 |
1 |
0B |
OUT寄存器內容(bit0對應OUT1)
DO2輸出狀態為“1”,DO1輸出狀態為“0” |
CRC碼 |
2 |
D049 |
由儀表計算得到CRC碼 |
2.4.3. 功能碼“0x03”
功能碼0x03的意思是:讀多路寄存器輸入
例如:主機要讀取儀表地址為0x01,起始地址為0x017A的3個從機寄存器數據。
從機(儀表)數據寄存器的地址和數據為:
寄存器地址 |
寄存器數據 |
對應儀表電量值 |
0x017A |
0x1784 |
UA A相電壓 |
0x017B |
0x1780 |
UA B相電壓 |
0x017C |
0x178A |
UA C相電壓 |
主機發送的報文格式:
主機發送 |
字節數 |
發送的信息 |
備注 |
從機地址 |
1 |
01 |
發送至地址為01的從機 |
功能碼 |
1 |
03 |
讀取寄存器 |
起始地址 |
2 |
017A |
起始寄存器地址為017A |
數據長度 |
2 |
0003 |
讀取3個寄存器(共6個字節) |
CRC碼 |
2 |
25EE |
由主機計算得到CRC碼 |
從機(儀表)響應返回的報文格式:
從機響應 |
字節數 |
返回的信息 |
備注 |
從機地址 |
1 |
01 |
來自地址為01的從機 |
功能碼 |
1 |
03 |
讀取寄存器 |
返回字節數 |
1 |
06 |
3個寄存器共6個字節 |
寄存器數據1 |
2 |
1784 |
寄存器地址為017A的內容 |
寄存器數據2 |
2 |
1780 |
寄存器地址為017B的內容 |
寄存器數據3 |
2 |
178A |
寄存器地址為017C的內容 |
CRC碼 |
2 |
5847 |
由儀表計算得到CRC碼 |
2.4.4.功能碼“0x04”
功能碼0x04的意思是:讀多路寄存器輸入
例如:主機要讀取儀表地址為0x01,起始地址為0x017A的3個從機寄存器數據。
從機(儀表)數據寄存器的地址和數據為:
寄存器地址 |
寄存器數據 |
對應儀表電量值 |
0x017A |
0x1784 |
UA A相電壓 |
0x017B |
0x1780 |
UA B相電壓 |
0x017C |
0x178A |
UA C相電壓 |
主機發送的報文格式:
主機發送 |
字節數 |
發送的信息 |
備注 |
從機地址 |
1 |
01 |
發送至地址為01的從機 |
功能碼 |
1 |
04 |
讀取寄存器 |
起始地址 |
2 |
017A |
起始寄存器地址為017A |
數據長度 |
2 |
0003 |
讀取3個寄存器(共6個字節) |
CRC碼 |
2 |
902E |
由主機計算得到CRC碼 |
從機(儀表)響應返回的報文格式:
從機響應 |
字節數 |
返回的信息 |
備注 |
從機地址 |
1 |
01 |
來自地址為01的從機 |
功能碼 |
1 |
04 |
讀取寄存器 |
返回字節數 |
1 |
06 |
3個寄存器共6個字節 |
寄存器數據1 |
2 |
1784 |
寄存器地址為017A的內容 |
寄存器數據2 |
2 |
1780 |
寄存器地址為017B的內容 |
寄存器數據3 |
2 |
178A |
寄存器地址為017C的內容 |
CRC碼 |
2 |
19A1 |
由儀表計算得到CRC碼 |
2.4.5. 功能碼“0x05”
功能碼“0x05”的意思是:寫1路開關量輸出(遙控)
例1:開關量輸出點OUT1,其當前狀態為“分”,主機要控制該路繼電器“合”。
控制命令為:
“0xFF00”為控制繼電器“合”;
“0x0000”為控制繼電器“分”;
主機發送的報文格式:
主機發送 |
字節數 |
發送的信息 |
備注 |
從機地址 |
1 |
01 |
發送至地址為01的從機 |
功能碼 |
1 |
05 |
寫開關量輸出狀態 |
輸出BIT位 |
2 |
0000 |
對應輸出繼電器BIT0位(OUT1) |
控制命令 |
2 |
FF00 |
控制該路繼電器輸出為“合”狀態位 |
CRC碼 |
2 |
8C3A |
由主機計算得到CRC碼 |
從機(儀表)響應返回的報文格式:
與主機發送的報文格式及數據內容完全相同。
例2:開關量輸出點OUT2,其當前狀態為“合”,主機要控制該路繼電器“分”。
主機發送的報文格式:
主機發送 |
字節數 |
發送的信息 |
備注 |
從機地址 |
1 |
01 |
發送至地址為01的從機 |
功能碼 |
1 |
05 |
寫開關量輸出狀態 |
輸出BIT位 |
2 |
0001 |
對應輸出繼電器BIT1位(OUT2) |
控制命令 |
2 |
0000 |
控制該路繼電器輸出為“分”狀態位 |
CRC碼 |
2 |
8C3A |
由主機計算得到CRC碼 |
從機(儀表)響應返回的報文格式:
與主機發送的報文格式及數據內容完全相同。
2.4.6. 功能碼“0x06”
功能碼“0x06”的意思是:寫單路寄存器
例如:主機要把數據0x07D0保存到地址為0x002C的從機寄存器中去(從機地址為0x01)。通訊數據保存結束后,寄存器地址0x002C的儀表原存儲信息為:
寄存器地址 |
原來存儲數據 |
0x002C |
0x04B0 |
主機發送的報文格式:
主機發送 |
字節數 |
發送的信息 |
備注 |
從機地址 |
1 |
01 |
發送至地址為01的從機 |
功能碼 |
1 |
06 |
寫單路寄存器 |
起始地址 |
2 |
002C |
要寫入的寄存器地址 |
寫入數據 |
2 |
07D0 |
對應的新數據 |
CRC碼 |
2 |
4BAF |
由主機計算得到CRC碼 |
從機(儀表)相應返回的報文格式:
與主機發送的報文格式及數據內容完全相同
2.4.7. 功能碼“0x10”
功能碼0x10的意思是:寫多路寄存器
主機利用這個功能碼把多個數據保存到儀表的數據存儲器中去。Modbus通訊協議中的寄存器指的是16位(2字節),并且高位在前。這樣儀表的存儲器都是2個字節。由于Modbus通訊協議允許每次最多保存60個寄存器,因此儀表一次最多允許保存60個數據寄存器。
例如:主機要把0x0064,0x0010保存到地址為0x002C,0x002D的從機寄存器中去(從機地址為0x01)。通訊數據保存結束后,地址為0x002C/0x002D的儀表內存儲信息為:
地址 |
原來存儲的數據 |
通訊結束后存儲的數據 |
0x002C |
0x04B0 |
0x0064 |
0x002D |
0x1388 |
0x0010 |
主機發送的報文格式:
主機發送 |
字節數 |
發送的信息 |
備注 |
從機地址 |
1 |
01 |
發送至地址為01的從機 |
功能碼 |
1 |
10 |
寫多路寄存器 |
起始地址 |
2 |
002C |
要寫入的寄存器起始地址 |
保存數據字長度 |
2 |
0002 |
保存數據的字長度(共2字) |
保存數據字節長 |
1 |
04 |
保存數據的字節長度(共4字節) |
保存數據1 |
2 |
04B0 |
數據地址為0x002C |
保存數據2 |
2 |
1388 |
數據地址為0x002D |
CRC碼 |
2 |
FC63 |
由主機計算得到CRC碼 |
從機(儀表)相應返回的報文格式:
主機相應 |
字節數 |
發送的信息 |
備注 |
從機地址 |
1 |
01 |
來自地址為01的從機 |
功能碼 |
1 |
10 |
寫多路寄存器 |
起始地址 |
2 |
002C |
起始地址為002C |
保存數據字長度 |
2 |
0002 |
保存2個字長度的數據 |
CRC碼 |
2 |
8001 |
由儀表計算得到CRC碼 |
2.4.8. 通訊錯誤信息及數據的處理
當儀表檢測到除了CRC碼出錯以外的錯誤時,必須向主機回送信息,功能碼的最高位置為1,即從機返送給主機的功能碼是在主機發送的功能碼的基礎上加128。以下的這些代碼表明有意外的錯誤發生。
儀表從主機接收到信息如有CRC錯誤,則將被儀表忽略。
儀表返送的錯誤碼的格式如下(CRC碼除外):
地址碼: 1字節
差錯碼: 1字節(最高位為1)
異常碼: 1字節
CRC碼: 2字節
儀表相應回送如下異常碼:
01:非法的錯誤碼
接收到的功能碼儀表不支持。
02:讀取非法的數據地址
指定的數據位置超出儀表的可讀取的地址范圍。
03:非法的數據值
接收到主機發送的數據值超出儀表相應地址的數據范圍。