C语言CRC通用模块代码

发布于:2024-04-14 ⋅ 阅读:(155) ⋅ 点赞:(0)

我这几天看了下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     ********************/

网站公告

今日签到

点亮在社区的每一天
去签到