2. GPIO输入读取按键状态
任务目标
在Zephyr OS中配置一个GPIO引脚为输入模式,读取按键电平状态,并在按键按下/释放时通过串口打印状态变化。本案例使用开发板自带的用户按键(若硬件无按键,可按文末说明外接),重点理解GPIO输入驱动的设备树配置与API调用流程。
硬件与设备树配置
以常见的nRF52840DK开发板为例,其板载用户按键BUTTON1连接到P0.11引脚(低电平有效,内部上拉)。若使用其他开发板,请查阅对应设备树文件确认按键引脚与有效电平。
在app.overlay中为按键添加设备树节点(若板级设备树已定义button节点则无需重复添加):
/ {
buttons {
compatible = "gpio-keys";
user_button: button_0 {
gpios = <&gpio0 11 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
label = "User button";
};
};
};
完整实现代码
创建src/main.c,实现GPIO输入读取与中断回调打印:
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys/printk.h>
/* 设备树节点标识 */
#define BUTTON_NODE DT_NODELABEL(user_button)
static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET(BUTTON_NODE, gpios);
static struct gpio_callback button_cb_data;
/* 按键中断回调:打印当前电平状态 */
void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
int val = gpio_pin_get_dt(&button);
if (val < 0) {
printk("Error reading button: %d\n", val);
return;
}
printk("Button state: %s\n", val ? "RELEASED" : "PRESSED");
}
int main(void)
{
int ret;
if (!device_is_ready(button.port)) {
printk("GPIO device not ready\n");
return -ENODEV;
}
/* 配置为输入,启用设备树指定的上拉 */
ret = gpio_pin_configure_dt(&button, GPIO_INPUT);
if (ret < 0) {
printk("Failed to configure button pin: %d\n", ret);
return ret;
}
/* 配置中断:下降沿(按下)与上升沿(释放)均触发 */
ret = gpio_pin_interrupt_configure_dt(&button, GPIO_INT_EDGE_BOTH);
if (ret < 0) {
printk("Failed to configure interrupt: %d\n", ret);
return ret;
}
gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin));
gpio_add_callback(button.port, &button_cb_data);
printk("GPIO input button example started. Press the button...\n");
/* 主线程空闲,实际工作由中断回调完成 */
while (1) {
k_sleep(K_MSEC(1000));
}
return 0;
}
构建与运行
- 将上述
app.overlay与src/main.c放入Zephyr应用工程目录(含CMakeLists.txt与prj.conf,本案例无需额外Kconfig配置)。 - 在应用目录下执行构建(以nRF52840DK为例):
west build -b nrf52840dk/nrf52840 .
- 烧录并打开串口终端(如
screen /dev/ttyACM0 115200):
west flash
验证方法与判定标准
- 程序启动后串口输出
GPIO input button example started...,说明GPIO设备初始化成功。 - 按下开发板
BUTTON1,串口立即输出Button state: PRESSED;松开后输出Button state: RELEASED。 - 若按键未按下时串口无输出,且按下/释放均有对应打印,则判定案例通过。
常见问题
- 编译报错“node not found”:确认
app.overlay中user_button标签与代码中DT_NODELABEL(user_button)一致,且overlay文件已被构建系统包含。 - 无按键响应:检查按键有效电平。若按键为高电平有效,需将设备树中
GPIO_ACTIVE_LOW改为GPIO_ACTIVE_HIGH,并移除GPIO_PULL_UP改用GPIO_PULL_DOWN。 - 外接按键场景:将按键一端接GPIO引脚,另一端接GND(低有效)或VCC(高有效),按上述有效电平调整设备树即可。