2014-01-21 359 views
5

我需要爲連同長度一起傳遞的數據計算CCITT 16位校驗和值。如果我用測試數據「123456789」填充我的數組TempStr,則使用長度不包含空終止字符的多項式0x8408,得到結果字符串6E90(十六進制)。加上空終止字符,我得到907A。當我將多項式換成0x1201時,我得到結果29E2(十六進制)和EFE8(十六進制)有和沒有終止字符。CCITT CRC 16位起始值0xffff

我的問題是: 我是否需要計算帶或不帶空終止符的CRC以獲得正確的值? 在算法中使用多項式0x1201還是反向多項式0x8408? 給定數據0x29B1的CRC是否正確?我需要正確的值來確定函數是否正常工作。 計算此特定CRC類型的算法是否正確? wData =(unsigned int)0xff & * pData ++ ?? 如果有人能向我解釋什麼是錯的,以及如何解決我的問題,我將非常感激。 謝謝

這是一個使用並顯示calculate_CRC16函數的代碼:

CHAR_t TestStr[] = {"123456789"}; 
unsigned short CrcTest = calculate_CRC16(TestStr,sizeof(TestStr)-1); 
QString CrcDisplay = QString("CrcTest : %1").arg(CrcTest); 
ui->txtDebug->setText(CrcDisplay); 

這是calculate_CRC16功能:

UINT16_t MainWindow::calculate_CRC16(CHAR_t* pData, UINT16_t wLength) 
{ 

    UCHAR_t i; 
    UINT16_t wData; 
    UINT16_t wCrc = 0xffff; 

    if (wLength == 0) 
    return (~wCrc); 

    do 
    { 
    for (i=0, wData=(unsigned int)0xff & *pData++; i < 8; i++, wData >>= 1) 
    { 
     if ((wCrc & 0x0001)^(wData & 0x0001)) 
      wCrc = (wCrc >> 1)^CRC_POLY; 
     else wCrc >>= 1; 
    } 
    } while (--wLength); 

    wCrc = ~wCrc; 
    wData = wCrc; 
    wCrc = (wCrc << 8) | (wData >> 8 & 0xff); 

    return (wCrc); 
} 
+0

我從來沒有見過CRC檢查,包括終止空或換行或任何東西。對於其他問題,抱歉,沒有足夠的專家。 –

+1

CRC計算中是否包含終止空值或換行完全取決於它們是否是接收端要檢查的數據的一部分。您需要將CRC應用於另一端將應用CRC的數據。還要記住,一些CRC計算函數需要通過CRC函數「推送」虛擬數據(例如一些零),以便從內部狀態機中獲取最終的CRC。這通常適用於CRC函數,該函數設計用於計算多個帶有漸進數據的調用的CRC。 –

回答

4

0x29b1的結果是針對"false" CCITT CRC-16(鏈接到CRC目錄)。這顯然是你需要的。從目錄中:

width=16 poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000 check=0x29b1 name="CRC-16/CCITT-FALSE" 

所以沒有位反轉(refinrefout假)。 CRC被初始化爲0xffff並且未被後處理。

用最少的改變解決您的代碼:

if (wLength == 0) 
    return wCrc; 

do 
{ 
    for (i=0, wData=((unsigned int)0xff & *pData++) << 8; i < 8; i++, wData <<= 1) 
    { 

     if ((wCrc & 0x8000)^(wData & 0x8000)) 
      wCrc = (wCrc << 1)^0x1021; 
     else wCrc <<= 1; 
    } 
} while (--wLength); 

return wCrc & 0xffff; 

,或者更合理的做到這一點:

while (wLength--) { 
    wCrc ^= *(unsigned char *)pData++ << 8; 
    for (i=0; i < 8; i++) 
     wCrc = wCrc & 0x8000 ? (wCrc << 1)^0x1021 : wCrc << 1; 
} 
return wCrc & 0xffff; 
+0

這個新的和簡單的代碼工作得非常好。非常感謝! –

2

如果你看一下,它會計算不同字符串的CRC(或十六進制序列,用於檢查是否帶有NUL) http://www.lammertbies.nl/comm/info/crc-calculation.html

據此,您不應該計算包含終止零的值,以便計算得到0x29B1的值。

既然您是從低位開始,那麼您應該使用「非反向」多項式。

我認爲問題在於,當您在計算中移動「wCrc」時,您正在轉移錯誤方式。

換句話說:

wCrc = (wCrc >> 1)^CRC_POLY; 

應該是:

wCrc = (wCrc << 1)^CRC_POLY; 

並且同樣地:

wCrc >>= 1; 

應該是:

wCrc <<= 1; 

但是,我不是100%確定的。

0

有許多的CRC算法的不同變種。

  • 位逐位計算相對於查找表
  • 反射字節與非反射的字節(最高位或第一,所以LSb)。
  • 消息末尾增加的位的附加或不附加。

最後一點是一個混亂的問題。回到CRC理論,CRC可以被看作GF(2)中的長分裂,其結果是長分裂的剩餘部分。根據基本理論做一個正確的計算,n爲了得到正確的答案,零位必須附加到消息的末尾。有這種方法進行計算的CRC算法。

然而,更常見的CRC算法是以不同的方式完成的,所以消息不需要附加到消息尾部的零位。這種計算通常被稱爲「直接算法」。除了之外,使用更方便,功能上等同,,算法的任何「初始值」需要被修改以說明這種變體算法。

對於CRC-16/CCITT,這會導致混淆正確的初始值:應該是0xFFFF還是?可以說,0xFFFF是將增補位附加到消息的算法的正確初始值。如果使用「直接算法」,則必須將初始值設置爲0x1D0F以獲得相同的結果。

因此,您需要了解這種差異,並使用需要與您連接的程序/系統進行交互操作的人員。

進一步閱讀: