5

我需要计算作为参数传递的数据的 CCITT 16 位校验和值以及长度。如果我用测试数据“123456789”填充我的数组 TempStr,使用长度不包括空终止字符的多项式 0x8408,我得到结果字符串 6E90(十六进制)。连同空终止字符,我得到 907A。当我将多项式换成 0x1201 时,我会得到带有和不带有终止字符的结果 29E2(Hex) 和 EFE8(Hex)。

我的问题是:我是否需要计算带有或不带有空终止字符的 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);
}
4

3 回答 3

4

结果0x29b1“假”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;
于 2014-01-21T16:06:57.337 回答
2

如果您查看一下,它将计算不同字符串(或十六进制序列,用于检查有无 NUL)的 CRC 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% 确定的。

于 2014-01-21T08:36:10.367 回答
1

CRC算法有许多不同的变体。

  • 逐位计算与查找表
  • 反射字节与非反射字节(首先是 MSbit 或 LSbit)。
  • 在消息末尾附加或不附加增强位。

最后一点是一个令人困惑的问题。回到 CRC 理论,CRC 可以看作 GF(2) 中的长除法,其结果是长除法的余数。为了根据基本理论进行正确的计算,必须在消息的末尾附加n 个零位才能得到正确的答案。有CRC算法以这种方式进行计算。

然而,更常见的 CRC 算法以不同的方式完成,因此消息不需要附加到消息末尾的零位。这种计算通常被称为“直接算法”。它使用起来更方便,并且在功能上等效,除了需要修改算法的任何“初始值”以解释这种变体算法。

在 CRC-16/CCITT 的情况下,这会导致对正确初始值的混淆:应该是0xFFFF还是0x1D0F?可以说,0xFFFF对于将增强位附加到消息的算法来说,它是正确的初始值。如果使用“直接算法”,则必须将初始值设置为0x1D0F以获得相同的结果。

因此,您需要意识到这种差异,并使用所需的任何一种来与您正在与之交互的程序/系统进行交互。

进一步阅读:

于 2015-10-22T00:52:54.477 回答