# 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

    /**
     * @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);
    }