{
wCrc ^= WORD(BYTE(pSendBuf[i]));
for(int j=0; j<8; j++)
{
if(wCrc & 1)
{
wCrc >>= 1;
wCrc ^= 0xA001;
}
else
{
wCrc >>= 1;
}
}
}
return wCrc;
}
對於一條RTU協議的命令可以簡單的通過以下的步驟轉化為ASCII協議的命令:
1、 把命令的CRC校驗去掉,並且計算出LRC校驗取代。
2、 把生成的命令串的每一個字節轉化成對應的兩個字節的ASCII碼,比如0x03轉化成0x30,0x33(0的ASCII碼和3的ASCII碼)。
3、 在命令的開頭加上起始標記“:”,它的ASCII碼為0x3A。
4、 在命令的尾部加上結束標記CR,LF(0xD,0xA),此處的CR,LF表示回車和換行的ASCII碼。
所以以下我們僅介紹RTU協議即可,對應的ASCII協議可以使用以上的步驟來生成。
下表是Modbus支持的功能碼:
|
功能碼 |
名稱 |
作用 |
|
01 |
讀取線圈狀態 |
取得一組邏輯線圈的當前狀態(ON/OFF) |
|
02 |
讀取輸入狀態 |
取得一組開關輸入的當前狀態(ON/OFF) |
|
03 |
讀取保持寄存器 |
在一個或多個保持寄存器中取得當前的二進製值 |
|
04 |
讀取輸入寄存器 |
在一個或多個輸入寄存器中取得當前的二進製值 |
|
05 |
強置單線圈 |
強置一個邏輯線圈的通斷狀態 |
|
06 |
預置單寄存器 |
把具體二進值裝入一個保持寄存器 |
|
07 |
讀取異常狀態 |
取得8個內部線圈的通斷狀態,這8個線圈的地址由控製器決定 |
|
08 |
回送診斷校驗 |
把診斷校驗報文送從機,以對通信處理進行評鑒 |
|
09 |
編程(隻用於484) |
使主機模擬編程器作用,修改PC從機邏輯 |
|
10 |
控詢(隻用於484) |
可使主機與一台正在執行長程序任務從機通信,探詢該從機是否已完成其操作任務,僅在含有功能碼9的報文發送後,本功能碼才發送 |
|
11 |
讀取事件計數 |
可使主機發出單詢問,並隨即判定操作是否成功,尤其是該命令或其他應答產生通信錯誤時 |
|
12 |
讀取通信事件記錄 |
可是主機檢索每台從機的ModBus事務處理通信事件記錄。如果某項事務處理完成,記錄會給出有關錯誤 |
|
13 |
編程(184/384 484 584) |
可使主機模擬編程器功能修改PC從機邏輯 |
|
14 |
探詢(184/384 484 584) |
可使主機與正在執行任務的從機通信,定期控詢該從機是否已完成其程序操作,僅在含有功能13的報文發送後,本功能碼才得發送 |
|
15 |
強置多線圈 |
強置一串連續邏輯線圈的通斷 |
|
16 |
預置多寄存器 |
把具體的二進製值裝入一串連續的保持寄存器 |
|
17 |
報告從機標識 |
可使主機判斷編址從機的類型及該從機運行指示燈的狀態 |
|
18 |
(884和MICRO 84) |
可使主機模擬編程功能,修改PC狀態邏輯 |
|
19 |
重置通信鏈路 |
發生非可修改錯誤後,是從機複位於已知狀態,可重置順序字節 |
|
20 |
讀取通用參數(584L) |
顯示擴展存儲器文件中的數據信息 |
|
21 |
寫入通用參數(584L) |
把通用參數寫入擴展存儲文件,或修改之 |
|
22~64 |
保留作擴展功能備用 |
|
|
65~72 |
保留以備用戶功能所用 |
留作用戶功能的擴展編碼 |
|
73~119 |
非法功能 |
|
|
120~127 |
保留 |
留作內部作用 |
|
128~255 |
保留 |
用於異常應答 |
在這些功能碼中較長使用的是1、2、3、4、5、6號功能碼,使用它們即可實現對下位機的數字量和模擬量的讀寫操作。
1、讀可讀寫數字量寄存器(線圈狀態):
計算機發送命令:[設備地址] [命令號01] [起始寄存器地址高8位] [低8位] [讀取的寄存器數高8位] [低8位] [CRC校驗的低8位] [CRC校驗的高8位]
例:[11][01][00][13][00][25][CRC低][CRC高]
意義如下:
<1>設備地址:在一個485總線上可以掛接多個設備,此處的設備地址表示想和哪一個設備通訊。例子中為想和17號(十進製的17是十六進製的11)通訊。
<2>命令號01:讀取數字量的命令號固定為01。
<3>起始地址高8位、低8位:表示想讀取的開關量的起始地址(起始地址為0)。比如例子中的起始地址為19。
<4>寄存器數高8位、低8位:表示從起始地址開始讀多少個開關量。例子中為37個開關量。
<5>CRC校驗:是從開頭一直校驗到此之前。在此協議的最後再作介紹。此處需要注意,CRC校驗在命令中的高低字節的順序和其他的相反。
設備響應:[設備地址] [命令號01] [返回的字節個數][數據1][數據2]...[數據n][CRC校驗的低8位] [CRC校驗的高8位]
例:[11][01][05][CD][6B][B2][0E][1B][CRC低][CRC高]
意義如下:
<1>設備地址和命令號和上麵的相同。
<2>返回的字節個數:表示數據的字節個數,也就是數據1,2...n中的n的值。
<3>數據1...n:由於每一個數據是一個8位的數,所以每一個數據表示8個開關量的值,每一位為0表示對應的開關斷開,為1表示閉合。比如例子中,表示20號(索引號為19)開關閉合,21號斷開,22閉合,23閉合,24斷開,25斷開,26閉合,27閉合...如果詢問的開關量不是8的整倍數,那麼最後一個字節的高位部分無意義,置為0。
<4>CRC校驗同上。
2、讀隻可讀數字量寄存器(輸入狀態):
和讀取線圈狀態類似,隻是第二個字節的命令號不再是1而是2。
3、寫數字量(線圈狀態):
計算機發送命令:[設備地址] [命令號05] [需下置的寄存器地址高8位] [低8位] [下置的數據高8位] [低8位] [CRC校驗的低8位] [CRC校驗的高8位]
例:[11][05][00][AC][FF][00][CRC低][CRC高]
意義如下:
<1>設備地址和上麵的相同。
<2>命令號:寫數字量的命令號固定為05。
<3>需下置的寄存器地址高8位,低8位:表明了需要下置的開關的地址。
<4>下置的數據高8位,低8位:表明需要下置的開關量的狀態。例子中為把該開關閉合。注意,此處隻可以是[FF][00]表示閉合[00][00]表示斷開,其他數值非法。
<5>注意此命令一條隻能下置一個開關量的狀態。
設備響應:如果成功把計算機發送的命令原樣返回,否則不響應。
4、讀可讀寫模擬量寄存器(保持寄存器):
計算機發送命令:[設備地址] [命令號03] [起始寄存器地址高8位] [低8位] [讀取的寄存器數高8位] [低8位] [CRC校驗的低8位] [CRC校驗的高8位]
例:[11][03][00][6B][00][03][CRC低][CRC高]
意義如下:
<1>設備地址和上麵的相同。
<2>命令號:讀模擬量的命令號固定為03。
<3>起始地址高8位、低8位:表示想讀取的模擬量的起始地址(起始地址為0)。比如例子中的起始地址為107。
<4>寄存器數高8位、低8位:表示從起始地址開始讀多少個模擬量。例子中為3個模擬量。注意,在返回的信息中一個模擬量需要返回兩個字節。
設備響應:[設備地址] [命令號03] [返回的字節個數][數據1][數據2]...[數據n][CRC校驗的低8位] [CRC校驗的高8位]
例:[11][03][06][02][2B][00][00][00][64][CRC低][CRC高]
意義如下:
<1>設備地址和命令號和上麵的相同。
<2>返回的字節個數:表示數據的字節個數,也就是數據1,2...n中的n的值。例子中返回了3個模擬量的數據,因為一個模擬量需要2個字節所以共6個字節。
<3>數據1...n:其中[數據1][數據2]分別是第1個模擬量的高8位和低8位,[數據3][數據4]是第2個模擬量的高8位和低8位,以此類推。例子中返回的值分別是555,0,100。
<4>CRC校驗同上。
5、讀隻可讀模擬量寄存器(輸入寄存器):
和讀取保存寄存器類似,隻是第二個字節的命令號不再是2而是4。
6、寫單個模擬量寄存器(保持寄存器):
計算機發送命令:[設備地址] [命令號06] [需下置的寄存器地址高8位] [低8位] [下置的數據高8位] [低8位] [CRC校驗的低8位] [CRC校驗的高8位]
例:[11][06][00][01][00][03][CRC低][CRC高]
意義如下:
<1>設備地址和上麵的相同。
<2>命令號:寫模擬量的命令號固定為06。
<3>需下置的寄存器地址高8位,低8位:表明了需要下置的模擬量寄存器的地址。
<4>下置的數據高8位,低8位:表明需要下置的模擬量數據。比如例子中就把1號寄存器的值設為3。
<5>注意此命令一條隻能下置一個模擬量的狀態。
設備響應:如果成功把計算機發送的命令原樣返回,否則不響應。