CRC16-CCITT 结果不正确?

CRC16-CCITT Incorrect result?

我正在制作一个程序,它将与引导加载程序通信以更新微控制器的固件。除了 CRC calculation.

之外,一切都准备就绪

我已经使用 here 中的 CRC 计算函数来计算多项式 x16 + x12 + x5 + 1 (0b10001000000100001) 的 CRC16。

但是输入 0x3304000012345678 的结果是错误的。我检查过这个website。另外,我已经仔细检查了我正在 C 中复制的 python 脚本。 python 脚本正确计算了 CRC

这是来自网站的代码:

uint16_t crc16(uint8_t *data_p, unsigned length)
{
  unsigned char i;
  unsigned int data;
  unsigned int crc = 0xffff;

  if (length == 0)
        return (~crc);

  do
  {
        for (i=0, data=(unsigned int)0xff & *data_p++;
             i < 8; 
             i++, data >>= 1)
        {
              if ((crc & 0x0001) ^ (data & 0x0001))
                    crc = (crc >> 1) ^ POLY;
              else  crc >>= 1;
        }
  } while (--length);

  crc = ~crc;
  data = crc;
  crc = (crc << 8) | (data >> 8 & 0xff);

  return (crc);
}

CRC-16 不是唯一的规范,它取决于初始值设定项和多项式。我怀疑 0xFFFF 您正在使用的网站使用 0x0000 作为初始值设定项。

在过去的工作中,我们使用 this website 来验证实现,首先验证几个已知输入的网站结果。

我将您发布的 C 代码与您链接的网站上的算法进行了比较,发现了两个主要区别:

1) 您发布的 C 代码以与网站相反的顺序处理位。对于 CRC 计算本身(右移,网站左移)和每个输入字节的处理(首先处理最低有效位,网站首先处理最高有效位)都是如此。

2) C代码在返回CRC值之前将CRC值中的所有位取反,并交换了低字节和高字节。该网站的算法不包括这样的 post-processing.

我更新了您粘贴的 C 代码以匹配网站:

uint16_t crc16(const uint8_t *data_p, unsigned length)
{
  unsigned char i;
  uint8_t data;
  unsigned int crc = 0; // 0xffff;

  while (length-- > 0)
  {
    for (i = 0, data = *data_p++; 
         i < 8;
         i++, data <<= 1)
    {
      if ((crc >> 15) ^ (data >> 7))
        crc = (crc << 1) ^ POLY;
      else
        crc <<= 1;

      crc &= 0xffff;
    }
  }

  return crc;
}

不同点:

1) data 局部变量现在是 uint8_t.

类型

2) 按照@AShelly 的建议,crc 变量被初始化为 0 而不是 0xFFFF。该网站特别提到它在开始计算之前将所有寄存器初始化为0。

3) 我没有单独测试长度 0,而是将循环从 'do' 循环重组为 'while' 循环,这样它就不会进入循环如果 'length' 为 0.

,则第一名

4) 在for循环中,data被左移而不是右移。这是因为我们想先处理它的 high 位,然后是它右边的位,依此类推——左移将每个后续位移动到高位位置。

5) 将进位与输入的新位组合在一起的if语句现在正在将CRC的高位(crc >> 15)与数据的高位(data >> 7),而不是每个的低位。其余代码确保 crc 不会在第 16 个位置有位,data 不会在第 8 个位置有位,因此这些移位保证产生一个位只有。

6) 实际 crc 计算向左移动而不是向右移动。

7) 向左移动 crc 后,我屏蔽掉从位置 16 开始的任何位。这是第 4 点中提到的代码的一部分,它确保 crc >> 15 只产生一个位。 (这也可以通过将 crc 设为 uint16_t 类型来完成。)

8) post-processing 代码被删除。最终的 crc 值在循环完成时按原样返回。

进行这些更改后,C 函数生成的 CRC 与网站匹配。