赞
踩
本文承接CRC校验算法及C语言实现,继续实现CRC16的校验算法。
CRC16常见的标准有以下几种,被用在各个规范中,其算法原理基本一致,就是在数据的输入和输出有所差异,下边把这些标准的差异列出,并给出C语言的算法实现。
定义多项式和初始值及结果处理(根据上表):
#define POLYNOMIAL 0x1021
#define POLY_INIT 0x0000
#define POLY_END 0x0000
CRC16代码实现方式(通用):
uint16_t crc16(uint8_t *ptr, unsigned char len,uint8_t input_invert)
{
unsigned char i;
uint16_t crc=POLY_INIT; /* 计算的初始crc值 */
const uint16_t polynomial= POLYNOMIAL;
while(len--)
{
if(input_invert)
{
crc ^= (uint16_t)(*ptr++); /* 每次先与需要计算的数据异或,计算完指向下一数据 */
for (i=8; i>0; --i) /* 下面这段计算过程与计算一个字节crc一样 */
{
if (crc & 0x0001)
crc = (crc >> 1) ^ (uint16_t)reverse_bits(polynomial,16);
else
crc = (crc >> 1);
}
//printf("0x%.4x, ", crc);
}else{
crc ^=((uint16_t)(*ptr++)<<8);
for (i=8; i>0; --i) /* 下面这段计算过程与计算一个字节crc一样 */
{
if (crc & 0x8000)
crc = (crc << 1) ^ polynomial;
else
crc = (crc << 1);
}
//printf("0x%.4x, ", crc);
}
}
crc=crc^POLY_END;
return (crc);
}
优化时间(空间换时间)
uint16_t crc16_plus(uint8_t *ptr, unsigned char len,uint8_t input_invert)
{
unsigned char i;
uint16_t index;
uint16_t to_xor;
uint16_t crc=POLY_INIT; /* 计算的初始crc值 */
const uint16_t polynomial= POLYNOMIAL;
while(len--)
{
if(input_invert)
{
index= (crc ^(uint16_t)(*ptr++))&0xFF;
to_xor=index;
for (i=8; i>0; --i) /* 下面这段计算过程与计算一个字节crc一样 */
{
if (to_xor & 0x0001)
to_xor = (to_xor >> 1) ^ (uint16_t)reverse_bits(polynomial,16);
else
to_xor = (to_xor >> 1);
}
crc=(crc>>8)^to_xor;
}else
{
index= (crc ^((uint16_t)(*ptr++)<<8))&0xFF00;
to_xor=index;
for (i=8; i>0; --i) /* 下面这段计算过程与计算一个字节crc一样 */
{
if (to_xor & 0x8000)
to_xor = (to_xor << 1) ^ polynomial;
else
to_xor = (to_xor << 1);
}
//printf("0x%.4x, ", crc);
//printf("0x%.4x, ", to_xor);
crc=(crc<<8)^to_xor;
}
}
crc=crc^POLY_END;
return (crc);
}
校验码表格元素生成:
uint16_t crc16_cal_table(uint8_t value,uint8_t input_invert)
{
unsigned char i;
uint16_t crc=POLY_INIT; /* 计算的初始crc值 */
const uint16_t polynomial= POLYNOMIAL;
if(input_invert)
{
crc =(uint16_t)value;
for (i=8; i>0; --i) /* 下面这段计算过程与计算一个字节crc一样 */
{
if (crc & 0x0001)
crc = (crc >> 1) ^ (uint16_t)reverse_bits(polynomial,16);
else
crc = (crc >> 1);
}
//printf("0x%.4x, ", crc);
}else{
crc =(((uint16_t)value)<<8);
for (i=8; i>0; --i) /* 下面这段计算过程与计算一个字节crc一样 */
{
if (crc & 0x8000)
crc = (crc << 1) ^ polynomial;
else
crc = (crc << 1);
}
//printf("0x%.4x, ", crc);
}
crc=crc^POLY_END;
return crc;
}
查表计算校验码函数:
uint16_t crc16_calc(const uint8_t *data, uint8_t len,uint8_t input_invert) {
uint16_t crc = POLY_INIT;
uint16_t i;
if(input_invert)
{
for (i = 0; i < len; i++) {
crc = (crc >> 8) ^ crc16_table[(crc ^ data[i]) & 0xFF];
}
}else
{
for (i = 0; i < len; i++) {
crc = (crc << 8) ^ crc16_table[((crc>>8) ^ data[i]) & 0xFF];
}
}
return crc;
}
表格生成函数(输出完整表格):
void create_crc16_table(void)
{
unsigned short i;
unsigned char j;
printf("unsigned uint16_t crc16_table[256] =\n{");
for (i=0; i<=0xFF; i++)
{
if (0 == (i%16))
printf("\n");
j = i&0xFF;
printf("0x%.4x, ", crc16_cal_table (j)); /*依次计算每个字节的crc校验值*/
if(i==0xFF){
printf("\n");
break;
}
}
printf("};");
}
按位颠倒:
uint32_t reverse_bits(uint32_t num, int num_bits) {
uint32_t result = 0;
int i;
for (i = 0; i < num_bits; i++) {
result = (result << 1) | (num & 1);
num >>= 1;
}
return result;
}
以上代码均通过验证。
因为篇幅较长,CRC8及CRC32请移步以下链接:
CRC8校验算法及C语言实现:https://blog.csdn.net/qq_28149763/article/details/134491529?spm=1001.2014.3001.5502
CRC32校验算法及C语言实现:https://blog.csdn.net/qq_28149763/article/details/134492023
PDF文档已上传(包括CRC8+CRC16+CRC32):https://download.csdn.net/download/qq_28149763/88552040
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。