如何在 C# 和 C 中计算 CRC16-CCITT/KERMIT
How to calculate CRC16-CCITT/KERMIT in both C# and C
我正在计算 CRC16-CCITT/KERMIT,以便我可以检查 C# Winforms 应用程序和微控制器 (PSoC5LP/Arm Cortex-M3) 之间传输的 64 字节数据包的数据完整性。我很接近,但只是没有完全让 CRC 计算在两者之间对齐并且很难找出原因。我计算 CRC 的示例数据包是:
02 03 01 02 03 04 05 07 08 09 0A 0B 00 00 06 0E 0C 0D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
在我的 Winforms 应用程序和这个 online CRC calculator
中,此数据包的 CRC 结果为 0x4D8C
由于这些排列,我假设 C# 计算中的计算是合法的。无论如何,这是代码。从 this page 中提取,唯一的变化是我对多项式 (0x8408) 进行了硬编码:
public static class Crc16
{
const ushort polynomial = 0x8408;
static readonly ushort[] table = new ushort[256];
public static ushort ComputeChecksum(byte[] bytes)
{
ushort crc = 0;
for (int i = 0; i < bytes.Length; ++i)
{
byte index = (byte)(crc ^ bytes[i]);
crc = (ushort)((crc >> 8) ^ table[index]);
}
return crc;
}
static Crc16()
{
ushort value;
ushort temp;
for (ushort i = 0; i < table.Length; ++i)
{
value = 0;
temp = i;
for (byte j = 0; j < 8; ++j)
{
if (((value ^ temp) & 0x0001) != 0)
{
value = (ushort)((value >> 1) ^ polynomial);
}
else
{
value >>= 1;
}
temp >>= 1;
}
table[i] = value;
}
}
}
现在问题正在为微控制器获取一个有效的 CRC16-CCITT/KERMIT 计算器函数,它将为该数据包生成相同的 CRC。
这是我目前拥有的(摘自 ):
uint16_t crc16k(uint16_t crc, uint8_t *mem, uint8_t len) {
uint8_t *data = mem;
if (data == NULL){
return 0;
}
crc = ~crc;
crc &= 0xffff;
while (len--) {
crc ^= *data++;
for (uint8_t k = 0; k < 8; k++)
crc = crc & 1 ? (crc >> 1) ^ 0x8408 : crc >> 1;
}
crc ^= 0xFFFF;
return crc;
}
我是这样称呼它的:
uint16_t crc_calc = crc16k(0x0000, message_in, 64);
这里是我要搞笑的地方。该数据包是 64 字节,但实际上(对于此数据包),只有前 29 个字节是我正在使用的数据。其余的只是填充以满足 64 字节。当我在 WinForms 端计算 CRC 时,看起来它使用了所有 64 个字节,包括填充。当我在微控制器端做同样的事情时,我得到的结果是 0xE918。奇怪的是,如果我将长度参数限制为我感兴趣的 29 个字节,我会得到 0x4C8B,它非常接近我正在寻找的 0x4D8C。我还注意到,在我使用的在线计算器中,它声称输出的 XOR 应该是 0x0000。我在输出上使用异或 0xFFFF 的 C 函数。将其更改为 0x0000(并处理所有 64 个字节)会得到 0x16E7。
所以我不确定问题出在哪里。这是我第一次使用 CRC,所以我可能会遗漏一些明显的东西。有什么想法吗?
提前感谢您的帮助!让我知道是否需要我提供任何其他信息。
当然,我在发布问题后不到 10 分钟就收到了(不是总是这样吗?)
我认为 CRC-16/KERMIT 的 C 代码看起来实际上是 CRC-16/X-25。我想我很困惑,因为我从 的答案中提取代码的问题是询问 KERMIT,但答案说它是 X-25。
删除函数开头的 crc 按位取反:
crc = ~crc;
以及删除
crc ^= 0xFFFF;
这给我留下了:
uint16_t crc16k(uint16_t crc, uint8_t *mem, uint8_t len) {
uint8_t *data = mem;
if (data == NULL){
return 0;
}
while (len--) {
crc ^= *data++;
for (uint8_t k = 0; k < 8; k++)
crc = crc & 1 ? (crc >> 1) ^ 0x8408 : crc >> 1;
}
return crc;
}
这似乎有效,并且 CRC 在我的 Winforms 应用程序和 PSoC5 之间匹配。我想我之前的 "near match" 只是巧合,数字相似?如果有人有解释,我很想听听。
我正在计算 CRC16-CCITT/KERMIT,以便我可以检查 C# Winforms 应用程序和微控制器 (PSoC5LP/Arm Cortex-M3) 之间传输的 64 字节数据包的数据完整性。我很接近,但只是没有完全让 CRC 计算在两者之间对齐并且很难找出原因。我计算 CRC 的示例数据包是:
02 03 01 02 03 04 05 07 08 09 0A 0B 00 00 06 0E 0C 0D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
在我的 Winforms 应用程序和这个 online CRC calculator
中,此数据包的 CRC 结果为 0x4D8C由于这些排列,我假设 C# 计算中的计算是合法的。无论如何,这是代码。从 this page 中提取,唯一的变化是我对多项式 (0x8408) 进行了硬编码:
public static class Crc16
{
const ushort polynomial = 0x8408;
static readonly ushort[] table = new ushort[256];
public static ushort ComputeChecksum(byte[] bytes)
{
ushort crc = 0;
for (int i = 0; i < bytes.Length; ++i)
{
byte index = (byte)(crc ^ bytes[i]);
crc = (ushort)((crc >> 8) ^ table[index]);
}
return crc;
}
static Crc16()
{
ushort value;
ushort temp;
for (ushort i = 0; i < table.Length; ++i)
{
value = 0;
temp = i;
for (byte j = 0; j < 8; ++j)
{
if (((value ^ temp) & 0x0001) != 0)
{
value = (ushort)((value >> 1) ^ polynomial);
}
else
{
value >>= 1;
}
temp >>= 1;
}
table[i] = value;
}
}
}
现在问题正在为微控制器获取一个有效的 CRC16-CCITT/KERMIT 计算器函数,它将为该数据包生成相同的 CRC。
这是我目前拥有的(摘自
uint16_t crc16k(uint16_t crc, uint8_t *mem, uint8_t len) {
uint8_t *data = mem;
if (data == NULL){
return 0;
}
crc = ~crc;
crc &= 0xffff;
while (len--) {
crc ^= *data++;
for (uint8_t k = 0; k < 8; k++)
crc = crc & 1 ? (crc >> 1) ^ 0x8408 : crc >> 1;
}
crc ^= 0xFFFF;
return crc;
}
我是这样称呼它的:
uint16_t crc_calc = crc16k(0x0000, message_in, 64);
这里是我要搞笑的地方。该数据包是 64 字节,但实际上(对于此数据包),只有前 29 个字节是我正在使用的数据。其余的只是填充以满足 64 字节。当我在 WinForms 端计算 CRC 时,看起来它使用了所有 64 个字节,包括填充。当我在微控制器端做同样的事情时,我得到的结果是 0xE918。奇怪的是,如果我将长度参数限制为我感兴趣的 29 个字节,我会得到 0x4C8B,它非常接近我正在寻找的 0x4D8C。我还注意到,在我使用的在线计算器中,它声称输出的 XOR 应该是 0x0000。我在输出上使用异或 0xFFFF 的 C 函数。将其更改为 0x0000(并处理所有 64 个字节)会得到 0x16E7。
所以我不确定问题出在哪里。这是我第一次使用 CRC,所以我可能会遗漏一些明显的东西。有什么想法吗?
提前感谢您的帮助!让我知道是否需要我提供任何其他信息。
当然,我在发布问题后不到 10 分钟就收到了(不是总是这样吗?)
我认为 CRC-16/KERMIT 的 C 代码看起来实际上是 CRC-16/X-25。我想我很困惑,因为我从 的答案中提取代码的问题是询问 KERMIT,但答案说它是 X-25。
删除函数开头的 crc 按位取反:
crc = ~crc;
以及删除
crc ^= 0xFFFF;
这给我留下了:
uint16_t crc16k(uint16_t crc, uint8_t *mem, uint8_t len) {
uint8_t *data = mem;
if (data == NULL){
return 0;
}
while (len--) {
crc ^= *data++;
for (uint8_t k = 0; k < 8; k++)
crc = crc & 1 ? (crc >> 1) ^ 0x8408 : crc >> 1;
}
return crc;
}
这似乎有效,并且 CRC 在我的 Winforms 应用程序和 PSoC5 之间匹配。我想我之前的 "near match" 只是巧合,数字相似?如果有人有解释,我很想听听。