ESP-IDF教程2 GPIO - 输入、输出和中断


本文介绍了 ESP-IDF 框架下的 ESP32 GPIO 相关功能,包括输入、输出和中断等,章节目录如下:


1、前提

1.1、基础知识

1.1.1、GPIO 分类

ESP32 系列芯片按照 GPIO 特殊的使用限制分类,可以将其分为如下几类:

  1. GPIO PIN
  2. GPI PIN
  3. Strapping PIN
  4. SPI FLASH PIN
  5. 特殊功能引脚

GPIO 引脚

表示通用的输入输出引脚,无使用限制,可以随意使用

GPI 引脚

表示仅支持输入的引脚,不具备软件使能的上拉或下拉功能,谨慎使用

Strapping 引脚

用于 ESP32 的启动配置项,ESP32 启动时需要配置如启动模式、内置 LDO 电压、U0TXD 打印使能等参数,这些参数需要芯片在上电或硬件复位时通过 Strapping 管脚采样其电平并锁存来决定,但当采样结束后 Strapping 引脚将恢复为普通 GPIO ,谨慎使用

SPI FLASH 引脚

因为大部分 ESP32 芯片封装内部无 FLASH 存储,因此需要依赖外部 FLASH 芯片存储程序和数据,SPI FLASH 引脚就是用于 ESP32 FLASH 通信使用的,共有 4-6 个引脚,不要使用这些引脚

特殊功能引脚

JTAG 和 UART0 这类专用于某一功能的引脚,除非不使用该特殊功能,否则不建议将其作为普通 GPIO 使用

1.1.2、FALSH SPI 模式

根据通信不同阶段使用的引脚数不同,ESP32 的 FALSH SPI 模式有如下四种:

  1. QIO
  2. QOUT
  3. DIO
  4. DOUT

四种 FLASH SPI 模式的具体区别如 SPI Flash Modes / Summary 所示,其中 QIO 和 QOUT 需要全部的 6 个 SPI FLASH 引脚,而 DIO 和 DOUT 仅需要其中的 4 个引脚,剩下未使用的引脚可做普通 GPIO 使用。

1.1.3、过滤器

ESP32 某些系列芯片支持 GPIO 过滤器,有如下两种:

  1. 毛刺过滤器
    1. 管脚毛刺过滤器(pin_glitch_filter)
    2. 灵活毛刺过滤器(flex_glitch_filter)
  2. 迟滞过滤器

管脚毛刺过滤器 pin_glitch_filter

仅能将脉冲宽度窄于 2 个采样时钟的信号剔除掉,采样时钟默认为 80MHz 的 SOC_MOD_CLK_APB 宏,因此过滤宽度 = 2 × (1/80 MHz) = 25 ns 。

灵活毛刺过滤器 flex_glitch_filter

会在 window_width_ns 时间窗口内,对信号采样多次,若某次“高”或“低”持续时间小于 window_thres_ns,则当作毛刺丢弃,该功能仅部分型号支持,比如 ESP32-C6、ESP32-H2 和 ESP32-P4 ,笔者尚未测试。

管脚毛刺过滤器和灵活毛刺过滤器是各自独立的,支持为同一 GPIO 同时启用这两种过滤器。

GPIO 迟滞过滤器

“支持输入引脚的硬件迟滞,可以减少由于输入电压在逻辑 0、1 临界值附近时采样不稳定造成的 GPIO 中断误触”,看起来或许可以作为按键消抖使用,该功能仅部分型号支持,比如 ESP32-C5、ESP32-H2 和 ESP32-P4 ,笔者尚未测试。

1.1.4、外部中断

ESP32 的 GPIO 支持如下类型的几种中断:

typedef enum {
    GPIO_INTR_DISABLE = 0,     /* 不使用中断*/
    GPIO_INTR_POSEDGE = 1,     /* 上升沿触发 */
    GPIO_INTR_NEGEDGE = 2,     /* 下降沿触发 */
    GPIO_INTR_ANYEDGE = 3,     /* 边沿(上升沿/下降沿)触发 */
    GPIO_INTR_LOW_LEVEL = 4,   /* 低电平触发 */
    GPIO_INTR_HIGH_LEVEL = 5,  /* 高电平触发 */
    GPIO_INTR_MAX,
} gpio_int_type_t;

与 STM32 逻辑开发环境的不同, ESP-IDF 从上到下已经有很多层,如下所示:

  1. APP
  2. Components
  3. HAL
  4. FreeRTOS
  5. FLASH BootLoader
  6. ROM BootLoader
  7. SoC

某些情况下,ESP32 的 FALSH 访问会被中断或者锁住,为确保中断服务函数能在任何时候可靠运行,要求中断服务函数满足以下两点要求:

  1. 纯粹运行在内部 RAM(IRAM)中
  2. 不访问 FLASH 中的数据或代码

使用属性宏 IRAM_ATTR 来告诉编译器,该函数必须放到 IRAM 中执行,外部中断服务函数模板如下:

static void IRAM_ATTR exti_isr_handler(void* arg) {
	//...
}

printf 函数存储在 FLASH 中,因此不要在中断中使用,如果非要使用请用以下函数代替:

#include <rom/ets_sys.h>

int ets_printf(const char *fmt, ...);

此外,不能在中断中执行能引起上下文切换的函数和中断不安全的函数,建议在中断中利用 FreeRTOS 的队列、事件组等任务间通信机制来传递信息。

中断在分配时有一些标志位 intr_alloc_flags ,这些标志位控制着 ISR 的行为,主要有如下一些标志位:

#define ESP_INTR_FLAG_LEVELx        (1<<x)  /* 中断优先级,x 从 1 到 6 */
#define ESP_INTR_FLAG_NMI           (1<<7)  /* 最高中断优先级 7 */
#define ESP_INTR_FLAG_SHARED        (1<<8)  /* 共享中断 */
#define ESP_INTR_FLAG_EDGE          (1<<9)  /* 边沿触发中断 */
#define ESP_INTR_FLAG_IRAM          (1<<10) /* 将中断处理函数放在 IRAM 中,避免访问 FLASH */
#define ESP_INTR_FLAG_INTRDISABLED  (1<<11) /* ISR 安装时默认不使能中断 */

#define ESP_INTR_FLAG_LOWMED    (ESP_INTR_FLAG_LEVEL1|ESP_INTR_FLAG_LEVEL2|ESP_INTR_FLAG_LEVEL3) /* 低中等级别优先级 */
#define ESP_INTR_FLAG_HIGH      (ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6|ESP_INTR_FLAG_NMI) /* 高等级优先级 */

使用 GPIO 外部中断时一般只需以下两步即可:

  1. gpio_install_isr_service
  2. gpio_isr_handler_add

1.2、数据结构

1.2.1、GPIO

ESP-IDF 驱动头文件

#include "driver/gpio.h"

GPIO 配置结构体

typedef struct {
    uint64_t pin_bit_mask; 					/* GPIO 引脚掩码 */
    gpio_mode_t mode; 						/* GPIO 模式 */
    gpio_pullup_t pull_up_en; 				/* GPIO 上拉使能 */
    gpio_pulldown_t pull_down_en; 			/* GPIO 下拉使能 */
    gpio_int_type_t intr_type; 				/* GPIO 中断类型*/
#if SOC_GPIO_SUPPORT_PIN_HYS_FILTER
    gpio_hys_ctrl_mode_t hys_ctrl_mode; 	/* GPIO 迟滞控制模式 */
#endif
}gpio_config_t;

1.2.2、毛刺过滤器

ESP-IDF 驱动头文件

#include "driver/gpio_filter.h"

管脚毛刺滤波器 配置结构体

typedef struct {
    glitch_filter_clock_source_t clk_src;	/* 时钟源 */
    gpio_num_t gpio_num; 					/* 引脚号 */
}gpio_pin_glitch_filter_config_t;

灵活毛刺滤波器 配置结构体

typedef struct {
    glitch_filter_clock_source_t clk_src; 	/* 时钟源 */
    gpio_num_t gpio_num;      				/* 引脚号 */
    uint32_t window_width_ns; 				/* 采样窗口宽度(ns) */
    uint32_t window_thres_ns; 				/* 采样窗口阈值(ns) */
} gpio_flex_glitch_filter_config_t;

1.3、硬件原理图

本文仅涉及 KEY 和 LED 两部分硬件,KEY 和 LED 部分的硬件原理图如下图所示:

GPIO-LED.png

GPIO-KEY.png

其中两个 LED 灯 D4 和 D5 分别由 ESP32 的 GPIO12 和 GPIO13 控制,当引脚输出高电平时对应的 LED 灯会被点亮。

ESP32 的 GPIO0 引脚可以初始化为上拉输入模式,当按键 S2 按下时,GPIO0 被拉低至地,这样就可以通过 GPIO0 输入获取按键的状态。

2、示例程序

2.1、GPIO 输出 - 点亮 LED 灯

功能:

  1. 固定每隔 1s 翻转一次 LED 灯的状态

程序流程:

  1. 使用 gpio_config() 配置 LED 引脚为 输出模式
  2. 通过 gpio_set_level() 固定周期设置引脚输出的高低电平

示例程序:

#include "freertos/FreeRTOS.h"
#include "driver/gpio.h"

#define LED_GPIO_PIN GPIO_NUM_13

/* The following does not need to be modified */
uint8_t led_pin_level = 0;

void led_init(void) {

    gpio_config_t io_cfg = {
        .pin_bit_mask = 1 << LED_GPIO_PIN,
        .mode = GPIO_MODE_OUTPUT,
        .pull_up_en = 0,
        .pull_down_en = 0,
        .intr_type = GPIO_INTR_DISABLE,
    };

    gpio_config( & io_cfg);
}

void app_main(void) {
    led_init();

    while (1) {
        led_pin_level = !led_pin_level;
        gpio_set_level(LED_GPIO_PIN, led_pin_level);
        vTaskDelay(1000);
    }
}

2.2、GPIO 输入 - 按键响应

功能:

  1. 按键 KEY 按下翻转 LED 状态

程序流程:

  1. 使用 gpio_config() 配置 LED 引脚为 输出模式
  2. 使用 gpio_config() 配置 KEY 引脚为 输入模式
  3. 通过 gpio_get_level() 获得 KEY 引脚输入的高低电平
  4. 当 KEY 引脚输入的电平为低电平时表示按键按下,通过 gpio_set_level() 翻转 LED 引脚输出电平

示例程序:

#include "freertos/FreeRTOS.h"
#include "driver/gpio.h"

#define KEY_GPIO_PIN GPIO_NUM_0
#define LED_GPIO_PIN GPIO_NUM_13

/* The following does not need to be modified */
uint8_t led_pin_level = 0;

void led_init(void) {

    gpio_config_t io_cfg = {
        .pin_bit_mask = 1 << LED_GPIO_PIN,
        .mode = GPIO_MODE_OUTPUT,
        .pull_up_en = 0,
        .pull_down_en = 0,
        .intr_type = GPIO_INTR_DISABLE,
    };

    gpio_config( & io_cfg);
    // The default output is high
	gpio_set_level(LED_GPIO_PIN, 1);
}

void key_init(void) {

    gpio_config_t io_cfg = {
        .pin_bit_mask = 1 << KEY_GPIO_PIN,
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = 1,
        .pull_down_en = 0,
        .intr_type = GPIO_INTR_DISABLE,
    };

    gpio_config( & io_cfg);
}

void app_main(void) {
    led_init();
    key_init();

    while (1) {

        if (gpio_get_level(KEY_GPIO_PIN) == 0) {
            vTaskDelay(5);
            if (gpio_get_level(KEY_GPIO_PIN) == 0) {
	            printf("KEY Pressed!\r\n");
                gpio_set_level(LED_GPIO_PIN, led_pin_level);
                led_pin_level = !led_pin_level;
                while (!gpio_get_level(KEY_GPIO_PIN)) {};
            }
        }
        vTaskDelay(10);
    }
}

2.3、GPIO 外部中断 - 按键响应

功能:

  1. 按键按下翻转 LED 状态

程序流程:

  1. 使用 gpio_config() 配置 LED 引脚为 输出模式
  2. 使用 gpio_config() 配置 KEY 引脚为 输入下降沿中断模式
  3. 调用 gpio_install_isr_service()gpio_isr_handler_add() 注册并使能 KEY 引脚中断
  4. 按键 KEY 按下触发下降沿中断,进入中断服务子程序,发送事件到队列
  5. 当检测到队列非空时,通过 gpio_set_level() 翻转 LED 灯状态

示例程序:

#include "freertos/FreeRTOS.h"
#include "driver/gpio.h"
#include <rom/ets_sys.h>

#define KEY_GPIO_PIN GPIO_NUM_0
#define LED_GPIO_PIN GPIO_NUM_13

/* The following does not need to be modified */
static uint8_t led_pin_level = 0;
static QueueHandle_t key_event_queue = NULL;

static void IRAM_ATTR exti_isr_handler(void * arg) {
    uint32_t gpio_num = (uint32_t) arg;
    BaseType_t hp = pdFALSE;
    ets_printf("KEY Pressed!\r\n");
    xQueueSendFromISR(key_event_queue, & gpio_num, & hp);
    if (hp) portYIELD_FROM_ISR();
}

void led_init(void) {

    gpio_config_t io_cfg = {
        .pin_bit_mask = 1 << LED_GPIO_PIN,
        .mode = GPIO_MODE_OUTPUT,
        .pull_up_en = 0,
        .pull_down_en = 0,
        .intr_type = GPIO_INTR_DISABLE,
    };

    gpio_config( & io_cfg);
    // The default output is high
	gpio_set_level(LED_GPIO_PIN, 1);
}

void key_init(void) {

    gpio_config_t io_cfg = {
        .pin_bit_mask = 1 << KEY_GPIO_PIN,
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = 1,
        .pull_down_en = 0,
        // edge
        .intr_type = GPIO_INTR_NEGEDGE,
    };

    gpio_config( & io_cfg);

    // Register a interrupt
    gpio_install_isr_service(ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM);

    // Add exti callback function to key gpio
    gpio_isr_handler_add(KEY_GPIO_PIN, exti_isr_handler, (void * ) KEY_GPIO_PIN);
}

static void key_task(void * arg) {
    uint32_t io_num;
    
    while (1) {
        if (xQueueReceive(key_event_queue, & io_num, portMAX_DELAY)) {
            // Key debouncing
            vTaskDelay(10);
            if (gpio_get_level(io_num) == 0) {
                // Release detection
                while (gpio_get_level(io_num) == 0) {
                    vTaskDelay(10);
                }
                gpio_set_level(LED_GPIO_PIN, led_pin_level);
                led_pin_level = !led_pin_level;
            }
        }
        vTaskDelay(10);
    }
    // Will not execute
    gpio_uninstall_isr_service();
}

void app_main(void) {
    // Configure the peripheral
	led_init();
	key_init();
	
    // Create event queue
    key_event_queue = xQueueCreate(10, sizeof(uint32_t));
    xTaskCreate(key_task, "key_task", 2048, NULL, 10, NULL);
}

3、常用函数

/* GPIO 配置函数 */
esp_err_t gpio_config(const gpio_config_t *pGPIOConfig)

/* 设置 GPIO 输出电平 */
esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level)

/* 获取 GPIO 输入电平 */
int gpio_get_level(gpio_num_t gpio_num);

/* 注册 GPIO 中断服务 */
esp_err_t gpio_install_isr_service(int intr_alloc_flags)
/* 添加 GPIO 中断服务函数 */
esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void *args)
/* GPIO 中断使能 */
esp_err_t gpio_intr_enable(gpio_num_t gpio_num)

4、烧录验证

使用逻辑分析仪捕获 LED_GPIO_PIN 引脚的电平,证明了其确实是 1s 翻转一次 LED 状态

“GPIO 输出 - 点亮 LED 灯” 实验效果如下:

GPIO-LED-RESULT.png

“GPIO 输入 - 按键响应” 和 “GPIO 外部中断 - 按键响应” 实验效果一样

使用串口助手和逻辑分析仪监测串口输出和 LED_GPIO_PIN 引脚电平状态,当按键按下时串口输出 ”KEY Pressed!“ ,同时逻辑分析捕获的 LED_GPIO_PIN 引脚电平翻转,符合预期,如下所示:

GPIO-KEY-RESULT.gif

<think>我们被要求查找ESP32-IDFGPIO输入中断的使用方法相关资料。根据提供的引用,特别是引用[2]引用[3],我们可以整理出使用GPIO中断的步骤关键API。 步骤: 1. 配置GPIO引脚的方向(设置为输入模式)上拉/下拉电阻(根据需要使用上拉或下拉,例如按键通常配置为上拉或下拉)。 2. 设置中断类型(例如上升沿触发、下降沿触发等)。 3. 注册中断服务函数(有两种方式:一种是直接注册单个中断处理函数,另一种是使用中断服务并添加多个中断处理函数)。 4. 在中断处理函数中执行需要的操作。 关键API(参考引用[2]引用[3]): - `gpio_set_direction`:设置GPIO方向(输入输出等)。 - `gpio_set_pull_mode`:设置上拉或下拉电阻。 - `gpio_set_intr_type`:设置中断触发类型(如上升沿、下降沿等)。 - 注册中断处理函数:有两种方法: 方法一:使用`gpio_isr_register`直接注册一个中断处理函数(全局中断处理函数)。 方法二:使用`gpio_install_isr_service`安装一个中断服务,然后使用`gpio_isr_handler_add`为特定的GPIO添加中断处理函数(推荐,因为可以更好地管理多个中断)。 另外,引用[3]中提到了GPIO中断API包括: - `gpio_set_intr_type` - `gpio_isr_register` - `gpio_install_isr_service` - `gpio_uninstall_isr_service` - `gpio_isr_handler_add` - `gpio_isr_handler_remove` 我们通常推荐使用第二种方法(安装中断服务并添加处理函数),因为它允许为不同的GPIO分别注册中断处理函数,并且更灵活。 具体步骤示例(参考引用[3]): 1. 配置GPIO输入模式,并设置上拉/下拉。 2. 安装GPIO中断服务(调用`gpio_install_isr_service`)。 3. 为特定的GPIO设置中断类型(`gpio_set_intr_type`)。 4. 使用`gpio_isr_handler_add`为该GPIO添加中断处理函数。 5. 在中断处理函数中,注意不要进行耗时操作,通常使用任务通知或队列来通知其他任务处理。 注意:在使用中断前,需要先配置GPIO引脚。 下面是一个简单的代码示例(根据引用内容整理): ```c #include "driver/gpio.h" #define GPIO_INPUT_IO_0 4 // 示例GPIO引脚号 // 中断处理函数 void IRAM_ATTR gpio_isr_handler(void* arg) { // 中断处理逻辑,注意要快速执行 // 可以通过队列或任务通知将事件发送给任务处理 } void app_main() { // 1. 配置GPIO gpio_config_t io_conf = {}; io_conf.intr_type = GPIO_INTR_NEGEDGE; // 下降沿触发 io_conf.mode = GPIO_MODE_INPUT; io_conf.pin_bit_mask = (1ULL << GPIO_INPUT_IO_0); io_conf.pull_down_en = 0; // 禁用下拉 io_conf.pull_up_en = 1; // 使能上拉 gpio_config(&io_conf); // 2. 安装GPIO中断服务 gpio_install_isr_service(0); // 参数是中断标志,0表示默认 // 3. 为GPIO注册中断处理函数 gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0); // ... 其他代码 } ``` 注意事项: - 中断处理函数应该放在IRAM中(使用`IRAM_ATTR`属性),因为当Flash缓存被禁用时(例如写Flash操作),中断必须能够被处理。 -中断处理函数中避免使用printf等耗时且可能不安全的函数,尽量简短。 引用说明: 引用[2]详细说明了`gpio_isr_register`函数的参数用法,但注意,引用[3]中提到了更推荐使用`gpio_install_isr_service``gpio_isr_handler_add`组合的方式,因为这样可以注册多个中断处理函数,而`gpio_isr_register`只能注册一个全局的中断处理函数(然后需要在该函数中判断是哪个引脚触发的中断)。 因此,我们一般使用安装中断服务的方式(方法二)。如果只有少量中断,也可以使用全局中断处理函数(方法一)。 建议查阅官方文档以获取最新信息,但根据提供的引用,以上方法可行。 相关问题: 1. 在ESP32-IDF中,如何配置GPIO中断的触发方式? 2. 使用GPIO中断时,中断处理函数应注意哪些问题? 3. 如何为多个GPIO引脚配置中断? </think>基于提供的引用内容,以下是ESP32-IDFGPIO输入中断的使用指南关键要点: ### GPIO输入中断配置步骤(ESP-IDF V4.4+) 1. **配置GPIO模式**(必须设置为输入) ```c gpio_config_t io_conf = { .pin_bit_mask = (1ULL << GPIO_NUM_X), // 替换X为实际引脚号 .mode = GPIO_MODE_INPUT, // 必须设为输入模式[^2][^3] .pull_up_en = 1, // 使能上拉电阻 .intr_type = GPIO_INTR_NEGEDGE // 设置中断类型(此处为下降沿触发) }; gpio_config(&io_conf); ``` 2. **安装中断服务** ```c gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1); // 安装全局中断服务[^3] ``` 3. **注册中断处理函数** ```c gpio_isr_handler_add(GPIO_NUM_X, isr_handler, NULL); // GPIO_NUM_X:目标引脚 // isr_handler:用户自定义中断函数[^3] ``` 4. **编写中断处理函数**(需标记`IRAM_ATTR`) ```c #include "freertos/FreeRTOS.h" #include "freertos/task.h" void IRAM_ATTR isr_handler(void* arg) { // 注意:避免耗时操作!推荐使用队列通知任务 BaseType_t high_task_wakeup = pdFALSE; xQueueSendFromISR(event_queue, &data, &high_task_wakeup); } ``` ### 关键API详解 | API | 功能 | 参数说明 | 来源 | |-----|------|----------|------| | `gpio_set_intr_type()` | 设置中断触发类型 | `gpio_intr_type_t`(上升沿/下降沿等) | [^3] | | `gpio_isr_register()` | 注册全局中断函数 | `fn`:处理函数指针,`arg`:参数 | [^2] | | `gpio_install_isr_service()` | 安装中断服务 | `intr_alloc_flags`:中断优先级标志 | [^3] | | `gpio_isr_handler_add()` | 绑定引脚与中断函数 | `gpio_num`:引脚号,`fn`:处理函数 | [^3] | ### 注意事项 1. **未配置输入模式时中断无效** 若引脚未通过`gpio_set_direction()`配置为输入模式,中断将无法触发[^2]。 2. **中断处理限制** - 必须使用`IRAM_ATTR`确保函数在RAM中执行 - 避免调用`printf()`等非中断安全函数 - 典型做法:通过队列/信号量通知外部任务[^3] 3. **中断类型选项** ```c typedef enum { GPIO_INTR_DISABLE = 0, // 禁用中断 GPIO_INTR_POSEDGE, // 上升沿触发 GPIO_INTR_NEGEDGE, // 下降沿触发 GPIO_INTR_ANYEDGE, // 双边沿触发 GPIO_INTR_LOW_LEVEL, // 低电平触发 GPIO_INTR_HIGH_LEVEL // 高电平触发 } gpio_int_type_t; ``` ### 完整示例代码 ```c #include "driver/gpio.h" #include "freertos/queue.h" #define GPIO_INPUT_PIN 4 QueueHandle_t gpio_evt_queue; void IRAM_ATTR gpio_isr_handler(void* arg) { uint32_t gpio_num = (uint32_t)arg; xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL); } void app_main() { // 创建事件队列 gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t)); // 配置GPIO gpio_config_t io_conf = { .pin_bit_mask = (1ULL << GPIO_INPUT_PIN), .mode = GPIO_MODE_INPUT, .pull_up_en = 1, .intr_type = GPIO_INTR_NEGEDGE }; gpio_config(&io_conf); // 安装中断服务 gpio_install_isr_service(0); gpio_isr_handler_add(GPIO_INPUT_PIN, gpio_isr_handler, (void*)GPIO_INPUT_PIN); // 任务处理队列事件 while(1) { uint32_t io_num; if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) { printf("GPIO[%d]中断触发\n", io_num); } } } ``` ### 官方资源推荐 1. [ESP-IDF GPIO API文档](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/gpio.html) 2. [GPIO中断示例代码](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/gpio/generic_gpio)
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OSnotes

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值