CRC校验本质就是将数据视作一个大整数使用指定POLY进行模二除法(异或)。行业上的CRC算法和网页上( 比如CRC(循环冗余校验)在线计算_ip33.com)的算法刚好左右相反比如0x8408会视为0x1021。这或许是手写和计算机数字表达方式不一致导致的。所以下面代码考虑了这点而写的。转换算法用碟式运算。此代码是基于c51设计的,仅是为了节省代码空间,所以尽量设计更通用。
#define CONFIG_CRC_POLY_INVERT 0 // 行业算法一般不使用反转,如果要在网页得出一致结果可以在调试时使用反转
typedef struct CRC16_PARAMS_ST{
u16 preval; // crc初始值
u16 xorout; // 输出值异或
u16 poly; // 表达式
bt is_input_invert; // 是否输入反转
bt is_output_invert; // 是否输出发转
}CRC16_PARAMS;
// 8位数据反转
u8 invert_u8_in_bit(u8 val)
{
u8 _dat;
_dat = (val << 4)|(val >> 4);
_dat = ((_dat << 2) & 0xcc)|((_dat >> 2) & 0x33);
_dat = ((_dat << 1) & 0xaa)|((_dat >> 1) & 0x55);
return _dat;
}
// 16位数据反转
u16 invert_u16_in_bit(u16 val)
{
u16 _dat;
_dat = (val << 8) | (val >> 8);
_dat = ((_dat << 4) & 0xF0FF) | ((_dat >> 4) & 0xFF0F);
_dat = ((_dat << 2) & 0xCCCC) | ((_dat >> 2) & 0x3333);
_dat = ((_dat << 1) & 0xAAAA) | ((_dat >> 1) & 0x5555);
return _dat;
}
u16 crypto_crc16_common(u8 xdata* buf, u16 len, CRC16_PARAMS xdata* params)
{
u8 _i, _dat;
u16 _chksum;
#if CONFIG_CRC_POLY_INVERT
u16 _poly;
_poly = invert_u16_in_bit(params->poly);
#else
#define _poly (params->poly)
#endif
_chksum = params->preval;
for (; len > 0; len--)
{
if(!params->is_input_invert)
_dat = invert_u8_in_bit(buf[0]);
else
_dat = buf[0];
_chksum ^= _dat; buf++;
for (_i = 0; _i < 8; _i++)
{
if (_chksum & 1)
_chksum = (_chksum >> 1) ^ _poly;
else
_chksum >>= 1;
}
}
if(!params->is_output_invert)
_chksum = invert_u16_in_bit(_chksum);
return(_chksum ^ params->xorout);
}