[应用相关] 如何通俗的理解CRC校验并用C语言实现

[复制链接]
4792|78
 楼主| functions 发表于 2020-4-9 11:09 | 显示全部楼层
使用C语言实现CRC校验
算法1 —— 按位校验思想
CRC4
对于简单的CRC-4,实现代码如下:
  1. #include <stdint.h>

  2. #define CRC4_POLYNOMIAL 0xC8   /* 11011后面补0凑8位数:11011000*/

  3. uint8_t CheckCrc4(uint8_t const message)
  4. {
  5.     uint8_t  remainder;        //余数
  6.     uint8_t  i = 0;         //循环变量

  7.     /* 初始化,余数=原始数据 */
  8.     remainder = message;

  9.     /* 从最高位开始依次计算  */
  10.     for (i = 0; i < 8; i++)
  11.     {
  12.         if (remainder & 0x80)
  13.         {
  14.             remainder ^= POLYNOMIAL;
  15.         }
  16.         remainder = (remainder << 1);
  17.     }

  18.     /* 返回计算的CRC码 */
  19.     return (remainder >> 4);
  20. }
 楼主| functions 发表于 2020-4-9 11:09 | 显示全部楼层
测试代码如下:
  1. #include <stdio.h>
  2. int main(void)
  3. {
  4.     uint8_t dat = 0xB3;
  5.     uint8_t crc = CheckCrc4(dat);

  6.     printf("crc = %#x\n", crc);
  7.     if(crc == 0x4)
  8.     {
  9.         printf("ok.\n");
  10.     }
  11.     else
  12.     {
  13.       printf("fail.\n");
  14.     }

  15.     return 0;
  16. }
 楼主| functions 发表于 2020-4-9 11:11 | 显示全部楼层
运行结果如下:
574785e8e92098da2b.png
 楼主| functions 发表于 2020-4-9 11:11 | 显示全部楼层
CRC8
根据一个字节数据的CRC校验实现思想,两个字节或多个字节的数据也是同样的道理,加一层循环就可以了,代码实现如下:
  1. #define CRC8_POLYNOMIAL 0x31

  2. uint8_t CheckCrc8(uint8_t* const message, uint8_t initial_value)
  3. {
  4.     uint8_t  remainder;        //余数
  5.     uint8_t  i = 0, j = 0;  //循环变量

  6.     /* 初始化 */
  7.     remainder = initial_value;

  8.     for(j = 0; j < 2;j++)
  9.     {
  10.         remainder ^= message[j];

  11.         /* 从最高位开始依次计算  */
  12.         for (i = 0; i < 8; i++)
  13.         {
  14.             if (remainder & 0x80)
  15.             {
  16.                 remainder = (remainder << 1)^CRC8_POLYNOMIAL;
  17.             }
  18.             else
  19.             {
  20.                 remainder = (remainder << 1);
  21.             }
  22.         }
  23.     }

  24.     /* 返回计算的CRC码 */
  25.     return remainder;
  26. }
 楼主| functions 发表于 2020-4-9 11:13 | 显示全部楼层
接下来用最开始在背景中提出的问题进行检,SHT30传感器的数据手册中给出了它计算CRC的生成多项式和初始值,并给出了一个示例,如图:
243215e8e9284d9c9e.png
 楼主| functions 发表于 2020-4-9 11:14 | 显示全部楼层
接下来我们使用示例测试一下:

  1. int main(void)
  2. {
  3.     char dat[2] = {0xBE,0xEF};
  4.     uint8_t crc = CheckCrc8(dat, 0xFF);

  5.     printf("crc = %#x\n", crc);
  6.     if(crc == 0x92)
  7.     {
  8.         printf("ok.\n");
  9.     }
  10.     else
  11.     {
  12.       printf("fail.\n");
  13.     }

  14.     return 0;
  15. }
 楼主| functions 发表于 2020-4-9 11:20 | 显示全部楼层
测试结果如下:
478975e8e932ee78a5.png
 楼主| functions 发表于 2020-4-9 11:22 | 显示全部楼层
算法2 —— 查表思想
生成表
首先需要编写一个程序,计算好所有的8位二进制数的CRC校验码,然后将它保存成一个256B大小的数组。

生成数组的代码如下:
  1. int main(void)
  2. {
  3.     uint16_t i = 0;
  4.     uint8_t crc = 0;

  5.     for(i = 0; i < 256; i++)
  6.     {
  7.         crc = CheckCrc4(i);
  8.         printf("0x%02x, ", crc);
  9.         if((i+1)%16 == 0)
  10.         {
  11.             printf("\n");
  12.         }
  13.     }

  14.     return 0;
  15. }
 楼主| functions 发表于 2020-4-9 11:25 | 显示全部楼层
生成的表如图:
302375e8e958dd0587.png
 楼主| functions 发表于 2020-4-9 11:25 | 显示全部楼层
查找表
将这张表保存为一个数组,然后编写新的校验CRC的程序:
  1. #include <stdio.h>
  2. #include <stdint.h>

  3. uint8_t CRC4_TABLE[256] = {
  4.     //……这里数据太多,省略
  5. };
  6. int main(void)
  7. {
  8.     uint8_t dat = 0xB3;
  9.     uint8_t crc = CRC4_TABLE[dat];      //直接查表

  10.     printf("crc = %#x\n", crc);
  11.     if(crc == 0x04)
  12.     {
  13.         printf("ok.\n");
  14.     }
  15.     else
  16.     {
  17.       printf("fail.\n");
  18.     }
  19.     return 0;
  20. }
 楼主| functions 发表于 2020-4-9 11:28 | 显示全部楼层
两种C语言实现方法比较

905265e8e965563515.png
 楼主| functions 发表于 2020-4-9 11:28 | 显示全部楼层
移植第三方库 —— LibCRC
CRC的计算确实是一个非常头疼的事情,所以国外有大神开源了一个库专门用于CRC计算 —— LibCRC。

Libcrc是一个C语言实现的多平台MIT许可CRC库,其官网链接为:www.libcrc.org,其Github仓库为:LibCRC。

有兴趣的读者可以移植分享一下~
 楼主| functions 发表于 2020-4-9 11:29 | 显示全部楼层
使用硬件CRC校验电路
在STM32L4上有一个专门的CRC校验外设,可以直接使用STM32CubeMX激活CRC校验,然后使用HAL调用进行校验,后续在使用硬件IIC和硬件CRC驱动SHT30这篇**中会有介绍,敬请期待~
 楼主| functions 发表于 2020-4-9 11:30 | 显示全部楼层
**作者:  Mculover666
**链接:  http://www.mculover666.cn/posts/1935373145/
版权声明:  本博客所有**除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Mculover666 !
labasi 发表于 2020-5-7 13:54 | 显示全部楼层
非常感谢楼主分享
paotangsan 发表于 2020-5-7 13:55 | 显示全部楼层
为什么会有这么多种类的算法呢
renzheshengui 发表于 2020-5-7 13:55 | 显示全部楼层
感觉就像是破译密码
wakayi 发表于 2020-5-7 13:56 | 显示全部楼层
有没有一种说法就是哪种算法更好呢 或者说更适用于什么环境
wowu 发表于 2020-5-7 13:56 | 显示全部楼层
解释的条理清晰
hotpower 发表于 2020-5-23 10:58 来自手机 | 显示全部楼层
www.hotcrc.com 它可以自动生成任意CRC表格或算法
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部