CCITT CRC 16位启动值0xffff

CCITT CRC 16 Bit Start Value 0xffff

本文关键字:0xffff 启动 16位 CRC CCITT      更新时间:2023-10-16

我需要计算一个CCITT 16位校验和值的数据,以作为参数和长度一起传递的数据。如果我用测试数据" 123456789"填充数组tempstr,请使用多项式0x8408,长度不包括无效终止字符,我会得到结果字符串6E90(HEX)。与Null终止符号一起,我获得了907a。当我将多项式交换为0x1201时,我将获得结果29E2(HEX)和EFE8(HEX),带有和不终止特征。

我的问题是: 我是否需要在有或没有零终止字符的情况下计算CRC以获得正确的值?我在算法中使用多项式0x1201还是反向多项式0x8408?给定数据0x29b1的正确CRC是正确的吗?我需要正确的值来确定该函数是否正常工作。计算此特定CRC类型的算法是否正确?wdata =(unsigned int)0xff&*pdata ??如果有人可以向我解释什么问题以及如何解决我的问题,我将非常感谢。谢谢你

这是使用和显示Counculate_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);

这是计算_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);
}

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 FALSE)。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;

如果您有查看,它将计算出不同字符串的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%确定的。

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

  • 逐个计算与查找表
  • 反射字节与未反复的字节(首先是MSBIT或LSBIT)。
  • 在消息结束时附加增强位。

最后一点是混乱的问题。回到CRC理论,可以将CRC视为GF(2)的长期分裂,结果是长期分裂的其余部分。要根据基本理论进行正确的计算, n 零位必须附加到消息的末尾,以获取正确的答案。有以下计算的CRC算法。

但是,更常见的是CRC算法是一种不同的方式,因此消息不需要附加到消息结束的零位。该计算通常称为"直接算法"。使用更方便,在功能上等效,,除了需要修改算法的任何"初始值"以说明此变体算法。

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

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

进一步阅读:

  • CRC-CCITT-16位(其他来源)
  • 第10章,"略微操纵的桌子驱动实现",《无痛指南关于CRC错误检测算法的指南》,罗斯·威廉姆斯
  • CRC-16/AUG-CCITT与CRC-16/CCITT-FALSE在参数化的CRC算法中
  • 在线CRC计算器允许使用"非直接"answers"直接"算法计算,并在这两种算法之间转换初始值。