2014-01-21 358 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以获得相同的结果。

因此,您需要了解这种差异,并使用需要与您连接的程序/系统进行交互操作的人员。

进一步阅读: