# 04.01_CRC-所有内置的CRC模型  

## 测试步骤  
先后计算01 02 03 04 05不同模型下的结果，然后和已知的CRC结果进行对比。
## 实测数据  
|参数模型|计算结果，数据：{1, 2, 3, 4, 5}|测试结果|  
|-|-|-|  
|CRC8|0xBC|正确|  
|CRC8_ITU|0xE9|正确|  
|CRC8_MAXIM|0x2A|正确|  
|CRC8_ROHC|0xFE|正确|  
|CRC16_IBM|0xBB0E|正确|  
|CRC16_MAXIM|0x44F1|正确|  
|CRC16_USB|0x44D5|正确|  
|CRC16_MODBUS|0xBB2A|正确|  
|CRC16_CCITT|0xED9B|正确|  
|CRC16_CCITT_FALSE|0x9304|正确|  
|CRC16_X25|0x22EC|正确|  
|CRC16_XMODEM|0x8208|正确|  
|CRC16_DNP|0xE674|正确|  
|CRC32|0x470B99F4|正确|  
|CRC32_MPEG_2|0xE28F4B83|正确|  

## 参考代码  
04.01_CRC_Calc.c
```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 (;;)
    {
    }
}
```

## 使用到的库函数  
库函数部分代码
```c
#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);
}
```
