【Modbus】 RTU CRC校驗碼計算方法



Modbus是美國Modicon公司(即現在的Schneider Electric公司)於1979年開發的一種通信協議,其目的是採用一根雙絞線實現多個設備之間的通信。

Modbus 協議採用問答式的通信方式,具有簡單、硬件便宜、通用性強、使用方便的優點,容易開發和實現。Modbus RTU幾乎成了國產PLC和變頻器首選的通信協議。

 Modbus 協議不需要專門的通信模塊,通信所需的堆棧和協議機制是以軟件形式實現的,屬於ISO-OSI 參考模型的第7層。它的另一個優點是可以通過任何傳輸媒介進行通信,包括雙絞線、無線通信、光導纖維、以太網、電話調制解調器、移動電話以及微波等。這樣可以很容易地在一個新的或者是現有的工廠裏建立起Modbus連接。


目前使用的Modbus有三個版本:Modbus ASCII、Modbus RTU和Modbus/TCP。

1.Modbus ASCII協議需要將一個字節的數據轉換爲兩個字節的ASCII碼後發送。Modbus RTU協議的數據以二進制進行編碼,每個字節的數據只需要一個字節的通信量。

 

2.Modbus RTU通信採用主-從方式,最多傳送255個字節的數據。主設備與一個或多個從設備進行通信。比較典型的主設備是PLC、PC、DCS(集散控制系統)或者RTU(遠程終端單元)。Modbus RTU的從設備一般是現場設備。當Modbus RTU主設備想要從一臺從設備得到數據的時候,主設備發送一條包含該從設備站地址、所需要的數據以及一個用於檢測錯誤的CRC校驗碼。網絡上所有其它設備都可以接收到這條信息,但是隻有地址被指定的從設備纔會作出反應。Modbus網絡上的從設備不能發起通信,它們只能在主設備對它說話的時候回答。

 Modbus RTU採用16位的循環冗餘校驗碼(CRC)。通過一個對數據進行“或”運算以及移位運算的複雜程序,由主設備產生CRC,並且由接收設備進行檢查。如果雙方計算出的CRC值不符,從設備就會要求重新傳送信息。
    Modbus RTU協議分爲Modbus RTU主站協議和Modbus RTU從站協議。Modbus通信是由功能碼來控制的,主站直接訪問從站的數據區。


3.Modbus /TCP可以被理解爲以太網上的Modbus。Modbus /TCP不過是採用TCP/IP標準,簡單地把Modbus信息包打包壓縮而已。這樣Modbus /TCP設備就可以通過以太網和光纖網絡進行連接和通信。與RS-485接口相比,Modbus /TCP還允許使用更多的地址、可以採用多主站架構、傳送速率可以達到GB/s的水平。Modbus /TCP網絡的從站數量僅受限於網絡物理層的能力。通常從站的數量一般在1024個左右。
   

附:Modbus RTU CRC校驗碼計算方法


在CRC計算時只用8個數據位,起始位及停止位,如有奇偶校驗位也包括奇偶校驗位,都不參與CRC計算。


CRC計算方法是:


1、  加載一值爲0XFFFF的16位寄存器,此寄存器爲CRC寄存器。


2、  把第一個8位二進制數據(即通訊信息幀的第一個字節)與16位的CRC寄存器的相異或,異或的結果仍存放於該CRC寄存器中。


3、  把CRC寄存器的內容右移一位,用0填補最高位,並檢測移出位是0還是1。


4、  如果移出位爲零,則重複第三步(再次右移一位);如果移出位爲1,CRC寄存器與0XA001進行異或。


5、  重複步驟3和4,直到右移8次,這樣整個8位數據全部進行了處理。


6、  重複步驟2和5,進行通訊信息幀下一個字節的處理。


7、  將該通訊信息幀所有字節按上述步驟計算完成後,得到的16位CRC寄存器的高、低字節進行交換


8、  最後得到的CRC寄存器內容即爲:CRC校驗碼



直接上代碼:

///<summary>

/// 轉換成CRC碼

///</summary>

///<param name="Array"></param>

///<param name="Rcvbuf"></param>

///<param name="Len"></param>

///<returns></returns>

//modbus CRC16

publicvoid CRC16Calc(byte[] dataBuff, int dataLen)

{

int CRCResult = 0xFFFF;

if (dataLen < 2)

{

   return;

}

for (int i = 0; i < (dataLen - 2); i++)

{

    CRCResult = CRCResult ^ dataBuff[i];

for (int j = 0; j < 8; j++)

{

if ((CRCResult & 1) == 1)

CRCResult = (CRCResult >> 1) ^ 0xA001;

else CRCResult >>= 1;

}

}

dataBuff[dataLen - 1] =Convert.ToByte(CRCResult >> 8);

dataBuff[dataLen - 2] =Convert.ToByte(CRCResult & 0xff);

}


部分參考:http://blog.sina.com.cn/s/blog_762cf5f80101ctkt.html


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章