如何计算C#和C中的CRC16-CCITT/KERMIT

如何计算C#和C中的CRC16-CCITT/KERMIT,c#,c,crc,crc16,psoc,C#,C,Crc,Crc16,Psoc,我正在计算CRC16-CCITT/KERMIT,以便检查C#Winforms应用程序和微控制器(PSoC5LP/Arm Cortex-M3)之间64字节数据包传输的数据完整性。我很接近,但只是没有把CRC计算结果排在两者之间,很难找出原因。我正在计算CRC的示例数据包是: 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

我正在计算CRC16-CCITT/KERMIT,以便检查C#Winforms应用程序和微控制器(PSoC5LP/Arm Cortex-M3)之间64字节数据包传输的数据完整性。我很接近,但只是没有把CRC计算结果排在两者之间,很难找出原因。我正在计算CRC的示例数据包是:

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 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 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

这个数据包的CRC在我的Winforms应用程序和这个应用程序中都显示为0x4D8C

既然这些都排好了,我假设C#计算中的计算是合法的。不管怎样,代码如下。从中提取,唯一的更改是I硬编码多项式(0x8408):

这是我得到一些有趣的东西的地方。这个数据包是64字节,但实际上(对于这个数据包),只有前29个字节是我正在使用的数据。其余的只是填充以满足64字节的要求。当我在WinForms端计算CRC时,它似乎使用了所有64个字节,包括填充。当我在微控制器端执行同样的操作时,得到的结果是0xE918。奇怪的是,如果我将length参数限制为我感兴趣的29个字节,我会得到0x4C8B,这与我正在寻找的0x4D8C非常接近。我还注意到,在我使用的在线计算器中,它声称输出上的XOR应该是0x0000。我在输出上使用的C函数是XORs 0xFFFF。将其更改为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;
}
uint16\u t crc16k(uint16\u t crc,uint8\u t*mem,uint8\u t len){
uint8_t*数据=内存;
如果(数据==NULL){
返回0;
}
而(len--){
crc^=*数据++;
对于(uint8k=0;k<8;k++)
crc=crc&1?(crc>>1)^0x8408:crc>>1;
}
返回crc;
}

这看起来很有效,我的Winforms应用程序和PSoC5之间的CRC匹配。我想我之前的“近似匹配”只是巧合——数字相似?如果有人有解释,我很想听听。

您在网页上使用哪些选项来获得正确的结果?sunshine的网页解释了这些选项:不确定你为什么有这个桌子。您可以使用表格方法,也可以不使用表格方法。您在网页上使用哪些选项来获得正确的结果?sunshine的网页解释了这些选项:不确定你为什么有这个桌子。您可以使用table方法,也可以不使用table方法。当您为16crc生成校验和时,您对长度x字节(不包括CRC)进行校验和。然后,当您验证是否对x+2(包括crc)字节执行此操作时,将得到全零或全一(取决于选项)。您是否知道
crc^=0x0000是否为禁止操作?以及
crc&=0xFFFF在uint16@Ctx哦,嘿,你完全正确,哈哈。当在线计算器说xorut=0x0000时,我没有想到这意味着不要对它进行XOR运算。我完全删除了这一行,因为它没有任何意义(并编辑了答案以匹配)。是的,crc上的面具是不需要的。我还想知道它为什么会出现(也许它最初为“unsigned”编写的是32位类型?)。在任何情况下,你是对的,我在使用uint16时不需要它。@K_Trenholm-有没有理由在C代码中不使用256项查找表,这会加快代码的速度?您只需将C#代码复制/翻译为C代码,只需稍作更改(C代码不需要是类的一部分)。@rcgldr除了我偶然发现的用于计算CRC16的C代码之外,没有其他特定原因没有使用表。在完成这个项目之前,我可能会回去做一个两端表。
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;
}