电路图 GPIO的中断类型 相关API函数 应用举例 总结 电路图 在ESP32中内部有完整的控制电路,比如上下拉以及滤波器等,所以我们这里可以直接用一个微动开关连接到地。 GPIO的中断类型 GPIO_INTR_DISABLE 不使能中断 GPIO_INTR_POSEDGE 上升沿触发 GPIO_INTR_NEGEDGE 下降沿触发 GPIO_INTR_ANYEDGE 上升沿和下降沿都触发 GPIO_INTR_LOW_LEVEL 低电平触发 GPIO_INTR_HIGH_LEVEL 高电平触发 在GPIO中断应用中,一般使用上升沿或者下降沿触发 相关API函数 GPIO配置结构体 typedef struct { uint64_t pin_bit_mask; /*gpio引脚的位掩码 ,设置为(1ULLGPIO_NUM)*/ 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 ; GPIO配置函数 esp_err_t gpio_config ( const gpio_config_t *pGPIOConfig) //参数为填充过的gpio_config_t结构体 //返回值:成功返回ESP_OK // 失败返回ESP_ERR_INVALID_ARG,表示参数错误 注册中断 //步骤一:安装中断服务,匹配一个gpio中断 esp_err_t gpio_install_isr_service ( int intr_alloc_flags //用于分配中断的标志,一般为ESP_INTR_FLAG_*,在 esp_intr_alloc.h定义 ) /*返回值: ESP_OK :成功 ESP_ERR_NO_MEM :没有内存安装这个服务 ESP_ERR_INVALID_STATE :中断服务已安装 ESP_ERR_NOT_FOUND :没有找到指定标志的空闲中断 ESP_ERR_INVALID_ARG :gpio错误 */ //步骤二:给gpio中断添加服务函数 esp_err_t gpio_isr_handler_add ( gpio_num_t gpio_num, //gpio编号 gpio_isr_t isr_handler, //中断服务函数 void *args //传递给中断服务函数的参数 ) 应用举例 /** * Copyright (C) 2024-2034 HalfMoon2. * All rights reserved. * * @file Filename without the absolute path * @brief Brief description * @author HalfMoon2 * @date 2025-06-10 * @version v0.1 * * @revision history: * 2025-06-10 - Initial version. */ # include stdio.h # include driver/gpio.h # include freertos/FreeRTOS.h # include freertos/task.h # include freertos/event_groups.h # include esp_log.h # define KEY_GPIO GPIO_NUM_7 # define LED_GPIO GPIO_NUM_4 # define EVENT_BIT0 (10) static EventGroupHandle_t gpio_event= NULL ; static void IRAM_ATTR gpio_isr_handler ( void *pvparam) { BaseType_t pxHigherPriorityTaskWoken= pdFALSE; //先储存下来,在此例程中不做处理 xEventGroupSetBitsFromISR (gpio_event,EVENT_BIT0,pxHigherPriorityTaskWoken); } void event_task ( void *pvparam) { while ( 1 ){ if ( xEventGroupWaitBits (gpio_event,EVENT_BIT0,pdTRUE,pdFALSE,portMAX_DELAY)== 0x01 ){ gpio_set_level (LED_GPIO, 1 ); vTaskDelay ( pdMS_TO_TICKS ( 100 )); gpio_set_level (LED_GPIO, 0 ); ESP_LOGI ( "key" , "Event Wait Success!!!" ); } } } /** * @brief GPIO初始化 */ void gpio_init ( void ) { /*配置LED所连接的GPIO*/ gpio_config_t led_config={ .mode=GPIO_MODE_OUTPUT, .pin_bit_mask=( 1ULL LED_GPIO), .pull_up_en=GPIO_PULLUP_DISABLE, .pull_down_en=GPIO_PULLDOWN_DISABLE, .intr_type=GPIO_INTR_DISABLE }; gpio_config (led_config); /*配置key所连接的GPIO*/ gpio_config_t key_config={ .mode=GPIO_MODE_INPUT, .pin_bit_mask=( 1ULL KEY_GPIO), .pull_up_en=GPIO_PULLUP_ENABLE, .pull_down_en=GPIO_PULLDOWN_DISABLE, .intr_type=GPIO_INTR_NEGEDGE }; gpio_config (key_config); /*创建事件组,用于发出中断事件*/ gpio_event= xEventGroupCreate (); /*任务创建 */ xTaskCreatePinnedToCore (event_task, "event_task" , 2048 , NULL , 10 , NULL , 1 ); /*安装中断服务,此函数进行中断寄存器初始化,并注册中断*/ gpio_install_isr_service ( 0 ); /*给特定GPIO添加中断服务函数 */ gpio_isr_handler_add (KEY_GPIO,gpio_isr_handler, NULL ); } void app_main ( void ) { gpio_init (); } 当每次按键按下,将触发中断服务函数,中断服务函数设置事件组,任务函数获取并处理事件。将得到如下情况: 总结 在中断服务函数中不要使用ESP_LOGI或者printf等打印函数,将报错 不能直接使用gpio_isr_register()函数,会报段错误,因为在注册之前需要清除中断寄存器等操作。可以通过分析gpio_install_isr_service()函数原型了解其中缘由。 GPIO中断服务函数前一定要添加IRAM_ATTR关键字,表示将此函数放在内部RAM中,未添加则将放在flash中,中断触发后会反应很慢。