4. 使用外部中断检测按键并控制LED

任务目标

使用GD32微控制器的外部中断(EXTI)功能,将按键连接到中断引脚。当按键按下时触发外部中断,在中断服务函数中翻转LED的亮灭状态。通过本案例掌握GD32外部中断的初始化流程、中断服务函数的编写方法以及中断优先级的配置。

硬件连接

  • 按键:一端接PA0(EXTI0),另一端接GND(按下为低电平)
  • LED:正极经限流电阻接PC13,负极接GND
  • 使用GD32F103系列MCU,开发板自带按键和LED亦可

实现原理

PA0配置为上拉输入模式,使能EXTI0中断线并设置为下降沿触发。当按键按下时,PA0电平从高变低,触发EXTI0中断,CPU跳转到中断服务函数执行LED翻转操作。中断服务函数中需清除中断挂起标志位,否则中断会反复触发。

完整代码

#include "gd32f10x.h"

/* LED引脚定义 - PC13 */
#define LED_PORT       GPIOC
#define LED_PIN        GPIO_PIN_13
#define LED_CLK        RCU_GPIOC

/* 按键引脚定义 - PA0 */
#define KEY_PORT       GPIOA
#define KEY_PIN        GPIO_PIN_0
#define KEY_CLK        RCU_GPIOA
#define KEY_EXTI_LINE  EXTI_0
#define KEY_EXTI_PORT_SOURCE  EXTI_SOURCE_GPIOA
#define KEY_EXTI_PIN_SOURCE   EXTI_SOURCE_PIN0

/* 函数声明 */
void gpio_config(void);
void exti_config(void);
void nvic_config(void);

int main(void)
{
    /* 系统时钟配置为108MHz */
    system_clock_108mhz();
    
    /* 初始化GPIO、EXTI和NVIC */
    gpio_config();
    exti_config();
    nvic_config();
    
    while(1)
    {
        /* 主循环为空,等待外部中断触发 */
    }
}

/* GPIO初始化 */
void gpio_config(void)
{
    /* 使能GPIO时钟 */
    rcu_periph_clock_enable(LED_CLK);
    rcu_periph_clock_enable(KEY_CLK);
    
    /* 配置LED引脚为推挽输出,最大速度50MHz */
    gpio_init(LED_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, LED_PIN);
    gpio_bit_reset(LED_PORT, LED_PIN);  /* 初始状态LED灭 */
    
    /* 配置按键引脚为上拉输入 */
    gpio_init(KEY_PORT, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, KEY_PIN);
}

/* 外部中断配置 */
void exti_config(void)
{
    /* 使能SYSCFG时钟(EXTI需要) */
    rcu_periph_clock_enable(RCU_SYSCFG);
    
    /* 将PA0连接到EXTI0 */
    syscfg_exti_line_config(KEY_EXTI_PORT_SOURCE, KEY_EXTI_PIN_SOURCE);
    
    /* 配置EXTI0为下降沿触发 */
    exti_init(KEY_EXTI_LINE, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
    exti_interrupt_flag_clear(KEY_EXTI_LINE);
}

/* NVIC中断优先级配置 */
void nvic_config(void)
{
    nvic_irq_enable(EXTI0_IRQn, 2, 0);  /* 抢占优先级2,子优先级0 */
}

/* EXTI0中断服务函数 */
void EXTI0_IRQHandler(void)
{
    /* 检查EXTI0中断挂起标志 */
    if(exti_interrupt_flag_get(KEY_EXTI_LINE) == SET)
    {
        /* 翻转LED状态 */
        gpio_bit_write(LED_PORT, LED_PIN, 
                       (gpio_input_bit_get(LED_PORT, LED_PIN) == SET) ? RESET : SET);
        
        /* 清除中断挂起标志 */
        exti_interrupt_flag_clear(KEY_EXTI_LINE);
    }
}

编译与下载

  1. 使用Keil MDK或IAR创建工程,选择GD32F103系列对应型号
  2. 添加上述代码到工程,并包含GD32标准固件库
  3. 编译工程,生成HEX文件
  4. 通过JTAG/SWD下载器将程序烧录到开发板

验证方法

  1. 上电后LED初始为熄灭状态
  2. 按下按键PA0,LED应立即点亮
  3. 再次按下按键,LED应熄灭
  4. 每次按下按键,LED状态翻转一次,无抖动导致的多次翻转(若抖动明显,可增加硬件RC滤波或软件消抖)

通过条件:每次按下按键LED状态都发生翻转,且松开按键后状态保持不变,说明外部中断检测和中断服务函数执行正确。

常见问题

  • 中断不触发:检查按键是否连接到PA0,确认GPIO配置为上拉输入,EXTI线号和引脚号匹配
  • LED状态乱跳:按键存在机械抖动,可在硬件上并联100nF电容,或在中断中加10~20ms软件延时消抖
  • 编译报错:确认已包含gd32f10x_exti.h、gd32f10x_gpio.h等头文件,并正确链接固件库