当前位置: 首页 > news >正文

ESP32-IDF GPIO 专题

目录

  • 一、基本介绍
    • 1、配置结构体
    • 2、API
      • 2.1 gpio_config
      • 2.2 gpio_reset_pin
      • 2.3 gpio_set_intr_type
      • 2.4 gpio_intr_enable
      • 2.5 gpio_intr_disable
      • 2.6 gpio_set_level
      • 2.7 gpio_get_level
      • 2.8 gpio_set_direction
      • 2.9 gpio_set_pull_mode
      • 2.10 gpio_isr_register
      • 2.11 gpio_install_isr_service
      • 2.12 gpio_uninstall_isr_service
      • 2.13 gpio_isr_handler_add
      • 2.14 gpio_isr_handler_remove
    • 3、枚举类型
      • 3.1 gpio_mode_t
      • 3.2 gpio_pullup_t
      • 3.3 gpio_pulldown_t
      • 3.4 gpio_pull_mode_t
      • 3.5 gpio_int_type_t
  • 三、实例操作
    • 1、例一——简单的点灯程序
    • 2、例二——添加中断
      • 2.1 通过 GPIO 读取实现
      • 2.2 通过中断函数实现


一、基本介绍

API 参考路径 esp-idf/components/esp_driver_gpio/include/driver/gpio.h

ESP-IDF 由多个组件组成,组件中包含专门为 ESP 芯片编写的代码或第三方库(即第三方组件)。对于某些第三方库,ESP-IDF 提供专用的包装器和接口,以简化对第三方库的使用,或提高其与 ESP-IDF 其他功能的兼容性。某些情况下,第三方组件将直接呈现底层库的原始 API。

1、配置结构体

为确保应用程序与未来 ESP-IDF 版本的兼容性,请正确初始化配置结构体。

多数 ESP-IDF 中的初始化、配置和安装函数(通常以 ..._init()..._config()..._install() 命名)都需要一个指向配置结构体的指针作为参数。例如:

const esp_timer_create_args_t my_timer_args = {.callback = &my_timer_callback,.arg = callback_arg,.name = "my_timer"
};
esp_timer_handle_t my_timer;
esp_err_t err = esp_timer_create(&my_timer_args, &my_timer);

初始化函数不会存储指向配置结构体的指针,因此在栈上分配结构体是安全的。

下面介绍 GPIO 的配置结构体:

typedef struct {uint64_t pin_bit_mask;          /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */gpio_mode_t mode;               /*!< GPIO mode: set input/output mode                     */gpio_pullup_t pull_up_en;       /*!< GPIO pull-up                                         */gpio_pulldown_t pull_down_en;   /*!< GPIO pull-down                                       */gpio_int_type_t intr_type;      /*!< GPIO interrupt type                                  */
#if SOC_GPIO_SUPPORT_PIN_HYS_FILTERgpio_hys_ctrl_mode_t hys_ctrl_mode;       /*!< GPIO hysteresis: hysteresis filter on slope input    */
#endif
} gpio_config_t;
  • pin_bit_mask:GPIO 引脚号。
    • 比如 GPIO_NUM_2,则配置为 .pin_bit_mask = (1 << GPIO_NUM_2)
  • mode:选择输入/输出模式
  • pull_up_en:引脚上拉设置
  • pull_down_en:引脚下拉设置
  • intr_type:中断模式

有关这几个类型的定义在本文第三小节可以找到

2、API

在使用 GPIO 相关的 API 时,要加上头文件:

#include "driver/gpio.h"

2.1 gpio_config

esp_err_t gpio_config(const gpio_config_t *pGPIOConfig);
  • 参数
    • pGPIOConfig:GPIO 配置结构体,见第一小节
  • 作用:
    • 该函数用于初始化 GPIO 的 Mode、pull-up、PullDown、IntrType,
  • 返回值
    • ESP_OK 成功
    • ESP_ERR_INVALID_ARG 参数错误

2.2 gpio_reset_pin

esp_err_t gpio_reset_pin(gpio_num_t gpio_num)
  • 参数:
    • gpio_num:引脚号
  • 作用
    • 重置 GPIO 到默认状态(选择 GPIO 功能,启用上拉,禁用输入和输出)。
  • 返回值
    • 总是返回 ESP_OK

2.3 gpio_set_intr_type

esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type)
  • 参数
    • gpio_num:引脚号
    • intr_type:中断类型,见第三小节
  • 作用
    • 设置 GPIO 中断类型
  • 返回值
    • ESP_OK 成功
    • ESP_ERR_INVALID_ARG 参数错误

2.4 gpio_intr_enable

esp_err_t gpio_intr_enable(gpio_num_t gpio_num)
  • 参数
    • gpio_num:引脚号
  • 作用
    • 使能 GPIO 中断
  • 返回值
    • ESP_OK 成功
    • ESP_ERR_INVALID_ARG 参数错误

2.5 gpio_intr_disable

esp_err_t gpio_intr_disable(gpio_num_t gpio_num)
  • 参数
    • gpio_num:引脚号
  • 作用
    • 禁用 GPIO 中断
  • 返回值
    • ESP_OK 成功
    • ESP_ERR_INVALID_ARG 参数错误

2.6 gpio_set_level

esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level)
  • 参数
    • gpio_num:引脚号
    • level:0: 低;1: 高
  • 作用
    • 设置 GPIO 输出电平
  • 返回值
    • ESP_OK 成功
    • ESP_ERR_INVALID_ARG 参数错误

通过启用 CONFIG_GPIO_CTRL_FUNC_IN_IRAM,此函数允许在 ISR 上下文中禁用缓存的情况下执行。

2.7 gpio_get_level

int gpio_get_level(gpio_num_t gpio_num)
  • 参数
    • gpio_num:引脚号
  • 作用
    • 获取 GPIO 输入电平
  • 返回值
    • 0:低电平;1:高电平

如果引脚未配置为输入(或输入和输出),返回的值始终为 0。

2.8 gpio_set_direction

esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode)
  • 参数
    • gpio_num:引脚号
    • mode:要设置的模式,见第三小节
  • 作用
    • 配置 GPIO 方向,例如仅输出,仅输入,输出和输入
  • 返回值
    • ESP_OK 成功
    • ESP_ERR_INVALID_ARG 参数错误

2.9 gpio_set_pull_mode

esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull_mode)
  • 参数
    • gpio_num:引脚号
    • pull_mode:GPIO 拉高/拉低模式,见第三小节
  • 作用
    • 配置 GPIO 上拉/下拉电阻
  • 返回值
    • ESP_OK 成功
    • ESP_ERR_INVALID_ARG 参数错误

2.10 gpio_isr_register

esp_err_t gpio_isr_register(void (*fn)(void*), void *arg, int intr_alloc_flags, gpio_isr_handle_t *handle)
  • 参数
    • fn:中断处理函数
    • arg :中断处理函数的参数
    • intr_alloc_flags:用于分配中断的标志。一个或多个(通过位或运算组合)ESP_INTR_FLAG_* 值。
    • handle:返回句柄的指针。如果非 NULL,这里将返回中断的句柄。

esp32_idf/esp-idf/components/esp_hw_support/include/esp_intr_alloc.h

//Keep the LEVELx values as they are here; they match up with (1<<level)
#define ESP_INTR_FLAG_LEVEL1        (1<<1)  ///< Accept a Level 1 interrupt vector (lowest priority)
#define ESP_INTR_FLAG_LEVEL2        (1<<2)  ///< Accept a Level 2 interrupt vector
#define ESP_INTR_FLAG_LEVEL3        (1<<3)  ///< Accept a Level 3 interrupt vector
#define ESP_INTR_FLAG_LEVEL4        (1<<4)  ///< Accept a Level 4 interrupt vector
#define ESP_INTR_FLAG_LEVEL5        (1<<5)  ///< Accept a Level 5 interrupt vector
#define ESP_INTR_FLAG_LEVEL6        (1<<6)  ///< Accept a Level 6 interrupt vector
#define ESP_INTR_FLAG_NMI           (1<<7)  ///< Accept a Level 7 interrupt vector (highest priority)
#define ESP_INTR_FLAG_SHARED        (1<<8)  ///< Interrupt can be shared between ISRs
#define ESP_INTR_FLAG_EDGE          (1<<9)  ///< Edge-triggered interrupt
#define ESP_INTR_FLAG_IRAM          (1<<10) ///< ISR can be called if cache is disabled
#define ESP_INTR_FLAG_INTRDISABLED  (1<<11) ///< Return with this interrupt disabled
  • 作用
    • 注册 GPIO 中断处理程序,该处理程序是一个 ISR。处理程序将被附加到运行此函数的相同 CPU 核心上。每当发生任何 GPIO 中断时,都会调用此 ISR。
  • 返回值
    • ESP_OK 成功
    • ESP_ERR_INVALID_ARG 参数错误
    • ESP_ERR_NOT_FOUND 在指定的标志下未找到可用的中断

2.11 gpio_install_isr_service

esp_err_t gpio_install_isr_service(int intr_alloc_flags)
  • 参数
    • intr_alloc_flags:分配中断时使用的标志。一个或多个(按 OR 运算)ESP_INTR_FLAG_* 值。见 2.10
  • 作用
    • 安装 GPIO 驱动程序的 ETS_GPIO_INTR_SOURCE ISR 处理程序服务,允许为每个引脚配置GPIO中断处理程序。
  • 返回值
    • ESP_OK 成功
    • ESP_ERR_INVALID_ARG 参数错误
    • ESP_ERR_NOT_FOUND 没有找到具有指定标志的空中断
    • ESP_ERR_INVALID_STATE ISR 服务未初始化。

此功能与 gpio_isr_register() 不兼容 - 如果使用该功能,将为所有 GPIO 中断注册一个全局中断服务程序(ISR)。如果使用此功能,中断服务提供了一个全局 GPIO ISR,通过 gpio_isr_handler_add() 函数注册单个引脚处理器。

2.12 gpio_uninstall_isr_service

void gpio_uninstall_isr_service(void)

卸载驱动的 GPIO ISR 服务,释放相关资源。

2.13 gpio_isr_handler_add

esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void* args)
  • 参数
    • gpio_num:引脚号
    • isr_handler:中断处理函数
    • args:中断处理函数的参数
  • 作用
    • 为相应的 GPIO 引脚添加 ISR 处理器。使用完 gpio_install_isr_service() 后,调用此函数以安装驱动程序的 GPIO ISR 服务。
  • 返回值
    • ESP_OK 成功
    • ESP_ERR_INVALID_ARG 参数错误
    • ESP_ERR_INVALID_STATE ISR 服务未初始化。

中断服务例行程序(ISR)处理器不再需要使用 IRAM_ATTR 进行声明,除非在为中断服务程序(ISR)分配 gpio_install_isr_service() 时传递 ESP_INTR_FLAG_IRAM 标志。

此 ISR 处理器将从 ISR 中调用。因此有一个堆栈大小限制(在 menuconfig 中可配置为“ISR 堆栈大小”)。与全局 GPIO 中断处理器相比,这个限制较小,因为多了一层间接性。

2.14 gpio_isr_handler_remove

esp_err_t gpio_isr_handler_remove(gpio_num_t gpio_num)
  • 参数
    • gpio_num:引脚号
  • 作用
    • 移除对应 GPIO 引脚的 ISR 处理器。
  • 返回值
    • ESP_OK 成功
    • ESP_ERR_INVALID_ARG 参数错误
    • ESP_ERR_INVALID_STATE ISR 服务未初始化。

3、枚举类型

选自文件:esp32_idf/esp-idf/components/hal/include/hal/gpio_types.h

3.1 gpio_mode_t

typedef enum {GPIO_MODE_DISABLE = GPIO_MODE_DEF_DISABLE,                                                         /* 禁用GPIO端口的输入和输出功能 */GPIO_MODE_INPUT = GPIO_MODE_DEF_INPUT,                                                             /* 输入模式 */GPIO_MODE_OUTPUT = GPIO_MODE_DEF_OUTPUT,                                                           /* 输出模式 */GPIO_MODE_OUTPUT_OD = ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)),                               /* 开漏模式,常用于与其他设备共享信号线的场景 */GPIO_MODE_INPUT_OUTPUT_OD = ((GPIO_MODE_DEF_INPUT) | (GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)), /* 同时作为输入和输出,并且具有开漏特性。这种组合模式常用于复杂的需求,如与外部设备双向通信 */GPIO_MODE_INPUT_OUTPUT = ((GPIO_MODE_DEF_INPUT) | (GPIO_MODE_DEF_OUTPUT)),                         /*同时作为输入和输出 */
} gpio_mode_t;

3.2 gpio_pullup_t

typedef enum {GPIO_PULLUP_DISABLE = 0x0,     /* 无上拉 */GPIO_PULLUP_ENABLE = 0x1,      /* 设置为上拉 */
} gpio_pullup_t;

3.3 gpio_pulldown_t

typedef enum {GPIO_PULLDOWN_DISABLE = 0x0,   /* 无下拉 */GPIO_PULLDOWN_ENABLE = 0x1,    /* 设置为下拉 */
} gpio_pulldown_t;

3.4 gpio_pull_mode_t

typedef enum {GPIO_PULLUP_ONLY,               /* 仅上拉 */GPIO_PULLDOWN_ONLY,             /* 仅下拉 */GPIO_PULLUP_PULLDOWN,           /* 同时配置为上拉和下拉 */GPIO_FLOATING,                  /* 浮动模式,即不施加任何上拉或下拉。引脚的电平状态是不确定的,通常用于测量或读取外部信号 */
} gpio_pull_mode_t;

3.5 gpio_int_type_t

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;

三、实例操作

1、例一——简单的点灯程序

这一小节,以一个简单的点灯程序为例,来熟悉一下 ESP32-IDF GPIO 的使用。

创建程序相关见前:ESP32-IDF 在 Ubuntu 下的配置

例程代码如下:

#define LED1_GPIO GPIO_NUM_12void led1_run_task(void)
{int gpio_level = 0;while(1){gpio_level = !gpio_level;gpio_set_level(LED1_GPIO, gpio_level);vTaskDelay(pdMS_TO_TICKS(500));}
}void app_main(void)
{gpio_config_t led_conf = {.pin_bit_mask = (1 << LED1_GPIO),.pull_up_en   = 1,.pull_down_en = GPIO_PULLDOWN_DISABLE,.mode         = GPIO_MODE_OUTPUT,.intr_type    = GPIO_INTR_DISABLE,};gpio_config(&led_conf);xTaskCreate((void *)led1_run_task, "led1", 1024 * 2, NULL, 0, NULL);
}

2、例二——添加中断

本例将读取外部按键 KEY 的状态,当按下 KEY 是窗口打印信息。

2.1 通过 GPIO 读取实现

这里通过 GPIO 读取 KEY 引脚来实现“中断”:

#define KEY_GPIO GPIO_NUM_9void app_main(void)
{gpio_config_t key_conf = {.pin_bit_mask = (1ULL << KEY_GPIO),.mode = GPIO_MODE_INPUT,.pull_up_en = GPIO_PULLUP_ENABLE,.pull_down_en = GPIO_PULLDOWN_DISABLE,.intr_type = GPIO_INTR_POSEDGE,};gpio_config(&key_conf);while (1) {if (gpio_get_level(KEY_GPIO) == 0){vTaskDelay(pdMS_TO_TICKS(10));while (gpio_get_level(KEY_GPIO) == 0);printf("KEY PRESSED\n");}}
}

2.2 通过中断函数实现

#define GPIO_INPUT_IO         9
#define GPIO_INPUT_PIN_SEL    1ULL<<GPIO_INPUT_IO
#define ESP_INTR_FLAG_DEFAULT 0static QueueHandle_t gpio_evt_queue = NULL;static void IRAM_ATTR gpio_isr_handler(void* arg)
{uint32_t gpio_num = (uint32_t) arg;xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}static void gpio_task_example(void* arg)
{uint32_t io_num;for(;;) {if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {printf("GPIO[%ld] intr, val: %d\n", (uint32_t)io_num, gpio_get_level(io_num));}}
}void app_main(void)
{gpio_config_t gpio_conf = {.intr_type = GPIO_INTR_ANYEDGE,      // 上升、下降沿都产生中断.pin_bit_mask = GPIO_INPUT_PIN_SEL,  // bit mask of the pins, use GPIO0 here.mode = GPIO_MODE_INPUT,             // 设置输入模式.pull_up_en = 1,                     // 使能上拉};gpio_config(&gpio_conf);//create a queue to handle gpio event from isrgpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));//start gpio taskxTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, 10, NULL);//install gpio isr servicegpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);//hook isr handler for specific gpio pingpio_isr_handler_add(GPIO_INPUT_IO, gpio_isr_handler, (void*) GPIO_INPUT_IO);
}


http://www.mrgr.cn/news/51871.html

相关文章:

  • x-cmd pkg | deno - Node.js 创始人的创新之作,安全且现代的 Node.js 替代方案
  • C++ 学习笔记八 数组
  • TCP/IP 协议【四次挥手】简要说明
  • 十三、事务基础知识
  • NASA:全球鹰无人机系统(UAS)上收集的在位云层测量
  • 【C++贪心】2086. 喂食仓鼠的最小食物桶数|1622
  • Java - Spring 表达式语言 (SpEL) 简单入门
  • 科研绘图系列:R语言柱状图(histogram)
  • 操作系统实验二:shell的实现
  • 制造企业数字化转型顶层规划案例(55页满分PPT)
  • 92、Python之异常:异常的概念及异常处理机制
  • MyBatis的占位符(day36)
  • 中科星图GVE案例——利用最短距离方法实现土地分类(合肥)
  • 【JavaEE】——三次握手()详细、易理解
  • Spring 声明式事务
  • 基于 MyBatis Plus 分页封装分页方法
  • 第九课:Python学习之函数基础
  • 2024年的5款AI写作工具,你用过几个?
  • 【含文档】基于Springboot+Vue的仓库管理系统设计与实现(含源码+数据库+lw)
  • 高级IO——五种IO模型