4. 外部中断控制LED

任务说明

本案例基于中微CMS32系列车规MCU,实现外部中断控制LED翻转功能。使用板载按键连接到外部中断输入引脚,每次按键按下时触发外部中断服务函数,在中断中翻转LED的亮灭状态。通过本案例掌握CMS32 MCU的GPIO外部中断配置流程、中断服务函数编写方法以及中断优先级设置。

硬件连接

  • LED:连接至PB0引脚(低电平点亮)
  • 按键:连接至PA1引脚(按下为低电平),外部中断输入

软件实现

本案例代码基于CMS32L051芯片,使用官方标准外设库。主要配置步骤包括:使能GPIO时钟、配置LED引脚为推挽输出、配置按键引脚为带上拉输入并开启外部中断、编写中断服务函数翻转LED状态。

#include "CMS32L051.h"

/* LED引脚定义 - PB0 */
#define LED_PORT       GPIOB
#define LED_PIN        GPIO_PIN_0

/* 按键引脚定义 - PA1 */
#define KEY_PORT       GPIOA
#define KEY_PIN        GPIO_PIN_1

/* 中断标志 */
volatile uint8_t key_flag = 0;

/* 外部中断服务函数 - EXTI1 */
void EXTI1_IRQHandler(void)
{
    if (EXTI_GetITStatus(EXTI_Line1) != RESET)
    {
        /* 清除中断标志 */
        EXTI_ClearITPendingBit(EXTI_Line1);
        /* 设置按键触发标志 */
        key_flag = 1;
    }
}

/* GPIO初始化 */
void GPIO_InitConfig(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    /* 使能GPIOA和GPIOB时钟 */
    CKCU_PeriphalClockConfig(CKCU_GPIOA | CKCU_GPIOB, ENABLE);
    
    /* 配置PB0为推挽输出,用于驱动LED */
    GPIO_InitStructure.Pin = LED_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(LED_PORT, &GPIO_InitStructure);
    
    /* 配置PA1为带上拉输入,用于按键检测 */
    GPIO_InitStructure.Pin = KEY_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_In_PU;
    GPIO_Init(KEY_PORT, &GPIO_InitStructure);
    
    /* 初始状态:LED熄灭(高电平) */
    GPIO_SetBits(LED_PORT, LED_PIN);
}

/* 外部中断初始化 */
void EXTI_InitConfig(void)
{
    EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    
    /* 配置PA1为外部中断输入 */
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);
    
    /* 外部中断配置:下降沿触发 */
    EXTI_InitStructure.EXTI_Line = EXTI_Line1;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);
    
    /* 配置NVIC中断优先级 */
    NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

/* 主函数 */
int main(void)
{
    /* 系统时钟初始化 */
    SysTick_Init();
    
    /* GPIO初始化 */
    GPIO_InitConfig();
    
    /* 外部中断初始化 */
    EXTI_InitConfig();
    
    while (1)
    {
        /* 检测到按键中断标志 */
        if (key_flag)
        {
            key_flag = 0;
            /* 翻转LED状态 */
            if (GPIO_ReadOutputDataBit(LED_PORT, LED_PIN) == Bit_SET)
            {
                GPIO_ResetBits(LED_PORT, LED_PIN);   /* LED点亮 */
            }
            else
            {
                GPIO_SetBits(LED_PORT, LED_PIN);     /* LED熄灭 */
            }
        }
    }
}

代码说明

  • GPIO_InitConfig():完成LED引脚(PB0)推挽输出配置和按键引脚(PA1)带上拉输入配置,初始状态LED熄灭。
  • EXTI_InitConfig():将PA1映射为外部中断线1,配置为下降沿触发(按键按下时产生下降沿),并使能NVIC中断通道。
  • EXTI1_IRQHandler():中断服务函数,清除中断标志并置位key_flag,主循环检测到标志后翻转LED。
  • 按键消抖通过硬件RC滤波或软件延时实现,本案例为简洁起见未加入软件消抖,实际应用中建议增加10~20ms延时消抖。

验证方法

  1. 编译代码并下载至CMS32L051开发板。
  2. 上电后观察LED初始状态为熄灭。
  3. 按下按键PA1,每次按下时LED状态应翻转(亮→灭或灭→亮)。
  4. 连续多次按键,LED状态每次均正确翻转,说明外部中断触发正常。

判定标准:每按一次按键,LED亮灭状态翻转一次,且无漏触发或误触发现象,即可判定本案例验证通过。

注意事项

  • 按键按下时引脚电平从高到低产生下降沿,因此配置为下降沿触发;若按键接法不同(上拉到VCC),需相应调整触发边沿。
  • 中断服务函数中应尽量执行简短操作,本案例仅置位标志位,实际LED翻转在主循环中完成,避免在中断中执行耗时操作。
  • 若需调整中断优先级,可修改NVIC_InitStructure中的抢占优先级和子优先级参数。
外部中断控制LED - 信号流与中断触发路径 按键 PA1 按下→低电平 EXTI_Line1 下降沿触发 NVIC 控制器 优先级1/0 EXTI1_IRQHandler 置位 key_flag 主循环 while(1) 检测 key_flag LED PB0 翻转亮灭状态 ① 按键按下产生下降沿 ② 硬件触发中断请求 ③ 中断服务函数执行 ④ 主循环翻转LED 验证观测点 1. 按键按下瞬间,EXTI_Line1中断标志置位 2. 程序进入EXTI1_IRQHandler,key_flag置1 3. 主循环检测到标志后翻转PB0电平,LED状态改变