C语言CRC通用模块代码

我这几天看了下CRC具体校验原理,我看网上都没有一个通用的CRC库,都是一个函数写一种校验方式的那种,以下代码是随手写的一个通用的CRC软件模块, 支持最小单位字节的输入,有问题大家一起讨论。

#ifndef __CRC_H
#define __CRC_H

#include <stdint.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_t Crc_Width;        /* CRC校验宽度位数 */    
    uint8_t Crc_InputInvert;  /* CRC校验输入反转 */ 
    uint8_t Crc_OutputInvert; /* CRC校验输出反转 */ 
    uint32_t Crc_Poly;        /* CRC校验多项式 */ 
    uint32_t Crc_Init_Value;  /* CRC校验初始值 */ 
    uint32_t Crc_Xorout;      /* CRC校验结果异或值 */ 
} CRC_TYPE;

uint32_t calc_crc(E_CRC_TYPE crc_type, uint8_t *pData, uint16_t u16Len);

#endif
#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},
};

/**
 * @brief  数据按位反转(支持小于等于32位数据反转)
 * @param  OutBuf                输出缓存首地址
 * @param  InBuf                 输入缓存首地址
 * @param  Bit_Len               位长度
 * @author xpx @date 2024-05-17 @version 1.0
 */
static void Data_Bit_Invert(uint8_t *OutBuf, uint8_t *InBuf, uint8_t Bit_Len)
{
	uint8_t i;
	uint32_t Intmp = 0;
    uint32_t 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))));
    }
}

/**
 * @brief  CRC校验函数接口(数据输入最小单位为字节)
 * @param  crc_type              CRC校验方式
 * @param  pData                 数据缓存首地址
 * @param  u16Len                数据字节长度
 * @return CRC校验值
 * @author xpx @date 2024-05-17 @version 1.0
 */
uint32_t calc_crc(E_CRC_TYPE crc_type, uint8_t *pData, uint16_t u16Len)
{
    uint8_t tmpdata = 0;
    uint8_t Crc_Width = crc_map[crc_type].Crc_Width;        /* CRC校验宽度位数 */    
    uint8_t Crc_InputInvert = crc_map[crc_type].Crc_InputInvert;  /* CRC校验输入反转 */ 
    uint8_t Crc_OutputInvert = crc_map[crc_type].Crc_OutputInvert; /* CRC校验输出反转 */ 
    uint32_t Crc_Poly = crc_map[crc_type].Crc_Poly;        /* CRC校验多项式 */ 
    uint32_t Crc_Init_Value = crc_map[crc_type].Crc_Init_Value;  /* CRC校验初始值 */ 
    uint32_t Crc_Xorout = crc_map[crc_type].Crc_Xorout;      /* CRC校验结果异或值 */     
	uint32_t 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_t 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_t) - Crc_Width));    /*截取CRC数据*/
        
        pData++;
	}

    if(TRUE == Crc_OutputInvert)        /* 输出数据反转(REFOUT)*/
    {
        Data_Bit_Invert((uint8_t*)&u32CrcVal, (uint8_t*)&u32CrcVal, Crc_Width);
    }    
    
    u32CrcVal ^= Crc_Xorout;            /* 输出结果异或XOROUT值*/

	return u32CrcVal;	
}

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值