3. Zephyr设备树配置TinyML模型输入输出张量
任务目标
在Zephyr RTOS环境下,通过GPIO中断方式检测按键按下事件,每次按下按键时切换LED的亮灭状态。本案例聚焦GPIO输入引脚配置、中断回调机制以及中断与主线程间的数据传递。
硬件需求
- 开发板:支持Zephyr的任意开发板(本案例以nRF52840DK为例)
- 按键:连接到GPIO引脚(默认P0.11,低电平有效)
- LED:连接到GPIO引脚(默认P0.13,高电平点亮)
实现原理
按键检测有两种方式:轮询和中断。本案例采用中断方式,按键按下时触发GPIO中断,在中断回调中通过Zephyr的原子变量或消息队列通知主线程,主线程负责翻转LED状态。中断回调运行在中断上下文,不能直接调用耗时操作,因此仅设置标志位,实际LED控制放在主线程中执行。
关键完整代码
/* main.c */
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys/printk.h>
/* 开发板引脚配置 - 根据实际硬件修改 */
#define LED_PIN 13
#define BTN_PIN 11
#define SW0_NODE DT_ALIAS(sw0)
#define LED0_NODE DT_ALIAS(led0)
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
static const struct gpio_dt_spec btn = GPIO_DT_SPEC_GET(SW0_NODE, gpios);
static struct gpio_callback btn_cb_data;
static atomic_t btn_pressed;
/* 按键中断回调 - 运行在中断上下文 */
static void button_isr(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
atomic_set(&btn_pressed, 1);
}
void main(void)
{
int ret;
/* 配置LED引脚为输出 */
if (!device_is_ready(led.port)) {
printk("LED device not ready\n");
return;
}
ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
printk("LED config failed: %d\n", ret);
return;
}
/* 配置按键引脚为输入,启用上拉电阻 */
if (!device_is_ready(btn.port)) {
printk("Button device not ready\n");
return;
}
ret = gpio_pin_configure_dt(&btn, GPIO_INPUT | GPIO_PULL_UP);
if (ret < 0) {
printk("Button config failed: %d\n", ret);
return;
}
/* 配置按键中断:下降沿触发(按下时从高到低) */
ret = gpio_pin_interrupt_configure_dt(&btn, GPIO_INT_EDGE_TO_ACTIVE);
if (ret < 0) {
printk("Button interrupt config failed: %d\n", ret);
return;
}
/* 注册中断回调 */
gpio_init_callback(&btn_cb_data, button_isr, BIT(btn.pin));
gpio_add_callback(btn.port, &btn_cb_data);
printk("GPIO button interrupt demo started\n");
while (1) {
/* 等待中断标志 */
if (atomic_get(&btn_pressed)) {
atomic_set(&btn_pressed, 0);
/* 翻转LED状态 */
gpio_pin_toggle_dt(&led);
printk("Button pressed, LED toggled\n");
}
k_sleep(K_MSEC(10));
}
}
工程配置(prj.conf)
CONFIG_GPIO=y
设备树覆盖(boards/nrf52840dk_nrf52840.overlay)
/ {
aliases {
sw0 = &button0;
led0 = &led0;
};
leds {
compatible = "gpio-leds";
led0: led_0 {
gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>;
label = "Green LED";
};
};
buttons {
compatible = "gpio-keys";
button0: button_0 {
gpios = <&gpio0 11 GPIO_ACTIVE_LOW>;
label = "User Button";
};
};
};
构建与运行
# 在Zephyr工程目录下执行
west build -b nrf52840dk_nrf52840 -d build/button_led .
west flash -d build/button_led
验证方法
- 程序启动后,串口终端应输出
GPIO button interrupt demo started。 - 按下开发板上的用户按键(P0.11),LED(P0.13)状态应翻转(亮变灭或灭变亮)。
- 串口终端每次按键后输出
Button pressed, LED toggled。 - 连续快速按键多次,LED状态应每次都翻转,无丢失响应。
常见问题
- 引脚不匹配:不同开发板按键和LED引脚不同,需根据硬件原理图修改overlay文件中的gpio引脚号和active电平。
- 按键抖动:本案例未做软件消抖,若出现一次按键多次翻转,可在中断回调中增加延时消抖或使用Zephyr的debounce API。
- 中断不触发:检查GPIO_INT_EDGE_TO_ACTIVE配置是否与按键实际电平匹配(低有效按键应配置为下降沿或TO_ACTIVE)。