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 可能无法正确触发中断。

经验分享 程序员 微信小程序 职场和发展