精华内容
下载资源
问答
  • CRC校验

    2020-12-21 15:07:19
    CRC循环冗余校验码是数据通信中的一种查错校验码。 原理 CRC 算法的基本思想是将传输的数据[M(X)] 当做一个位数很长的数。将这个数除以另一个数[G(X)] ,得到的余数[R(X)] 作为校验数据附加到原数据后面,组成循环校验...

    何为CRC

    简介

    CRC即循环冗余校验码(Cyclic Redundancy Check)是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定。循环冗余检查(CRC)是一种数据传输检错功能,对数据进行多项式计算,并将得到的结果附在帧的后面,接收设备也执行类似的算法,以保证数据传输的正确性和完整性。

    原理

    CRC 算法的基本思想是将传输的数据[M(X)] 当做一个位数很长的数。将这个数除以另一个数[G(X)] ,得到的余数[R(X)] 作为校验数据附加到原数据后面,组成循环校验码。

    M(X) 代表待编码的有效信息
    G(X) 代表约定好的多项式
    R(X) 代表代表检验位
    

    由于,CRC的结构 = 信息位(N位) + 校验位(K位)

    所以,CRC编码 = M(X) + R(X)

    CRC编码方法

    • 把待编码的N位有效信息位表示为多项式M(X)

    • M(X)左移K位,得到M(X)*X^K,这样就空出了K位,以便拼接K位余数,这里的K位是由多项式G(X)的最高位决定的

    • 选取一个生成多项式G(x),对M(X)*X^K做模二除 (多项式G(X)一般会直接给你,模二除看下面例子,实质是异或运算),以下是运算公式
      ( M(X) * X^K ) / G(X) = Q(X) + R(X) / G(X)
      这里的Q(X)是商,它本身不重要,这里最重要的是求出余数R(X)

    • 将信息位M(X)与余数R(X)拼接起来,构成CRC循环冗余校验码
      CRC编码 = M(X) + R(X)

    常见的校验

    奇偶校验

    为了解决数据传输过程中可能存在数据错误的问题,有人提出了一种比较简单的方式——奇偶校验法。

    奇偶校验主要原理如下:
    在原始数据流的头部或者末尾添加一位bit,此bit用于校验此数据包的正确与否。

    例如

    原始码奇校验(奇数个1)偶校验(偶数个1)
    10110001011000010110001
    10100001010000110100000

    优缺点

    奇偶校验法优点:

    • 原理简单,实现方便。

    奇偶校验法缺点:

    • 奇偶校验的检错率只有50%,因为只有奇数个数据位发生变化能检测到,如果偶数个数据位发生变化,奇偶校验方式不能检测出错误。
    • 奇偶校验每传输一个字节都需要加一位校验位,对传输效率影响很大。
    • 奇偶校验只能发现错误,但不能纠正错误,也就是说它只能告诉你出错了,但不能告诉你怎么出错了,一旦发现错误,只好重发。

    累加和校验

    所谓的累加和校验有很多种,最常见的一种是在每次通信数据包最后都加一个字节的校验数据,这个校验字节里的数据是通信数据包里所有数据的不进位累加和
    在这里插入图片描述

    比如下面的例子:

    我们要传输的信息为: 6、23、4

    加上校验和后的数据包:6、23、4、33

    这里 33 为前三个字节的校验和。 接收方收到全部数据后对前三个数据进行同样的累加计算,如果累加和与最后一个字节相同的话就认为传输的数据没有错误。

    累加和校验由于实现起来非常简单,也被广泛的采用。但是这种校验方式的检错能力也比较一般,对于单字节的校验和大概有1/256 的概率将原本是错误的通讯数据误判为正确数据。 之所以这里介绍这种校验,是因为CRC校验在传输数据的形式上与累加和校验是相同的,都可以表示为:通讯数据 校验字节(也可能是多个字节)

    优缺点

    • 实现起来方便简单,被广泛运用。
    • 检错率一般,例如一个字节多1,一个字节少1,则会出现误判。
    • 和奇偶校验一样,只能发现错误,但不能纠正错误。

    海明码校验

    你看得懂的海明码校验和纠错原理

    CRC校验

    模2除法

    基于有限域GF(2)(即除以2的同余)的多项式环。

    先说下什么是“模2除法”,我们知道模2加减是不进位、不借位的加减法,比如1+1=0,1+0=1,101+011=110,等于每一位的异或运算,相同bit加减为0,不同bit加减则为1。模2除法同理,即当部分余数首位是1时商取1,反之商取0。然后每一位的减法运算是按位减,不产生借位。余数的位数一定要是比除数位数只能少一位,哪怕前面位是0,甚至是全为0(附带好整除时)也都不能省略。举例如下图所示:
    在这里插入图片描述

    CRC校验码的计算示例

    现假设选择的CRC生成多项式为G(X) = X4 + X3 + 1,要求出二进制序列10110011的CRC校验码。下面是具体的计算过程:

    1. 首先把生成多项式转换成二进制数,由G(X) = X4 + X3 + 1可以知道(,它一共是5位(总位数等于最高位的幂次加1,即4+1=5),然后根据多项式各项的含义(多项式只列出二进制值为1的位,也就是这个二进制的第4位、第3位、第0位的二进制均为1,其它位均为0)很快就可得到它的二进制比特串为11001。
    2. 因为生成多项式的位数为5,根据前面的介绍,得知CRC校验码的位数为4(校验码的位数比生成多项式的位数少1)。因为原数据帧10110011,在它后面再加4个0,得到101100110000,然后把这个数以“模2除法”方式除以生成多项式,得到的余数(即CRC码)为0100,如图5-10所示。注意参考前面介绍的“模2除法”运算法则。
      在这里插入图片描述
    3. 把上步计算得到的CRC校验0100替换原始帧101100110000后面的四个“0”,得到新帧101100110100。再把这个新帧发送到接收端。
    4. 当以上新帧到达接收端后,接收端会把这个新帧再用上面选定的除数11001以“模2除法”方式去除,验证余数是否为0,如果为0,则证明该帧数据在传输过程中没有出现差错,否则出现了差错。

    CRC校验电路原理图

    在这里插入图片描述

    常见CRC参数模型

    CRC算法名称多项式公式宽度多项式初始值结果异或值输入反转输出反转
    CRC-4/ITUx4 + x + 14030000truetrue
    CRC-5/EPCx5 + x3 + 15090900falsefalse
    CRC-5/ITUx5 + x4 + x2 + 15150000truetrue
    CRC-5/USBx5 + x2 + 15051F1Ftruetrue
    CRC-6/ITUx6 + x + 16030000truetrue
    CRC-7/MMCx7 + x3 + 17090000falsefalse
    CRC-8x8 + x2 + x + 18070000falsefalse
    CRC-8/ITUx8 + x2 + x + 18070055falsefalse
    CRC-8/ROHCx8 + x2 + x + 1807FF00truetrue
    CRC-8/MAXIMx8 + x5 + x4 + 18310000truetrue
    CRC-16/IBMx16 + x15 + x2 + 116800500000000truetrue
    CRC-16/MAXIMx16 + x15 + x2 + 11680050000FFFFtruetrue
    CRC-16/USBx16 + x15 + x2 + 1168005FFFFFFFFtruetrue
    CRC-16/MODBUSx16 + x15 + x2 + 1168005FFFF0000truetrue
    CRC-16/CCITTx16 + x12 + x5 + 116102100000000truetrue
    CRC-16/CCITT-FALSEx16 + x12 + x5 + 1161021FFFF0000falsefalse
    CRC-16/X25x16 + x12 + x5 + 1161021FFFFFFFFtruetrue
    CRC-16/XMODEMx16 + x12 + x5 + 116102100000000falsefalse
    CRC-16/DNPx16 + x13 + x12 + x11 + x10 + x8 + x6 + x5 + x2 + 1163D650000FFFFtruetrue
    CRC-32x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 13204C11DB7FFFFFFFFFFFFFFFFtruetrue
    CRC-32/MPEG-2x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 13204C11DB7FFFFFFFF00000000falsefalse

    CRC算法参数模型解释

    NAME:参数模型名称。
    WIDTH:宽度,即CRC比特数。
    POLY:生成项的简写,以16进制表示。例如:CRC-32即是0x04C11DB7,忽略了最高位的"1",即完整的生成项是0x104C11DB7。
    INIT:这是算法开始时寄存器(crc)的初始化预置值,十六进制表示。
    REFIN:待测数据的每个字节是否按位反转,True或False。
    REFOUT:在计算后之后,异或输出之前,整个数据是否按位反转,True或False。
    XOROUT:计算结果与此参数异或后得到最终的CRC值。

    Java 实现参考

        static int crc16tab[] = {
                0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
                0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
                0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
                0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
                0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
                0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
                0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
                0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
                0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
                0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
                0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
                0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
                0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
                0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
                0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
                0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
                0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
                0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
                0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
                0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
                0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
                0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
                0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
                0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
                0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
                0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
                0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
                0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
                0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
                0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
                0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
                0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
        };
    
        public static int crc16(String buf) {
            int counter;
            int crc = 0;
            for (counter = 0; counter < buf.length(); counter++) {
                int crcUnsign = (crc << 8) & 0xFFFF;
                crc = crcUnsign ^ crc16tab[((crc >> 8) ^ (int) buf.charAt(counter)) & 0x00FF];
            }
            return crc;
        }
    
    public static int get(byte[] bytes) {
    
            int[] table = {
                    0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
                    0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
                    0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
                    0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
                    0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
                    0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
                    0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
                    0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
                    0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
                    0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
                    0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
                    0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
                    0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
                    0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
                    0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
                    0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
                    0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
                    0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
                    0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
                    0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
                    0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
                    0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
                    0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
                    0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
                    0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
                    0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
                    0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
                    0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
                    0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
                    0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
                    0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
                    0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040,
            };
    
            int crc = 0x0000;
            for (byte b : bytes) {
                crc = (crc >>> 8) ^ table[(crc ^ b) & 0xff];
            }
    
            return crc;
        }
    

    参考

    展开全文
  • 详述CRC校验码(附代码)

    千次阅读 2021-08-26 00:15:28
    关注+星标公众号,不错过精彩内容来源| 一口LinuxCRC校验应用比较广泛,通常在通信领域用的比较多,即便是自定义通信协议,也可以添加CRC校验码,使其通信更加可靠。今天就来进一步描述...

    关注+星标公众,不错过精彩内容

    来源 | 一口Linux

    CRC校验应用比较广泛,通常在通信领域用的比较多,即便是自定义通信协议,也可以添加CRC校验码,使其通信更加可靠。

    今天就来进一步描述CRC校验码。

    一、CRC概念

    1. 什么是CRC?

    CRC(Cyclic Redundancy Checksum)是一种纠错技术,代表循环冗余校验和。

    数据通信领域中最常用的一种差错校验码,其信息字段和校验字段长度可以任意指定,但要求通信双方定义的CRC标准一致。主要用来检测或校验数据传输或者保存后可能出现的错误。它的使用方式可以说明如下图所示:

    在数据传输过程中,无论传输系统的设计再怎么完美,差错总会存在,这种差错可能会导致在链路上传输的一个或者多个帧被破坏(出现比特差错,0变为1,或者1变为0),从而接受方接收到错误的数据。

    为尽量提高接受方收到数据的正确率,在接收方接收数据之前需要对数据进行差错检测,当且仅当检测的结果为正确时接收方才真正收下数据。检测的方式有多种,常见的有奇偶校验因特网校验循环冗余校验等。

    2. 使用方法概述

    循环冗余校验是一种用于校验通信链路上数字传输准确性的计算方法(通过某种数学运算来建立数据位和校验位的约定关系的 )。

    发送方计算机使用某公式计算出被传送数据所含信息的一个值,并将此值 附在被传送数据后,接收方计算机则对同一数据进行 相同的计算,应该得到相同的结果。

    如果这两个 CRC结果不一致,则说明发送中出现了差错,接收方计算机可要求发送方计算机重新发送该数据。

    3. 应用广泛

    在诸多检错手段中,CRC是最著名的一种。CRC的全称是循环冗余校验,其特点是:检错能力强,开销小,易于用编码器及检测电路实现。从其检错能力来看,它所不能发现的错误的几率仅为0.0047%以下。

    从性能上和开销上考虑,均远远优于奇偶校验及算术和校验等方式。

    因而,在数据存储和数据通讯领域,CRC无处不在:著名的通讯协议X.25的FCS(帧检错序列)采用的是CRC-CCITT,WinRAR、NERO、ARJ、LHA等压缩工具软件采用的是CRC32,磁盘驱动器的读写采用了CRC16,通用的图像存储格式GIF、TIFF等也都用CRC作为检错手段。

    二、CRC名称的定义

    这里需要知道几个组成部分或者说计算概念:多项式公式、多项式简记式、数据宽度、初始值、结果异或值、输入值反转、输出值反转、参数模型。

    1、多项式公式

    对于CRC标准除数,一般使用多项式(或二项式)公式表示,如下图中除数11011(poly值为0x1b)的二项式为G(X)=X4+X3+X+1,X的指数就代表了该bit位上的数据为1,(最低位为0)。

    这里特别注意一下位数问题,除数的位数为二项式最高次幂+1(4+1=5),这个很重要。

    2、多项式简记式

    通过对CRC的基本了解我们知道,多项式的首尾必定为1,而这个1的位置在下一步计算一定为0,所以就把前面这个1给省略掉了,出现了一个叫简记式的东西,如上例中除数11011的简记式为1011,很多看过CRC高级语言源码的人会知道,对于CRC_16标准下G(X)=X16+X15+X2+1(16#18005)的poly值实际上是8005,这里使用的就是简记式。后面会对这个用法做一个说明。

    3、数据宽度

    数据宽度指的就是CRC校验码的长度(二进制位数),知道了CRC的运算概念和多项式,就可以理解这个概念了,CRC长度始终要比除数位数少1,与简记式长度是一致的。

    以上三个数据就是我们经常能够用到的基本数据

    4、初始值与结果异或值

    在一些标准中,规定了初始值,则数据在进行上述二项式运算之前,需要先将要计算的数据与初始值的最低字节进行异或,然后再与多项式进行计算。

    而在结果异或值不为零的情况下,则需要将计算得到的CRC结果值再与结果异或值进行一次异或计算,得到的最终值才是我们需要的CRC校验码。

    这里可以看出,初始值与结果值的位数要求与数据宽度一致。

    5、输入值反转与输出值反转

    输入值反转的意思是在计算之前先将二项式反转,然后再用得到的新值和数据进行计算。如对于G(X)=X16+X15+X2+1(16#18005),其正向值为1 1000 0000 0000 0101,反转值则为1010 0000 0000 0001 1

    输出值反转则是将最终得到的CRC结果反转。

    通常,输入值反转后的结果值也会是反转的,所以这两个选项一般是同向的,我们只有在在线CRC计算器中会看到自由选择正反转的情况存在。

    三、常见的CRC算法

    虽然CRC可以任意定义二项式、数据长度等,但没有一个统一的标准的话,就会让整个计算变得非常的麻烦。但实际上,不同的厂家经常采用不同的标准算法,这里列出了一些国际常用的模型表:

    名称多项式表示法应用举例
    CRC-8X8+X2+X+10X107
    CRC-12X12+X11+X3+X2+X+10X180Ftelecom systems
    CRC-16X16+X15+X2+10X18005Bisync, Modbus, USB, ANSI X3.28, SIA DC-07, many others; also known as CRC-16 and CRC-16-ANSI
    CRC-CCITTX16+X12+X5+10X11021ISO HDLC, ITU X.25, V.34/V.41/V.42, PPP-FCS
    CRC-32X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X+10x104C11DB7ZIP, RAR, IEEE 802 LAN/FDDI, IEEE 1394, PPP-FCS
    CRC-32CX32+X28+X27+X26+X25+X23+X22+X20+X19+X18+X14+X13+X11+X10+X9+X8+X6+10x11EDC6F41iSCSI, SCTP, G.hn payload, SSE4.2, Btrfs, ext4, Ceph

    四、CRC校验算法前置知识

    在学习CRC校验算法之前,先复习一下CRC会涉及的主要几个主要的算法。

    1. 异或

    异或,就是不同为1,相同为0,运算符号是^。

    0^0 = 0
    0^1 = 1
    1^1 = 0
    1^0 = 1
    

    异或运算存在如下几个规律,需要了解。

    0^x = x 即0 异或任何数等于任何数
    1^x = ~x 即1异或任何数等于任何数取反
    x^x = 0 即任何数与自己异或,结果为0
    a ^ b = b ^ a 交换律
    a ^ (b ^ c) = (a ^ b) ^c 结合律
    

    2. 模2加法

    模2加法相对于普通的算术加法,主要的区别在模2加法,不做进位处理。具体结果如下。0+0 = 0 0+1 = 1 1+1 = 0 1+0 = 1 我们发现模2加法的计算结果,同异或运算结果一模一样。进一步推演,我们会发现,异或运算的5个规律,同样适合于模2加法。这里,就不在一一列举了。

    3. 模2减法

    模2减法相对于普通的算术减法,主要的区别在模2减法,不做借位处理。具体结果如下。0-0 = 0 0-1 = 1 1-1 = 0 1-0 = 1 我们发现模2减法的计算结果,同模2加法,以及异或的运算结果一模一样。进一步推演,我们会发现,异或运算的5个规律,同样适合于模2减法。这里,就不在一一列举了。

    4. 模2除法

    模2除法相对于普通的算术除法,主要的区别在模2除法,它既不向上位借位,也不比较除数和被除数的相同位数值的大小,只要以相同位数进行相除即可。

    五、CRC原理

    CRC原理:在K位信息码(目标发送数据)后再拼接R位校验码,使整个编码长度为N位,因此这种编码也叫(N,K)码。

    通俗的说,就是在需要发送的信息后面附加一个数(即校验码),生成一个新的发送数据发送给接收端。这个数据要求能够使生成的新数据被一个特定的数整除。这里的整除需要引入模 2除法的概念。

    那么,CRC校验的具体做法就是

    (1)选定一个标准除数(K位二进制数据串)

    (2)在要发送的数据(m位)后面加上K-1位0,然后将这个新数(M+K-1位)以模2除法的方式除以上面这个标准除数,所得到的余数也就是该数据的CRC校验码(注:余数必须比除数少且只少一位,不够就补0)

    (3)将这个校验码附在原m位数据后面,构成新的M+K-1位数据,发送给接收端。

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

    注意:CRC校验中有两个关键点:

    一是要预先确定一个发送端和接收端都用来作为除数的二进制比特串(或多项式);

    二是把原始帧与上面选定的除进行二进制除法运算,计算出FCS。

    前者可以随机选择,也可按国际上通行的标准选择,但最高位和最低位必须均为“1”

    六、循环冗余的计算

    实例:

    由于CRC-32、CRC-16、CCITT和CRC-4的编码过程基本一致,只有位数和生成多项式不一样,下面就举例,来说明CRC校验码生成过程。

    对于数据1110 0101(16#E5),以指定除数11011求它的CRC校验码,其过程如下:

    使用上面计算的校验和和消息数据,可以创建要传输的码字。

    有时候,我们需要填充checksum到制定的位置,这就涉及到字节序问题,建议用memcpy()进行拷贝。

    七、代码实现

    实现算法参考网络相关代码,进行整理并验证,可直接使用。crc.c

    /*  
     *一口Linux
     *2021.6.21
     *version: 1.0.0
    */
    #include "crc.h"
    #include <stdio.h>
    
    typedef enum {
     REF_4BIT = 4,
     REF_5BIT = 5,
     REF_6BIT = 6,
     REF_7BIT = 7,
     REF_8BIT = 8,
     REF_16BIT = 16,
     REF_32BIT = 32
    }REFLECTED_MODE;
    
    uint32_t ReflectedData(uint32_t data, REFLECTED_MODE mode)
    {
     data = ((data & 0xffff0000) >> 16) | ((data & 0x0000ffff) << 16);
     data = ((data & 0xff00ff00) >> 8) | ((data & 0x00ff00ff) << 8);
     data = ((data & 0xf0f0f0f0) >> 4) | ((data & 0x0f0f0f0f) << 4);
     data = ((data & 0xcccccccc) >> 2) | ((data & 0x33333333) << 2);
     data = ((data & 0xaaaaaaaa) >> 1) | ((data & 0x55555555) << 1);
    
     switch (mode)
     {
     case REF_32BIT:
      return data;
     case REF_16BIT:
      return (data >> 16) & 0xffff;
     case REF_8BIT:
      return (data >> 24) & 0xff;
     case REF_7BIT:
      return (data >> 25) & 0x7f;
     case REF_6BIT:
      return (data >> 26) & 0x7f;
     case REF_5BIT:
      return (data >> 27) & 0x1f;
     case REF_4BIT:
      return (data >> 28) & 0x0f;
     }
     return 0;
    }
    
    uint8_t CheckCrc4(uint8_t poly, uint8_t init, bool refIn, bool refOut, uint8_t xorOut,
     const uint8_t *buffer, uint32_t length)
    {
     uint8_t i;
     uint8_t crc;
    
     if (refIn == true)
     {
      crc = init;
      poly = ReflectedData(poly, REF_4BIT);
    
      while (length--)
      {
       crc ^= *buffer++;
       for (i = 0; i < 8; i++)
       {
        if (crc & 0x01)
        {
         crc >>= 1;
         crc ^= poly;
        }
        else
        {
         crc >>= 1;
        }
       }
      }
    
      return crc ^ xorOut;
     }
     else
     {
      crc = init << 4;
      poly <<= 4;
    
      while (length--)
      {
       crc ^= *buffer++;
       for (i = 0; i < 8; i++)
       {
        if (crc & 0x80)
        {
         crc <<= 1;
         crc ^= poly;
        }
        else
        {
         crc <<= 1;
        }
       }
      }
    
      return (crc >> 4) ^ xorOut;
     }
    }
    
    uint8_t CheckCrc5(uint8_t poly, uint8_t init, bool refIn, bool refOut, uint8_t xorOut,
     const uint8_t *buffer, uint32_t length)
    {
     uint8_t i;
     uint8_t crc;
    
     if (refIn == true)
     {
      crc = init;
      poly = ReflectedData(poly, REF_5BIT);
    
      while (length--)
      {
       crc ^= *buffer++;
       for (i = 0; i < 8; i++)
       {
        if (crc & 0x01)
        {
         crc >>= 1;
         crc ^= poly;
        }
        else
        {
         crc >>= 1;
        }
       }
      }
    
      return crc ^ xorOut;
     }
     else
     {
      crc = init << 3;
      poly <<= 3;
    
      while (length--)
      {
       crc ^= *buffer++;
       for (i = 0; i < 8; i++)
       {
        if (crc & 0x80)
        {
         crc <<= 1;
         crc ^= poly;
        }
        else
        {
         crc <<= 1;
        }
       }
      }
    
      return (crc >> 3) ^ xorOut;
     }
    }
    
    uint8_t CheckCrc6(uint8_t poly, uint8_t init, bool refIn, bool refOut, uint8_t xorOut,
     const uint8_t *buffer, uint32_t length)
    {
     uint8_t i;
     uint8_t crc;
    
     if (refIn == true)
     {
      crc = init;
      poly = ReflectedData(poly, REF_6BIT);
    
      while (length--)
      {
       crc ^= *buffer++;
       for (i = 0; i < 8; i++)
       {
        if (crc & 0x01)
        {
         crc >>= 1;
         crc ^= poly;
        }
        else
        {
         crc >>= 1;
        }
       }
      }
    
      return crc ^ xorOut;
     }
     else
     {
      crc = init << 2;
      poly <<= 2;
    
      while (length--)
      {
       crc ^= *buffer++;
       for (i = 0; i < 8; i++)
       {
        if (crc & 0x80)
        {
         crc <<= 1;
         crc ^= poly;
        }
        else
        {
         crc <<= 1;
        }
       }
      }
    
      return (crc >> 2) ^ xorOut;
     }
    }
    
    uint8_t CheckCrc7(uint8_t poly, uint8_t init, bool refIn, bool refOut, uint8_t xorOut,
     const uint8_t *buffer, uint32_t length)
    {
     uint8_t i;
     uint8_t crc;
    
     if (refIn == true)
     {
      crc = init;
      poly = ReflectedData(poly, REF_7BIT);
    
      while (length--)
      {
       crc ^= *buffer++;
       for (i = 0; i < 8; i++)
       {
        if (crc & 0x01)
        {
         crc >>= 1;
         crc ^= poly;
        }
        else
        {
         crc >>= 1;
        }
       }
      }
    
      return crc ^ xorOut;
     }
     else
     {
      crc = init << 1;
      poly <<= 1;
    
      while (length--)
      {
       crc ^= *buffer++;
       for (i = 0; i < 8; i++)
       {
        if (crc & 0x80)
        {
         crc <<= 1;
         crc ^= poly;
        }
        else
        {
         crc <<= 1;
        }
       }
      }
    
      return (crc >> 1) ^ xorOut;
     }
    }
    
    uint8_t CheckCrc8(uint8_t poly, uint8_t init, bool refIn, bool refOut, uint8_t xorOut,
     const uint8_t *buffer, uint32_t length)
    {
     uint32_t i = 0;
     uint8_t crc = init;
    
     while (length--)
     {
      if (refIn == true)
      {
       crc ^= ReflectedData(*buffer++, REF_8BIT);
      }
      else
      {
       crc ^= *buffer++;
      }
    
      for (i = 0; i < 8; i++)
      {
       if (crc & 0x80)
       {
        crc <<= 1;
        crc ^= poly;
       }
       else
       {
        crc <<= 1;
       }
      }
     }
    
     if (refOut == true)
     {
      crc = ReflectedData(crc, REF_8BIT);
     }
    
     return crc ^ xorOut;
    }
    
    uint16_t CheckCrc16(uint16_t poly, uint16_t init, bool refIn, bool refOut, uint16_t xorOut,
     const uint8_t *buffer, uint32_t length)
    {
     uint32_t i = 0;
     uint16_t crc = init;
    
     while (length--)
     {
      if (refIn == true)
      {
       crc ^= ReflectedData(*buffer++, REF_8BIT) << 8;
      }
      else
      {
       crc ^= (*buffer++) << 8;
      }
    
      for (i = 0; i < 8; i++)
      {
       if (crc & 0x8000)
       {
        crc <<= 1;
        crc ^= poly;
       }
       else
       {
        crc <<= 1;
       }
      }
     }
    
     if (refOut == true)
     {
      crc = ReflectedData(crc, REF_16BIT);
     }
    
     return crc ^ xorOut;
    }
    
    uint32_t CheckCrc32(uint32_t poly, uint32_t init, bool refIn, bool refOut, uint32_t xorOut,
     const uint8_t *buffer, uint32_t length)
    {
     uint32_t i = 0;
     uint32_t crc = init;
    
     while (length--)
     {
      if (refIn == true)
      {
       crc ^= ReflectedData(*buffer++, REF_8BIT) << 24;
      }
      else
      {
       crc ^= (*buffer++) << 24;
      }
    
      for (i = 0; i < 8; i++)
      {
       if (crc & 0x80000000)
       {
        crc <<= 1;
        crc ^= poly;
       }
       else
       {
        crc <<= 1;
       }
      }
     }
    
     if (refOut == true)
     {
      crc = ReflectedData(crc, REF_32BIT);
     }
    
     return crc ^ xorOut;
    }
    
    uint32_t CrcCheck(CRC_Type crcType, const uint8_t *buffer, uint32_t length)
    {
     switch (crcType.width)
     {
     case 4:
      return CheckCrc4(crcType.poly, crcType.init, crcType.refIn, crcType.refOut,
       crcType.xorOut, buffer, length);
     case 5:
      return CheckCrc5(crcType.poly, crcType.init, crcType.refIn, crcType.refOut,
       crcType.xorOut, buffer, length);
     case 6:
      return CheckCrc6(crcType.poly, crcType.init, crcType.refIn, crcType.refOut,
       crcType.xorOut, buffer, length);
     case 7:
      return CheckCrc7(crcType.poly, crcType.init, crcType.refIn, crcType.refOut,
       crcType.xorOut, buffer, length);
     case 8:
      return CheckCrc8(crcType.poly, crcType.init, crcType.refIn, crcType.refOut,
       crcType.xorOut, buffer, length);
     case 16:
      return CheckCrc16(crcType.poly, crcType.init, crcType.refIn, crcType.refOut,
       crcType.xorOut, buffer, length);
     case 32:
      return CheckCrc32(crcType.poly, crcType.init, crcType.refIn, crcType.refOut,
       crcType.xorOut, buffer, length);
     }
     return 0;
    }
    
    

    crc.h

    /*  
     *一口Linux
     *2021.6.21
     *version: 1.0.0
    */
    #ifndef __CRC_H__
    #define __CRC_H__
    
    #include <stdint.h>
    #include <stdbool.h>
    
    typedef struct {
     uint8_t width;
     uint32_t poly;
     uint32_t init;
     bool refIn;
     bool refOut;
     uint32_t xorOut;
    }CRC_Type;
    
    uint32_t CrcCheck(CRC_Type crcType, const uint8_t *buffer, uint32_t length);
    
    #endif
    

    main.c

    /*  
     *一口Linux
     *2021.6.21
     *version: 1.0.0
    */
    #include <stdio.h>
    #include <stdint.h>
    #include <stdbool.h>
    #include "crc.h"
    
    #define LENGTH 8
    const uint8_t data[3][LENGTH] = {
     { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 },
     { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 },
     { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f }};
    
    typedef struct {
     CRC_Type crcType;
     uint32_t result[3];
    }CRC_Test;
    
    CRC_Test crc4_ITU = { { 4, 0x03, 0x00, true, true, 0x00 }, { 0x0f, 0x0a, 0x0e } };
    CRC_Test crc5_EPC = { { 5, 0x09, 0x09, false, false, 0x00 }, { 0x00, 0x0c, 0x17 } };
    CRC_Test crc5_ITU = { { 5, 0x15, 0x00, true, true, 0x00 }, { 0x16, 0x0a, 0x17 } };
    CRC_Test crc5_USB = { { 5, 0x05, 0x1f, true, true, 0x1f }, { 0x10, 0x09, 0x17 } };
    CRC_Test crc6_ITU = { { 6, 0x03, 0x00, true, true, 0x00 }, { 0x1d, 0x30, 0x00 } };
    CRC_Test crc7_MMC = { { 7, 0x09, 0x00, false, false, 0x00 }, { 0x57, 0x30, 0x5b } };
    CRC_Test crc8 = { { 8, 0x07, 0x00, false, false, 0x00 }, { 0x3e, 0xe1, 0x36 } };
    CRC_Test crc8_ITU = { { 8, 0x07, 0x00, false, false, 0x55 }, { 0x6b, 0xb4, 0x63 } };
    CRC_Test crc8_ROHC = { { 8, 0x07, 0xff, true, true, 0x00 }, { 0x6b, 0x78, 0x93 } };
    CRC_Test crc8_MAXIM = { { 8, 0x31, 0x00, true, true, 0x00 }, { 0x83, 0x60, 0xa9 } };
    CRC_Test crc16_IBM = { { 16, 0x8005, 0x0000, true, true, 0x0000 }, { 0xc4f0, 0x2337, 0xa776 } };
    CRC_Test crc16_MAXIM = { { 16, 0x8005, 0x0000, true, true, 0xffff }, { 0x3b0f, 0xdcc8, 0x5889 } };
    CRC_Test crc16_USB = { { 16, 0x8005, 0xffff, true, true, 0xffff }, { 0x304f, 0xd788, 0x53c9 } };
    CRC_Test crc16_MODBUS = { { 16, 0x8005, 0xffff, true, true, 0x0000 }, { 0xcfb0, 0x2877, 0xac36 } };
    CRC_Test crc16_CCITT = { { 16, 0x1021, 0x0000, true, true, 0x0000 }, { 0xeea7, 0xfe7c, 0x7919 } };
    CRC_Test crc16_CCITT_FALSE = { { 16, 0x1021, 0xffff, false, false, 0x0000 }, { 0x4792, 0x13a7, 0xb546 } };
    CRC_Test crc16_X25 = { { 16, 0x1021, 0xffff, true, true, 0xffff }, { 0x6dd5, 0x7d0f, 0xfa6a } };
    CRC_Test crc16_XMODEM = { { 16, 0x1021, 0x0000, false, false, 0x0000 }, { 0x76ac, 0x2299, 0x8478 } };
    CRC_Test crc16_DNP = { { 16, 0x3D65, 0x0000, true, true, 0xffff }, { 0x7bda, 0x0535, 0x08c4 } };
    CRC_Test crc32 = { { 32, 0x04c11db7, 0xffffffff, true, true, 0xffffffff }, { 0x3fca88c5, 0xe0631a53, 0xa4051a26 } };
    CRC_Test crc32_MPEG2 = { { 32, 0x4c11db7, 0xffffffff, false, false, 0x00000000 }, { 0x14dbbdd8, 0x6509b4b6, 0xcb09d294 } };
    
    void CrcTest(CRC_Test crcTest)
    {
     uint32_t i;
     for (i = 0; i < 3; i++)
     {
      printf("%08x\t%08x\r\n", CrcCheck(crcTest.crcType, data[i], LENGTH), crcTest.result[i]);
     }
     printf("\r\n");
    }
    
    int main(void)
    {
     CrcTest(crc4_ITU);
     CrcTest(crc5_EPC);
     CrcTest(crc5_ITU);
     CrcTest(crc5_USB);
     CrcTest(crc6_ITU);
     CrcTest(crc7_MMC);
     CrcTest(crc8);
     CrcTest(crc8_ITU);
     CrcTest(crc8_ROHC);
     CrcTest(crc8_MAXIM);
     CrcTest(crc16_IBM);
     CrcTest(crc16_MAXIM);
     CrcTest(crc16_USB);
     CrcTest(crc16_MODBUS);
     CrcTest(crc16_CCITT);
     CrcTest(crc16_CCITT_FALSE);
     CrcTest(crc16_X25);
     CrcTest(crc16_XMODEM);
     CrcTest(crc16_DNP);
     CrcTest(crc32);
     CrcTest(crc32_MPEG2);
    
     return 0;
    }
    
    

    注意

    不同的CRC算法,对00H或FFH数据流的计算结果不一样,部分算法存在校验结果也为00H或FFH的情况(也就意味着存储空间处于初始化状态时:全0或全1,CRC校验反而是正确的),在应用中需要注意避免。

    ------------ END ------------


    ●嵌入式专栏精选教程

    ●精选汇总 | ST工具、下载编程工具

    ●精选汇总 | 嵌入式软件设计与开发

    ●精选汇总 | STM32、MCU、单片机

    迎关注我的公众号回复“加群”按规则加入技术交流群,回复“1024”查看更多内容。

    欢迎关注我的视频号:

    点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。

    展开全文
  • C语言实现CRC校验

    2021-05-19 18:32:26
    #include #include // 转化后的二进制最多的位数#define MAX_BIN_LENGHT 100// 输入的表达式最多的字符数#define MAX_EXP_LENGHT 100// 根据表达式得到二进制数void...// 根据两个二进制数,得到CRC校验结果void get...

    #include

    #include

    // 转化后的二进制最多的位数

    #define MAX_BIN_LENGHT 100

    // 输入的表达式最多的字符数

    #define MAX_EXP_LENGHT 100

    // 根据表达式得到二进制数

    void getBinary(char *express,int binary[MAX_BIN_LENGHT]);

    // 根据两个二进制数,得到CRC校验结果

    void getQuoRem(int *binaryY,int binaryG[MAX_BIN_LENGHT], int result[MAX_BIN_LENGHT]);

    // 打印二进制数

    void printBinary(int binary[MAX_BIN_LENGHT]);

    // 得到正序的二进制数

    void getOrderedBinary(int originalBinary[MAX_BIN_LENGHT],int orderedBinary[MAX_BIN_LENGHT]);

    // 得到二进制位数

    int getBinaryLength(int originalBinary[MAX_BIN_LENGHT]);

    int main(int argc,char *argv[])

    {

    int binaryY[MAX_BIN_LENGHT]={0}; // 存放Y(x)转化后的二进制数

    int binaryG[MAX_BIN_LENGHT]={0}; // 存放G(x)转化后的二进制数

    int binaryTemp[MAX_BIN_LENGHT]={0}; // 存放表达式转化后的倒序二进制数

    int binaryResult[MAX_BIN_LENGHT]={0}; // 存放最后要发送的加上校验码的数据

    char express[MAX_EXP_LENGHT]; //存放输入的表达式

    printf("请输入Y(x)表达式:\n");

    scanf("%s",express);

    getBinary(express,binaryTemp);

    getOrderedBinary(binaryTemp,binaryY);

    printf("请输入G(x)表达式:\n");

    scanf("%s",express);

    getBinary(express,binaryTemp);

    getOrderedBinary(binaryTemp,binaryG);

    // 得到有校验码的数据

    getQuoRem(binaryY,binaryG,binaryResult);

    printf("\nY(x)的二进制为:");

    printBinary(binaryY);

    printf("G(x)的二进制为:");

    printBinary(binaryG);

    printf("最终的CRC校验数据为:");

    printBinary(binaryResult);

    return 0;

    }

    /**********************

    * 根据表达式得到二进制数

    ***********************/

    void getBinary(char *express,int binary[MAX_BIN_LENGHT])

    {

    int i;

    int num=0;

    char tempc;

    // 让binary清零

    for(i=0;i

    {

    binary[i]=0;

    }

    // 求倒序的二进制

    for(i=0;i

    {

    if(*(express+i)=='^')

    {

    // 如果是^号,表示接下来的就是指数了

    for(i=i+1;i

    {

    tempc=*(express+i);

    if(tempc>='0' && tempc<='9')

    {

    num=num*10+(tempc-'0');

    if((i+1)>=strlen(express))

    {

    binary[num]=1;

    }

    }

    else

    {

    /*

    得到相应的指数,将对应的二进制位数设置为1。

    此时二进制的最低位对应的是binary[0],二进制的最高位对应的是binary[MAX_BIN_LENGHT-1]

    */

    binary[num]=1;

    num=0;

    break;

    }

    }

    }

    else

    {

    if(*(express+i)=='1'&& (i+1)>=strlen(express))

    {

    // 如果最后一个数字是1,那么二进制最低位binary[0]设置为1

    binary[0]=1;

    }

    i++;

    }

    }

    }

    /**************************

    * 根据两个二进制数,得到CRC校验结果

    * 参数: binaryY 二进制被除数

    * binaryG 二进制除数

    * quotient 商

    * remainder 余数

    * result 带校验码的最终结果

    **************************/

    void getQuoRem(int binaryY[MAX_BIN_LENGHT],int binaryG[MAX_BIN_LENGHT],int result[MAX_BIN_LENGHT])

    {

    int i,j,index=0,k;

    int lengthY,lengthG,lengthB;

    int quotient[MAX_BIN_LENGHT]={0}; // 存放商的二进制数

    int remainder[MAX_BIN_LENGHT]={0}; // 存放余数的二进制数

    lengthY=getBinaryLength(binaryY);

    lengthG=getBinaryLength(binaryG);

    if(lengthG>lengthY)

    {

    printf("除数比余数大!无法得到正确商和余数!");

    quotient[1]=-1;

    remainder[1]=-1;

    return ;

    }

    /*

    * 将被除数的后边加上除数对应的0,结果存入到result中。

    * 添加的0的个数与除数中x^n的最大指数值n相同

    */

    for(i=0;i

    {

    // 最终的结果前面与被除数相同

    if(i

    {

    result[i]=binaryY[i];

    }

    // 最终结果的后面填充相应个数的0

    else

    {

    result[i]=0;

    }

    }

    // result尾部加上结束符

    result[i]=-1;

    // 得到被除数总的位数长度

    lengthB=getBinaryLength(result);

    // 先得到最开始的余数

    for(i=0;i

    {

    remainder[i]=result[i];

    }

    // 循环得到商和余数

    for(i=lengthG-1;i

    {

    if(remainder[0]==1)

    {

    // 商1

    quotient[index]=1;

    // remainder余数与除数按位异或,结果存remainder余数中

    for(j=0;j

    {

    if(remainder[j]==binaryG[j])

    {

    remainder[j]=0;

    }

    else

    {

    remainder[j]=1;

    }

    }

    }

    else

    {

    // 商0

    quotient[index]=0;

    // 商0的话,remainder余数与全0按位异或,余数结果是不变的

    }

    index++;

    // 舍弃余数最高位,后边的依次前移1位

    for(j=1;j

    {

    remainder[j-1]=remainder[j];

    }

    // 将被除数的下一位数字加到余数的最低位处,这样就可以进行下一次的除法

    if((i+1)

    {

    remainder[lengthG-1]=result[i+1];

    }

    }

    // 循环结束,将商和余数的数组末尾加上结束符号

    remainder[lengthG-1]=-1;

    quotient[index]=-1;

    /*

    printf("商为:");

    printBinary(quotient);

    printf("余数为:");

    printBinary(remainder);

    */

    // 将被除数后面的0换成相应的余数,这样被除数就变成要发送的带校验码的数据

    for(i=lengthY;i

    {

    result[i]=remainder[i-lengthY];

    }

    }

    /**************************

    * 打印二进制数

    **************************/

    void printBinary(int binary[MAX_BIN_LENGHT])

    {

    int i;

    for(i=0;i

    {

    printf("%d",binary[i]);

    }

    printf("\n");

    }

    /**************************

    * 得到正序的二进制数

    **************************/

    void getOrderedBinary(int originalBinary[MAX_BIN_LENGHT],int orderedBinary[MAX_BIN_LENGHT])

    {

    /*

    *因为originalBinary数组中originalBinary[0]存放的是二进制的最低位,originalBinary[MAX_BIN_LENGHT-1]存放的是二进制的最高位,

    *将数组倒序后存放到orderedBinary中

    */

    int i;

    int j=0;

    for(i=MAX_BIN_LENGHT-1;i>=0;i--)

    {

    if(originalBinary[i]==1)

    {

    for(j=0;i>=0;i--)

    {

    orderedBinary[j]=originalBinary[i];

    j++;

    }

    }

    else if(i==0)

    {

    orderedBinary[j]=originalBinary[i];

    j++;

    }

    }

    // 设置结束标志

    orderedBinary[j]=-1;

    }

    /**************************

    * 得到二进制位数

    **************************/

    int getBinaryLength(int binary[MAX_BIN_LENGHT])

    {

    int i;

    for(i=0;i

    {

    if(binary[i]==-1)

    {

    break;

    }

    }

    return i;

    }

    /*-----------------------------测试结果------------------------------*/

    请输入Y(x)表达式:

    x^5+x^3+1

    请输入G(x)表达式:

    x^3+x^2+1

    Y(x)的二进制为:101001

    G(x)的二进制为:1101

    最终的CRC校验数据为:101001001

    展开全文
  • crc校验matlab

    2021-04-18 11:43:45
    CRC 循环冗余校验码 2 1.概要 1.1...结果:出错了 七、思考题 1.掌握按字节编码的过程,试着写出CRC 校验编码的Matlab 程序? %main program clear all; input=[1 1 0 0] CRC_Number=[3 8 12......本次课程设计研究了...

    关键词: MATLAB;C 语言 ;CRC 循环冗余校验码 2 1.概要 1.1...

    结果:出错了 七、思考题 1.掌握按字节编码的过程,试着写出CRC 校验编码的Matlab 程序? %main program clear all; input=[1 1 0 0] CRC_Number=[3 8 12......

    本次课程设计研究了纠错码及循环冗余校验码的原理,以及利用 MATLAB 对其进行了编码和 译码仿真,实现了 CRC 循环冗余校验码的编码及校验,在接收端收到通过校验的码......

    实验目的 1、复习 matlab 的基本编写方法。 2、学习 CRC 编码基本流程, 学会调试循环冗余校验码编码程序。 3、根据给出的资料,掌握 CRC 校验码的编码原理。 二......

    1、介绍CRC码的编解码原理和方法。 2、使用matlab软件仿真方法。 3、介绍CRC编解码在FPGA硬件平台上的开发方法和Quatus仿真。隐藏>> 实验二 CRC(循环冗余校验码)......

    本次课程设计研究了纠错码及循环冗余校验码的原理, 以及利用 MATLAB 对其进行了编码和 译码仿真,实现了 CRC 循环冗余校验码的编码及校验,在接收端收到通过校验的......

    CRC 校验的实现 转 CRC 算法原理及 C 语言实现 nios II 实验五 数码管显示数字钟定时器实现 Matlab 中单边谱 FFT 变换实现实例触摸屏维修之故障分析 大功率直流......

    基于Matlab的Kruskal-Wallis和Nemenyi检验的界面实现_生物学_自然科学_专业资料。?...CRC5.chowodsin sC,CII卸g M,PongA.Stati蚯calconside糟ti∞ofclinicaI a......

    “分而治之Turbo编码HARQ”方案 系统模块的DSP实现与优化– 循环冗余校验码的快速实现 – Max-Log-MAP算法的实现与优化 4 Bell Joint Lab OFDM——抗多径衰落的......

    matlab源码-RS编码 RS 编码 RS(255,249) 码的生成多项式为 G (x) = 是本...(1101), 以选 1011 为(7, 4)CRC 码的生成多项式, 用矩阵表示如下式 2 ......

    11 dSPACE GmbH 2/11 dSPACE Advanced CRC RTICANMM 1 Introduction The ...4.1 Used Versions Software Matlab dSPACE RTI ControlDesk NG Release 2009bSP1......

    最后基于MATLAB仿真平台对该算法进行仿真,仿真结果表明该算法具有较高的检测精度。...hoeiaaayiadtiteacrc n esblyoh lohiieeni rvdtruhtertclnlssn srcmahmai eu......

    (2)所用软件:Matlab 或者 C 了解循环冗余检验码的编码、检错的基本原理及其特点;熟练掌握循环冗余检验码编码、检错 的方法与步骤; (1)编写对应 CRC 校验码生成......

    王雷 奇偶校验编码仿真 2013 年 7 月 5 日星期五 学号: 20105615 指导教师: 秦明伟 设计要求: (1)基于 MATLAB 编写 M 文件,实现 CRC 编码的奇偶校验,数据帧......

    实验七一、实验目的 循环冗余码编码 1.复习和熟悉循环冗余码编码的原理 2.熟悉专业编程软件 matlab 在通信领域的应用 3.掌握部分 matlab 指令 二、实验环境1.硬件......

    网络资源,在这个学习的过程中,我也进一步了解到 Matlab 的实用价 值,更加深刻地理解了通信这门课程中纠错码与纠错原理,更加深刻地理解了循环冗 余校验码 CRC ......

    理论研究 适意信息 基于Matlab的高光谱遥感数据降维并行计算分析刘春①~,陈燕①,...'jobmanager’);Job=crcateJob(jm,…‘FileDepencies',{‘downsample’},........

    采用BPSK调制和解调方法;采用AWGN信道;通过CRC校验判断数据帧接收正确与...

    是 *该输入参数表仅适合BI-AWGN信道仿真 否 uA 长度为K的信息比特序列 按输出顺序逐一对各译码序列 进行CRC校验:一旦校验通 过,即输出为最终译码结果; 若均......

    主要对GPS的L5信号的结构、产生原理、自相关特性及互相关特性、频谱进行了研究。基于Matlab验证了其相关特性。结果表明,L5信号具有良好的自相关特性。 更多还原 ......

    展开全文
  • CRC校验码学习笔记

    2021-10-27 10:26:17
    一、CRC校验的作用 CRC:循环冗余校验码,是数据通信领域中最常用的一种查错校验码,它的优点是信息字段和校验字段的长度可以任意选定。使用CRC的方法是,在数据传输前计算信息字段的CRC,将其作为校验字段附在帧...
  • 在一些通信规约中,经常会用到数据校验,其中CRC(Cyclical Redundancy Check)最为常见。它是利用除法及余数的原理来作错误侦测的,实际应用时,发送装置计算出CRC值并随数据一同发送给接收装置,接收装置对收到的...
  • java实现CRC校验

    2021-02-12 19:48:27
    这两天项目中要使用到CRC校验功能,网上大量的例子是针对c、delphi的例子,前期没有做过,理论上也欠缺很多知识,在这里对java如何实现我们想要的crc校验功能做一下自己的总结,以下内容有本分转自网上,希望对有...
  • C语言:CRC校验

    2021-05-20 12:51:08
    一、CRCCRC:Cylic Reduancy check译作汉语就是循环冗余校验码。二、XORXOR:逻辑运算符异或,不知道用符号怎么写,总之其运算法则是,不同为1,相同为0。三、用XOR代替算术运算上除法的两个例子。1、10110010000/...
  • CRC校验码的基本思想是利用线性编码理论,在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的监督码(既CRC码)r位,并附在信息后边,构成一个新的二进制码序列数共(k+ r)位,最后发送出去。...
  • CRC校验的数学原理
  • crc7.h #ifndef CRC7_H #define CRC7_H /* Includes ------------------------------------------------------------------*/ #include "stm32f4xx_hal.h" /* Private function prototypes ---------------------...
  • CRC校验原理及其C语言实现 CRC校验码的基本思想是利用线性编码理论,在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的监督码(既CRC码)r位,并附在信息后边,构成一个新的二进制码序列数共(k+ r)...
  • CRC校验查表法详解

    2021-09-04 13:42:47
    CRC校验的查表法理解算法原理基础计算查表法原理及计算查表法中的表CRC校验中数据逆序CRC校验中的其它参数 算法原理 CRC(Cyclic Redundance Check)循环冗余校验,是基于某个多项式计算出一组校验码,用于核对数据...
  • Modbus协议CRC校验

    2021-01-21 09:05:01
    Modbus协议CRC校验 最近在开发Modbus协议网关,使用到了CRC校验,做了一点记录,希望对有需要的人有点帮助。 // CRC16高位码表 static const UInt8 CRC16HiTable[] = { 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, ...
  • CRC校验算法原理

    2021-01-16 15:20:17
    CRC校验采用多项式编码方法。被处理的数据块可以看作是一个二进制多项式,例如,10110101可以看作是2^7+2^5+2^4+2^2+2^0,多项式乘除法运算过程与普通代数多项式的乘除法相同。多项式的加减法运算以2为模,加减时不进...
  • 如何检查 | 基本原理 校验手段有很多,比如 和校验、MD5 校验CRC 校验,这里我们使用 CRC,因为一般芯片内部会内置该外设硬件计算(如果没有,可以纯 CPU 计算)。 然后我们需要了解完整性检查的基本原理。 所谓...
  • CRC校验 CRC原理 CRC实现非常简单,但想要真正掌握CRC算法原理,就必须清楚地了解有限域的运算规则,知道CRC就是有限域中的除法余数,并且清楚如何将串行CRC转换为并行CRC,此时才能设计出使用的CRC电路。 如果不想...
  • 一、16位CRC校验计算方法 1、 预置1个16位的寄存器为十六进制FFFF(全1),此寄存器为CRC寄存器。 2、 把第一个8位二进制数据(即通讯信息帧的第一个字节)与16位的CRC寄存器的低八位相异或,吧结果存放于CRC寄存器...
  • CRC校验 - 基于FPGA的实现

    千次阅读 2021-01-14 11:11:02
    CRC校验 - 基于FPGA的实现 0 背景 CRC即循环冗余校验:常用于数据通信领域中,通常由发送端添加校验码于单帧数据的尾部,并由接受方进行提取和校验该帧数据传输是否正确。 循环冗余检查(CRC)是一种数据传输...
  • 使用verilog实现CRC校验

    千次阅读 2021-02-23 15:02:35
    碰巧,我这个假期自学了verilog,那就让我来试试可不可以用Verilog来写一段CRC校验吧。 什么是CRC? 循环冗余校验码简称CRC(循环码),是一种能力相当强的检错、纠错码,并且实现编码和检码的电路比较简单,常用于...
  • C++开发之CRC校验实例详解CRC:(循环冗余校验)循环冗余校验是数据通信领域中最常用的一种差错校验码,主要用来检测或校验数据传输或者保存后可能出现的错误。其特征是信息字段和校验字段的长度可以任意选定。工作...
  • Modbus中的CRC校验程序

    2021-09-05 21:53:03
    CRC校验的应用 工业领域常用到的协议中,串口的modbus-rtu尤为常见,我们可能使用一些类似libmodbus库,来帮我们完成CRC校验工作,但是有些设备中,不是直接通过串口,而是通过网口,网口发送modbus-rtu格式的数据...
  • 校验的方式可以采用累加和校验或者BCH校验(一种CRC校验方法)。当采用BCH校验时,其分组附加的冗余字节可以集中在程序区之外的某个EPROM区域里。校验方法是在某个短小而且经常发生的中断服务程序内安排一个校验模块,...
  • CRC(Cyclic Redundancy Check)校验应用较为广泛,以前为了处理简单,在程序中大多数采用LRC(Longitudinal Redundancy Check)校验,LRC校验很好理解,编程实现简单。用了一天时间研究了CRC的C语言实现,理解和掌握了...
  • JavaCRC校验原理

    2021-02-28 15:24:27
    一、基本原理CRC检验原理实际上就是在一个p位二进制数据序列之后附加一个r位二进制检验码(序列),从而构成一个总长为n=p+r位的二进制序列;附加在数据序列之后的这个检验码与数据序列的内容之间存在着某种特定的...
  • JS实现CRC校验

    2021-09-17 14:01:37
    var crc_ret = 0; // JS计算出来的CRC结果 var crc32_table = new Array(); var crc_generate_one_flag = 0; //如果是负数,0变1,1变0 function exchange(str){ var arr = str.split(''); for(var i = 0; i...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 58,330
精华内容 23,332
关键字:

crc检验