2011-10-23 113 views
0

我要連接到一個設備(MODBUS協議),我必須計算CRC(CRC16)。有此協議的標準實現,但是我有使用此公式創建我CRC:奇怪的CRC計算

X15 + X2 + 1(有一個與此公式標準實現:X16 + X15 + X2 + 1)

我已經測試了不同的CRC值,但他們都沒有給我正確的答案。我應該向端口寫入一些字節,並且在該字節串的末尾,我應該寫入兩個CRC字節以獲取我的設備信息。

+0

那麼問題是什麼? – Amy

+0

我的問題是關於使用X15 + X2 + 1公式找到CRC的正確方法,我應該如何將這些字節寫入我的端口?我使用C#(VS2010),我應該使用port.write還是port.writeline?我應該如何將這些字節傳遞給端口? ascii字符串還是hex?謝謝 –

+1

您應該將字節作爲原始二進制字符串(您可以從字節數組中形成)傳遞,既不是ASCII字符串也不是十六進制。你可以使用Port.Write。您可能需要使用[Port.ByteArrayToString](http://franson.com/serialtools/reference_manual.asp?class=Port&item=ByteArrayToString&platform=net)。 –

回答

2

你的問題是什麼? 我假設您的問題是「如何在消息結尾計算MODBUS CRC,以便電纜另一端的MODBUS設備將其識別爲有效的MODBUS消息?」

在我實現另一個校驗和或CRC函數之前,我試着首先獲取測試向量, 。

您是否有任何有效消息的例子,包括最終的正確/期望的CRC?

根據Wikipedia:cyclic redundancy check, 「由於高序位始終爲1,並且由於n位CRC必須由第(n + 1)比特的除數,其溢出的n位寄存器所定義,一些作者認爲沒有必要提到除數的高位。「因此,說MODBUS使用「X^15 + X^2 + 1」多項式(由於它是16位CRC,因此理解爲X^16)的作者指的是與其他作者完全相同的多項式即MODBUS使用「X^16 + X^15 + X^2 + 1」多項式。兩位作者都將編寫生成完全相同CRC的代碼,並且可以相互交互操作。

另外,在「前進」方向計算標準MODBUS CRC的人經常使用魔術常數「0x8005」。 那些在「反向」方向計算標準MODBUS CRC的人經常使用魔術常數「0xA001」代替(「0x8005」的位反轉)。 兩個人都編寫的代碼能夠生成完全相同的CRC字節,並且可以相互交互操作。

MODBUS CRC計算有許多在線實現;也許你可能會發現其中一個有用。

abcdefghi:有許多選項 http://www.zorc.breitbandkatze.de/crc.html

在線CRC計算 http://www.lammertbies.nl/comm/info/crc-calculation.html

和許多人一樣,沒有特定的順序

在線直播CRC計算器jklm nopq

許多實現是面向字節的,它運行快一點,但需要一個大的查找表 (和它的對我來說遠不是顯而易見的查找表如何測試是否有效)。

許多實現是面向比特的,其產生短得多的程序大小 和具有更少的塵土飛揚角落裏的錯誤可以潛伏(但採取只要計算校驗和大約8倍),如下面的:

// warning: untested code 
// optimized for size rather than speed 
// (i.e., uses a bit-oriented calculation rather than table-driven calculation) 
uint16_t modbusCRC(uint8_t* data, int length) { 
    uint16_t crc = 0xFFFF; 
    for(int pos = 0; pos<length; pos++){ 
     crc ^= (uint16_t)data[pos]; 
     for(int i=0; i<8; i++){ 
      if(crc & 1){  // LSB is set 
       crc >>= 1;     // Shift right 
       crc ^= 0xA001;    // XOR 0xA001 
      }else{       // LSB is not set 
       crc >>= 1; 
      }; 
     }; 
    }; 
    return crc; 
} 
int main(void){ 
    uint8_t message[80] = { // 6-byte test vector 
     0x11, 0x03, 0x00, 0x6B, 0x00, 0x03 
    }; 
    int message_length = 6; 
    uint16_t the_CRC = modbusCRC(message, message_length); // find CRC of the message 
    message[message_length++] = the_CRC & 0xFF; // send low byte first 
    message[message_length++] = the_CRC >> 8; // then send high byte 
    assert(0x76 == message[6]); // test against known-good CRC 
    assert(0x87 == message[7]); 
    send_message(message, message_length); // send all 8 bytes of the message, 
    // including the two MODBUS CRC bytes. 
    // (Must send *all* 8 bytes of the message, 
    // even though there are multiple 0x00 bytes). 
} 

「二進制MODBUS」(「Modbus RTU幀格式」)將消息的所有數據作爲原始8位字節發送,包括2個CRC字節。

「ASCII MODBUS」(「Modbus ASCII幀格式」)以大致簡單的ASCII文本(包括8位校驗和)發送消息。 (校驗和傳輸爲2個字節 - 作爲2個ASCII十六進制字符)。