我正在制作一个程序,它将与引导加载程序通信以更新微控制器的固件。除CRC calculation
以外,一切准备就绪。
我使用了来自here的CRC计算函数来计算多项式x16 + x12 + x5 + 1
(0b10001000000100001)的CRC16。
但是输入0x3304000012345678
的结果出现了错误。我检查了这个website。此外,我已经使用python脚本进行了双重检查,我在C
复制。 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);
}
答案 0 :(得分:3)
我将您发布的C代码与您链接的网站上的算法进行了比较,我发现了两个主要区别:
1)您发布的C代码按照网站的相反顺序处理这些位。这对于CRC计算本身(向右移动,网站向左移动)和输入的每个字节的处理都是如此(首先处理最低有效位,其中网站首先处理最高有效位)。
2)C代码在返回之前反转CRC值中的所有位,并且还交换低字节和高字节。该网站的算法不包括此类后处理。
我已更新您粘贴的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)crc
变量初始化为0而不是0xFFFF,如@AShelly所示。该网站特别提到在开始计算之前将所有寄存器初始化为0.
3)我没有单独测试长度为0,而是将循环从'do'循环重构为'while'循环,这样如果'length',它就不会首先进入循环是0。
4)在for
循环中,data
左移而不是右移。这是因为我们首先要处理其高位,然后是右边的位,依此类推 - 左移位将每个后续位移动到高位位置。
5)将进位与新位输入组合在一起的if
语句现在将CRC的高位(crc >> 15
)与数据的高位进行比较({{1} }),而不是每个的低位。其余的代码确保data >> 7
在第16位没有位,crc
在第8位不会有位,所以这些位移保证产生一位仅
6)实际的data
计算向左移动而不是向右移动。
7)将crc
向左移动后,我屏蔽了位置16上的任何位。这是第4点中提到的代码的一部分,它确保crc
只产生一个位。 (这也可以通过使crc >> 15
为crc
类型来完成。)
8)删除后处理代码。最后的uint16_t
值将在循环完成时返回。
通过这些更改,C函数生成的CRC与网站匹配。
答案 1 :(得分:1)
CRC-16不是唯一的规范,它取决于初始化器和多项式。我怀疑0xFFFF
您使用的网站使用0x0000
作为初始化程序。
在过去的工作中,我们使用this website来验证实施,首先验证了几个已知输入的网站结果。