数据校验--CRC校验

2024-05-01 13:48
文章标签 数据 校验 crc

本文主要是介绍数据校验--CRC校验,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

工作原理:
    CRC即循环冗余校验码(Cyclic Redundancy Check):是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定。
    循环冗余检查(CRC)是一种数据传输检错功能,对数据进行多项式计算,并将得到的结果附在帧的后面,接收设备也执行类似的算法,以保证数据传输的正确性和完整性。
    循环冗余校验码(CRC)的基本原理是:在K位信息码后再拼接R位的校验码,整个编码长度为N位,因此,这种编码也叫(N,K)码。
    对于一个给定的(N,K)码,可以证明存在一个最高次幂为N-K=R的多项式G(x)。根据G(x)可以生成K位信息的校验码,而G(x)叫做这个CRC码的生成多项式。 
    校验码的具体生成过程为:假设要发送的信息用多项式C(X)表示,将C(x)左移R位(可表示成C(x)*2^R),这样C(x)的右边就会空出R位,这就是校验码的位置。
    用 C(x)*2^R 除以生成多项式G(x)得到的余数就是校验码。
    任意一个由二进制位串组成的代码都可以和一个系数仅为‘0’和‘1’取值的多项式一一对应。例如:代码1010111对应的多项式为x6+x4+x2+x+1,而多项式为x5+x3+x2+x+1对应的代码101111。
基本概念:
    对应关系:
        多项式和二进制数有直接对应关系:X的最高幂次对应二进制数的最高位,以下各位对应多项式的各幂次,有此幂次项对应1,无此幂次项对应0。
        可以看出:X的最高幂次为R,转换成对应的二进制数有R+1位。
        多项式包括生成多项式G(X)和信息多项式C(X)。
        如生成多项式为G(X)=X4+X3+X+1, 可转换为二进制数码11011
        而发送信息位 101111,可转换为数据多项式为C(X)=X5+X3+X2+X+1。
    生成多项式:
        是接受方和发送方的一个约定,也就是一个二进制数,在整个传输过程中,这个数始终保持不变。
        在发送方,利用生成多项式对信息多项式做模2除生成校验码。在接收方利用生成多项式对收到的编码多项式做模2除检测和确定错误位置。
        应满足以下条件:
            A、生成多项式的最高位和最低位必须为1。
            B、当被传送信息(CRC码)任何一位发生错误时,被生成多项式做除后应该使余数不为0。
            C、不同位发生错误时,应该使余数不同。
            D、对余数继续做除,应使余数循环。
    校验码位数:
        CRC校验码位数 = 生成多项式位数 - 1。注意有些生成多项式的简记式中将生成多项式的最高位1省略了。
    生成步骤:
        1、将X的最高次幂为R的生成多项式G(X)转换成对应的R+1位二进制数。
        2、将信息码左移R位,相当于对应的信息多项式C(X)*2^R。
        3、用生成多项式(二进制数)对信息码做除,得到R位的余数(注意:这里的二进制做除法得到的余数其实是模2除法得到的余数,并不等于其对应十进制数做除法得到的余数。)。
        4、将余数拼到信息码左移后空出的位置,得到完整的CRC码。
        例:假设使用的生成多项式是G(X)=X3+X+1。4位的原始报文为1010,求编码后的报文。
        1、将生成多项式G(X)=X3+X+1转换成对应的二进制除数1011。
        2、此题生成多项式有4位(R+1)(注意:4位的生成多项式计算所得的校验码为3位,R为校验码位数),要把原始报文C(X)左移3(R)位变成1010 000
        3、用生成多项式对应的二进制数对左移3位后的原始报文进行模2除(高位对齐),相当于按位异或:
        1010000
        1011
        ————————————
        0001000
        1000
        1011
        ————————————
        0011
        得到的余位011,所以最终编码为:1010 011
生成方法:
    借助于模2除法则,其余数为校验字段。
    例如:信息字段代码为: 1011001;对应m(x)=x6+x4+x3+1
    假设生成多项式为:g(x)=x4+x3+1;则对应g(x)的代码为: 11001
    x^4*m(x)=x10+x8+x7+x4 对应的代码记为:10110010000(相当于1011001<<4);
    采用模2除法则: 得余数为: 1010(即校验字段为:1010)
    发送方:发出的传输字段为: 10110011010 信息字段+校验字段
    接收方:使用相同的生成码进行校验:接收到的字段/生成码(二进制除法)如果能够除尽,则正确,
    给出余数(1010)的计算步骤:
    除法没有数学上的含义,而是采用计算机的模二除法,即除数和被除数做异或运算。进行异或运算时除数和被除数最高位对齐,按位异或。
    10110010000
    11001
    ————————————
    01111010000
    1111010000
    11001
    ————————————
    0011110000
    11110000
    11001
    ————————————
    00111000
    111000
    11001
    ————————————
    001010
    1010
    则四位CRC校验码就为:1010。
    利用CRC进行检错的过程可简单描述为:在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的r位监督码(CRC码),附在原始信息后边,构成一个新的二进制码序列数共k+r位,
    后发送出去。在接收端,根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。这个规则,在差错控制理论中称为“生成多项式”。
位宽:
    有一点要特别注意:生成多项式经常会说到多项式的位宽(Width,简记为W),这个位宽不是多项式对应的二进制数的位数,而是二进制位数减1。比如CRC8中用到的位宽为8的生成多项式,
    其实对应得二进制数有九位:100110001。另外一点,多项式表示和二进制表示都很繁琐,交流起来不方便,因此,多用16进制简写法来表示,因为生成多项式的最高位肯定为1,
    最高位的位置由位宽可知,故在简记式中,将最高的1统一去掉了,如CRC32的生成多项式简记为04C11DB7实际上表示的是104C11DB7。


CRC算法的编程实现:
    STM32硬件实现:
        1. 开启CRC单元的时钟。RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE)
        2. 复位CRC模块(设置CRC_CR=0x01),这个操作把CRC余数初始化为0xFFFFFFFF  CRC_ResetDR(void) 
        3. 把要计算的数据按逐个地写入CRC_DR寄存器  
            uint32_t CRC_CalcCRC(uint32_t Data); 将一个数据写入CRC_DR寄存器,返回值为计算结果。
            uint32_t CRC_CalcBlockCRC(uint32_t pBuffer[], uint32_t BufferLength);计算一个数组的CRC 值。
        4. 写完所有的数据字后,从CRC_DR寄存器读出计算的结果
        例程:
        #include "stm32f10x.h"
        #define BUFFER_SIZE    114
        static const uint32_t DataBuffer[BUFFER_SIZE] =
          {
            0x00001021, 0x20423063, 0x408450a5, 0x60c670e7, 0x9129a14a, 0xb16bc18c,
            0xd1ade1ce, 0xf1ef1231, 0x32732252, 0x52b54294, 0x72f762d6, 0x93398318,
            0xa35ad3bd, 0xc39cf3ff, 0xe3de2462, 0x34430420, 0x64e674c7, 0x44a45485,
            0xa56ab54b, 0x85289509, 0xf5cfc5ac, 0xd58d3653, 0x26721611, 0x063076d7,
            0x569546b4, 0xb75ba77a, 0x97198738, 0xf7dfe7fe, 0xc7bc48c4, 0x58e56886,
            0x78a70840, 0x18612802, 0xc9ccd9ed, 0xe98ef9af, 0x89489969, 0xa90ab92b,
            0x4ad47ab7, 0x6a961a71, 0x0a503a33, 0x2a12dbfd, 0xfbbfeb9e, 0x9b798b58,
            0xbb3bab1a, 0x6ca67c87, 0x5cc52c22, 0x3c030c60, 0x1c41edae, 0xfd8fcdec,
            0xad2abd0b, 0x8d689d49, 0x7e976eb6, 0x5ed54ef4, 0x2e321e51, 0x0e70ff9f,
            0xefbedfdd, 0xcffcbf1b, 0x9f598f78, 0x918881a9, 0xb1caa1eb, 0xd10cc12d,
            0xe16f1080, 0x00a130c2, 0x20e35004, 0x40257046, 0x83b99398, 0xa3fbb3da,
            0xc33dd31c, 0xe37ff35e, 0x129022f3, 0x32d24235, 0x52146277, 0x7256b5ea,
            0x95a88589, 0xf56ee54f, 0xd52cc50d, 0x34e224c3, 0x04817466, 0x64475424,
            0x4405a7db, 0xb7fa8799, 0xe75ff77e, 0xc71dd73c, 0x26d336f2, 0x069116b0,
            0x76764615, 0x5634d94c, 0xc96df90e, 0xe92f99c8, 0xb98aa9ab, 0x58444865,
            0x78066827, 0x18c008e1, 0x28a3cb7d, 0xdb5ceb3f, 0xfb1e8bf9, 0x9bd8abbb,
            0x4a755a54, 0x6a377a16, 0x0af11ad0, 0x2ab33a92, 0xed0fdd6c, 0xcd4dbdaa,
            0xad8b9de8, 0x8dc97c26, 0x5c644c45, 0x3ca22c83, 0x1ce00cc1, 0xef1fff3e,
            0xdf7caf9b, 0xbfba8fd9, 0x9ff86e17, 0x7e364e55, 0x2e933eb2, 0x0ed11ef0
          };
        __IO uint32_t CRCValue = 0;
        /**
          * @brief  Main program.
          * @param  None
          * @retval None
          */
        int main(void)
        {
          /*!< At this stage the microcontroller clock setting is already configured, 
               this is done through SystemInit() function which is called from startup
               file (startup_stm32f10x_xx.s) before to branch to application main.
               To reconfigure the default setting of SystemInit() function, refer to
               system_stm32f10x.c file
             */       
          /* Enable CRC clock */
          RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);
          /* Compute the CRC of "DataBuffer" */
          CRCValue = CRC_CalcBlockCRC((uint32_t *)DataBuffer, BUFFER_SIZE);
          while (1)
          {
          }
        }


    软件编程(CRC32):
    #define poly 0xEDB88320
    int crc32(char *addr, int num, int crc)
    {
        int i;

        for (; num>0; num--)              /* Step through bytes in memory */
        {
          crc = crc ^ *addr++;            /* Fetch byte from memory, XOR into CRC */
          for (i=0; i<8; i++)             /* Prepare to rotate 8 bits */
          {
            if (crc & 1)                  /* b0 is set... */
              crc = (crc >> 1) ^ poly;    /* rotate and XOR with ZIP polynomic */
            else                          /* b0 is clear... */
              crc >>= 1;                  /* just rotate */
            }                             /* Loop for 8 bits */
        }                                 /* Loop until num=0 */
          return(crc);                    /* Return updated CRC */
    }

这篇关于数据校验--CRC校验的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/951857

相关文章

Linux下利用select实现串口数据读取过程

《Linux下利用select实现串口数据读取过程》文章介绍Linux中使用select、poll或epoll实现串口数据读取,通过I/O多路复用机制在数据到达时触发读取,避免持续轮询,示例代码展示设... 目录示例代码(使用select实现)代码解释总结在 linux 系统里,我们可以借助 select、

Java中的Schema校验技术与实践示例详解

《Java中的Schema校验技术与实践示例详解》本主题详细介绍了在Java环境下进行XMLSchema和JSONSchema校验的方法,包括使用JAXP、JAXB以及专门的JSON校验库等技术,本文... 目录1. XML和jsON的Schema校验概念1.1 XML和JSON校验的必要性1.2 Sche

C#使用iText获取PDF的trailer数据的代码示例

《C#使用iText获取PDF的trailer数据的代码示例》开发程序debug的时候,看到了PDF有个trailer数据,挺有意思,于是考虑用代码把它读出来,那么就用到我们常用的iText框架了,所... 目录引言iText 核心概念C# 代码示例步骤 1: 确保已安装 iText步骤 2: C# 代码程

Pandas处理缺失数据的方式汇总

《Pandas处理缺失数据的方式汇总》许多教程中的数据与现实世界中的数据有很大不同,现实世界中的数据很少是干净且同质的,本文我们将讨论处理缺失数据的一些常规注意事项,了解Pandas如何表示缺失数据,... 目录缺失数据约定的权衡Pandas 中的缺失数据None 作为哨兵值NaN:缺失的数值数据Panda

C++中处理文本数据char与string的终极对比指南

《C++中处理文本数据char与string的终极对比指南》在C++编程中char和string是两种用于处理字符数据的类型,但它们在使用方式和功能上有显著的不同,:本文主要介绍C++中处理文本数... 目录1. 基本定义与本质2. 内存管理3. 操作与功能4. 性能特点5. 使用场景6. 相互转换核心区别

python库pydantic数据验证和设置管理库的用途

《python库pydantic数据验证和设置管理库的用途》pydantic是一个用于数据验证和设置管理的Python库,它主要利用Python类型注解来定义数据模型的结构和验证规则,本文给大家介绍p... 目录主要特点和用途:Field数值验证参数总结pydantic 是一个让你能够 confidentl

JAVA实现亿级千万级数据顺序导出的示例代码

《JAVA实现亿级千万级数据顺序导出的示例代码》本文主要介绍了JAVA实现亿级千万级数据顺序导出的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 前提:主要考虑控制内存占用空间,避免出现同时导出,导致主程序OOM问题。实现思路:A.启用线程池

SpringBoot AspectJ切面配合自定义注解实现权限校验的示例详解

《SpringBootAspectJ切面配合自定义注解实现权限校验的示例详解》本文章介绍了如何通过创建自定义的权限校验注解,配合AspectJ切面拦截注解实现权限校验,本文结合实例代码给大家介绍的非... 目录1. 创建权限校验注解2. 创建ASPectJ切面拦截注解校验权限3. 用法示例A. 参考文章本文

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

PHP轻松处理千万行数据的方法详解

《PHP轻松处理千万行数据的方法详解》说到处理大数据集,PHP通常不是第一个想到的语言,但如果你曾经需要处理数百万行数据而不让服务器崩溃或内存耗尽,你就会知道PHP用对了工具有多强大,下面小编就... 目录问题的本质php 中的数据流处理:为什么必不可少生成器:内存高效的迭代方式流量控制:避免系统过载一次性