crc算法

前言

crc算法通过给定的多项式, 再模二除此多项式, 最后除尽得到的余数就是我们需要的crc校验码. crc算法在工业上有一个统一标准, 被称为crc参数模型.

一个完整的CRC参数模型应该包含以下信息:WIDTH,POLY,INIT,REFIN,REFOUT,XOROUT。

  • NAME:参数模型名称。
  • WIDTH:宽度,即生成的CRC数据位宽,如CRC-8,生成的CRC为8位
  • POLY:十六进制多项式,省略最高位1,如 x8 + x2 + x + 1,二进制为1 0000 0111,省略最高位1,转换为十六进制为0x07。
  • INIT:CRC初始值,和WIDTH位宽一致。
  • REFIN:true或false,在进行计算之前,原始数据是否翻转,如原始数据:0x34 = 0011 0100,如果REFIN为true,进行翻转之后为0010 1100 = 0x2c
  • REFOUT:true或false,运算完成之后,得到的CRC值是否进行翻转,如计算得到的CRC值:0x97 = 1001 0111,如果REFOUT为true,进行翻转之后为11101001 = 0xE9。
  • XOROUT:计算结果与此参数进行异或运算后得到最终的CRC值,和WIDTH位宽一致。

在这里, 我们主要从代码实现的原理分析crc算法并用c语言给出crc算法实现的两种版本

1. 直接计算版本

首先从一个例子展开, 设有一个多项式 p = x^4 + 0^3 + 0^2 + x^1 + x^0,  被除数 1101011011

由此可以得出 除数为 10011, 被除数 11010110110000

通过模2除可以得到如图所示的结果, 余数即为我们需要的crc校验码.

我们使用伪代码模拟一遍上述crc算法的计算过程.

#define POLYNOMIAL (1)0011b

uint16_t crc = 11010110110000b;

FOR( int i = 0; i < 10; i++ )

BEGIN

        IF [ crc & (1 << 9) ] //如果被除数的最高位为1, 直接左移1位, 和剩余几位作模二减.

                 crc =  (crc << 1) ^ POLYNOMIAL

        ELSE

                crc <<= 1

        ENDIF

END

接下来使用c语言实现一个crc-8多项式的算法

#define POLYMORPHISM 0xaa(少生成一个bit, 最高位默认为1, 因为是模二除, 所以可以使用左移补偿)
uint8_t generate_crc(uint8_t *data, int len)
{
    uint8_t crc = 0;
    for(int i = 0; i < len; i++)
    {
        crc ^= data[i];
        if( crc & 0x80 )
        {
            crc = (crc << 1 ) ^ POLYMORPHISM;
        }else crc <<= 1;
    }
    return crc;
}

这样, 一个基础的crc-8 校验码生成算法就写好了, crc16思路大致与此相同, 可以自行修改.

2. 查表生成法

由于crc生成的校验码必然还在原来的值范围内, 例如 crc8 校验算法只会生成0 - 255之间的数值, 因此我们可以提前将 0 -255的数据值生成一张表, 在生成crc校验码的时候可以直接查找

2.1 生成表

void crcInit(void)
{
    width_t remainder;
    width_t dividend;
    int bit;
    /* Perform binary long division, a bit at a time. */
    for(dividend = 0; dividend < 256; dividend++)
    {
        /* Initialize the remainder.  */
        remainder = dividend << (WIDTH - 8);
        /* Shift and XOR with the polynomial.   */
        for(bit = 0; bit < 8; bit++)
        {
            /* Try to divide the current data bit.  */
            if(remainder & TOPBIT)
            {
                remainder = (remainder << 1) ^ POLYNOMIAL;
            }
            else
            {
                remainder = remainder << 1;
            }
        }
        /* Save the result in the table. */
        crcTable[dividend] = remainder;
    }
} /* crcInit() */
width_t crcCompute(unsigned char * message, unsigned int nBytes)
{
    unsigned int offset;
    unsigned char byte;
    width_t remainder = INITIAL_REMAINDER;
    /* Divide the message by the polynomial, a byte at a time. */
    for( offset = 0; offset < nBytes; offset++)
    {
        byte = (remainder >> (WIDTH - 8)) ^ message[offset];
        remainder = crcTable[byte] ^ (remainder << 8);
    }
    /* The final remainder is the CRC result. */
    return (remainder ^ FINAL_XOR_VALUE);
} /* crcCompute() */
 

有了crc表, 在生成crc的时候可以通过查表直接获得该值对应的余数, 提高了生成效率. 典型的空间换时间.

参考

Introduction to Cyclic Redundancy Check (CRC) algorithm written to embedded programmers

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值