# 02.01_CLU-与门

## 测试步骤

使用clu实现与门逻辑，使用P0.0(A)P0.6(B)两个IO口，结果输出到P2.6

## 实测数据

T | A | B | Y
--- | --- | --- | ---
0 | 0 | 0 | 0
1 | 1 | 0 | 0
2 | 0 | 1 | 0
3 | 1 | 1 | 1

## 参考代码

02.01_CLU_init.c

    /**
     * @brief CLU-与门
     * @details
     * 使用clu实现与门逻辑，使用P0.0(A)P0.6(B)两个IO口，结果输出到P2.6
     */
    #include "lks32mc09x_clu.h"
    #include "lks32mc09x_gpio.h"
    #include "lks32mc09x_sys.h"
    /**
     * @brief 主函数，用于测试HSI时钟输出及GPIO翻转
     */
    int main(void)
    {
        SYS_ModuleClockCmd(SYS_MODULE_GPIO, ENABLE);
        SYS_ModuleClockCmd(SYS_MODULE_CL0, ENABLE);
        CLU_InitTypeDef cluconfig;

        CLU_StructInit(&cluconfig);

        cluconfig.EN = ENABLE;             ///< 模块使能 0关闭模块 1打开模块
        cluconfig.FIE = DISABLE;           ///< 下降沿中断使能
        cluconfig.RIE = DISABLE;           ///< 上升沿中断使能
        cluconfig.MXA = CLU_MXA_CLU0_P0_0; ///< A输入复用选择 格式 CLU_MXA_CLUa_b a取值范围为[0 1 2 3] 对应不同的CLU b表示选择不同的输入信号
        cluconfig.MXB = CLU_MXB_CLU0_P0_6; ///< B输入复用选择 格式 CLU_MXB_CLUa_b a取值范围为[0 1 2 3] 对应不同的CLU b表示选择不同的输入信号
        cluconfig.FN = CLU_FN_A_B;         ///< 真值表 格式 CLU_FN_x x取值范围为[A NOTA A_NOTB ...]对应为最简与或式下的最小相 例如 y=a+bc+!c 表示为 CLU_FN_A|CLU_FN_B_C|CLU_FN_NOTC
        cluconfig.OUTSEL = 1;              ///< 输出选择 0: D 触发器输出 1: LUT 输出
        cluconfig.OEN = 1;                 ///< 输出使能 0: 关闭 1: 使能
        cluconfig.CLKINV = 0;              ///< D 触发器时钟电平 0: 同相 1: 反向
        cluconfig.CLKSEL = 0;              ///< D 触发器时钟选择 0x0: 进位输入 0x1: MXA 输入 0x2: ALTCLK0 0x3: ALTCLK1
        CLU_Init(CLU, CLU_MODEL_CLU0, &cluconfig);
        GPIO_Config(GPIO0, GPIO_PinSource_0, GPIO_Mode_IN, GPIO_AF_CL);
        GPIO_Config(GPIO0, GPIO_PinSource_6, GPIO_Mode_IN, GPIO_AF_CL);
        GPIO_Config(GPIO2, GPIO_PinSource_6, GPIO_Mode_OUT, GPIO_AF_CL);
        while (1)
        {
        }
    }

## 使用到的库函数

库函数部分代码

    #define CLU_FN_A 0xf0
    #define CLU_FN_B_C 0x88
    #define CLU_FN_NOTC 0x55
    #define CLU_MODEL_CLU0 BIT0
    #define CLU_MODEL_CLU1 BIT1
    #define CLU_MODEL_CLU2 BIT2
    #define CLU_MODEL_CLU3 BIT3
    #define GPIO_AF_I2C 6
    #define REG_RESET(reg,mask) reg &= ~(mask)
    #define REG_SET(reg,mask) reg |= (mask)
    #define REG_WRITE(reg,mask) reg = (mask)
    #define REG_WRITE_BIT(reg,mask,val) reg = ((reg) & ~(mask)) | (val)
    #define SYS0 ((SYS_TypeDef *)(SYS_BASE))
    #define SYS_MODULE_CL0 BIT21
    #define SYS_MODULE_GPIO BIT11
    /**
     * @brief GPIO功能配置结构体句柄
     */
    typedef struct GPIO_InitTypeDef {
        uint32_t GPIO_Pin;
        GPIO_Mode_TypeDef GPIO_Mode;
        GPIO_PuPd_TypeDef GPIO_PuPd;
        uint32_t GPIO_PODEna;
        uint32_t GPIO_PFLT;
    };
    /**
     * @brief GPIO模式选择枚举
     */
    typedef enum GPIO_Mode_TypeDef {
        GPIO_Mode_IN = 0,
        GPIO_Mode_OUT = 1,
        GPIO_Mode_ANA = 2,
        GPIO_Mode_IO = 3,
    }} {enum_name};
    typedef struct CLU_InitTypeDef {
        uint32_t EN;
        uint32_t FIE;
        uint32_t RIE;
        uint32_t MXA;
        uint32_t MXB;
        uint32_t FN;
        uint32_t OUTSEL;
        uint32_t OEN;
        uint32_t CLKINV;
        uint32_t CLKSEL;
    };
    /**
     * @brief  GPIO配置函数
     * @param  GPIOx: GPIO端口
     * @param  GPIO_PinSource: GPIO引脚
     * @param  mode: GPIO模式
     * @param  GPIO_AF_x: GPIO复用功能选择
     */
    void GPIO_Config(GPIO_TypeDef *GPIOx, uint32_t GPIO_PinSource, GPIO_Mode_TypeDef mode, uint32_t GPIO_AF_x)
    {
        GPIO_PinAFConfig(GPIOx, GPIO_PinSource, GPIO_AF_x);
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_StructInit(&GPIO_InitStructure);
        GPIO_InitStructure.GPIO_Pin  = 1 << GPIO_PinSource;
        GPIO_InitStructure.GPIO_Mode = mode;
        if (GPIO_AF_x == GPIO_AF_I2C)
        {
            GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
        }
        else
        {
            __NOP();
        }
        GPIO_Init(GPIOx, &GPIO_InitStructure);
    }
    /**
     * @brief CLU初始化结构体初始化
     */
    void CLU_StructInit(CLU_InitTypeDef *CLU_InitStruct)
    {
        CLU_InitStruct->FIE    = 0; ///< 下降沿中断使能
        CLU_InitStruct->RIE    = 0; ///< 上升沿中断使能
        CLU_InitStruct->EN     = 0; ///< 模块使能 0关闭模块 1打开模块
        CLU_InitStruct->MXA    = 0; ///< A输入复用选择 格式 CLU_MXA_CLUa_b a取值范围为[0 1 2 3] 对应不同的CLU b表示选择不同的输入信号
        CLU_InitStruct->MXB    = 0; ///< B输入复用选择 格式 CLU_MXB_CLUa_b a取值范围为[0 1 2 3] 对应不同的CLU b表示选择不同的输入信号
        CLU_InitStruct->FN     = 0; ///< 真值表 格式 CLU_FN_x x取值范围为[A NOTA A_NOTB ...]对应为最简与或式下的最小相 例如 y=a+bc+!c 表示为 CLU_FN_A|CLU_FN_B_C|CLU_FN_NOTC
        CLU_InitStruct->OUTSEL = 0; ///< 输出选择 0: D 触发器输出 1: LUT 输出
        CLU_InitStruct->OEN    = 0; ///< 输出使能 0: 关闭 1: 使能
        CLU_InitStruct->CLKINV = 0; ///< D 触发器时钟电平 0: 同相 1: 反向
        CLU_InitStruct->CLKSEL = 0; ///< D 触发器时钟选择 0x0: 进位输入 0x1: MXA 输入 0x2: ALTCLK0 0x3: ALTCLK1
    }
    /**
     * @brief CLU模块时钟使能
     */
    void CLU_Enable(CLU_TypeDef *CLUx)
    {
        SYS_ModuleClockCmd(SYS_MODULE_CL0, ENABLE);
    }
    /**
     * @brief CLU计算初始化
     */
    void CLU_Init(CLU_TypeDef *CLUx, uint8_t CLU_MODEL_CLUx, CLU_InitTypeDef *CLU_InitStruct)
    {
        CLU_Enable(CLUx);
        if ((CLU_MODEL_CLUx & CLU_MODEL_CLU0) != 0)
        {
            REG_WRITE_BIT(CLUx->EN, BIT0, CLU_InitStruct->EN ? BIT0 : 0);
            REG_WRITE_BIT(CLUx->IE, BIT0, CLU_InitStruct->FIE ? BIT0 : 0);
            REG_WRITE_BIT(CLUx->IE, BIT1, CLU_InitStruct->RIE ? BIT1 : 0);
            REG_WRITE_BIT(CLUx->MX, 0x000f, (CLU_InitStruct->MXA << 4) | (CLU_InitStruct->MXB));
            REG_WRITE_BIT(CLUx->FN, 0x000f, CLU_InitStruct->FN);
            REG_WRITE_BIT(CLUx->CF, 0x000f, (CLU_InitStruct->OUTSEL << 7) | (CLU_InitStruct->OEN << 6) | (CLU_InitStruct->CLKINV << 2) | (CLU_InitStruct->CLKSEL));
            REG_SET(CLUx->CF, BIT3);
        }
        if ((CLU_MODEL_CLUx & CLU_MODEL_CLU1) != 0)
        {
            REG_WRITE_BIT(CLUx->EN, BIT1, CLU_InitStruct->EN ? BIT1 : 0);
            REG_WRITE_BIT(CLUx->IE, BIT2, CLU_InitStruct->FIE ? BIT2 : 0);
            REG_WRITE_BIT(CLUx->IE, BIT3, CLU_InitStruct->RIE ? BIT3 : 0);
            REG_WRITE_BIT(CLUx->MX, 0x00f0, (CLU_InitStruct->MXA << 12) | (CLU_InitStruct->MXB << 8));
            REG_WRITE_BIT(CLUx->FN, 0x00f0, CLU_InitStruct->FN << 8);
            REG_WRITE_BIT(CLUx->CF, 0x00f0, (CLU_InitStruct->OUTSEL << 15) | (CLU_InitStruct->OEN << 14) | (CLU_InitStruct->CLKINV << 10) | (CLU_InitStruct->CLKSEL << 8));
            REG_SET(CLUx->CF, BIT11);
        }
        if ((CLU_MODEL_CLUx & CLU_MODEL_CLU2) != 0)
        {
            REG_WRITE_BIT(CLUx->EN, BIT2, CLU_InitStruct->EN ? BIT2 : 0);
            REG_WRITE_BIT(CLUx->IE, BIT4, CLU_InitStruct->FIE ? BIT4 : 0);
            REG_WRITE_BIT(CLUx->IE, BIT5, CLU_InitStruct->RIE ? BIT5 : 0);
            REG_WRITE_BIT(CLUx->MX, 0x0f00, (CLU_InitStruct->MXA << 20) | (CLU_InitStruct->MXB << 16));
            REG_WRITE_BIT(CLUx->FN, 0x0f00, CLU_InitStruct->FN << 16);
            REG_WRITE_BIT(CLUx->CF, 0x0f00, (CLU_InitStruct->OUTSEL << 23) | (CLU_InitStruct->OEN << 22) | (CLU_InitStruct->CLKINV << 18) | (CLU_InitStruct->CLKSEL << 16));
            REG_SET(CLUx->CF, BIT19);
        }
        if ((CLU_MODEL_CLUx & CLU_MODEL_CLU3) != 0)
        {
            REG_WRITE_BIT(CLUx->EN, BIT3, CLU_InitStruct->EN ? BIT3 : 0);
            REG_WRITE_BIT(CLUx->IE, BIT6, CLU_InitStruct->FIE ? BIT6 : 0);
            REG_WRITE_BIT(CLUx->IE, BIT7, CLU_InitStruct->RIE ? BIT7 : 0);
            REG_WRITE_BIT(CLUx->MX, 0xf000, (CLU_InitStruct->MXA << 28) | (CLU_InitStruct->MXB << 24));
            REG_WRITE_BIT(CLUx->FN, 0xf000, CLU_InitStruct->FN << 24);
            REG_WRITE_BIT(CLUx->CF, 0xf000, (CLU_InitStruct->OUTSEL << 31) | (CLU_InitStruct->OEN << 30) | (CLU_InitStruct->CLKINV << 26) | (CLU_InitStruct->CLKSEL << 24));
            REG_SET(CLUx->CF, BIT27);
        }
    }
    /**
     * @brief 初始化GPIO
     * @param GPIOx GPIO模块指针
     * @param GPIO_InitStruct 指向包含初始化参数的GPIO_InitTypeDef结构体
     */
    void GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_InitStruct)
    {
        // 使能GPIO时钟
        SYS_ModuleClockCmd(SYS_MODULE_GPIO, ENABLE);

        // 配置引脚模式
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IN)
        {
            GPIOx->PIE |= GPIO_InitStruct->GPIO_Pin;  // 打开输入使能
            GPIOx->POE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭输出使能
            GPIOx->PUE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭上拉使能
        }
        else if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_OUT)
        {
            GPIOx->PIE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭输入使能
            GPIOx->POE |= GPIO_InitStruct->GPIO_Pin;  // 使能输出
        }
        else if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IO)
        {
            GPIOx->PIE |= GPIO_InitStruct->GPIO_Pin; // 使能输入
            GPIOx->POE |= GPIO_InitStruct->GPIO_Pin; // 使能输出
        }
        else // GPIO_Mode_ANA
        {
            GPIOx->PIE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭输入使能
            GPIOx->POE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭输出使能
            GPIOx->PUE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭上拉使能
        }

        if (GPIO_InitStruct->GPIO_PuPd == GPIO_PuPd_UP)
        {
            GPIOx->PUE |= GPIO_InitStruct->GPIO_Pin; // 使能上拉
        }
        else
        {
            GPIOx->PUE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭上拉
        }
        // 配置开漏使能
        if (GPIO_InitStruct->GPIO_PODEna)
        {
            GPIOx->PODE |= GPIO_InitStruct->GPIO_Pin;
        }
        else
        {
            GPIOx->PODE &= ~GPIO_InitStruct->GPIO_Pin;
        }

        // 配置滤波使能
        if (GPIO_InitStruct->GPIO_PFLT)
        {
            GPIOx->PFLT |= GPIO_InitStruct->GPIO_Pin;
        }
        else
        {
            GPIOx->PFLT &= ~GPIO_InitStruct->GPIO_Pin;
        }
    }
    /**
     * @brief 初始化GPIO结构体为默认值
     * @param GPIO_InitStruct 指向要初始化的GPIO_InitTypeDef结构体
     */
    void GPIO_StructInit(GPIO_InitTypeDef *GPIO_InitStruct)
    {
        for (int i = 0; i < sizeof(GPIO_InitTypeDef); i++)
        {
            ((uint8_t *)GPIO_InitStruct)[i] = 0;
        }
    }
    /**
     * @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 配置GPIO引脚复用功能
     * @param GPIOx GPIO模块指针
     * @param GPIO_PinSource 引脚源
     * @param GPIO_AF 复用功能选择
     */
    void GPIO_PinAFConfig(GPIO_TypeDef *GPIOx, uint32_t GPIO_PinSource, uint32_t GPIO_AF)
    {
        uint8_t offset;
        uint8_t pins = GPIO_PinSource >> 2;
        offset       = ((GPIO_PinSource & 0x3) * 4);
        switch (pins)
        {
            case 0:
                GPIOx->F3210 = (GPIOx->F3210 & ~(0xf << offset)) | (GPIO_AF << offset);
                break;
            case 1:
                GPIOx->F7654 = (GPIOx->F7654 & ~(0xf << offset)) | (GPIO_AF << offset);
                break;
            case 2:
                GPIOx->FBA98 = (GPIOx->FBA98 & ~(0xf << offset)) | (GPIO_AF << offset);
                break;
            case 3:
                GPIOx->FFEDC = (GPIOx->FFEDC & ~(0xf << offset)) | (GPIO_AF << offset);
                break;
            default:
                break;
        }
    }