CRC原理和C语言实现CRC

〇、参考文章
  1. 最通俗的CRC校验原理剖析
  2. 循环冗余校验(CRC)算法入门引导
  3. CRC的基本原理详解
  4. CRC编码及C++实现
  5. CRC原理简介
一、CRC原理

CRC是对传输的数据进行一个差错校验的,但是不对数据进行纠错,CRC检测不通过的时候丢弃数据

CRC注意点

首先先明确几个点:

  • 多项式的被除数M,也就是信息码(数据)
  • 多项式的除数G,也叫生成多项式
  • 得到的结果冗余校验码R
  • 以及冗余校验码的宽度W
  • 规定:生成多项式对应的二进制位数比W多一位,但是把第1位忽略掉

比如:

生成多项式 x 4 + x 3 + 1 x^{4} + x^{3}+1 x4+x3+1 ,对应的二进制是 11001,那么所求的就是 CRC-4,是所求的CRC位数来决定多项式的


新的运算法则

CRC算法的是以GF(2)(2元素伽罗瓦域)多项式算术为数学基础的,注意,这是一种新的运算法则

法则规定,加减不考虑进位,所以加减是一致的,式子中不出现减号,以加号代替,因此可以用二进制的异或来运算其加法(在运算异或的时候就是加法)

P1 = x^3  + x^2 + 1,P2 = x^3  + x^1 + 1,P1 + P2为:

	x^3 + x^2     + 1									1101
+	x^3       + x  + 1						         ^  1011
------------------------------      >>      ------------------------------
          x^2 + x                                       0110

了解一下异或的一些性质:(下面的代码中用到了交换律)

1. a ⊕ a = 0
2. a ⊕ b = b ⊕ a    						//  异或运算满足交换律
3. a ⊕ b ⊕ c = a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c; //  异或运算满足结合律
4. d = a ⊕ b ⊕ c 可以推出 a = d ⊕ b ⊕ c.
5. a ⊕ b ⊕ a = b.

CRC原理

假设信息 M M M,多项式 G G G,在 M M M 后面添加 W W W 0 0 0,也就是 M ′ = M ∗ x W M' = M*x^{W} M=MxW ,除以多项式 G G G,的到商 Q Q Q,余下余数 R R R

M ′ ÷ G = Q ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ R M'÷G = Q······R M÷G=Q⋅⋅⋅⋅⋅⋅R

比如说我们的需要发送的信息是0x01 0x02 0x03 0x04,求CRC-8,会把所有信息的二进制拼在一起,然后末尾添加80

	0x01	0x02	0x03	0x04
0000000100000010000000110000010000000000 =>M'

M' 是多出了R的,对M'使用新的运算法则,(M'+R)会把多余的R消除掉,因为a ⊕ a = 0,所以有(M'+R)÷G = Q······0

  • 发送方对信息进行CRC验算,然后把余数R(CRC)附加在信息的后面0x01 0x02 0x03 0x04 R(CRC),相当于(M'+R),一起发给接收方
  • 接收方接收到信息后,可以直接对多项式求余数,余数等于0,说明接收到的信息是正确的
  • 当然也可以去掉R(CRC),同样使用M'G求余数,结果跟发过来的R(CRC)一样说明接收的数据是正确的

CRC例子

下面是以对信息0x01 0x02 0x03 0x04为例求CRC-16的过程,商不重要,所以没有写

在这里插入图片描述


二、CRC检验C语言

实际如果信息字节数比较多,是没有办法用一个变量存储所有的字节的,这不现实

所以需要使用到异或的性质:交换律和结合律

0x0102,有0x0102 = 0x0100 ⊕ 0x02

0x0102 ⊕ 0x1021,有 0x0100 ⊕ 0x02 ⊕ 0x1021= (0x0100 ⊕ 0x1021) ⊕ 0x02

其中0x0100只有高8位是有数据的,所以只要逐个左移8位去找到数据位为1的开始异或,这里找到数据位为1之后还要左移一次再异或就是因为隐藏了最高位的1

for (i = 0; i < 8; i++)             // 一个字节8位,一位一位的去异或
{
    if (crc & 0x8000)            // 判断CRC的首位,如果是1的活,那么左移一位之后,其首位和除数被忽略的那个最高位的1异或结果位0,也可以忽略
        crc = (crc << 1) ^ POLY;	// 左移后进行异或
    else                         // 首位为0,比如异或之后结果为0,应该选首位为1的位开始继续异或,直接跳过0位
        crc <<= 1;               
}                             

0x0100 左移了8位,异或多项式得到余数,所以后面的0x02,也是需要左移8位的,再异或余数的

crc = crc ^ (*addr++ << 8);

那么结合起来的总代码就是下面的这个

#define POLY        0x1021
/**
 *	@param:	addr:	存放数据的数组地址
 *			lenth:	数组长度
 *			crc:	crc初始化的值
 */
uint16_t crc16(unsigned char *addr, int lenth, uint16_t crc)
{
    int i;
    for (; lenth> 0; lenth--)           	// 数组有多少字节进行多少次计算
    {
        crc = crc ^ (*addr++ << 8);     	
        for (i = 0; i < 8; i++)            
        {
            if (crc & 0x8000)           
                crc = (crc << 1) ^ POLY;   
            else                          
                crc <<= 1;                 
        }                            
        crc &= 0xFFFF;                 // 确保出来的CRC是16位,多余的清零,这个不是结果异或值 XOROUT
    }                               
    return(crc);                   
}

三、测试:
AA 55 12 AA AA AA 12 34 56 78

在这里插入图片描述


2020.8.25
  • 6
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值