目录

03.01_CMP-基本功能

测试步骤

比较器模拟部分 使用CMP0_IN0 P0.15和CMP0_IP0 P2.9作为输入,P0.14输出比较器结果 其中N端信号固定为1V P端信号从0.9到1.1线性变化 分别记录0.9->1.1V和1.1V->0.9V时,比较器输出变化波形

实测数据

CMP_HYS_20mV

CMP_HYS_0mV

参考代码

03.01_CMP_Compare.c

/**
 * @brief CMP-基本功能
 * @details
 * 比较器模拟部分
 * 使用CMP0_IN0 P0.15和CMP0_IP0 P2.9作为输入,P0.14输出比较器结果
 * 其中N端信号固定为1V
 * P端信号从0.9到1.1线性变化
 * 分别记录0.9->1.1V和1.1V->0.9V时,比较器输出变化波形
 */
#include "lks32mc09x_cmp.h"
#include "lks32mc09x_gpio.h"
#include "lks32mc09x_sys.h"
volatile uint32_t sethys = CMP_HYS_20mV;
/**
 * @brief 主函数,用于测试HSI时钟输出及GPIO翻转
 */
int main(void)
{
    SYS_ModuleClockCmd(SYS_MODULE_GPIO, ENABLE);
    CMP_Enable(CMP_CHN_0);
    CMP_SetSignal(CMP_CHN_0, CMP_SELN_0_IN_CMP0, CMP_SELP_0_CMP0_IP0); // CMP0_IN0 P0.15 CMP0_IP0 P2.9
    GPIO_Config(GPIO0, GPIO_PinSource_14, GPIO_Mode_OUT, GPIO_AF_CMP_OUT);
    while (1)
    {
        CMP_SetHysteresis(sethys);
    }
}

使用到的库函数

库函数部分代码

#define CMP_CHN_0 0
#define CMP_CHN_1 1
#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 SYS0 ((SYS_TypeDef *)(SYS_BASE))
#define SYS_MODULE_CMP BIT2
#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};
/**
 * @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 使能比较器
 * @param CMP_CHN_x: 比较器通道选择,CMP_CHN_0, CMP_CHN_1
 */
void CMP_Enable(uint8_t CMP_CHN_x)
{
    SYS_ModuleClockCmd(SYS_MODULE_CMP, ENABLE);
    if (CMP_CHN_x == CMP_CHN_0)
    {
        SYS0->PROTECT = 0x7a83;
        SYS0->AFE_REG5 |= BIT6;
        SYS0->PROTECT = 0;
    }
    else
    {
        __NOP();
    }
    if (CMP_CHN_x == CMP_CHN_1)
    {
        SYS0->PROTECT = 0x7a83;
        SYS0->AFE_REG5 |= BIT7;
        SYS0->PROTECT = 0;
    }
    else
    {
        __NOP();
    }
}
/**
 * @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 设置比较器信号来源
 * @param CMP_CHN_x: 比较器通道选择,CMP_CHN_0, CMP_CHN_1
 * @param CMP_SELN_x_x: 信号负端选择,注意,由于比较器的各个通道不完全一样,所以这里需要指明使用的比较器
 * @param CMP_SELP_x_x: 信号正端选择,注意,由于比较器的各个通道不完全一样,所以这里需要指明使用的比较器
 */
void CMP_SetSignal(uint8_t CMP_CHN_x, uint8_t CMP_SELN_x_x, uint8_t CMP_SELP_x_x)
{
    if (CMP_CHN_x == CMP_CHN_0)
    {
        SYS0->PROTECT  = 0x7a83;
        SYS0->AFE_REG3 = (SYS0->AFE_REG3 & (~(0x0707))) |
                         (CMP_SELP_x_x << 8) |
                         (CMP_SELN_x_x);
        SYS0->PROTECT = 0;
    }
    else
    {
        __NOP();
    }
    if (CMP_CHN_x == CMP_CHN_1)
    {
        SYS0->PROTECT  = 0x7a83;
        SYS0->AFE_REG3 = (SYS0->AFE_REG3 & (~(0x7070))) |
                         (CMP_SELP_x_x << 12) |
                         (CMP_SELN_x_x << 4);
        SYS0->PROTECT = 0;
    }
    else
    {
        __NOP();
    }
}
/**
 * @brief 设置比较器回差(两个比较器共用同一个回差)
 * @param CMP_HYS_x: 回差选择,CMP_HYS_20mV, CMP_HYS_0mV
 */
void CMP_SetHysteresis(uint8_t CMP_HYS_x)
{
    SYS0->PROTECT  = 0x7a83;
    SYS0->AFE_REG3 = (SYS0->AFE_REG3 & (~(BIT7))) |
                     (CMP_HYS_x << 7);
    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;
    }
}