0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

嵌入式开发的crc算法知识精选

h1654155971.7688 来源:互联网 作者:佚名 2017-11-08 11:28 次阅读
CRC校验(循环冗余校验)是数据通讯中最常采用的校验方式。在嵌入式软件开发中,经常要用到CRC 算法对各种数据进行校验。因此,掌握基本的CRC算法应是嵌入式程序员的基本技能。可是,嵌入式程序员中能真正掌握CRC算法的人很少,平常在项目中见到的CRC的代码多数都是那种效率非常低下的实现方式。其实,在网上有一篇介绍CRC 算法的非常好的文章,作者是Ross Williams,题目叫:“A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS”。阅读英文没有障碍的朋友也可以去读Ross Williams的原文。本文的读者群设定为软件开发人员,尤其是从事嵌入式软件开发的程序员,而不是专业从事数学或通讯领域研究的学者。因此,本文的目标是介绍CRC算法的基本原理和实现方式,用到的数学尽量控制在高中生可以理解的深度。从奇偶校验说起所谓通讯过程的校验是指在通讯数据后加上一些附加信息,通过这些附加信息来判断接收到的数据是否和发送出的数据相同。比如说RS232串行通讯可以设置奇偶校验位,所谓奇偶校验就是在发送的每一个字节后都加上一位,使得每个字节中1的个数为奇数个或偶数个。比如我们要发送的字节是0x1a,二进制表示为0001 1010。

采用奇校验,则在数据后补上个0,数据变为0001 1010 0,数据中1的个数为奇数个(3个)

采用偶校验,则在数据后补上个1,数据变为0001 1010 1,数据中1的个数为偶数个(4个)

接收方通过计算数据中1个数是否满足奇偶性来确定数据是否有错。奇偶校验的缺点也很明显,首先,它对错误的检测概率大约只有50%。也就是只有一半的错误它能够检测出来。另外,每传输一个字节都要附加一位校验位,对传输效率的影响很大。因此,在高速数据通讯中很少采用奇偶校验。奇偶校验优点也很明显,它很简单,因此可以用硬件来实现,这样可以减少软件的负担。因此,奇偶校验也被广泛的应用着。奇偶校验就先介绍到这来,之所以从奇偶校验说起,是因为这种校验方式最简单,而且后面将会知道奇偶校验其实就是CRC 校验的一种(CRC-1)。累加和校验

另一种常见的校验方式是累加和校验。所谓累加和校验实现方式有很多种,最常用的一种是在一次通讯数据包的最后加入一个字节的校验数据。这个字节内容为前面数据包中全部数据的忽略进位的按字节累加和。比如下面的例子:

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

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

这里 33 为前三个字节的校验和。接收方收到全部数据后对前三个数据进行同样的累加计算,如果累加和与最后一个字节相同的话就认为传输的数据没有错误。累加和校验由于实现起来非常简单,也被广泛的采用。但是这种校验方式的检错能力也比较一般,对于单字节的校验和大概有1/256 的概率将原本是错误的通讯数据误判为正确数据。之所以这里介绍这种校验,是因为CRC校验在传输数据的形式上与累加和校验是相同的,都可以表示为:通讯数据 校验字节(也可能是多个字节)初识 CRC 算法CRC 算法的基本思想是将传输的数据当做一个位数很长的数。将这个数除以另一个数。得到的余数作为校验数据附加到原数据后面。还以上面例子中的数据为例:

6、23、4 可以看做一个2进制数: 0000011000010111 00000010

假如被除数选9,二进制表示为:1001

则除法运算可以表示为:

可以看到,最后的余数为1。如果我们将这个余数作为校验和的话,传输的数据则是:6、23、4、1

CRC 算法和这个过程有点类似,不过采用的不是上面例子中的通常的这种除法。在CRC算法中,将二进制数据流作为多项式的系数,然后进行的是多项式的乘除法。还是举个例子吧比如说我们有两个二进制数,分别为:1101 和1011。1101 与如下的多项式相联系:1x3+1x2+0x1+1x0=x3+x2+x01011与如下的多项式相联系:1x3+0x2+1x1+1x0=x3+x1+x0

两个多项式的乘法:(x3+x2+x0)(x3+x1+x0)=x6+x5+x4+x3+x3+x3+x2+x1+x0

得到结果后,合并同类项时采用模2运算。也就是说乘除法采用正常的多项式乘除法,而加减法都采用模2运算。所谓模2运算就是结果除以2后取余数。比如3 mod 2 = 1。因此,上面最终得到的多项式为:x6+x5+x4+x3+x2+x1+x0,对应的二进制数:111111

加减法采用模2运算后其实就成了一种运算了,就是我们通常所说的异或运算:

上面说了半天多项式,其实就算是不引入多项式乘除法的概念也可以说明这些运算的特殊之处。只不过几乎所有讲解 CRC 算法的文献中都会提到多项式,因此这里也简单的写了一点基本的概念。不过总用这种多项式表示也很罗嗦,下面的讲解中将尽量采用更简洁的写法。

除法运算与上面给出的乘法概念类似,还是遇到加减的地方都用异或运算来代替。下面是一个例子:

要传输的数据为:1101011011

除数设为:10011

在计算前先将原始数据后面填上4个0:11010110110000,之所以要补0,后面再做解释。

从这个例子可以看出,采用了模2的加减法后,不需要考虑借位的问题,所以除法变简单了。最后得到的余数就是CRC 校验字。为了进行CRC运算,也就是这种特殊的除法运算,必须要指定个被除数,在CRC算法中,这个被除数有一个专有名称叫做“生成多项式”。生成多项式的选取是个很有难度的问题,如果选的不好,那么检出错误的概率就会低很多。好在这个问题已经被专家们研究了很长一段时间了,对于我们这些使用者来说,只要把现成的成果拿来用就行了。

最常用的几种生成多项式如下:CRC8=X8+X5+X4+X0CRC-CCITT=X16+X12+X5+X0CRC16=X16+X15+X2+X0CRC12=X12+X11+X3+X2+X0CRC32=X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+X0

有一点要特别注意,文献中提到的生成多项式经常会说到多项式的位宽(Width,简记为W),这个位宽不是多项式对应的二进制数的位数,而是位数减1。比如CRC8中用到的位宽为8的生成多项式,其实对应得二进制数有九位:

100110001。另外一点,多项式表示和二进制表示都很繁琐,交流起来不方便,因此,文献中多用16进制简写法来表示,因为生成多项式的最高位肯定为1,最高位的位置由位宽可知,故在简记式中,将最高的1统一去掉了,如CRC32的生成多项式简记为04C11DB7实际上表示的是104C11DB7。当然,这样简记除了方便外,在编程计算时也有它的用处。对于上面的例子,位宽为4(W=4),按照CRC算法的要求,计算前要在原始数据后填上W个0,也就是4个0。

位宽W=1的生成多项式(CRC1)有两种,分别是X1和X1+X0,读者可以自己证明10 对应的就是奇偶校验中的奇校验,而11对应则是偶校验。

因此,写到这里我们知道了奇偶校验其实就是CRC校验的一种特例,这也是我要以奇偶校验作为开篇介绍的原因了。CRC算法的编程实现

说了这么多总算到了核心部分了。从前面的介绍我们知道CRC校验核心就是实现无借位的除法运算。下面还是通过一个例子来说明如何实现CRC校验。

假设我们的生成多项式为:100110001(简记为0x31),也就是CRC-8

则计算步骤如下:

(1)将CRC寄存器(8-bits,比生成多项式少1bit)赋初值0(2)在待传输信息流后面加入8个0(3)While (数据未处理完)(4)Begin(5)If (CRC寄存器首位是1)(6)reg = reg XOR 0x31(7)CRC寄存器左移一位,读入一个新的数据于CRC寄存器的0 bit的位置。(8)End(9)CRC寄存器就是我们所要求的余数。

实际上,真正的CRC 计算通常与上面描述的还有些出入。这是因为这种最基本的CRC除法有个很明显的缺陷,就是数据流的开头添加一些0并不影响最后校验字的结果。这个问题很让人恼火啊,因此真正应用的CRC 算法基本都在原始的CRC算法的基础上做了些小的改动。

所谓的改动,也就是增加了两个概念,第一个是“余数初始值”,第二个是“结果异或值”。

所谓的“余数初始值”就是在计算CRC值的开始,给CRC寄存器一个初始值。“结果异或值”是在其余计算完成后将CRC寄存器的值在与这个值进行一下异或操作作为最后的校验值。

常见的三种CRC 标准用到个各个参数如下表。

加入这些变形后,常见的算法描述形式就成了这个样子了:(1)设置CRC寄存器,并给其赋值为“余数初始值”。(2)将数据的第一个8-bit字符与CRC寄存器进行异或,并把结果存入CRC寄存器。(3)CRC寄存器向右移一位,MSB补零,移出并检查LSB。(4)如果LSB为0,重复第三步;若LSB为1,CRC寄存器与0x31相异或。(5)重复第3与第4步直到8次移位全部完成。此时一个8-bit数据处理完毕。(6)重复第2至第5步直到所有数据全部处理完成。(7)最终CRC寄存器的内容与“结果异或值”进行或非操作后即为CRC值。示例性的C代码如下所示,因为效率很低,项目中如对计算时间有要求应该避免采用这样的代码。不过这个代码已经比网上常见的计算代码要好了,因为这个代码有一个crc的参数,可以将上次计算的crc结果传入函数中作为这次计算的初始值,这对大数据块的CRC计算是很有用的,不需要一次将所有数据读入内存,而是读一部分算一次,全读完后就计算完了。这对内存受限系统还是很有用的。

上面的代码是我从http://mdfs.net/Info/Comp/Comms/CRC16.htm找到的,不过原始代码有错误,我做了些小的修改。

下面对这个函数给出个例子片段代码:

读者可以验算,c1、c2 的结果都为 29b1。上面代码中crc 的初始值之所以为0xffff,是因为CCITT标准要求的除数初始值就是0xffff。

上面的算法对数据流逐位进行计算,效率很低。实际上仔细分析CRC计算的数学性质后我们可以多位多位计算,最常用的是一种按字节查表的快速算法。该算法基于这样一个事实:计算本字节后的CRC码,等于上一字节余式CRC码的低8位左移8位,加上上一字节CRC右移 8位和本字节之和后所求得的CRC码。如果我们把8位二进制序列数的CRC(共256个)全部计算出来,放在一个表里,编码时只要从表中查找对应的值进行处理即可。

按照这个方法,可以有如下的代码(这个代码也不是我写的,是我在Micbael Barr的书“Programming Embedded Systems in C and C++” 中找到的,同样,我做了点小小的改动。):
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • CRC校验
    +关注

    关注

    0

    文章

    84

    浏览量

    15188
  • CRC算法
    +关注

    关注

    0

    文章

    15

    浏览量

    8847

原文标题:嵌入式程序员的循环冗余校验(CRC)算法最简单入门

文章出处:【微信号:weixin21ic,微信公众号:21ic电子网】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    一文了解嵌入式软件开发的对象

    以前应用场景很单一,嵌入式开发可能谈不上面向对象开发。但现在,做嵌入式开发,没有面向对象开发,你就有点落伍了。 本文结合个人经验和周立功《抽象接口技术和组件
    的头像 发表于 11-15 10:31 241次阅读
    一文了解<b class='flag-5'>嵌入式</b>软件<b class='flag-5'>开发</b>的对象

    零基础嵌入式开发学习路线

    的数据结构与算法能够提升运行效率,同样不好的数据结构与算法也会造成空间的浪费。对于嵌入式开发来说,掌握一些比较基础的数据结构还是非常有必要的。比如线性结构如链表、栈、队列、树、图等。可以通过这些逻辑
    发表于 10-25 15:55

    嵌入式开发常见问题排查

    嵌入式开发问题排查很多人认为嵌入式开发很难,主要是因为在这个过程中常常会遇到各式各样的问题。这些问题的复杂性和多样性使得许多人感到困惑和无所适从。然而,如果将这些问题逐一拆解,实际上大部分都可以
    的头像 发表于 09-22 08:04 265次阅读
    <b class='flag-5'>嵌入式开发</b>常见问题排查

    【「ARM MCU嵌入式开发 | 基于国产GD32F10x芯片」阅读体验】+书籍整体概况

    一、导言 上周收到《ARM MCU嵌入式开发 | 基于国产GD32F10x芯片》书籍,该纸质书籍内容可谓是面面俱到,由“清华大学出版社”出版,印刷第1版时间为2024年6月份,总共464千字
    发表于 08-25 22:48

    聚焦嵌入式开发中的合规性工具、项目管理工具、版本迭代工具应用

    日前,龙智携嵌入式开发及管理解决方案亮相2024上海国际嵌入式展(embedded world China 2024)。展会期间,我们对话了多位龙智资深DevSecOps顾问及技术支持专家
    的头像 发表于 07-29 15:15 472次阅读

    嵌入式开发前景怎么样?

    嵌入式开发前景非常广阔,这主要得益于物联网、人工智能、大数据等技术的快速发展,以及嵌入式系统在各个领域的广泛应用。以下是对嵌入式开发前景的详细分析
    的头像 发表于 07-10 09:00 2496次阅读
    <b class='flag-5'>嵌入式开发</b>前景怎么样?

    嵌入式开发者的未来

    嵌入式系统的就业方向非常广泛,涵盖了许多不同的行业和领域。以下是一些常见的嵌入式系统就业方向:消费电子产品:这包括智能手机、平板电脑、智能电视、智能家居设备等。嵌入式系统工程师可以参与设计、
    的头像 发表于 06-23 08:10 327次阅读
    <b class='flag-5'>嵌入式开发</b>者的未来

    嵌入式开发就业前景怎么样?

    发动机控制、底盘控制、车身控制等。嵌入式开发人员需要掌握相关的硬件和软件技术,如处理器、传感器、通信技术、汽车控制算法等,同时也需要具备一定的汽车结构和原理知识。 5)航空航天 航空航天是指应用于
    发表于 06-07 14:51

    ARM Cortex-A53嵌入式开发平台Android手册

    电子发烧友网站提供《ARM Cortex-A53嵌入式开发平台Android手册.pdf》资料免费下载
    发表于 04-28 15:10 0次下载

    fpga是嵌入式开发

    FPGA(现场可编程门阵列)与嵌入式开发之间确实存在一定的关联,但它们在本质上是两个不同的领域。
    的头像 发表于 03-15 14:18 979次阅读

    嵌入式软件开发应该掌握哪些知识?

    知识点学习 熟悉 Linux 的基本使用对于嵌入式软件开发至关重要。包括文件系统的管理、用户权限的控制、软件包管理等。嵌入式开发人员需要能够在 Linux 环境下进行
    发表于 02-19 11:23

    嵌入式自学好书推荐

    工作经验的薪资可达10-15k;而拥有3年以上工作经验的薪资可在15-25k范围内。 嵌入式开发的前期入门知识主要包括以下四个方面: 1.电路知识:学习基础的电路、模拟电路和数字电路,了解基础器件、放大
    发表于 01-11 15:13

    嵌入式开发常见的C语言技巧与方法分享

    嵌入式开发中,常常要操作寄存器,对寄存器进行写入,读出等等操作。每个寄存器都有自己固有的地址,通过C语言访问这些地址就变得尤为重要。
    的头像 发表于 12-26 09:55 1055次阅读

    嵌入式开发学习的十三法则分享

    嵌入式开发学习是一个不断积累和总结的过程,来自一个嵌入式开发高级工程师为我们总结的关于嵌入式开发学习的十三法则,大家不妨参考一下: 一、冗余度法则 在嵌入式系统具有足够的冗余度
    发表于 12-21 06:32

    嵌入式开发中的交叉编译详解

    嵌入式开发中,经常会遇到目标平台资源贫乏,无法运行需要的编译器。亦或是目标平台上不允许或不能够安装需要的编译器。这时候就需要使用交叉编译了。
    的头像 发表于 12-01 13:24 1152次阅读
    <b class='flag-5'>嵌入式开发</b>中的交叉编译详解