数据传输过程中差错不可避免,接收方在收到数据后,先对数据的准确性进行校验,异常数据特殊处理。校验的方式有很多,常见的有CRC循环冗余校验。CRC算法检错能力强,效率高,是信息通信领域最为普遍的校验方式。CRC校验算法应用广,且实现算法简单,但其背后的涉及的纠错码的代数理论,不是一般人可以理解的。所以,在不理解循环校验原理的基础上,贸然分析算法流程是不明智的,根据源码倒推实现流程,也不会明白为什么要这样执行?一般关注CRC以应用为主,以及为什么都是CRC16算法,得出的结果却不同。本文的意图只是这个。

1、CRC定义
假设要发送996这个数字,将其除以7余数为2,发送时将996-2合并后发出,接收方按同样运算判断数据包是否正确。同样的源数据,因为除数不同而余数不同。CRC算法也是因为类似原理。

CRC算法中参数解释如下:
1、除法定为模2除法

2、除数定为多项式,如x16+x12+x^5+1(0x1021) 216+212+25+20=65536+4096+32+1= 69665=0x11021 。依据不可描述的标准,多项式最高位和最低位必须为1,所以一般简化为0x1021,忽略最高位,记为Poly。

3、因为多项式长度不同,一般分为CRC8、CRC16和CRC32,因为模2除法简化为异或和移位操作,其初始值为Init。

4、还有三个参数

RefIn:待测数据的每个字节是否按位反转,TRUE或FALSE。

RefOut:在计算后之后,异或输出之前,整个数据是否按位反转,TRUE或FALSE。

XorOut:计算结果与此参数异或后得到最终的CRC值。但是任何数与0异或还是它本身,所以该值为0时可以忽略。

5、因为多项式Poly,初始值等差异,CRC有不同的版本。理论上是多项式是可以随意定义的,但是通用的标准多项式是经过数学推导的,尽可能的保证不同的数据求出的CRC值不相同。

6、参考https://crccalc.com/ 的定义,不同场景使用不同的多项式。


2、CRC算法与模板
通用版的CRC算法如下:
CRC8

//以CRC-8/ITU为参考
unsigned char CRC8(unsigned char *data, unsigned int len)
{unsigned char i;unsigned char poly = 0x07;//与表中的Poly列对应unsigned char init = 0x00;//与表中的Init列对应unsigned char wChar = 0;while (len--){wChar = *(data++);//RefIn为TRUE时执行,FALSE时删除//InvertUint8(&wChar,&wChar);init ^= wChar;for( i = 0;i < 8;i++){if(init & 0x80){init = (init << 1) ^ poly;}else{init = init << 1;}}}//RefOut为TRUE时执行,FALSE时删除//InvertUint8(&init,&init);//与XorOut进行异或,若为0时执行或不执行没有区别init=init^0x55;return (init);}

CRC16

//以CRC-16/X-25为参考
unsigned short CRC16(unsigned char *data, unsigned int len)
{unsigned char i;unsigned short poly = 0x1021;//与表中的Poly列对应unsigned short init = 0xFFFF;//与表中的Init列对应unsigned char wChar = 0;while (len--){wChar = *(data++);//RefIn为TRUE时执行,FALSE时删除InvertUint8(&wChar,&wChar);init ^= (wChar << 8);for( i = 0;i < 8;i++){if(init & 0x8000){init = (init << 1) ^ poly;}else{init = init << 1;}}}//RefOut为TRUE时执行,FALSE时删除InvertUint16(&init,&init);//与XorOut进行异或,若为0时执行或不执行没有区别init=init^0xFFFF;return (init);
}

CRC8和CRC16,根据不同版本的参数差异,查表,将模板里的参数改为对应值,即可得出对应版本的CRC值。其中涉及到数据反转的代码如下:

void InvertUint8(unsigned char *DesBuf, unsigned char *SrcBuf)
{int i;unsigned char temp = 0;for(i = 0; i < 8; i++){if(SrcBuf[0] & (1 << i)){temp |= 1 << (7 - i);}}*DesBuf = temp;
}void InvertUint16(unsigned short *DesBuf, unsigned short *SrcBuf)
{int i;unsigned short temp = 0;for(i = 0; i < 16; i++){if(SrcBuf[0] & (1 << i)){temp |= 1 << (15 - i);}}*DesBuf = temp;
}

3、查表
针对上面的代码,求解CRC移位异或运算的循环体,对时间要求较高的场景,可以提前计算生成数值表,以空间换时间。

//以CRC-8/ITU为例,生成数组查表
void creatTable(void)
{unsigned char i,init;unsigned short j;for(j=0;j<=255;j++){if(j%16==0){printf("\r\n");}init=j;for( i = 0;i < 8;i++){if(init & 0x80){init = (init << 1) ^ 0x07;//以实际poly为准;}else{init = init << 1;}}printf("0x%02X,", init);}
}

确定poly后,假设init为0-255,求出256个参数,转为一维数组。如上,以CRC-8/ITU为例,生成数组如下:

原来的直接计算改为查表,如下:

//以CRC-8/ITU为参考
unsigned char CRC8(unsigned char *data, unsigned int len)
{unsigned char i;unsigned char poly = 0x07;//与表中的Poly列对应unsigned char init = 0x00;//与表中的Init列对应unsigned char wChar = 0;while (len--){wChar = *(data++);//RefIn为TRUE时执行,FALSE时删除//InvertUint8(&wChar,&wChar);init ^= wChar;/************************************************************/
#if 1init=crcTable[init];//查表,空间换时间
#elsefor( i = 0;i < 8;i++){if(init & 0x80){init = (init << 1) ^ poly;}else{init = init << 1;}}
#endif
/************************************************************/}//RefOut为TRUE时执行,FALSE时删除//InvertUint8(&init,&init);//与XorOut进行异或,若为0时执行或不执行没有区别init=init^0x55;return (init);
}

对于CRC16也可以使用查表法。

【嵌入式算法】CRC校验算法相关推荐

  1. 【FPGA】CRC校验算法从数学原理到代码实现

    老规矩,转b站 [[FPGA]CRC校验算法从数学原理到代码实现-哔哩哔哩]

  2. CRC校验算法的数学原理(上)

    介绍   CRC是Cyclic Redundancy Check的缩写,用中文来讲,就是 循环冗余校验.是一种通过对数据产生固定位数校验码以备侦测数据错误的数据校验技术,主要用来侦测数据传输错误,也可 ...

  3. 嵌入式算法7---CRC校验算法模板

    数据传输过程中差错不可避免,接收方在收到数据后,先对数据的准确性进行校验,异常数据特殊处理.校验的方式有很多,常见的有CRC循环冗余校验.CRC算法检错能力强,效率高,是信息通信领域最为普遍的校验方式 ...

  4. modbus c语言校验算法,Modbus CRC校验算法

    终于找到了 Modbus CRC 校验算法 算法一: unsigned int calccrc(uchar crcbuf,uint crc) { uchar i; crc=crc ^ crcbuf; ...

  5. c# 如何编写CRC校验算法

    在C#中编写CRC校验算法,可以使用以下步骤: 首先需要确定CRC校验的多项式和初始值.根据具体的需求和应用场景,选择合适的CRC多项式和初始值. 定义一个计算CRC校验值的函数,函数的输入参数为待校 ...

  6. CRC-16原理及通用的16位CRC校验算法代码

    CRC-16原理及通用的16位CRC校验算法代码 循环冗余码校验英文名称为Cyclical Redundancy Check,简称CRC.它是利用除法及余数的原理来作错误侦测(Error Detect ...

  7. CRC校验算法的解析,暨对网上的CRC详解的补充

    一.CRC的形象理解 本文面向对CRC校验有一定基础的读者,如果你不懂,请戳这里.维基百科还有图解版的. 在CRC的具体实现中,如果要计算CRC的数据很长,一般都会用到寄存器,用来保存当前的计算到的C ...

  8. 16位CRC校验算法,16进制crc校验

    在CRC计算时只用8个数据位,起始位及停止位,如有奇偶校验位也包括奇偶校验位,都不参与CRC计算. CRC计算方法是: 1. 加载一值为0XFFFF的16位寄存器,此寄存器为CRC寄存器. 2. 把第 ...

  9. crc16算法php实现,关于实现CRC16校验算法的两个函数

    之前在2017年2月份发布过一个主题,也是关于CRC16的,现在我直接把函数写出来,希望能帮到有需要的朋友.对于在线监测设备数据传输标准来说,CRC16校验算法有基于通用modbus协议的,有基于环保 ...

  10. Adler-32校验算法

    Adler-32校验算法 Adler-32是Mark Adler发明的校验和算法,和32位CRC校验算法一样,都是保护数据防止意外更改的算法,但是这个算法较容易被伪造,所以是不安全的保护措施.但是比C ...

最新文章

  1. ie关闭浏览器tab提示信息
  2. python中setup函数的用法_Vue 3 setup 函数
  3. SqlServer2012清除日志文件
  4. 计算机网络-基本概念(8)【网络层】集线器、网桥和路由器的区别
  5. QT-QPainter绘制曲线等基本图形
  6. 解题报告 Diamonds
  7. 前端“黑话”polyfill
  8. github 创建文件夹
  9. 求数的绝对值一定是正数_人教版初中数学七年级上册绝对值公开课优质课课件教案视频...
  10. java 4位数,java 找出4位数的所有吸血鬼数字
  11. 平衡二叉树删除_AVL 平衡树
  12. 近几年微软笔试题汇总分类解析
  13. Power bi 3.6 百分比堆积柱形图
  14. 利用文本挖掘技术来找出《天龙八部》中的“小鲜词”
  15. 3GPP RAN第一次F2F会议,都干了些啥?
  16. 【九度】题目1419:文献排序
  17. 好佳居窗帘十大品牌 窗帘的发展故事
  18. Golang的单引号、双引号与反引号用法
  19. 每日学习一个设计模式--观察者模式(发布-订阅模式)
  20. 智能风控平台核心之风控决策引擎(四)

热门文章

  1. 一文全记录斐讯K3刷机+打印服务器+私人云盘+frp内网穿透+ftp远程上传下载
  2. Java开发手册(嵩山版)
  3. 20个常用模拟电路(嵌入式硬件篇)
  4. 5款Java微服务开源框架
  5. linux检测摄像头驱动程序,linux usb 摄像头测试软件
  6. 【UnityDragonBones】纸娃娃(一)替换身体部位图片
  7. Hamcrest Tutorial
  8. 使用阿里云code和git管理项目
  9. Windows上提升舒适度的好物分享(没恰饭)
  10. 缠论中枢python源码_缠论画中枢主图指标 源码 通达信 贴图