Modbus功能碼詳解
Modbus功能碼是Modbus消息幀(報(bào)文)的重要組成部分,是Modubs協(xié)議中通信事務(wù)處理的基礎(chǔ),代表消息將要執(zhí)行的動(dòng)作。
功能碼概要
簡(jiǎn)而言之,Modbus功能碼占用一個(gè)字節(jié),取值范圍是1127,之所以127以上不能使用,是因?yàn)镸odbus規(guī)定出現(xiàn)異常時(shí),功能碼+0x80(十進(jìn)制128)代替異常狀態(tài),因此129(1+128)255(127+128)的取值代表異常碼。
Modbus標(biāo)準(zhǔn)協(xié)議中規(guī)定了由3類Modbus功能碼,分別是:
-
公共功能碼
- 被明確定義的功能碼
- 保證唯一性
- 由Modbus協(xié)會(huì)確認(rèn),并提供公開的文檔;
- 可進(jìn)行一致性測(cè)試
- 包括協(xié)議定義的功能碼和保留將來使用的功能碼
-
用戶自定義功能碼
- 有兩個(gè)用戶自定義功能碼區(qū)域,分別是6572和100110;
- 用戶自定義,不保證唯一性。
-
保留功能碼
保留功能碼是因?yàn)闅v史遺留原因,某些公司的傳統(tǒng)產(chǎn)品上現(xiàn)行使用的功能碼不作為公共使用。
Modbus部分功能碼如下:
代碼 | 名稱 | 寄存器PLC地址 | 位/字操作 | 操作數(shù)量 |
---|---|---|---|---|
01 | 讀線圈狀態(tài) | 00001~09999 | 位操作 | 單個(gè)或多個(gè) |
02 | 讀離散輸入狀態(tài) | 10001~19999 | 位操作 | 單個(gè)或多個(gè) |
03 | 讀保持寄存器 | 40001~49999 | 字操作 | 單個(gè)或多個(gè) |
04 | 讀輸入寄存器 | 30001~39999 | 字操作 | 單個(gè)或多個(gè) |
05 | 寫單個(gè)線圈 | 00001~09999 | 位操作 | 單個(gè) |
06 | 寫單個(gè)保持寄存器 | 40001~49999 | 字操作 | 單個(gè) |
15 | 寫多個(gè)線圈 | 00001~09999 | 位操作 | 多個(gè) |
16 | 寫多個(gè)保持寄存器 | 40001~49999 | 字操作 | 多個(gè) |
功能碼可分為位操作和字操作兩類。位操作的最小單位為一位(bit),字操作的最小單位為兩個(gè)字節(jié)。
- 位操作指令:讀線圈狀態(tài)功能碼01,讀(離散)輸入狀態(tài)功能碼02,寫單個(gè)線圈功能碼06和寫多個(gè)線圈功能碼15.
- 字操作指令:讀保持寄存器功能碼03,讀輸入寄存器功能碼04,寫單個(gè)保持寄存器功能碼06,寫多個(gè)保持寄存器功能碼16.
01(0x01)讀取線圈/離散量輸出狀態(tài)
功能說明讀取從設(shè)備的線圈或離散量輸出的狀態(tài),即各DO的ON/OFF狀態(tài)。消息幀中指定了需讀取的線圈起始地址和線圈數(shù)目。需要注意的一點(diǎn)是,在Modbus協(xié)議規(guī)定的PDU中,規(guī)定所有線圈或寄存器地址從0開始計(jì)算。
查詢報(bào)文查詢幀的消息里,定義了從設(shè)備地址為3,并讀取從設(shè)備的Modbus地址0001900055(線圈地址0002000056)共計(jì)37個(gè)狀態(tài)值。起始線圈地址為0x13(即十進(jìn)制00019),因?yàn)榫圈地址從0開始計(jì)數(shù)。
Modbus協(xié)議規(guī)定,起始地址由2個(gè)字節(jié)構(gòu)成,取值范圍為0x00000xFFFF;線圈數(shù)量由2個(gè)字節(jié)構(gòu)成,取值范圍為0x00010x07D0(即十進(jìn)制1~2000).
ASCII模式中直接按每4個(gè)位拆分為對(duì)應(yīng)的字符表示。
響應(yīng)報(bào)文響應(yīng)報(bào)文的數(shù)據(jù)字段中,每一個(gè)線圈占用1個(gè)位(bit),狀態(tài)被表示為1=ON和0=OFF兩種類型。第1個(gè)數(shù)據(jù)字節(jié)的LSB(最低有效位)標(biāo)識(shí)查詢報(bào)文中的起始地址線圈的狀態(tài)值,其他線圈依次類推,一直到這個(gè)字節(jié)的MSB(最高有效位)位置,并在后續(xù)字節(jié)中按照同樣的方式(由低到高)排列。
一個(gè)字節(jié)可以表示8個(gè)線圈的狀態(tài),如果最后的數(shù)據(jù)字節(jié)中不能填滿8個(gè)線圈的狀態(tài),則由0填充。對(duì)應(yīng)于查詢報(bào)文中需要讀取37個(gè)線圈的狀態(tài),則共需要5個(gè)字節(jié)保存狀態(tài)值。
02(0x02)讀取離散量輸入值
功能說明該功能碼用于讀取從設(shè)備的離散輸入即DI的ON/OFF狀態(tài)。消息幀中制定了需讀取的離散輸入寄存器起始地址和數(shù)目,可讀取1~2000個(gè)連續(xù)的離散量輸入狀態(tài)。如果從設(shè)備接受主設(shè)備的請(qǐng)求則回復(fù)功能碼02,并返回離散量輸入各離散量的當(dāng)前狀態(tài)。如果返回的離散輸入數(shù)量的個(gè)數(shù)不是8的整數(shù)倍,將用0填充最后數(shù)據(jù)字節(jié)的剩余位。
03(0x03)讀取保持寄存器值
功能說明用于讀取從設(shè)備保持寄存器的內(nèi)容,不支持廣播模式。消息幀中指定了需讀取的保持寄存器的起始地址和數(shù)目。而保持寄存器中各地址的具體內(nèi)容和意義,則由設(shè)備開發(fā)者自行規(guī)定。
查詢報(bào)文在查詢報(bào)文中,必須指定保持寄存器的開始地址和需讀取的寄存器數(shù)量。起始位置由2個(gè)字節(jié)構(gòu)成,取值范圍為0x00000xFFFF;寄存器數(shù)量由2個(gè)字節(jié)構(gòu)成,取值范圍為0x00010x007D(即十進(jìn)制1~255),即最多可以連續(xù)讀取125個(gè)寄存器。
有一點(diǎn)特別需要注意,Modbus的保持寄存器和輸入寄存器是以字(Word)為基本單位的(1Word=2byte),所以,如果讀取保持寄存器地址為40001開始的一個(gè)16位(bit)的無符號(hào)數(shù),那么返回2個(gè)字節(jié)(byte),并可以從40002開始讀取下一個(gè)16位的無符號(hào)數(shù)。如果需讀取寄存器地址40001開始的是一個(gè)32位浮點(diǎn)數(shù),則需要返回4個(gè)字節(jié),即必須連續(xù)讀取40001和40002的內(nèi)容,而且下一個(gè)32位浮點(diǎn)數(shù)必須從40003開始讀取。對(duì)于浮點(diǎn)數(shù)(或者32位的整數(shù))而言,連續(xù)讀取的兩個(gè)寄存器之間存在字節(jié)序和大小端的問題,這一點(diǎn)在開發(fā)時(shí)必須引起注意。
04(0x04)讀取輸入寄存器值
功能說明同功能碼03類似,該功能碼用于讀取從設(shè)備輸入寄存器的內(nèi)容,不支持廣播模式。消息幀中指定了需讀取的輸入寄存器的起始地址和數(shù)目。而輸入寄存器中各地址的具體內(nèi)容和意義,則由設(shè)備開發(fā)者自行規(guī)定。
查詢報(bào)文在查詢報(bào)文中,必須指定輸入寄存器的起始地址和需讀取的寄存器數(shù)量。
本功能碼中,起始地址由2個(gè)字節(jié)構(gòu)成,取值范圍為0x00000xFFFF;寄存器數(shù)量由2個(gè)字節(jié)構(gòu)成,取值范圍為0x00010x007D(即十進(jìn)制1~125),即最多可以連續(xù)讀取125個(gè)寄存器。
同樣有一點(diǎn)需要注意,Modbus的保持寄存器和輸入寄存器是以字為基本單位的。所以對(duì)于浮點(diǎn)數(shù)(或32為的整數(shù))而言,連續(xù)讀取的兩個(gè)寄存器之間存在字節(jié)序和大小端的問題。
05(0x05)寫單個(gè)線圈或單個(gè)離散輸出
功能說明用于將單個(gè)線圈寄存器(或離散輸入)設(shè)置為ON或OFF,該功能碼支持廣播模式,在廣播模式下,所有從站設(shè)備的同一地址的值將被統(tǒng)一修改,查詢報(bào)文中的ON或OFF狀態(tài)由報(bào)文數(shù)據(jù)字段的常熟指定,0xFF00表示ON狀態(tài),0x0000表示OFF狀態(tài)。其他所有值均是非法的,并且對(duì)寄存器不起作用,將會(huì)返回異常相應(yīng)。
查詢報(bào)文本功能碼中,起始地址由2個(gè)字節(jié)構(gòu)成,取值范圍為0x0000~0xFFFF;變更目標(biāo)數(shù)據(jù)由2個(gè)字節(jié)構(gòu)成,取值只能為0xFF00或0x0000.
響應(yīng)報(bào)文對(duì)于從設(shè)備,在線圈或離散輸出寄存器正常變更的情況下,則返回于查詢報(bào)文一樣的響應(yīng)報(bào)文。如果修改失敗,則返回一個(gè)異常響應(yīng)。
06(0x06)寫單個(gè)保持寄存器
用于更新從設(shè)備的單個(gè)保存寄存器的值。該功能嗎支持廣播模式,在廣播模式下,所有設(shè)備的同一地址的值將被統(tǒng)一修改。
查詢報(bào)文查詢報(bào)文中需要指定從設(shè)備地址以及需要變更的保持寄存器地址和設(shè)定的值。同樣需要注意的是,查詢報(bào)文中,寄存器地址從地址0開始技術(shù)。
本功能碼中,起始地址由2個(gè)字符構(gòu)成,取值范圍為0x00000xFFFF;變更目標(biāo)數(shù)據(jù)由2個(gè)字節(jié)構(gòu)成,取值范圍為0x00000xFFFF。
響應(yīng)報(bào)文對(duì)于從設(shè)備,在保持寄存器正常變更的情況下,則返回于查詢報(bào)文一樣的響應(yīng)報(bào)文。如果修改失敗,則返回一個(gè)異常返回。
08(0x08)診斷功能
功能說明該功能碼僅用于串行鏈路,主要用于檢測(cè)主設(shè)備和從設(shè)備之間的通信故障,或檢測(cè)從設(shè)備的各種內(nèi)部故障,該功能碼不支持廣播。為了區(qū)別各診斷類型,查詢報(bào)文中提供了2各字節(jié)的子功能碼字段。
通常在正常的響應(yīng)報(bào)文中,從設(shè)備將鴛鴦回復(fù)功能碼和子功能碼。
查詢報(bào)文查詢報(bào)文中需要指定從設(shè)備地址、功能碼以及子功能碼。
例如,表4-15中表示了子功能碼“原樣返回查詢數(shù)據(jù)”的診斷功能,其中子功能碼為0(0x0000)。在子功能碼0x0000的情況下,數(shù)據(jù)字段可以為任意值。
本功能碼中,子功能碼由2個(gè)字節(jié)構(gòu)成,取值則根據(jù)意義不同;數(shù)據(jù)字段由2個(gè)字節(jié)構(gòu)成,其取值由子功能碼確定。
響應(yīng)報(bào)文對(duì)于從設(shè)備,在保持寄存器正常變更的情況下,則返回與查詢報(bào)文一樣的響應(yīng)報(bào)文。如果修改失敗,則返回一個(gè)異常響應(yīng)。
診斷子功能碼
各常用診斷子功能碼定義如下:
- 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 Communications 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,0x02 |
查詢報(bào)文數(shù)據(jù)字段 | 0x00,0x00 |
響應(yīng)報(bào)文數(shù)據(jù)字段 | 診斷寄存器的內(nèi)容 |
- Force Listen Only Mode(04)
診斷內(nèi)容 | 強(qiáng)制只聽模式 強(qiáng)制被尋址的從站設(shè)備進(jìn)入只聽模式,使得此設(shè)備與網(wǎng)絡(luò)中的其他設(shè)備斷開,不返回響應(yīng) |
---|---|
子功能碼 | 0x00,0x0A |
查詢報(bào)文數(shù)據(jù)字段 | 0x00,0x00 |
響應(yīng) |
- Clear Counters and Diagnostic Register(10,0x0A)
診斷內(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)文的計(jì)數(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è)備接收?qǐng)?bào)文總數(shù) |
- Return Slave No Response Count(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ù)量 |
11(0x0B)獲取通信事件計(jì)數(shù)器
功能說明該功能碼主要用于獲取從設(shè)備通信計(jì)數(shù)器中的狀態(tài)字和事件計(jì)數(shù)的值,本功能不支持廣播模式。通過在通信報(bào)文之前和之后讀取通信事件計(jì)數(shù)值,可以確定從設(shè)備是否正常處理報(bào)文。
對(duì)于正常完成報(bào)文處理和傳輸?shù)膱?chǎng)合,事件計(jì)數(shù)器增加1;而對(duì)于異常響應(yīng)、輪詢命令或讀取事件計(jì)數(shù)器(即0x0B功能碼)的場(chǎng)合,則計(jì)數(shù)器不變。通過【0x08】診斷功能中的子功能碼【Restart Communiaction Option (0x01)】和【Clear Counters and Diagnostic Register(0x00A)】,可以復(fù)位事件寄存器。
響應(yīng)報(bào)文對(duì)于從設(shè)備,在正常情況下,響應(yīng)報(bào)文返回2個(gè)字節(jié)的狀態(tài)字和2個(gè)字節(jié)的事件計(jì)數(shù)。其中,如果從站設(shè)備處于忙狀態(tài),那么狀態(tài)字將為0xFFFF,否則狀態(tài)字將為0x0000.
12(0x0C)獲取通信事件記錄
功能說明該功能碼主要用于從從設(shè)備獲取轉(zhuǎn)狀態(tài)字、事件計(jì)數(shù)、報(bào)文計(jì)數(shù)以及事件字節(jié)字段。其中狀態(tài)字和事件計(jì)數(shù)與功能碼11(0x0B)獲取的值一致。
響應(yīng)報(bào)文對(duì)于從站設(shè)備,在正常情況下響應(yīng)報(bào)文包括一個(gè)2字節(jié)狀態(tài)字字段、一個(gè)2字節(jié)事件計(jì)數(shù)字段、一個(gè)2字節(jié)消息計(jì)數(shù)字段以及0~64個(gè)字節(jié)的事件字段。因?yàn)槭录侄问亲冮L(zhǎng)的,所以增加了一個(gè)1字節(jié)的數(shù)據(jù)長(zhǎng)度字段,以方便讀取響應(yīng)數(shù)據(jù)。
15(0x0F)寫多個(gè)線圈
功能說明該功能碼,用于將連續(xù)的多個(gè)線圈或離散輸出設(shè)置為ON/OFF狀態(tài),支持廣播模式,在廣播模式下,所有從站設(shè)備的同一地址被統(tǒng)一修改。本功能碼中,起始地址字段由2個(gè)字節(jié)構(gòu)成,取值范圍為0x00000xFFFF;而寄存器數(shù)量字段由2個(gè)字節(jié)構(gòu)成,取值范圍為0x00010x07B0.
查詢報(bào)文查詢報(bào)文中,包含了請(qǐng)求數(shù)據(jù)字段,用于定義ON/OFF狀態(tài)。數(shù)據(jù)字段中為邏輯1的位對(duì)應(yīng)ON;邏輯0的位對(duì)應(yīng)OFF。其中,ON/OFF與數(shù)據(jù)字段的對(duì)應(yīng)關(guān)系可參考“01(0x01)讀取線圈/離散量輸出狀態(tài)”中的內(nèi)容
響應(yīng)報(bào)文對(duì)于從設(shè)備,在正常情況下響應(yīng)報(bào)文包括功能碼、起始地址以及寫入的線圈數(shù)量。
16(0x10)寫多個(gè)保持寄存器
功能說明該功能碼用于設(shè)置或?qū)懭霃脑O(shè)備保持寄存器的多個(gè)連續(xù)的地址塊(1123個(gè)寄存器),支持廣播模式,在廣播模式下,所有從站設(shè)備的同一地址的值將被統(tǒng)一修改。本功能碼中,起始地址字段由2個(gè)字節(jié)構(gòu)成,取值范圍為0x00000xFFFF;而寄存器數(shù)量字段由2個(gè)字節(jié)構(gòu)成,取值范圍為0x0001~0x007B。
查詢報(bào)文查詢報(bào)文中,包含了請(qǐng)求數(shù)據(jù)字段。數(shù)據(jù)字段保存需寫入的數(shù)值,各數(shù)據(jù)按每個(gè)寄存器2個(gè)字節(jié)存放。
響應(yīng)報(bào)文對(duì)于從設(shè)備,在正常情況下響應(yīng)報(bào)文包括功能碼、起始地址以及寫入的寄存器數(shù)量。
在實(shí)際開發(fā)過程中,功能碼“16(0x10)寫多個(gè)寄存器”常常用于方便用戶寫入多字節(jié)類型的數(shù)據(jù)。
17(0x11)報(bào)告從站ID(僅用于串行鏈路)
功能說明該功能碼用于讀取從站設(shè)備的ID、類型描述、當(dāng)前狀態(tài)以及其他信息,不支持廣播模式。響應(yīng)消息的構(gòu)成依賴于設(shè)備而不同。
響應(yīng)報(bào)文對(duì)于從設(shè)備,在正常情況下響應(yīng)報(bào)文包括從站ID、運(yùn)行狀態(tài)以及其他附加信息。響應(yīng)報(bào)文的組成由開發(fā)者決定。
Modbus異常響應(yīng)
以上介紹了一些常見的公共功能碼的報(bào)文(消息幀)構(gòu)成,對(duì)于廣播模式以外的查詢報(bào)文,都希望能夠獲取一個(gè)正常的響應(yīng)報(bào)文。在通常的情況下,從站設(shè)備將返回一個(gè)正常響應(yīng)報(bào)文,但是,在某些特殊情況下,將返回異常響應(yīng)報(bào)文。對(duì)于查詢報(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é)議中功能碼占用一個(gè)字節(jié),故用表達(dá)式描述為:異常功能碼=正常功能碼+0x80.
常見的異常碼說明
異常碼 名稱 說明 01 非法功能碼 從站設(shè)備不支持此功能碼 02 非法數(shù)據(jù)地址 指定的數(shù)據(jù)地址在從站設(shè)備中不存在 03 非法數(shù)據(jù)值 指定的數(shù)據(jù)超過范圍或者不允許使用 04 從站設(shè)備故障 從站設(shè)備處理響應(yīng)的過程中,出現(xiàn)未知錯(cuò)誤等