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延时消抖。
验证方法
- 编译代码并下载至CMS32L051开发板。
- 上电后观察LED初始状态为熄灭。
- 按下按键PA1,每次按下时LED状态应翻转(亮→灭或灭→亮)。
- 连续多次按键,LED状态每次均正确翻转,说明外部中断触发正常。
判定标准:每按一次按键,LED亮灭状态翻转一次,且无漏触发或误触发现象,即可判定本案例验证通过。
注意事项
- 按键按下时引脚电平从高到低产生下降沿,因此配置为下降沿触发;若按键接法不同(上拉到VCC),需相应调整触发边沿。
- 中断服务函数中应尽量执行简短操作,本案例仅置位标志位,实际LED翻转在主循环中完成,避免在中断中执行耗时操作。
- 若需调整中断优先级,可修改NVIC_InitStructure中的抢占优先级和子优先级参数。