目录

04.01_CRC-所有内置的CRC模型

测试步骤

先后计算01 02 03 04 05不同模型下的结果,然后和已知的CRC结果进行对比。

实测数据

参数模型计算结果,数据:{1, 2, 3, 4, 5}测试结果
CRC80xBC正确
CRC8_ITU0xE9正确
CRC8_MAXIM0x2A正确
CRC8_ROHC0xFE正确
CRC16_IBM0xBB0E正确
CRC16_MAXIM0x44F1正确
CRC16_USB0x44D5正确
CRC16_MODBUS0xBB2A正确
CRC16_CCITT0xED9B正确
CRC16_CCITT_FALSE0x9304正确
CRC16_X250x22EC正确
CRC16_XMODEM0x8208正确
CRC16_DNP0xE674正确
CRC320x470B99F4正确
CRC32_MPEG_20xE28F4B83正确

参考代码

04.01_CRC_Calc.c

/**
 * @brief CRC-所有内置的CRC模型
 * @details
 * 先后计算01 02 03 04 05不同模型下的结果,然后和已知的CRC结果进行对比。
 */
#include "lks32mc09x_lib.h"

u8 crc_data[5] = {1, 2, 3, 4, 5};
volatile uint32_t crc8_answer, crc8_ITU_answer, crc8_ROHC_answer, crc8_MAXIM_answer;
volatile uint32_t crc16_IBM_answer, crc16_MAXIM_answer, crc16_USB_answer, crc16_MODBUS_answer, crc16_CCITT_answer, crc16_CCITT_FALSE_answer, crc16_X25_answer, crc16_XMODEM_answer, crc16_DNP_answer;
volatile uint32_t crc32_answer, crc32_MPEG_2_answer;

volatile uint32_t crc8_errflg = 0;
volatile uint32_t crc8_ITU_errflg = 0;
volatile uint32_t crc8_ROHC_errflg = 0;
volatile uint32_t crc8_MAXIM_errflg = 0;
volatile uint32_t crc16_IBM_errflg = 0;
volatile uint32_t crc16_MAXIM_errflg = 0;
volatile uint32_t crc16_USB_errflg = 0;
volatile uint32_t crc16_MODBUS_errflg = 0;
volatile uint32_t crc16_CCITT_errflg = 0;
volatile uint32_t crc16_CCITT_FALSE_errflg = 0;
volatile uint32_t crc16_X25_errflg = 0;
volatile uint32_t crc16_XMODEM_errflg = 0;
volatile uint32_t crc16_DNP_errflg = 0;
volatile uint32_t crc32_errflg = 0;
volatile uint32_t crc32_MPEG_2_errflg = 0;

int main(void)
{
    crc8_answer = CRC_CalcCommon(CRC0, crc_data, sizeof(crc_data), CRC_MODEL_CRC_8);                           ///< 计算CRC_8
    crc8_ITU_answer = CRC_CalcCommon(CRC0, crc_data, sizeof(crc_data), CRC_MODEL_CRC_8_ITU);                   ///< 计算CRC_8_ITU
    crc8_ROHC_answer = CRC_CalcCommon(CRC0, crc_data, sizeof(crc_data), CRC_MODEL_CRC_8_ROHC);                 ///< 计算CRC_8_ROHC
    crc8_MAXIM_answer = CRC_CalcCommon(CRC0, crc_data, sizeof(crc_data), CRC_MODEL_CRC_8_MAXIMx);              ///< 计算CRC_8_MAXIMx
    crc16_IBM_answer = CRC_CalcCommon(CRC0, crc_data, sizeof(crc_data), CRC_MODEL_CRC_16_IBMx1);               ///< 计算CRC_16_IBMx1
    crc16_MAXIM_answer = CRC_CalcCommon(CRC0, crc_data, sizeof(crc_data), CRC_MODEL_CRC_16_MAXIM);             ///< 计算CRC_16_MAXIM
    crc16_USB_answer = CRC_CalcCommon(CRC0, crc_data, sizeof(crc_data), CRC_MODEL_CRC_16_USBx1);               ///< 计算CRC_16_USBx1
    crc16_MODBUS_answer = CRC_CalcCommon(CRC0, crc_data, sizeof(crc_data), CRC_MODEL_CRC_16_MODBU);            ///< 计算CRC_16_MODBU
    crc16_CCITT_answer = CRC_CalcCommon(CRC0, crc_data, sizeof(crc_data), CRC_MODEL_CRC_16_CCITT);             ///< 计算CRC_16_CCITT
    crc16_CCITT_FALSE_answer = CRC_CalcCommon(CRC0, crc_data, sizeof(crc_data), CRC_MODEL_CRC_16_CCITT_FALSE); ///< 计算CRC_16_CCITT_FALSE
    crc16_X25_answer = CRC_CalcCommon(CRC0, crc_data, sizeof(crc_data), CRC_MODEL_CRC_16_X25);                 ///< 计算CRC_16_X25
    crc16_XMODEM_answer = CRC_CalcCommon(CRC0, crc_data, sizeof(crc_data), CRC_MODEL_CRC_16_XMODEM);           ///< 计算CRC_16_XMODEM
    crc16_DNP_answer = CRC_CalcCommon(CRC0, crc_data, sizeof(crc_data), CRC_MODEL_CRC_16_DNP);                 ///< 计算CRC_16_DNP
    crc32_answer = CRC_CalcCommon(CRC0, crc_data, sizeof(crc_data), CRC_MODEL_CRC_32);                         ///< 计算CRC_32
    crc32_MPEG_2_answer = CRC_CalcCommon(CRC0, crc_data, sizeof(crc_data), CRC_MODEL_CRC_32_MPEG_2);           ///< 计算CRC_32_MPEG_2

    if (crc8_answer != 0xbc)
    {
        crc8_errflg = 1;
    }
    if (crc8_ITU_answer != 0xe9)
    {
        crc8_ITU_errflg = 1;
    }
    if (crc8_ROHC_answer != 0xfe)
    {
        crc8_ROHC_errflg = 1;
    }
    if (crc8_MAXIM_answer != 0x2a)
    {
        crc8_MAXIM_errflg = 1;
    }
    if (crc16_IBM_answer != 0xbb0e)
    {
        crc16_IBM_errflg = 1;
    }
    if (crc16_MAXIM_answer != 0x44f1)
    {
        crc16_MAXIM_errflg = 1;
    }
    if (crc16_USB_answer != 0x44d5)
    {
        crc16_USB_errflg = 1;
    }
    if (crc16_MODBUS_answer != 0xbb2a)
    {
        crc16_MODBUS_errflg = 1;
    }
    if (crc16_CCITT_answer != 0xed9b)
    {
        crc16_CCITT_errflg = 1;
    }
    if (crc16_CCITT_FALSE_answer != 0x9304)
    {
        crc16_CCITT_FALSE_errflg = 1;
    }
    if (crc16_X25_answer != 0x22ec)
    {
        crc16_X25_errflg = 1;
    }
    if (crc16_XMODEM_answer != 0x8208)
    {
        crc16_XMODEM_errflg = 1;
    }
    if (crc16_DNP_answer != 0xe674)
    {
        crc16_DNP_errflg = 1;
    }
    if (crc32_answer != 0x470b99f4)
    {
        crc32_errflg = 1;
    }
    if (crc32_MPEG_2_answer != 0xe28f4b83)
    {
        crc32_MPEG_2_errflg = 1;
    }
    for (;;)
    {
    }
}

使用到的库函数

库函数部分代码

#define CRC0 ((CRC_TypeDef *)CRC0_BASE)
#define CRC_MODEL_CRC_16_CCITT 8
#define CRC_MODEL_CRC_16_CCITT_FALSE 9
#define CRC_MODEL_CRC_16_DNP 12
#define CRC_MODEL_CRC_16_MAXIM 5
#define CRC_MODEL_CRC_16_MODBU 7
#define CRC_MODEL_CRC_16_X25 10
#define CRC_MODEL_CRC_16_XMODEM 11
#define CRC_MODEL_CRC_32 13
#define CRC_MODEL_CRC_32_MPEG_2 14
#define CRC_MODEL_CRC_8 0
#define CRC_MODEL_CRC_8_ITU 1
#define CRC_MODEL_CRC_8_ROHC 2
#define CRC_WIDTH_16 1
#define CRC_WIDTH_32 0
#define CRC_WIDTH_7 3
#define CRC_WIDTH_8 2
#define REG_RESET(reg,mask) reg &= ~(mask)
#define REG_SET(reg,mask) reg |= (mask)
#define REG_WRITE(reg,mask) reg = (mask)
#define SYS0 ((SYS_TypeDef *)(SYS_BASE))
#define SYS_MODULE_CRC0 BIT16
/**
 * @brief CRC初始化结构体
 */
typedef struct CRC_InitTypeDef {
    uint32_t POLY;
    uint32_t INIT;
    uint32_t XOROUT;
    uint8_t REFIN;
    uint8_t REFOUT;
    uint8_t WIDTH;
    uint8_t null;
};
/**
 * @brief CRC计算初始化
 */
void CRC_Init(CRC_TypeDef *CRCx, CRC_InitTypeDef *CRC_InitStruct)
{
    if (CRC_InitStruct->WIDTH > 3)
    {
        switch (CRC_InitStruct->WIDTH)
        {
            case 7:
                CRC_InitStruct->WIDTH = CRC_WIDTH_7;
                break;
            case 8:
                CRC_InitStruct->WIDTH = CRC_WIDTH_8;
                break;
            case 16:
                CRC_InitStruct->WIDTH = CRC_WIDTH_16;
                break;
            case 32:
                CRC_InitStruct->WIDTH = CRC_WIDTH_32;
                break;
            default:
                CRC_InitStruct->WIDTH = CRC_WIDTH_8;
                break;
        }
    }
    else
    {
        __NOP();
    }
    CRC_Enable(CRCx);
    SYS_SoftResetModule(SYS_MODULE_CRC0);
    CRC0_CR = (u32)(CRC_InitStruct->REFOUT << 12) | (u32)(CRC_InitStruct->REFIN << 8) | (u32)(CRC_InitStruct->WIDTH << 4);
    CRC0_CR |= BIT0; // 复位
    CRC0_POL  = CRC_InitStruct->POLY;
    CRC0_INIT = CRC_InitStruct->INIT;
    if (CRC_InitStruct->WIDTH == CRC_WIDTH_16)
    {
        CRC_XOROUT = CRC_InitStruct->XOROUT << 16;
    }
    else
    {
        CRC_XOROUT = CRC_InitStruct->XOROUT;
    }
}
/**
 * @brief 使用常见模型计算CRC值
 * @param CRCx CRC模块指针
 * @param data 数据指针
 * @param len 数据长度
 * @param CRC_MODEL_x CRC模型
 * @return 计算得到的CRC值
 */
uint32_t CRC_CalcCommon(CRC_TypeDef *CRCx, uint8_t *data, uint32_t len, uint16_t CRC_MODEL_x)
{
    u32 val;
    CRC_InitTypeDef CRC_InitStruct;
    switch (CRC_MODEL_x)
    {
        case CRC_MODEL_CRC_8: //  8   07          00          00          false   false

            CRC_InitStruct.WIDTH  = CRC_WIDTH_8; // 宽度
            CRC_InitStruct.POLY   = 0x07;        // 多项式
            CRC_InitStruct.INIT   = 0x00;        // 初始值
            CRC_InitStruct.XOROUT = 0x00;        // 结果异或值
            CRC_InitStruct.REFIN  = DISABLE;     // 输入数据反转
            CRC_InitStruct.REFOUT = DISABLE;     // 输出数据反转
            CRC_Init(CRCx, &CRC_InitStruct);
            break;
        case CRC_MODEL_CRC_8_ITU:                // 8   07          00          55          false   false
            CRC_InitStruct.WIDTH  = CRC_WIDTH_8; // 宽度
            CRC_InitStruct.POLY   = 0x07;        // 多项式
            CRC_InitStruct.INIT   = 0x00;        // 初始值
            CRC_InitStruct.XOROUT = 0x55;        // 结果异或值
            CRC_InitStruct.REFIN  = DISABLE;     // 输入数据反转
            CRC_InitStruct.REFOUT = DISABLE;     // 输出数据反转
            CRC_Init(CRCx, &CRC_InitStruct);
            break;
        case CRC_MODEL_CRC_8_ROHC: //  8   07          FF          00          true    true

            CRC_InitStruct.WIDTH  = CRC_WIDTH_8; // 宽度
            CRC_InitStruct.POLY   = 0x07;        // 多项式
            CRC_InitStruct.INIT   = 0xff;        // 初始值
            CRC_InitStruct.XOROUT = 0x00;        // 结果异或值
            CRC_InitStruct.REFIN  = ENABLE;      // 输入数据反转
            CRC_InitStruct.REFOUT = ENABLE;      // 输出数据反转
            CRC_Init(CRCx, &CRC_InitStruct);
            break;
        case CRC_MODEL_CRC_8_MAXIMx: //  8   31          00          00          true    true

            CRC_InitStruct.WIDTH  = CRC_WIDTH_8; // 宽度
            CRC_InitStruct.POLY   = 0x31;        // 多项式
            CRC_InitStruct.INIT   = 0x00;        // 初始值
            CRC_InitStruct.XOROUT = 0x00;        // 结果异或值
            CRC_InitStruct.REFIN  = ENABLE;      // 输入数据反转
            CRC_InitStruct.REFOUT = ENABLE;      // 输出数据反转
            CRC_Init(CRCx, &CRC_InitStruct);
            break;
        case CRC_MODEL_CRC_16_IBMx1: //  16  8005        0000        0000        true    true

            CRC_InitStruct.WIDTH  = CRC_WIDTH_16; // 宽度
            CRC_InitStruct.POLY   = 0x8005;       // 多项式
            CRC_InitStruct.INIT   = 0x0000;       // 初始值
            CRC_InitStruct.XOROUT = 0x0000;       // 结果异或值
            CRC_InitStruct.REFIN  = ENABLE;       // 输入数据反转
            CRC_InitStruct.REFOUT = ENABLE;       // 输出数据反转
            CRC_Init(CRCx, &CRC_InitStruct);
            break;
        case CRC_MODEL_CRC_16_MAXIM: //  16  8005        0000        FFFF        true    true

            CRC_InitStruct.WIDTH  = CRC_WIDTH_16; // 宽度
            CRC_InitStruct.POLY   = 0x8005;       // 多项式
            CRC_InitStruct.INIT   = 0x0000;       // 初始值
            CRC_InitStruct.XOROUT = 0xffff;       // 结果异或值
            CRC_InitStruct.REFIN  = ENABLE;       // 输入数据反转
            CRC_InitStruct.REFOUT = ENABLE;       // 输出数据反转
            CRC_Init(CRCx, &CRC_InitStruct);
            break;
        case CRC_MODEL_CRC_16_USBx1: //  16  8005        FFFF        FFFF        true    true

            CRC_InitStruct.WIDTH  = CRC_WIDTH_16; // 宽度
            CRC_InitStruct.POLY   = 0x8005;       // 多项式
            CRC_InitStruct.INIT   = 0xffff;       // 初始值
            CRC_InitStruct.XOROUT = 0xffff;       // 结果异或值
            CRC_InitStruct.REFIN  = ENABLE;       // 输入数据反转
            CRC_InitStruct.REFOUT = ENABLE;       // 输出数据反转
            CRC_Init(CRCx, &CRC_InitStruct);
            break;
        case CRC_MODEL_CRC_16_MODBU: //  16  8005        FFFF        0000        true    true

            CRC_InitStruct.WIDTH  = CRC_WIDTH_16; // 宽度
            CRC_InitStruct.POLY   = 0x8005;       // 多项式
            CRC_InitStruct.INIT   = 0xffff;       // 初始值
            CRC_InitStruct.XOROUT = 0x0000;       // 结果异或值
            CRC_InitStruct.REFIN  = ENABLE;       // 输入数据反转
            CRC_InitStruct.REFOUT = ENABLE;       // 输出数据反转
            CRC_Init(CRCx, &CRC_InitStruct);
            break;
        case CRC_MODEL_CRC_16_CCITT: //  16  1021        0000        0000        true    true

            CRC_InitStruct.WIDTH  = CRC_WIDTH_16; // 宽度
            CRC_InitStruct.POLY   = 0x1021;       // 多项式
            CRC_InitStruct.INIT   = 0x0000;       // 初始值
            CRC_InitStruct.XOROUT = 0x0000;       // 结果异或值
            CRC_InitStruct.REFIN  = ENABLE;       // 输入数据反转
            CRC_InitStruct.REFOUT = ENABLE;       // 输出数据反转
            CRC_Init(CRCx, &CRC_InitStruct);
            break;
        case CRC_MODEL_CRC_16_CCITT_FALSE: //  16  1021        FFFF        0000        false   false

            CRC_InitStruct.WIDTH  = CRC_WIDTH_16; // 宽度
            CRC_InitStruct.POLY   = 0x1021;       // 多项式
            CRC_InitStruct.INIT   = 0xffff;       // 初始值
            CRC_InitStruct.XOROUT = 0x0000;       // 结果异或值
            CRC_InitStruct.REFIN  = DISABLE;      // 输入数据反转
            CRC_InitStruct.REFOUT = DISABLE;      // 输出数据反转
            CRC_Init(CRCx, &CRC_InitStruct);
            break;
        case CRC_MODEL_CRC_16_X25: //  16  1021        FFFF        FFFF        true    true

            CRC_InitStruct.WIDTH  = CRC_WIDTH_16; // 宽度
            CRC_InitStruct.POLY   = 0x1021;       // 多项式
            CRC_InitStruct.INIT   = 0xffff;       // 初始值
            CRC_InitStruct.XOROUT = 0xffff;       // 结果异或值
            CRC_InitStruct.REFIN  = ENABLE;       // 输入数据反转
            CRC_InitStruct.REFOUT = ENABLE;       // 输出数据反转
            CRC_Init(CRCx, &CRC_InitStruct);
            break;
        case CRC_MODEL_CRC_16_XMODEM: //  16  1021        0000        0000        false   false

            CRC_InitStruct.WIDTH  = CRC_WIDTH_16; // 宽度
            CRC_InitStruct.POLY   = 0x1021;       // 多项式
            CRC_InitStruct.INIT   = 0x0000;       // 初始值
            CRC_InitStruct.XOROUT = 0x0000;       // 结果异或值
            CRC_InitStruct.REFIN  = DISABLE;      // 输入数据反转
            CRC_InitStruct.REFOUT = DISABLE;      // 输出数据反转
            CRC_Init(CRCx, &CRC_InitStruct);
            break;
        case CRC_MODEL_CRC_16_DNP: //  16  3D65        0000        FFFF        true    true

            CRC_InitStruct.WIDTH  = CRC_WIDTH_16; // 宽度
            CRC_InitStruct.POLY   = 0x3d65;       // 多项式
            CRC_InitStruct.INIT   = 0x0000;       // 初始值
            CRC_InitStruct.XOROUT = 0xffff;       // 结果异或值
            CRC_InitStruct.REFIN  = ENABLE;       // 输入数据反转
            CRC_InitStruct.REFOUT = ENABLE;       // 输出数据反转
            CRC_Init(CRCx, &CRC_InitStruct);
            break;
        case CRC_MODEL_CRC_32: //  32  04C11DB7    FFFFFFFF    FFFFFFFF    true    true

            CRC_InitStruct.WIDTH  = CRC_WIDTH_32; // 宽度
            CRC_InitStruct.POLY   = 0x04C11DB7;   // 多项式
            CRC_InitStruct.INIT   = 0xFFFFFFFF;   // 初始值
            CRC_InitStruct.XOROUT = 0xFFFFFFFF;   // 结果异或值
            CRC_InitStruct.REFIN  = ENABLE;       // 输入数据反转
            CRC_InitStruct.REFOUT = ENABLE;       // 输出数据反转
            CRC_Init(CRCx, &CRC_InitStruct);
            break;
        case CRC_MODEL_CRC_32_MPEG_2: //  32  04C11DB7    FFFFFFFF    00000000    false   false

            CRC_InitStruct.WIDTH  = CRC_WIDTH_32; // 宽度
            CRC_InitStruct.POLY   = 0x04C11DB7;   // 多项式
            CRC_InitStruct.INIT   = 0xFFFFFFFF;   // 初始值
            CRC_InitStruct.XOROUT = 0x00000000;   // 结果异或值
            CRC_InitStruct.REFIN  = DISABLE;      // 输入数据反转
            CRC_InitStruct.REFOUT = DISABLE;      // 输出数据反转
            CRC_Init(CRCx, &CRC_InitStruct);
            break;
    }
    val = CRC_Calc(CRCx, data, len);
    if (CRC_InitStruct.REFOUT)
    {
        switch (CRC_InitStruct.WIDTH)
        {
            case CRC_WIDTH_8:
                val >>= 24;
                break;
            case CRC_WIDTH_16:
                val >>= 16;
                break;
            default:
                break;
        }
    }
    else
    {
        __NOP();
    }
    return val;
}
/**
 * @brief 使能CRC模块
 * @param CRCx CRC模块指针
 */
void CRC_Enable(CRC_TypeDef *CRCx)
{
    if (CRCx == CRC0)
    {
        SYS_ModuleClockCmd(SYS_MODULE_CRC0, ENABLE);
    }
    else
    {
        __NOP();
    }
}
/**
 * @brief 数字模块时钟使能
 * @param nModule 模块编号
 * @param state 使能或禁用状态
 */
void SYS_ModuleClockCmd(uint32_t nModule, uint8_t state)
{
    REG_WRITE(SYS0->PROTECT, 0x7a83);
    if (state)
    {
        REG_SET(SYS0->CLK_FEN, nModule);
    }
    else
    {
        REG_RESET(SYS0->CLK_FEN, nModule);
    }
    REG_WRITE(SYS0->PROTECT, 0);
}
/**
 * @brief 计算CRC值
 * @param CRCx CRC模块指针
 * @param data 数据指针
 * @param len 数据长度
 * @return 计算得到的CRC值
 */
uint32_t CRC_Calc(CRC_TypeDef *CRCx, uint8_t *data, uint32_t len)
{
    u32 val;
    if (len == 0)
    {
        return 0;
    }
    else
    {
        while ((len--) != 0)
        {
            REG8(&CRCx->DR) = *data;
            data++;
        }
    }
    val = (REG32(&CRCx->DR)) ^ CRC_XOROUT;
    return val;
}
/**
 * @brief 软复位模块
 * @param nModule 模块编号
 */
void SYS_SoftResetModule(uint32_t nModule)
{
    REG_WRITE(SYS0->PROTECT, 0x7a83);
    REG_SET(SYS0->SFT_RST, nModule);
    REG_RESET(SYS0->SFT_RST, nModule); // 触发复位后需清除复位位
    REG_WRITE(SYS0->PROTECT, 0);
}