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 与网站匹配。
我正在制作一个程序,它将与引导加载程序通信以更新微控制器的固件。除了 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 与网站匹配。