ESP32 之 ESP-IDF教学(二)——GPIO(2) 中断的简单配置
↓↓↓通过下方对话框进入专栏目录页↓↓↓ 请求进入目录 _ O x 是否进入ESP32教学导航(基于ESP-IDF)?
一、配置GPIO中断
通过gpio_config()函数传递一个结构体gpio_config_t指针,在gpio_config_t结构体中声明中断类型。或通过函数gpio_set_intr_type()函数(前文中省略了函数参数)
注意:必须将GPIO配置为包含输入的模式,比如 GPIO_MODE_INPUT 或 GPIO_MODE_INPUT_OUTPUT 等。
(1)函数gpio_set_intr_type()解析 1、功能简介 GPIO set interrupt trigger type. 2、返回值 类型 名称 意义 ESP_OK 配置成功 同上 ESP_ERR_INVALID_ARG Parameter error 3、参数值 [类型] 名称 意义 [gpio_num_t]或[uint32_t] gpio_num GPIO number. If you want to set the trigger type of e.g. of GPIO16, gpio_num should be GPIO_NUM_16 (16); [gpio_int_type_t] intr_type Interrupt type, select from ←点红字看详情
(2)配置中断示例(两种方法)
提前将GPIO配置为包含输入的模式 / 方向
gpio_config_t ioConfig = {
// . .... = ... , //省略
// . .... = ... , //省略
.intr_type = GPIO_INTR_NEGEDGE, //本例中设置为下降沿触发中断
.pull_down_en = 1, //要触发下降沿中断,所以要允许下拉
};
gpio_config(&ioConfig);
或
gpio_set_intr_type(18, GPIO_INTR_NEGEDGE);
二、让你的ESP32响应中断
(1)步骤
1、安装 / 建立中断服务 2、创建一个静态的,带有IRAM_ATTR宏的函数作为中断服务程序 Handler(函数的模板将在下文给出)
原因是GPIO的中断在IRAM中工作。这样的好处是在flash禁用的情况下也可以响应中断。且速度更快,对于这种频繁触发的中断是有利的。但是这个中断也因此无法使用printf等串口打印工作,需要转入其他Task中执行。详见官网API参考—— 中断分配
3、为某个GPIO口设置中断服务程序 Handler(interrupt service routine Handler) 4、在设置的中断服务程序 Handler函数中,使用FreeRTOS的队列在另一个任务Task中进行处理(此方法需要一个任务Task来循环检测队列来执行中断后要做的事)ISR 程序要保持简短,不能执行耗时的工作
(2)示例中必要的 FreeRTOS API 简介(待续)
待续
(3)示例代码
本例中为GPIO18配置了一个双沿中断,主线程执行普通任务(1秒输出一个"mian function is running! ")当GPIO18响应中断后输出此时(发生中断时)GPIO18的电平。
#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
static xQueueHandle gpioEventQueue = NULL;
static void IRAM_ATTR intrHandler (void *arg){
uint32_t gpio_num = (uint32_t)arg;
xQueueSendFromISR(gpioEventQueue, &gpio_num, NULL);
}
static void gpioTaskExample(void *arg){
uint32_t ioNum = (uint32_t) arg;
while (1)
{
if (xQueueReceive(gpioEventQueue, &ioNum, portMAX_DELAY)){
printf("GPIO[%d] intrrupted, level: %d
", ioNum, gpio_get_level(ioNum));
}
}
}
void app_main(void)
{
gpio_config_t gpio18 = {
.pin_bit_mask = 1ull << 18,
.mode = GPIO_MODE_INPUT_OUTPUT,
.intr_type = GPIO_INTR_ANYEDGE,
.pull_down_en = 1,
};
gpio_config(&gpio18);
gpio_set_level(18, 1);
gpioEventQueue = xQueueCreate(10, sizeof(uint32_t));
xTaskCreate(gpioTaskExample, "ExampleTask", 2048, NULL, 10, NULL);
gpio_install_isr_service(0);
gpio_isr_handler_add(18, intrHandler, (void*)18);
printf("finished");
while (1)
{
printf("mian function is running!
");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
三、中断使用中的 Bug 及解决方案 —— GPIO 可能无法正确触发中断
在 ESP32 《勘误表及解决办法》 文档 3.14 小节中提到了这样一个Bug:
下载:
ESP32 GPIO 可能无法正确触发中断。
