CRC原理介绍及STM32 CRC外设的使用

1. CRC简介

循环冗余校验(英语:Cyclic redundancy check,简称CRC),由 W. Wesley Peterson 于 1961 年首次提出的一种纠错码理论。

CRC是一种数据纠错方法,主要应用于数据通信或者数据存储的场合,用来检测或校验数据传输或者数据存储后可能出现的错误,特别是擅长检测由传输通道中的噪声引起的常见错误。

CRC是数据通信领域中最流行的一种错误检测方法,传输过程中的数据信息字段长度,以及校验码的字段长度可以任意自定义的指定,但是通信双方必须使用同一标准的CRC校验。

2. CRC模型及其相关概念

很多大佬们在研究CRC算法的时候,设计了各种CRC的算法模型,这些模型可以适用不同的校验场合,比如 CRC-16 ,CRC-32 等不同的算法模型。

一般我们在具体的项目中,要使用CRC校验的时候,首先就要选择合适的算法模型,根据选定的CRC算法模型,才能计算得到对应的CRC校验码。然后,通信双方约定好使用的CRC校验模型,才能保证校验的一致性。

下图截图自一个CRC校验码在线计算工具网站的常用的CRC算法模型:

在这里插入图片描述

注:上面的多项式表示中,是16进制数,而且是省略了最高位的。

这些CRC算法模型中,有几个重要的组成部分,或者说计算CRC校验码时,需要知道的一些概念,如多项式公式、16进制多项式、宽度、初始值、结果异或值等等。

2.1 多项式公式

多项式公式,是CRC校验中最重要的一个概念。

任意的二进制数都可以构造一个与其对应的二进制系数多项式公式。

比如,二进制:10011b,它对应的二进制系数多项式就是:
P ( x ) = x 4 + x + 1 P(x) = x^4 + x + 1 P(x)=x4+x+1

这个公式怎么来的呢?

# 二进制数      1 0 0 1 1
# 下标         4 3 2 1 0
# 二进制多项式   1 * X4 + 0 * X3 + 0 * X2 + 1 * X1 + 1 * X0# 所以最后得出的多项式公式就是:X4 + X + 1

成为多项式要满足的条件

  • 最高位和最低位都必须是1
  • 当数据在传输过程中出错时,CRC的校验码不应该是0(也就是要有余数)
  • 该多项式要有最大的错误检测能力

2.2 16进制的多项式表示

一般在计算CRC校验码的时候,我们习惯使用16进制的多项式,这个16进制的多项式,是被省略了最高位 1 的。

因为前面说了,多项式的最高位和最低位,都必须是1,所以一般都会把这个多项式的最高位给省略掉(这里我也没搞懂,反正当它是一个不可描述的规定吧)。

比如前面介绍的,P(x) = X4 + X + 1 ,这个多项式公式,他对应的CRC模型就是 CRC-4/ITU ,然后它的多项式使用16进制表示就是 0x03 ,本来这个多项式应该是0x13的,但是省略了最高位,所以变成了 0x03.

2.3 位宽

位宽,指的就是CRC校验码的二进制位数。这个是和你选择的CRC模型有关的,你选择不同的CRC模型,那么CRC的多项式公式就不一样,所以对应的CRC校验码数据位宽也不一样。

比如前面介绍的多项式公式 :P(x) = X4 + X + 1 ,那么CRC的校验码位宽就是 4 个二进制位数。因为多项式的最高位为4.

2.4 CRC变体相关的概念

前面介绍的3个参数概念,是CRC模型中必须要有的概念。其他一些概念,比如初始值、输入数据反转,输出数据反转,结果值是否异或处理等,这些都属于CRC变体的处理。

如果没有特意规定的话,那么这些参数默认都是没有的,比如初始值没有规定,则默认为0。没有说明是否反转,那么一般不会对数据进行反转的操作等。

2.4.1 初始值

CRC模型中,有些模型规定CRC的初始值不是0。这个初始值,其实就是CRC校验码的计算过程中,在第一次进行异或计算时,是否有一个初始值。这个如果看C言语实现CRC计算过程就比较直观。

初始值的数据位宽和CRC校验码的位宽是一样的。

2.4.2 输出结果值异或

计算得到了CRC校验码后,如果规定了输出的结果值要进行异或的数不为0,那么最后得到CRC校验码时,还得进行结果值异或这步操作。这样才能最终得到CRC校验码

2.4.3 输入输出值反转

在一些CRC模型中,还会规定输入值与输出值是否反转。

输入值反转,就是在计算CRC校验码之前,是否对原始数据(待测数据)进行按位反转。比如:1010001,反转之后就是:1000101

输出值反转,就是最终得到的CRC结果值,是否进行反转操作。

3. 模2运算

CRC校验的计算理论源自多项式除法,它是一种二进制除法,被叫做模2除法。待检测的数据除以多项式,最终得到的余数就是CRC检验码。

模2运算,是一种二进制运算,是二进制编码理论中的运算基础。这种运算和我们以前学的四则运算的规则不同,模2运算不考虑进位、借位这些规则,它有着新的运算规则。

模2运算也有加减乘除,下面是它们的运算示例。

3.1 模2加法

加法规则:1+1=0 0+0=0 1+0=1 0+1=1

  1 0 1 0
+ 1 1 0 0
-----------0 1 1 0

3.2 模2减法

减法规则:0-0=0 1-1=0 0-1=1 1-0=1

  1 0 1 0
- 1 1 0 0
-----------0 1 1 0

3.3 模2乘法

乘法规则:0×0=0 0×1=0 1×0=0 1×1=1

模2乘法与普通的乘法一样的演算规则,只不过在按位相加时,是按照模2加法规则进行的。

       1 0 1 1x   1 0 1----------------1 0 1 10 0 0 01 0 1 1----------------1 0 0 1 1 1

3.4 模2除法

除法规则:0÷1=0 1÷1=1

模2除法与普通的除法也是一样的演算规则,但是就是在按位相减时,是按照模2减法规则进行的。

                1 1 1 0 ()|-----------------
1 0 1 1 | 1 1 0 0 1 0 0 (被除数)1 0 1 1-----------------0 1 1 1 11 0 1 1-----------------0 1 0 0 01 0 1 1-----------------0 0 1 1 0 (最后余数)

从上面的模2运算示例可以看出一些规律:

  1. 模2的加减法运算结果是一样的,他和C语言的异或运算有着一样的规则。所以我们软件实现这个算法时就是使用异或实现的。
  2. 模2的乘除法运算,与普通的运算有着类似的演算规则。但是在乘法时乘积相加,除法时余数和除数相减,就需要安装模2加减法规则运算。
  3. 当余数的位数小于除数时,模2除法停止运算
  4. 当被除数,或者在除法进行过程中得到的部分余数,它们与除数位数一样多,那么商1,否则商0.

4. CRC校验码的计算和检测原理

4.1 CRC校验码的计算

CRC校验码的计算,其实就是模2除法的运算过程。

在计算过程中,我们首先要知道二进制多项式,这个多项式其实就是除数,而待校验的数据就是被除数,最终进行模2除法运算得到的余数,就是CRC校验码。

下面以多项式: P(x) = x^4 + x + 1 为例,该多项式对应的二进制数就是:10011 ,进行计算演示。

第一步:原始数据补充 n 个 0

假设要进行编码的原始数据为:1100110,而前面约定好了的多项式的最高位是4,所以CRC校验码的位宽就是4。所以我们先假设余数是 0000 四个0,补充在原始数据的后面,那么最终参与计算的数就是:11001100000

第二步:进行模2除法运算

1 1 0 0 1 1 0 0 0 0 0   (原始数据,后面加了4个0)1 0 0 1 1               (多项式)
----------------------------------0 1 0 1 0 11 0 0 1 1 
----------------------------------0 0 1 1 0 0 01 0 0 1 1 
----------------------------------0 1 0 1 1 01 0 0 1 1 
----------------------------------0 0 1 0 1 0 01 0 0 1 1 
----------------------------------0 0 1 1 1

当最终计算得到的余数的位数,小于多项式的位数的时候,运算停止,然后得到的余数就是CRC的校验码。

在数据传输过程中,就会把这个校验码放到原始数据的后面,组成一个新的数:11001100111 ,发送给接收方。当接收方在接收到这个数据后,就会进行CRC校验,也就是除以约定好的多项式,如果最终的余数为0,那么说明接收方接收的数据正确。

4.2 CRC校验检测原理

上面介绍计算CRC校验码说了,我们首先要约定好收发双方的除数,这个除数其实就是多项式。进行校验检测的大概过程就是:

(1) 先约定好收发双方选择的CRC多项式 多项式,这个多项式其实就是计算过程中的除数。

(2) 在待校验的数据(可看作是发送方的数据)后面加上 n 个0,这个 n 是多少取决于你所选择的多 项式。比如你选择的多项式是:P(x) = x^4 + x + 1 。那么CRC检验码的位宽就是4,也就是说你要补4个0

(3) 对待校验数据进行模2除法运算,得出的余数就是CRC校验值。

(4) 然后把CRC检验码添加到待检验数据的末尾。这样就组成了一个新的数了,这个是是添加了CRC校验码的。然后把这个新的数发送给接收方。

(5) 接收方,把接收到的数据,也进行模2除法的计算过程,如果余数为0,那么接收正确,如果不为0,那么数据在传输过程中出错。

5. CRC校验的软件代码

我们前面一直说了,CRC校验码的计算,其实就是模2除法。然后模2除法,对应到C言语中来,那就可以通过异或和移位操作来实现。

所以,CRC算法的软件实现,主要就是异或和移位操作实现的。实现方法主要有两种: 按位校验和查表。按位校验法消耗更多的CPU算力,查表法则消耗更多的RAM空间。

不同的CRC模型,按位校验法有不同的算法实现,主要是CRC变体的处理,初始值的不同等。不过也是有相似的规律,大致的代码实现过程是相同的。

网上也有大佬们已经实现了的各种CRC模型的算法库,我这里给出一个网上比较全的CRC算法库,如果有我们需要软件实现CRC校验的话,可以去移植过来。

LibCRC官网:https://www.libcrc.org/

LibCRC github仓库:https://github.com/lammertb/libcrc

还有下面这个,主要是按位校验法实现的CRC代码库:

https://github.com/whik/crc-lib-c

5.1 软件实现的代码片段

下面是摘抄自 wiki 的其中一种按位校验方式实现的CRC算法,大致的代码思路如下:

function crc(byte array string[1..len], int len) 
{remainderPolynomial := 0  // 多项式的初始值// 这里有一个流行的变体对剩余多项式进行补充,比如输入数据是否进行反转for i from 1 to len{//  这个步骤要看不同的CRC模型,有不同的处理。n是CRC的位宽,如果小于8的位宽,不用移位remainderPolynomial := remainderPolynomial xor (string[i] * (n << 8))for j from 1 to 8 {    // 每个字节是 8 bitif (remainderPolynomial最高位为1){remainderPolynomial := (remainderPolynomial << 1) xor generatorPolynomial(多项式)}else {remainderPolynomial := (remainderPolynomial << 1)}}}// 这里有一个流行的变体对剩余多项式进行补充,比如是否对CRC校验码进行输出反转,进行异或处理return remainderPolynomial
}

基本上,按位校验法的CRC代码实现,就是上面的这个套路。

5.2 CRC32-MPEG-2 模型的代码实现

这里给出一个 CRC32-MPEG-2 这个模型的CRC代码实现。

uint32_t crc32_mpeg2(uint8_t data[], uint32_t length)
{uint32_t crc = 0xffffffff;for (int i = 0; i < length; i++){crc = crc ^ (data[i] << 24);for (int j = 0; j < 8; j++){if ( crc & 0x80000000 ){crc = (crc << 1) ^ 0x04C11DB7;}else{crc = crc << 1;}}}return crc;
}

上面这个模型,其实也是一些MCU硬件的CRC实现的模型,比如STM32、APM32的MCU。

6. STM32的CRC外设使用

STM32 的 CRC 外设,使用的算法模型是 CRC32-MPEG-2

STM32 CRC 的数据位宽为 32 位,十六进制多项式为 0x4C11DB7, INIT=0xFFFFFFFF, REFIN=false,REFOUT=false, XOROUT=0x00000000

对于 STM32 CRC外设的使用也很简单,在使能了CRC外设时钟之后,就可以调用SDK(我使用的是STM32的标准固件库函数)提供的CRC计算函数,然后就可以得到对应数据的CRC校验码了。

下面以 STM32F407 为例,使用CRC外设计算校验码的代码:

static uint32_t CRC_Test_Buff[2] = {0x01, 0x02};int main(void)
{uint32_t uCRCValue = 0;/* Enable CRC Periph clock */RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);/* Resets the CRC Data register */CRC_ResetDR();/* Calculate the 32-bit CRC value */uCRCValue = CRC_CalcBlockCRC(CRC_Test_Buff, sizeof(CRC_Test_Buff) / 4);printf("CalculateBlockCRC = 0x%08X \r\n", uCRCValue);while (1){}
}

其中要注意的是,CRC_CalcBlockCRC 这个函数提供的输入数据类型是 32 位 的。

运行上面的代码输出结果如下:

在这里插入图片描述

然后我们到CRC校验码的在线计算工具,验证下我们使用STM32 CRC外设计算得到的校验码是否一致。计算结果如下图:

在这里插入图片描述

我们要选择的参数模型是, CRC32-MPEG-2 这个,输入的数据类型要注意一下是16进制,而且是1个字节。这个和我们STM32的代码是4个字节的数据不同,要自己拆分为1个字节输入到那个框框里面。

然后最终的计算结果是:0x298BE7BA ,这个值和我们使用 STM32 外设计算出来的结果是一致的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/74950.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TLS协议深度解析:挖掘现代网络安全防御的底层技术

正常简单的通讯 1、服务器生成一对密钥&#xff0c;公钥A、私钥A 2、浏览器请求服务器时&#xff0c;服务器把公钥A传给浏览器 3、浏览器随机生成一个对称加密的密码S&#xff0c;用公钥A加密后传给服务器 4、服务器接收后&#xff0c;用私钥A解密&#xff0c;得到密钥S 5、浏…

java中HashMap如何根据value的值去获取key是多少

在Java中&#xff0c;HashMap是一种基于键值对存储数据的数据结构。HashMap并没有直接提供根据value获取key的方法。但你可以通过遍历HashMap的entrySet&#xff0c;找到对应的value&#xff0c;然后获取其对应的key。 以下是一个示例代码&#xff1a; public <K, V> K…

【深度学习实战—6】:基于Pytorch的血细胞图像分类(通用型图像分类程序)

✨博客主页&#xff1a;米开朗琪罗~&#x1f388; ✨博主爱好&#xff1a;羽毛球&#x1f3f8; ✨年轻人要&#xff1a;Living for the moment&#xff08;活在当下&#xff09;&#xff01;&#x1f4aa; &#x1f3c6;推荐专栏&#xff1a;【图像处理】【千锤百炼Python】【深…

dji uav建图导航系列()move_base

文章目录 1、导航框架2、move_base功能包3、amcl功能包4、代价地图的配置4.1、通用配置文件4.2、全局规划配置文件4.3、局部规划配置文件5、局部规划器配置6、launch文件1、导航框架 导航的关键是机器人定位和路径规划两大部分 move_base:实现机器人导航中的最优路径规划 am…

datagrip 相关数据连接信息无缝迁移

背景 因为公司换电脑了&#xff0c;接触的项目比较多&#xff0c;不同项目&#xff0c;不同环境的数据库连接有好几十个&#xff0c;如果在新电脑上挨个重新连接一遍劳心劳力&#xff0c;所以想看一下能不能直接将之前保存的连接信息直接迁移到新的电脑上面。 为此&#xff0c…

Docker:01 OverView

Docker&#xff1a;01 OverView 基本介绍 Docker是一个用于开发、交付、运行应用程序的开放平台&#xff0c;可以使应用程序与基础架构分开&#xff0c;以便快速交付软件。 Docker在一个被叫做容器的隔离环境下&#xff0c;提供了打包和运行的能力。 容器非常轻量化&#x…

Android studio 调整jar包顺序

第一步&#xff1a;编译jar包&#xff0c;放入lib路径下&#xff1a;如&#xff1a; 第二步&#xff1a;app 目录下build.gradle 中添加 compileOnly files(libs/classes.jar) 第三步&#xff1a;project目录下build.gradle 中添加 allprojects {gradle.projectsEvaluated {t…

第50节:cesium 绘制指定类型区域(含源码+视频)

结果示例: 完整源码: <template><div class="viewer"><el-button-group class="top_item"><el-button type=

1、Flutter移动端App实战教程【环境配置、模拟器配置】

一、概述 Flutter是Google用以帮助开发者在IOS和Android 两个平台开发高质量原生UI的移动SDK&#xff0c;一份代码可以同时生成IOS和Android两个高性能、高保真的应用程序。 二、渲染机制 之所以说Flutter能够达到可以媲美甚至超越原生的体验&#xff0c;主要在于其拥有高性…

Jetsonnano B01 笔记5:IIC通信

今日继续我的Jetsonnano学习之路&#xff0c;今日学习的是IIC通信&#xff0c;并尝试使用Jetson读取MPU6050陀螺仪数据。文章提供源码。文章主要是搬运的官方PDF说明&#xff0c;这里结合自己实际操作作笔记。 目录 IIC通信&#xff1a; IIC硬件连线&#xff1a; 安装IIC库文…

智能小车之蓝牙控制并测速小车、wife控制小车、4g控制小车、语音控制小车

目录 1. 蓝牙控制小车 2. 蓝牙控制并测速小车 3. wifi控制测速小车 4. 4g控制小车 5. 语音控制小车 1. 蓝牙控制小车 使用蓝牙模块&#xff0c;串口透传蓝牙模块&#xff0c;又叫做蓝牙串口模块 串口透传技术&#xff1a; 透传即透明传送&#xff0c;是指在数据的传输过…

掌握AI助手的魔法工具:解密`Prompt`(提示)在AIGC时代的应用(下篇)

前言&#xff1a;在前面的两篇文章中&#xff0c;我们深入探讨了AI助手中的魔法工具——Prompt&#xff08;提示&#xff09;的基本概念以及在AIGC&#xff08;Artificial Intelligence-Generated Content&#xff0c;人工智能生成内容&#xff09;时代的应用场景。在本篇中&am…

10.Xaml ListBox控件

1.运行界面 2.运行源码 a.Xaml 源码 <Grid Name="Grid1"><!--IsSelected="True" 表示选中--><ListBox x:Name="listBo

生成树协议 STP(spanning-tree protocol)

一、STP作用 1、消除环路&#xff1a;通过阻断冗余链路来消除网络中可能存在的环路。 2、链路备份&#xff1a;当活动路径发生故障时&#xff0c;激活备份链路&#xff0c;及时恢复网络连通性。 二、STP选举机制 1、目的&#xff1a;找到阻塞的端口 2、STP交换机的角色&am…

【Vue2.0源码学习】生命周期篇-初始化阶段(initState)

文章目录 1. 前言2. initState函数分析3. 初始化props3.1 规范化数据3.2 initProps函数分析3.3 validateProp函数分析3.4 getPropDefaultValue函数分析3.5 assertProp函数分析 4. 初始化methods5. 初始化data6. 初始化computed6.1 回顾用法6.2 initComputed函数分析6.3 defineC…

Hadoop的HDFS的集群安装部署

注意&#xff1a;主机名不要有/_等特殊的字符&#xff0c;不然后面会出问题。有问题可以看看第5点&#xff08;问题&#xff09;。 1、下载 1.1、去官网&#xff0c;点下载 下载地址&#xff1a;https://hadoop.apache.org/ 1.2、选择下载的版本 1.2.1、最新版 1.2.2、其…

docker报错解决方法

ERROR: readlink /var/lib/docker/overlay2/l: invalid argument 注意&#xff1a;会清空已有安装 sudo service docker stop sudo rm -rf /var/lib/docker sudo service docker start

酷开系统游戏空间,开启大屏娱乐新玩法

在这个充满科技感和无限创意的时代&#xff0c;游戏已经成为我们生活的一部分。而随时着科技的不断发展&#xff0c;以及游戏爱好者的游戏需求在不断提高&#xff0c;促使游戏体验也向更加丰富多彩的方向发展。显然&#xff0c;酷开科技早已经认识到游戏发展的新蓝图&#xff0…

一百七十二、Flume——Flume采集Kafka数据写入HDFS中(亲测有效、附截图)

一、目的 作为日志采集工具Flume&#xff0c;它在项目中最常见的就是采集Kafka中的数据然后写入HDFS或者HBase中&#xff0c;这里就是用flume采集Kafka的数据导入HDFS中 二、各工具版本 &#xff08;一&#xff09;Kafka kafka_2.13-3.0.0.tgz &#xff08;二&#xff09;…

javaee springMVC model的使用

项目结构图 pom依赖 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org…