第 2 课 - 输入(按键)控制输出(LED)-中断

今天学习GPIO中断控制LED.一般来说外部中断的使用步骤分为:引脚配置,中断配置,编写中断回调,开启中断。

配置中断引脚

ret = gpio_pin_interrupt_configure_dt(&button, GPIO_INT_EDGE_TO_ACTIVE);

定义回调函数

void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
    gpio_pin_toggle_dt(&led);
}

定义并初始化gpio_callback

static struct gpio_callback button_cb_data;
gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin));

调用gpio_add_callback()添加回调函数

gpio_add_callback(button.port, &button_cb_data);

删除轮询部分代码

	while (1)
	{
		
		k_msleep(SLEEP_TIME_MS);
	}

完整代码

点击查看代码
/*
 * @Author: dengyp sniper15@139.com
 * @Date: 2024-11-26 14:18:01
 * @LastEditors: dengyp sniper15@139.com
 * @LastEditTime: 2025-03-11 09:44:21
 * @FilePath: \lesson2_blink\src\main.c
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
/*
 * Copyright (c) 2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>


#define SLEEP_TIME_MS 10000

/* The devicetree node identifier for the "led0" alias. */
#define LED0_NODE DT_ALIAS(led0) //通过别名获取设备树的 led0 节点
//  通过 别名 获取设备树的一个button节点
#define SW0_NODE	DT_ALIAS(sw0) 
/*
 * A build error on this line means your board is unsupported.
 * See the sample documentation for information on how to fix this.
 */
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios); //通过节点获取一个 gpio 的实例
// 通过节点获取一个 gpio 的实例
static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET(SW0_NODE, gpios); 
//定义 static struct gpio_callback类型的变量 用于把1个回调函数添加到驱动的回调函数列表中
static struct gpio_callback button_cb_data;
int app_led_init(void)
{
	int ret;
	//在使用gpio外设之前判断是否可用
	if (!gpio_is_ready_dt(&led))
	{
		return 0;
	}
	//配置为输出模式
	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
	if (ret < 0)
	{
		return 0;
	}
	return 1;
}
// TODO: 2.定义中断回调函数
void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
    gpio_pin_toggle_dt(&led);
}
int app_button_init(void)
{
	int ret;
	// 判断button 是否可用
	if (!gpio_is_ready_dt(&button))
	{
		return 0;
	}
	ret = gpio_pin_configure_dt(&button, GPIO_INPUT);
	if (ret < 0) {
		return 0;
	}
	//TODO: 1.配置button 中断 为状态转变为逻辑1时触发
	ret = gpio_pin_interrupt_configure_dt(&button, GPIO_INT_EDGE_TO_ACTIVE);
	if (ret < 0)
	{
		return 0;
	}
	
	gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin));
	//TODO: 3.添加中断回调函数到button的回调函数列表中
	gpio_add_callback(button.port, &button_cb_data);
	return 1;
}

int main(void)
{
	
	app_led_init();
	app_button_init();
	
	while (1)
	{
		//TODO: 4.删除轮询代码
		k_msleep(SLEEP_TIME_MS);
	}
	return 0;
}

总结

NCS中外部中断的使用方法跟传统的使用方法没多大区别,不同的地方是中断函数注册,由于zephyr设备驱动的高度解耦,所以回调函数注册稍微麻烦一点。
另外需要注意的一点是,中断的触发方式:上升沿触发(GPIO_INT_EDGE_RISING)和状态变为逻辑1触发(GPIO_INT_EDGE_TO_ACTIVE)是有区别的。

posted @ 2025-03-11 09:53  NEIKOO  阅读(308)  评论(0)    收藏  举报