CRC详解

article/2025/10/5 11:03:05

CRC-知识解析 cyclic redundancy check

写在前面的话:

之前在做学校项目的时候用到了CRC 原理,但在网上查找的过程中,发现讲解CRC知识的资源很多,但是对新手比较友好的、讲的十分清楚的又很少,很多博主也不求甚解,弄得读起来心中常常不由自主地奔腾过上千个“为什么”“为什么”, 本文是我在阅读了许多资料的基础上整理、解析出来的文章,尽可能的对新手友好、解答CRC里面的一些知识点,而不是简单的应用。

依据学习目的不同,如果大家只想简单应用,不求原理,那么直接复制--粘贴最后的代码即可。

------------------------------这是一条华丽的分界线------------------------------

1. CRC 算法原理

在对信息的处理过程中,我们可以将要被处理的数据块M看成一个n阶的二进制多项式,其形式如下:

 

CRC校验就是基于这种多项式进行的运算,以GF(2)(The integers modulo 2)多项式算术为数学基础,即(模-2)除法的余数运算(其实说白了就是异或Xor(见2.2)),使用的除数不同,CRC的类型也就不一样。CRC传输实际上就是在长度为 k 的数据后面添加供差错检测(Frame Check Sequence) 用的 r 位冗余码(Redundant code 没错CRC里面的R就是这个),使原数据构成 n = k + r 位并发送出去, 此方式又叫(n, k)码。可以证明存在一个最高次幂为n-k=r的多项式G(x),  根据G(x)可以生成k位信息的校验码,而 G(x) 叫做这个CRC码的生成多项式( Poly )。而根据 k 值的不同,就形成了不同的CRC码的生成多项式,以下为各种常用的多项表达式:

 

这些多项表达式的值便是(模-2)除法的除数,本博客这里选取CRC-32多项式(即为对应除数)格式,通过取余做操,获取CRC检验码。

 

2. CRC 传输过程

2.1 传输原理

 

按 1. CRC 算法原理 所述,将长度为 k 位的数据块对应一个GF(2)多项式M,以 8 位数据块11100110举例,如果先传输MSB(Most Significant Bit),则它对应的多项式为x^7 + x^6 + x^5 + x^2 + x (8位对应x的7次幂,因为从x0 开始计数,2进制为1时有效)。发送端和接收端约定一个次数为 的CRC多项式,取CRC-4 为例:x^4 + x + 1,r = 4。在数据块后面加上r个0对应的多项式为M',显然有M' = Mx^r 。用 M' 除以CRC-4 将得到一个次数等于或小于 r-1 的余数多项式 R,其对应的 r 位数值则为校验码。发送方通过指定的CRC多项式产生r位的CRC校验码,接收方则通过该CRC多项式来验证收到的报文码的CRC校验码是否为0。

 

具体推算如下:

设CRC多项式为G(x): 

假设发送信息用信息多项式C(x)表示,将C(x)左移 r 位,则可表示成C(x)x^r,这样C(x)的右边就会空出r位校验码的位置,使用GF(2)(模2除法),得到的余数R就是校验码。发送的CRC编码是, 至于验证接收到的报文编码是否至正确,方法依然是做模2除:,若余数为0则正确。

 

2.2 逻辑异或运算

CRC校验是基于多项式进行的运算,其加减法运算以2为模GF(2) ,加减时不进(借)位,实际上与逻辑异或(XOR)运算是一致, XOR是将参加运算的两个数据,按二进制位进行“异或”运算。

异或运算规则(^)规则如下:

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

即:参加运算的两个对象,如果两个相应位为“异”(值不同),则该位结果为1,否则为0。

 

2.3 传输计算示例

以G(X)=X4+X3+1为例,设原数据为10110011。

 (1)G(X)=X4+X3+1, 二进制比特串为11001。(在 X 的n 次方不为0处2的n次方的位=1 )

 (2)因为校验码4位,所以10110011后面需加4个0,得到101100110000,用“模2除法” (即逻辑亦或^) 即可得出结果:

 

(3)即CRC^101100110000得到101100110100,并发送到接收端。

(4)接收端收到101100110100后除以11001(以“模2除法”方式去除),余数为0则无差错。

3. CRC 的实现(Reversed 反向校验模式)

一般来说CRC有多种实现方式,在本文中我们以C语言为例,并给出 直接生成法 和 查表法 两个例子。

直接生成法 适用于 CRC 次幂较小的格式,当CRC 次幂逐渐增高时,因为其复杂的Xor 逻辑运算会拖累系统运行速度,不再建议使用直接生成法,取而代之的是查表法——将数据块M 的一部分提前运算好,并将结果存入数组中,系统开始执行运算时,相当于省去了之前的操作,直接从类似中间的位置开始计算,所以会提高效率。

 

在计算CRC时也可以选择正向校验(Normal) 或者反向校验(Reversed),由于 Normal 和 Reversed 是镜像关系,两种方法会影响到最后的校验码,使得两种方式最后得到的校验码呈现镜像关系。 但这对CRC 本身的成功率并没有影响,只不过是: 正向走一遍,还是镜像走一遍罢了。

 

为什么还会有Reversed格式呢? 是因为在大多数硬件系统的传输中,普遍先发送LSB,而Reversed 的CRC 正是满足于这种LSB First 的格式,因此适用。

 

下面为计算过程:

 

设数据块为Mx, CRC校验式为G(x) FCS位数为 r。

如下表所示,当采取反向校验设计时, 需进行以下操作:

Name

Polynomial Representations

Normal

Reversed

Reciprocal

Reversed reciprocal

CRC-3-GSM

0x3 

0x6 

 0x5

 0x5

CRC-8

0xD5 

 0xAB

 0x57

0xEA 

CRC-16-CCITT

0x1021 

0x8408 

0x811 

0x8810 

CRC-32

0x04C11DB7

0xEDB88320

0xDB710641

0x82608EDB

 

(1)将翻转后的Mx^r的后r位放入一个长度为r的寄存器中;

(2)如果寄存器的首位为1,将寄存器右移1位(将Mx^r剩下部分的MSB移入寄存器的MSB(高八位)),再与G(x) 的后r位异或,否则仅将寄存器右移1位(将Mx^r剩下部分的LSB(低八位)移入寄存器的LSB);

(3)重复第2步,直到M全部 Mx^r 移入寄存器;

(4)寄存器中的值则为校验码。

代码如下(基于C语言):

复制代码

#include<stdio.h>unsigned int CRC32_table[256] = {0};void init_CRC32_table()
{for (int i = 0; i != 256; i++){unsigned int CRC = i;for (int j = 0; j != 8; j++){if (CRC & 1)CRC = (CRC >> 1) ^ 0xEDB88320;elseCRC >>= 1;}CRC32_table[i] = CRC;}
}unsigned int GetCRC32(unsigned int crc, unsigned char *data, unsigned int size)
{for (unsigned int i = 0; i < size; i++){crc = ((crc >> 8) & 0xFFFFFF) ^ CRC32_table[(crc ^ data[i]) & 0xFF];}return crc;
}int main()
{// 初始化数据表init_CRC32_table();printf("CRC32 TABLE:\n");for(int i=0;i<256;i++){printf("0x%08x ",CRC32_table[i]);if((i+1)%8 == 0) printf("\n");}printf("\n");// 计算CRCunsigned char data[8] = {0x00,0x00,0x00,0x00,0x06,0x0d,0xd2,0xe3};printf("BUFFER i's CRC32: 0x%x\n", ~GetCRC32(0xffffffff, data, 8));// 分段计算unsigned int crc = 0xffffffff;for(int i=0; i<4; i++){crc = GetCRC32(crc, data+i*2, 2);}printf("BUFFER i's CRC32: 0x%x\n", ~crc);
}

复制代码

4. 生成多项式的选择

不同的CRC生成多项式,其检错能力是不同的。要使用R位校验码,生成多项式的次幂应为R。同时生成多项式应该包含项"1",否则校验码的LSB(Least Significant Bit)将始终为0。如果数据块M (包括校验码) 在传输过程中产生了差错,则接收端收到的消息可以表示为M +R’。若R’ 不能被CRC 生成多项式G 除尽,则该差错可以被检测出。考虑以下几种情况:

 

1) 1位差错,即R’ = x^n = 100...00,n >= 0。只要G至少有2位1,R'就不能被G除尽。这是因为G x^k相当于将G左移k位,对任意多项式Q,QG相当于将多个不同的G的左移相加。如果G至少有两位1,它的多个不同的左移相加结果至少有两位1。

 

2)奇数位差错,只要G含有因子F = x + 1,  R' 就不能被G除尽。这是因为QG = Q'F,由1)的分析,F的多个不同的左移相加结果1的位数必然是偶数。

 

3)爆炸性差错,即R' = (x^n + ... + 1)x^m = 1...100...00,n >= 1,m >= 0,显然只要G包含项"1",且次数大于n,就不能除尽R'。

 

4)2位差错,即R' = (x^n + 1)x^m = 100...00100...00,n >= 0。设x^n + 1 = QG + R,则R' = QGx^m + Rx^m,由3)可知R'能被G除尽当且仅当R为0。因此只需分析x^n + 1,对于次数R,总存在一个生成多项式G,使得n最小为2^R - 1时,才能除尽x^n + 1。称该生成多项式是原始的(primitive),它提供了在该次数上检测2位差错的最高能力,因为当n = 2^R - 1时,x^n + 1能被任何R次多项式除尽。

------------------------------这又是一条华丽的分界线------------------------------

 

5. Q & A

 

Q: 为什么寄存器初始化置0?

 

A: 寄存器的初始值不为 0,那么寄存器中的值就相当于是待测数据,这样算出的 CRC 结果并不正确。再考虑CRC32 模型的 Init=0xFFFFFFFF,待测数据的内容和长度为随机,如果寄存器初始值为 0,那么待测字节则为 1 字节 0x00,计算出来的 CRC32 值也就为 0。寄存器用0xFFFFFFFF 进行初始化,就可以避免这个问题

 

 

 

Q:为什么先移位再XOR?

 

A: 0xEDB88320已经是Gx 去掉最高项的简写,为了确保运算无误,所以需要先移位再XOR。这不会影响最后的结果,因为在做XOR运算时,gx 的最高位都会被消掉(因为在除法运算中每次循环都是从1 开始除, 而gx 的最高项就是1,所以每次都会被消掉)

 

 

Q: 查表法的index 是什么,而内容又是什么?

 

A: Index 为数据块M 的前8位,内容是前8位与CRC XOR后的值,用时需再与gx异或。

 

 

Q: 查表法为什么会有256个字符?

 

A: 在CRC-16和32中,一次移出的待测数据为 8 位 bits,即一次进行一个字节的计算,则表格有 2^8=256 个表值。一个字节有8位二进制数,每一位都有2种选择。

 

6. 参考资料推荐

http://www.ip33.com/crc.html(CRC在线计算)

 

https://bbs.pediy.com/thread-17195.htm  (通俗解释)

 

https://www.cnblogs.com/bugutian/p/6221783.html(解释移位原理)

 

https://blog.csdn.net/mish84/article/details/27528125(解释代码)


http://chatgpt.dhexx.cn/article/K0slbAJi.shtml

相关文章

CCR(Condition Code Register:条件代码寄存器)的作用

CCR是一个显示执行指令后的结果和处理器的状态的8位寄存器。根据微型计算机的不同&#xff0c;名称也会不同&#xff0c;但是所有的微型计算机都有。在大多数微型计算机的情况下&#xff0c;用户不能直接读写&#xff0c;但有些微型计算机可以读写。您可以通过执行可以测试CCR位…

STM32定时器的预装寄存器及影子寄存器PSC—ARR-CCRx

在谈预装寄存器及影子寄存器的差别前&#xff0c;不妨先对STM32定时器的时基单元做个基本了解。STM32各系列的定时器结构和框架基本是一样的&#xff0c;时基单元也一样。 下面时基单元是以STM32F3系列为参考。 时基单元中的TIMx_PSC、 TIM_ARR两个寄存器加上捕捉比较模块中TIM…

输出比较功能中的pwm以及其他功能的区分

首先我们要知道的是pwm是输出比较的子集 PWM模式下&#xff1a; ARR 决定输出频率 &#xff0c;CCR决定输出占空比 输出比较模式下&#xff1a; ARR 决定输出频率 CCRx 决定每个通道的初始相位。 一般使用输出比较都是想要去输出一个频率可变的pwm信号&#xff0c;那怎么通过…

STM32 PWM输出

STM32 PWM输出 工作过程&#xff1a; 我们假定定时器工作在向上计数PWM 模式&#xff0c;且当 CNT<CCRx 时&#xff0c;输出 0&#xff0c;当 CNT>CCRx 时输出1。那么就可以得到如上的PWM 示意图&#xff1a; 当 CNT 值小于 CCRx 的时候&#xff0c;IO 输出低电平(0)&a…

简单明了的说明STM32的PWM原理以及实现方法

申明以下都是个人理解&#xff0c;仅供参考。如果错误欢迎指教。本文不讲底层&#xff0c;根据实际使用来逆向讲解。 1.什么是pwm&#xff1f; pwm最简单的理解就是“功率”&#xff0c;调节PWM的占空比就是调节功率。 2.如何调节占空比&#xff1f; 图1 根据图1很容易看出…

CCRX寄存器

TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);// TIMx_CCRx寄存器能够在任何时候通过软件进行更新以控制输出波形&#xff0c;条件是未使用预装载寄存器(OCxPE’0’&#xff0c;否则TIMx_CCRx影子寄存器只能在发生下一次更新事件时被更新)。这里设置为Disable 就是为了…

JavaScript权威指南 第13章 异步JavaScript

JavaScript权威指南 第13章 异步JavaScript 13章 异步JavaScript13.1 使用回调的异步编程13.1.1 定时器13.1.2 事件13.1.3 网络事件13.1.4 Node中的回调与事件 13.2 期约13.2.1 使用期约使用期约处理错误 13.2.2 期约链13.2.2 解决期约13.2.4 再谈期约和错误catch和finally方法…

javascript权威指南(第四版)

Java Script是一种功能强大的基于对象的脚本语言。Java Script程序可以直接嵌入HTML页面。与Web浏览器定义的文档对象模型(DOM)一起使用时&#xff0c;JavaScript可以创建动态HTML(DHTML)内容&#xff0c;允许用户与客户端的Web应用程序交互。 JavaScript语法以流行的程序设计语…

《JavaScript权威指南》学习笔记(一)

跟着《JavaScript权威指南》整理的一些知识点和自己的小拓展。有不足之处请指正。 1、try catch 防止程序异常直接报错退出&#xff0c;而是能对异常进行一些处理&#xff0c;具体处理就在catch中。最好是在最外层函数使用。 2、HTML不区分大小写、XHTML区分大小写、JavaScri…

《javascript权威指南》精读笔记-持续更新

《javascript权威指南》 作用域链 表达式 原始表达式 对象和数组的初始化表达式 函数定义表达式 函数直接量 属性访问表达式 调用表达式 对象创建表达式 运算符 表达式计算 var function for in with debugger use strict 对象 创建对象 属性的查询和设置 作为关联数组的对象 继…

JavaScript权威指南(第6版)

JavaScript权威指南&#xff08;第6版&#xff09; JavaScript权威指南 第6版&#xff08;影印版&#xff09;上册 Beginning iOS Programming, 2014年 Gradle for Android (2016年3月 Finished)

JavaScript权威指南 第11章JavaScript标准库

JavaScript权威指南 第11章JavaScript标准库 第11章 JavaScript标准库11.1 集合与映射11.1.1 Set类11.1.2 Map类11.1.3 WeakMap和WeakSet 11.2 定型数组与二进制数据11.2.1 定型数组的类型11.2.2 创建定型数组11.2.3 使用定型数组11.2.4 定型数组的方法与属性11.2.5 DateView与…

JavaScript 权威指南-学习笔记(一)

本文所有教程及源码、软件仅为技术研究。不涉及计算机信息系统功能的删除、修改、增加、干扰,更不会影响计算机信息系统的正常运行。不得将代码用于非法用途,如侵立删!JavaScript 权威指南-学习笔记 JavaScript是一门高级、动态、解释型变成语言,非常适合面向对象和函数式编…

JavaScript权威指南笔记-masaikk

JavaScript权威指南笔记-马赛柯柯 源代码位于masaikk/interviewAccess - Gitee.com 前五章笔记略 第六章 对象 防止某个对象被第三方库意外修改&#xff0c;建议使用Object.create()方法 ★ \bigstar ★ let o {foo: bar}; library.func(Object.create(o))解释Object.crea…

【JavaScript权威指南(第七版)】之阅读学习总结

写在前面 最近借着空闲时间断断续续两个月看完了《JavaScript权威指南(第七版)》&#xff0c;《JavaScript权威指南》一直以来被称为“犀牛书”&#xff0c;前面的第六版我大概略过一遍&#xff0c;由于书的厚度实在有点“厚重”&#xff0c;将近1000多页左右&#xff0c;有一些…

JavaScript权威指南(原书第7版) 犀牛书

第3章 语法结构 3.10.1 使用let和const声明 ES6后&#xff0c;变量通过let关键字声明 let i let sum可以使用一条let语句声明多个变量 let i, sum声明变量的同时&#xff0c;&#xff08;如果可能&#xff09;也为其赋予一个初始值 let message hello let i 0, j 1let …

JavaScript权威指南-总结

章2 词法结构 1.什么是字面量&#xff0c;标识符&#xff0c;保留字&#xff1f; 字面量即程序中的数据的值&#xff1b;标识符指数据的名字&#xff08;字母、下划线_或美元符号$开头&#xff0c;为了和数值区分开&#xff0c;标识符不能用数字开头&#xff0c;&#xff09;…

javascript 权威指南笔记

1.如果没有用var语句给一个变量指初始值&#xff0c;那么虽然这个变量被声明了&#xff0c;但是在给它存一个值之前&#xff0c;它的初始值就是 undefined 2.使用var语句多次声明一个变量不仅是合法的&#xff0c;而且也不会造成任何错误。如果重复的声明有一个初始值&#xf…

【WCF】使用WCF测试客户端

【是什么】 WCF测试客户端&#xff08;WCF Test Client&#xff09;是一个用来测试WCF服务程序的调试工具&#xff0c;能够使开发WCF服务更加方便。 【打开方法】 有四种打开方式 1、找到Vs的安装路径&#xff0c;找到Common7\IDE\WcfTestClient.exe&#xff0c;双击打开。如…

WCF 介绍(一)

前言&#xff1a;WCF是微软基于SOA&#xff08;Service Oriented Architecture&#xff09;推出的.Net平台下的框架产品&#xff0c;它代表了软件架构设计与开发的一种发展方向&#xff0c;在微软的战略计划中也占有非常重要的地位。了解和掌握WCF&#xff0c;对于程序员特别是…