在本练习中,我们将修改应用程序以使用更节能的基于中断的方法,正如我们在 GPIO 通用 API 中所解释的那样。配置按钮,使其在每次按下时生成中断。然后,在按钮的中断处理程序(回调函数)中,我们将翻转 LED 状态。
1. 在 VS Code 中,选择 Open an existing application,就像我们在上一个练习中所做的那样。
2. 在本课程的 GitHub 仓库中,打开此练习的练习代码库,位于 l2/l2_e2。
3. 配置按钮引脚上的中断。
通过调用函数 gpio_pin_interrupt_configure_dt() 来配置与按钮关联的引脚上的中断。
在 main.c 中搜索 STEP 3 并添加以下代码:
ret = gpio_pin_interrupt_configure_dt(&button, GPIO_INT_EDGE_TO_ACTIVE);C4. 定义回调函数 button_pressed()。
定义在按下按钮以翻转 LED 状态时运行的回调函数。
搜索 STEP 4 并添加以下代码:
void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
gpio_pin_toggle_dt(&led);
}C5. 定义一个类型为 static struct gpio_callback 的变量。
在 main.c 中搜索 STEP 5 并添加以下行:
static struct gpio_callback button_cb_data;C6. 初始化 static struct gpio_callback 变量。
通过传递此变量,以及回调函数和 GPIO 引脚 button.pin 的位掩码给 gpio_init_callback(),来初始化结构体 gpio_callback button_cb_data。
搜索 STEP 6 并添加以下行:
gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin)); C7. 通过调用 gpio_add_callback() 添加回调函数。
搜索 STEP 7 并添加以下行:
gpio_add_callback(button.port, &button_cb_data);C8. 我们将移除主循环中所有的轮询代码,并保留对函数 k_msleep() 的调用,以使主线程(在第 7 课中介绍)休眠很长时间。

9. 将 main 函数中的休眠时间从 100 ms 增加到 10 分钟。这是通过将宏 SLEEP_TIME_MS 的值从 100 更改为 10*60*1000 来完成的。
在本示例中,没有其他高优先级线程在运行。因此,将自动调用空闲线程以使 CPU 进入休眠状态。每当按下按钮时,CPU 就会唤醒,它将调用 ISR,从而翻转 LED 状态。然后恢复执行回到无限循环,再次调用休眠函数。
由于 main 函数除了配置 GPIO 和回调函数外没有任何功能,我们通过调用 k_msleep() 让它让出 CPU 使用权,以便 RTOS 调度器可以选择一个就绪线程来运行。更好的方法实际上是在 while 循环中调用 k_yield()。
第 7 课将涵盖不同的 Zephyr 系统线程。
10. 构建练习并将其烧录到开发板。观察按下按钮 1 时,LED1 状态翻转(在 nRF54 DK 上,是按钮 0 和 LED0)。
此练习的解决方案可以在 GitHub 仓库 l2/l2_2_sol 中找到。