我这几天看了下CRC具体校验原理,我看网上都没有一个通用的CRC库,都是一个函数写一种校验方式的那种,以下代码是随手写的一个通用的CRC软件模块, 支持最小单位字节的输入,有问题大家一起讨论。移植时需要修改的点可能是数据类型的重新定义。
/******************************************************************************************
源文件名: crc.h
文件描述: CRC校验
作者信息: Bachelor Tse
创建日期: 2024-04-01
最新版本: 0.0.1
修改记录:
*****************************************************************************/
#ifndef __CRC_H
#define __CRC_H
#include "BSPTypeDef.h"
typedef enum
{
CRC4_ITU, /*CRC-4/ITU*/
CRC5_EPC, /*CRC-5/EPC*/
CRC5_ITU, /*CRC-5/ITU*/
CRC5_USB, /*CRC-5/USB*/
CRC6_ITU, /*CRC-6/ITU*/
CRC7_MMC, /*CRC-7/MMC*/
CRC8, /*CRC-8*/
CRC8_ITU, /*CRC-8/ITU*/
CRC8_ROHC, /*CRC-8/ROHC*/
CRC8_MAXIM, /*CRC-8/MAXIM*/
CRC16_IBM, /*CRC-16/ITU*/
CRC16_MAXIM, /*CRC-16/MAXIM*/
CRC16_USB, /*CRC-16/USB*/
CRC16_MODBUS, /*CRC-16/MODBUS*/
CRC16_CCITT, /*CRC-16/CCITT*/
CRC16_CCITT_FALSE, /*CRC-16/CCITT_FALSE*/
CRC16_X25, /*CRC-16/X25*/
CRC16_XMODEM, /*CRC-16/XMODEM*/
CRC16_DNP, /*CRC-16/DNP*/
CRC32, /*CRC-32*/
CRC32_MPEG2, /*CRC-32/MPEG-2*/
CRC_TYPE_NUM, /*CRC校验方式数量*/
} E_CRC_TYPE;
typedef struct
{
E_CRC_TYPE Crc_Type; /*CRC校验方式*/
uint8 Crc_Width; /*CRC校验宽度位数*/
uint8 Crc_InputInvert; /*CRC校验输入反转*/
uint8 Crc_OutputInvert; /*CRC校验输出反转*/
uint32 Crc_Poly; /*CRC校验多项式*/
uint32 Crc_Init_Value; /*CRC校验初始值*/
uint32 Crc_Xorout; /*CRC校验结果异或值*/
} CRC_TYPE;
/******************** 全局函数声明 ********************/
uint32 calc_crc(E_CRC_TYPE crc_type, uint8 *pData, uint16 u16Len);
/**************************************************************/
#endif
/***************************************************************************************************
源文件名: crc.c
文件描述: CRC校验
作者信息: Bachelor Tse
创建日期: 2024-04-01
最新版本: 0.0.1
修改记录:
*****************************************************************************/
#include "crc.h"
CRC_TYPE crc_map[] = {
/*CRC校验方式 宽度位数 输入反转 输出反转 多项式 初始值 结果异或值*/
{CRC4_ITU, 4, TRUE, TRUE, 0x03, 0x00, 0x00},
{CRC5_EPC, 5, FALSE, FALSE, 0x09, 0x09, 0x00},
{CRC5_ITU, 5, TRUE, TRUE, 0x15, 0x00, 0x00},
{CRC5_USB, 5, TRUE, TRUE, 0x05, 0x1F, 0x1F},
{CRC6_ITU, 6, TRUE, TRUE, 0x03, 0x00, 0x00},
{CRC7_MMC, 7, FALSE, FALSE, 0x09, 0x00, 0x00},
{CRC8, 8, FALSE, FALSE, 0x07, 0x00, 0x00},
{CRC8_ITU, 8, FALSE, FALSE, 0x07, 0x00, 0x55},
{CRC8_ROHC, 8, TRUE, TRUE, 0x07, 0xFF, 0x00},
{CRC8_MAXIM, 8, TRUE, TRUE, 0x31, 0x00, 0x00},
{CRC16_IBM, 16, TRUE, TRUE, 0x8005, 0x0000, 0x0000},
{CRC16_MAXIM, 16, TRUE, TRUE, 0x8005, 0x0000, 0xFFFF},
{CRC16_USB, 16, TRUE, TRUE, 0x8005, 0xFFFF, 0xFFFF},
{CRC16_MODBUS, 16, TRUE, TRUE, 0x8005, 0xFFFF, 0x0000},
{CRC16_CCITT, 16, TRUE, TRUE, 0x1021, 0x0000, 0x0000},
{CRC16_CCITT_FALSE, 16, FALSE, FALSE, 0x1021, 0xFFFF, 0x0000},
{CRC16_X25, 16, TRUE, TRUE, 0x1021, 0xFFFF, 0xFFFF},
{CRC16_XMODEM, 16, FALSE, FALSE, 0x1021, 0x0000, 0x0000},
{CRC16_DNP, 16, TRUE, TRUE, 0x3D65, 0x0000, 0xFFFF},
{CRC32, 32, TRUE, TRUE, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF},
{CRC32_MPEG2, 32, FALSE, FALSE, 0x04C11DB7, 0xFFFFFFFF, 0x00000000},
};
/******************** 静态函数声明 ********************/
static void Data_Bit_Invert(uint8_t *OutBuf, uint8_t *InBuf, uint8 Bit_Len);
/**************************************************************/
/******************** 静态函数Start ********************/
/*=============================================================================================
** Function : static void Data_Bit_Invert(uint8_t *OutBuf, uint8_t *InBuf, uint8 Bit_Len)
** Description : v0.1 2024-04-01 xpx
** Remark : 数据按位反转(支持小于等于32位数据反转)
=============================================================================================*/
static void Data_Bit_Invert(uint8_t *OutBuf, uint8_t *InBuf, uint8 Bit_Len)
{
uint8 i;
uint32 Intmp = 0;
uint32 Outtmp = 0;
if((void*)0 == OutBuf || (void*)0 == InBuf || 32 < Bit_Len)
{
return;
}
for(i = 0; i < Bit_Len / 8; i++)
{
Intmp |= (InBuf[i] << (i * 8));
}
if(0 != Bit_Len%8)
{
Intmp |= ((InBuf[i] << (i * 8)) & ((0xFF >> (8 - (Bit_Len % 8))) << (i * 8)));
}
for(i = 0; i < Bit_Len; i++)
{
if(Intmp & (1 << i))
{
Outtmp |= (1 << (Bit_Len - 1 - i));
}
}
for(i = 0; i < Bit_Len / 8; i++)
{
OutBuf[i] = ((Outtmp >> (i * 8)) & 0xFF);
}
if(0 != Bit_Len % 8)
{
OutBuf[i] &= (~(0xFF >> (8 - (Bit_Len % 8))));
OutBuf[i] |= ((Outtmp >> (i * 8)) & (0xFF >> (8 - (Bit_Len % 8))));
}
}
/******************** 静态函数End ********************/
/******************** 全局函数Start ********************/
/*=============================================================================================
** Function : uint32 calc_crc(E_CRC_TYPE crc_type, uint8 *pData, uint16 u16Len)
** Description : v0.1 2024-04-01 xpx
** Remark : CRC校验函数接口(数据输入最小单位为字节)
=============================================================================================*/
uint32 calc_crc(E_CRC_TYPE crc_type, uint8 *pData, uint16 u16Len)
{
uint8 tmpdata = 0;
uint8 Crc_Width = crc_map[crc_type].Crc_Width; /*CRC校验宽度位数*/
uint8 Crc_InputInvert = crc_map[crc_type].Crc_InputInvert; /*CRC校验输入反转*/
uint8 Crc_OutputInvert = crc_map[crc_type].Crc_OutputInvert; /*CRC校验输出反转*/
uint32 Crc_Poly = crc_map[crc_type].Crc_Poly; /*CRC校验多项式*/
uint32 Crc_Init_Value = crc_map[crc_type].Crc_Init_Value; /*CRC校验初始值*/
uint32 Crc_Xorout = crc_map[crc_type].Crc_Xorout; /*CRC校验结果异或值*/
uint32 u32CrcVal = 0;
if ((void*)0 == pData || 0 == u16Len || CRC_TYPE_NUM <= crc_type)
{
return u32CrcVal;
}
u32CrcVal = Crc_Init_Value; /* CRC寄存器装载初始值INIT */
while(u16Len--)
{
if(TRUE == Crc_InputInvert) /* 输入数据反转(REFIN)*/
{
Data_Bit_Invert(&tmpdata, pData, 8);
}
else
{
tmpdata = *pData;
}
if(Crc_Width >= 8) /* 需将字节数据最高位与CRC校验值最高位对齐再异或 */
{
u32CrcVal ^= (tmpdata << (Crc_Width - 8));
}
else
{
u32CrcVal <<= (8 - Crc_Width); /* CRC校验宽度位数小于8时 将CRC校验值最高位与字节数据最高位(第7位)对齐 */
u32CrcVal ^= tmpdata;
}
for (uint8 i = 0; i < 8; i++)
{
if(Crc_Width >= 8)
{
if (u32CrcVal & (0x00000001 << (Crc_Width - 1)))
{
u32CrcVal <<= 1;
u32CrcVal ^= Crc_Poly;
}
else
{
u32CrcVal <<= 1;
}
}
else /* 上方因便于数据计算而对齐至第7位,故CRC校验值异或多项式时也需将其移位 */
{
if (u32CrcVal & (0x00000001 << 7))
{
u32CrcVal <<= 1;
u32CrcVal ^= (Crc_Poly << (8 - Crc_Width));
}
else
{
u32CrcVal <<= 1;
}
}
}
if(Crc_Width >= 8)
{
}
else /* CRC校验宽度位数小于8时,为了便于数据计算而对齐,故输出时需将其恢复原位 */
{
u32CrcVal >>= (8 - Crc_Width);
}
u32CrcVal &= (0xFFFFFFFF >> (8 * sizeof(uint32) - Crc_Width)); /*截取CRC数据*/
pData++;
}
if(TRUE == Crc_OutputInvert) /* 输出数据反转(REFOUT)*/
{
Data_Bit_Invert((uint8*)&u32CrcVal, (uint8*)&u32CrcVal, Crc_Width);
}
u32CrcVal ^= Crc_Xorout; /* 输出结果异或XOROUT值*/
return u32CrcVal;
}
/******************** 全局函数End ********************/