使用字节数据的 CRC16 是如何工作的? (用于 CAN 总线实现)

How CRC16 using bytes data is woking ? (for CAN bus implementation)

我在为 can 消息实现 CRC16 时遇到了一些问题,我按照本网站给出的说明进行操作 https://barrgroup.com/embedded-systems/how-to/crc-calculation-c-code and http://www.sunshine2k.de/articles/coding/crc/understanding_crc.html#ch5, plus other implention I have seen in here ( for example Function to Calculate a CRC16 Checksum)。

我不明白它是如何处理的。 我这里的消息是字节形式的,比如char message[4] = {0x12, 0x34, 0x56, 0x78}。当我通过第一个循环时,我只取第一个字节,将其移动 8 并用 16 bitsPOLYNOME 计算 remainder。 这意味着我们有 0x1200 并且我们用它进行第二个循环,这意味着我用存储在 remainder 中的 POLYNOME 做了一个 XOR 但我没有不太明白为什么会这样,尤其是当我查看这段代码时,我的消息的 2nd3rd4th bytes 应该得到 XORed POLYNOME8 first bits 在某些时候根本没有经过它。 根据维基百科的解释 https://en.wikipedia.org/wiki/Cyclic_redundancy_check 多项式一次遍历整个消息,而不是逐字节遍历。 我不知道这如何转化为逐字节执行 0x12345678 的 CRC。

uint16_t Compute_CRC16_Simple(char* message, int nbOfBytes)
{
    uint16_t POLYNOME = 0xC599; 
    uint16_t remainder = 0; 
    for (int byte = 0;byte < nbOfBytes; byte++)
    {
        remainder ^= (message[byte] << 8); 

        for (int i = 0; i < 8; i++)
        {
            if (remainder  & 0x8000) 
            {
                remainder = (remainder << 1) ^ POLYNOME ;
            }
            else
            {
                remainder <<= 1;
            }
        }
    }
    return remainder;
}

I don't understand how it is processed.

也许描述8位数据的逐位操作会有所帮助:

crc[bit15] ^= data[bit7]
if(crc[bit15] == 1) crc = (crc << 1) ^ poly
else crc = crc << 1
crc[bit15] ^= data[bit6]
if(crc[bit15] == 1) crc = (crc << 1) ^ poly
else crc = crc << 1
...
crc[bit15] ^= data[bit0]
if(crc[bit15] == 1) crc = (crc << 1) ^ poly
else crc = crc << 1

注意if语句只依赖于crc[bit15]中的位值,所以与数据异或的固定部分可以一步完成:

crc[bit15 .. bit8] ^= data[bit7 .. bit0]
if(crc[bit15] == 1) crc = (crc << 1) ^ poly
else crc = crc << 1
if(crc[bit15] == 1) crc = (crc << 1) ^ poly
else crc = crc << 1
...
if(crc[bit15] == 1) crc = (crc << 1) ^ poly
else crc = crc << 1

使用 if ... then (shift + xor poly) else (just shift) 循环 8 次 CRC 可以为 crc[bit15 .. bit8] 中的所有 256 个可能值预先计算,并存储在table 用于 table 查找以循环 CRC 8 次。