• 注册 / 登录
  • 切换到窄版
  • 查看: 510|回复: 0

    图文解说数据传输CRC校验

    [复制链接]

    665

    主题

    679

    帖子

    6461

    积分

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    6461
    发表于 2024-5-21 22:00:16 | 显示全部楼层 |阅读模式

    路线栈欢迎您!

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    前言

    数据传输中经常听到CRC效验,一个完整的数据帧通常由以下部分构成:帧头+数据+校验位+帧尾

    校验位是为了保证数据在传输过程中的完整性,采用一种指定的算法对原始数据进行计算,得出的一个校验值。接收方接收到数据时,采用同样的校验算法对原始数据进行计算,如果计算结果和接收到的校验值一致,说明数据校验正确,这一帧数据可以使用,如果不一致,说明传输过程中出现了差错,这一帧数据丢弃,请求重发。

    1.png

    常用的校验算法有奇偶校验、校验和、CRC,还有LRC、BCC等不常用的校验算法。

    以串口通讯中的奇校验为例,如果数据中1的个数为奇数,则奇校验位0,否则为1。

    例如原始数据为:0001 0011,数据中1的个数(或各位相加)为3,所以奇校验位为0。这种校验方法很简单,但这种校验方法有很大的误码率。假设由于传输过程中的干扰,接收端接收到的数据是0010 0011,通过奇校验运算,得到奇校验位的值为0,虽然校验通过,但是数据已经发生了错误。

    2.png

    校验和同理也会有类似的错误:

    3.png

    一个好的校验校验方法,配合数字信号编码方式,如(差分)曼彻斯特编码,(不)归零码等对数据进行编码,可大大提高通信的健壮性和稳定性。例如以太网中使用的是CRC-32校验,曼彻斯特编码方式。

    RC 算法(模二计算)

    CRC 算法的基本思想是将传输的数据当做一个位数很长的数。将这个数除以另一个数。得到的余数作为校验数据附加到原数据后面。

    模二计算本质上就是异或运算,相同的位为0,不同的位为1,也就是不考虑进位、错位的二进制加减法运算,例如:10011011 + 11001010 = 01010001.

    接收方接收此数据后,再做除数运算,余数应该为0。

    1.宽度(Width): 指CRC校验码的宽度,同时也是指多项式的宽度。

    crc16的width是16,crc32的宽度是32。

    2.多项式(Poly):指CRC校验的多项式的二进制码去掉最高位。

    crc8的Poly:gx=x8+x2+x1+1,二进制码100000111,去掉最高位所以POLY这个参数为:0x07

    3.初始值(Init),是指CRC的寄存器的初始值。

    4.输入值反转(RefIN):是指需要校验的数据(输入值)二进制位数相反。

    输入值为:10101100,则实际进行校验的值为00110101。

    5.输出值反转(RefOut):指输出的校验码二进制位进行反转。

    输出值为:10101100,则实际输出值为00110101。

    6.结果异或值(XorOut): 指运算出的校验码与结果异或值异或之后,最终最为校验码。

    XorOut为0xff,计算的校验码为0x17,则输出校验码为:0xff^0x17。

    规定:生成多项式对应的二进制位数 比 CRC校验码的宽度多一位。

    CRC校验的流程

    1.选定一个标准除数(二进制数据)。

    2.在要发送的数据后面加上冗余校验码的宽度位0,然后将这个新数  以模2除法的方式除以上面这个标准除数,所得到的余数也就是该数据的CRC校验码。

    (注:余数必须比除数少且只少一位,不够就补0)

    3.将这个校验码附在 被除数 后面,构成新的数据,发送给接收端。

    4.接收端将接收到的数据 除以标准除数,如果余数为0则认为数据正确。

    (1). 只有当位串的最高位为1,我们才将它与poly做XOR运算,否则我们只是将位串左移一位。

    (2). 异或运算的结果实质上是被操作位串与poly位长-1的各位进行运算的结果,因为最高位总为0。

    因为除数和被除数第一位必定是1 异或之后就是0

    4.png

    代码
    1. #define POLY        0x1021
    2. /**
    3. *        @param:        addr:        存放数据的数组地址
    4. *                        lenth:        数组长度
    5. *                        crc:        crc初始化的值
    6. */
    7. uint16_t crc16(unsigned char *addr, int lenth, uint16_t crc)
    8. {
    9.     int i;
    10.     for (; lenth> 0; lenth--)                   // 数组有多少字节进行多少次计算
    11.     {
    12.         crc = crc ^ (*addr++ << 8);   //先算第一个字节
    13.         for (i = 0; i < 8; i++)            
    14.         {
    15.             if (crc & 0x8000)           
    16.                 crc = (crc << 1) ^ POLY;   
    17.             else                          
    18.                 crc <<= 1;                 
    19.         }                           
    20.         crc &= 0xFFFF;                 // 确保出来的CRC是16位,多余的清零
    21.     }                              
    22.     return   crc;<span style="background-color: rgb(255, 255, 255);">     </span>
    复制代码

    通用CRC表

    5.png

    • 芯片DS2401/DS18B20,都是使用的CRC-8/MAXIM模型
    • SD卡或MMC使用的是CRC-7/MMC模型
    • Modbus通信使用的是CRC-16/MODBUS参数模型
    • USB协议中使用的CRC-5/USB和CRC-16/USB模型
    • 很多ARM芯片带硬件CRC计算模块使用的是CRC-32模型

    结语

    CRC校验并不能100%的检查出数据的错误,非常低的概率会出现CRC校验正确但数据中有错误位的情况。这和CRC的位数,多项式的选择等等有很大的关系,所以在实际使用中尽量选择标准CRC参数模型,这些多项式参数都是经过理论计算得出的,可以提高CRC的检错能力。更多相关内容请看:常用的crc16标准校验算法和C代码HC32F4A0 CRC32校验

    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    小黑屋|路丝栈 ( 粤ICP备2021053448号 )

    GMT+8, 2024-9-8 09:01 , Processed in 0.047626 second(s), 22 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表