3. GPIO中断触发按键事件

GPIO中断触发按键事件 学习卡片

任务目标

在 Zephyr OS 中,使用 GPIO 中断 API 为按键注册回调函数,实现按键按下时触发中断并执行事件处理(如翻转 LED 状态),掌握中断驱动开发的基本流程。

环境依赖

  • Zephyr OS 3.x(以 nrf52840dk_nrf52840 开发板为例)
  • 板载按键:DK_BTN1_0(对应 P0.11,低电平有效)
  • 板载 LED:DK_LED1(对应 P0.13,高电平点亮)

关键完整代码

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys/printk.h>

/* 开发板按键与LED的设备树别名 */
#define SW0_NODE    DT_ALIAS(sw0)
#define LED0_NODE   DT_ALIAS(led0)

static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET(SW0_NODE, gpios);
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);

static struct gpio_callback button_cb_data;

/* 中断回调函数:翻转LED状态 */
void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
    gpio_pin_toggle_dt(&led);
    printk("Button pressed, LED toggled\n");
}

int main(void)
{
    int ret;

    /* 配置LED为输出 */
    ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
    if (ret < 0) {
        return ret;
    }

    /* 配置按键为输入,并使能内部上拉 */
    ret = gpio_pin_configure_dt(&button, GPIO_INPUT | GPIO_PULL_UP);
    if (ret < 0) {
        return ret;
    }

    /* 配置按键中断:下降沿触发(按下时电平由高变低) */
    ret = gpio_pin_interrupt_configure_dt(&button, GPIO_INT_EDGE_TO_ACTIVE);
    if (ret < 0) {
        return ret;
    }

    /* 初始化回调并注册 */
    gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin));
    gpio_add_callback(button.port, &button_cb_data);

    printk("GPIO interrupt example started\n");

    while (1) {
        k_msleep(1000);
    }
    return 0;
}

构建与运行

west build -b nrf52840dk_nrf52840 .
west flash

验证方法

  1. 程序启动后,串口终端应输出 GPIO interrupt example started。
  2. 按下开发板上的 SW0 按键,每次按下时串口输出 Button pressed, LED toggled,同时板载 LED1 状态翻转(亮/灭交替)。
  3. 松开按键后无额外输出,说明中断仅在下降沿触发一次,未发生抖动重复触发(若需消抖可增加软件延时或使用硬件消抖电路)。

关键说明

  • GPIO_INT_EDGE_TO_ACTIVE 表示在按键从非激活电平(高电平)跳变到激活电平(低电平)时触发中断,即按下瞬间触发一次。
  • 回调函数在中断上下文中执行,应保持简短,避免阻塞操作;本示例仅做 GPIO 翻转和日志输出。
  • 若使用其他开发板,需确认设备树中 sw0 和 led0 别名是否存在,或直接使用 DT_NODELABEL() 引用具体节点。