先放原文链接:CRC32校验算法C语言版(查表法)
这几天搞串口通信,用到CRC32,把以前用到的东西整理一下,方便以后使用。
STM32F103 芯片自带的CRC32硬件算法,匹配上位机CRC32算法。
CRC校验变化太多,有CRC4/5/6/7/8/16/32,每一种的多项式也有很多种变化,输入输出方式也有区别,有一些初始值是0,有一些初始值是0xFFFFFFFF,有一些直接返回,有一些异或返回,因此,CRC校验很难用一个代码兼容全部,只能根据具体项目修改相关参数。
本次使用查表法处理:
计算方法:
-
先要知道多项式是什么样子,以这个IEEE802.3标准CRC32多项式为例:x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x+ 1,根据位取值不同,会有各种多项式。
-
STM32F103 使用CRC-32(以太网)多项式:0x4C11DB7
x32 则对应32bit = 1, x26 则对应26bit=1,得出一个值:(1<<32)|(1<<26)|(1<<23)|(1<<22)|…|(1<<1)|(1)=0x104C11DB7,最高位固定为1,均忽略,对于CRC32取低32位,则多项式的值为 0x4C11DB7 -
用这个值生成长度为256的码表,对于CRC32表内每个元素都为32bit.
-
使用时查表得出CRC32值。
具体算法代码如下
/*
* CRC校验算法,查表法
*/
#include "crc.h"
static unsigned long table[256];
//位翻转
static unsigned long bitrev(unsigned long input, int bw)
{
int i;
unsigned long var;
var = 0;
for(i=0;i<bw;i++)
{
if(input & 0x01)
{
var |= 1<<(bw-1-i);
}
input>>=1;
}
return var;
}
//码表生成
//如:X32+X26+...X1+1,poly=(1<<26)|...|(1<<1)|(1<<0)
void crc32_init(unsigned long poly)
{
int i;
int j;
unsigned long c;
poly=bitrev(poly,32);
for(i=0; i<256; i++)
{
c = i;
for (j=0; j<8; j++)
{
if(c&1)
{
c=poly^(c>>1);
}
else
{
c=c>>1;
}
}
table[i] = c;
}
}
unsigned long crc32(unsigned long crc, void* input, int len)
{
int i;
unsigned char index;
unsigned char* pch;
pch = (unsigned char*)input;
for(i=0;i<len;i++)
{
index = (unsigned char)(crc^*pch);
crc = (crc>>8)^table[index];
pch++;
}
return crc;
}
测试用例:
void main(void)
{
unsigned long crc;
crc32_init(0x4C11DB7,table);
crc = 0xFFFFFFFF;
crc=crc32(crc,"1234567890",10);
crc ^= 0xFFFFFFFF;
printf("CRC32=%08X\n",crc);
system("pause");
}
计算结果:CRC32=0x261DAEE5
注意:实际使用中可能会调整 CRC 的初值为 0 或 位翻转。