ESP32 (GPIO)-GPIO学习(5)

提示:本博客作为学习笔记,有错误的地方希望指正

一、ESP32 GPIO介绍

参考资料:ESP IDF编程手册V4.4
  ESP32 芯片有 34 个物理 GPIO pad。每个 pad 都可用作一个通用 IO,或连接一个内部的外设信号。IO_MUX、RTCIO_MUX 和 GPIO 交换矩阵用于将信号从外设传输至 GPIO pad。这些模块共同组成了芯片的 IO 控制。
注意:这 34 个物理 GPIO pad 的序列号为:0-19, 21-23, 25-27, 32-39。其中 GPIO 34-39 仅用作输入管脚,其
他的既可以作为输入又可以作为输出管脚。

  这里描述数字 pad(控制信号:FUN_SEL、IE、OE、WPU、WDU 等)和 162 个外设输入以及 176 个设输出信号(控制信号:SIG_IN_SEL、SIG_OUT_SEL、IE、OE 等)和快速外设输入/输出信号(控制信号:IE、OE 等)以及 RTC IO_MUX 之间的信号选择和连接关系。
在这里插入图片描述

  1. IO_MUX 中每个 GPIO pad 有一组寄存器。每个 pad 可以配置成 GPIO 功能(连接 GPIO 交换矩阵)或者
    直连功能(旁路 GPIO 交换矩阵,快速信号如以太网、SDIO、SPI、JTAG、UART 等会旁路 GPIO 交换矩
    阵以实现更好的高频数字特性。所以高速信号会直接通过 IO_MUX 输入和输出。)
  2. GPIO 交换矩阵是外设输入和输出信号和 pad 之间的全交换矩阵。
    • 芯片输入方向:162 个外设输入信号都可以选择任意一个 GPIO pad 的输入信号。
    • 芯片输出方向:每个 GPIO pad 的输出信号可来自 176 个外设输出信号中的任意一个。
  3. RTC IO_MUX 用于控制 GPIO pad 的低功耗和模拟功能。只有部分 GPIO pad 具有这些功能。
      ESP32的GPIO矩阵是非常好用的,但是还是要的注意些使用情况,在使用SPI IO矩阵的时候就会出现速度不如原配的那几个IO的速度快,这个具体更多的还是查看数据手册。

二、硬件设计

  任何ESP32模块和开发版都适合。

三、实现代码

  这里主要实现的功能有ESP32的GPIO输出功能以及GPIO中断输入功能的测试,使用队列实现对于ESP32GPIO中断IO编号的数据发送。
  初始化流程
在这里插入图片描述

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"

#define GPIO_OUTPUT_IO_0    18
#define GPIO_OUTPUT_IO_1    19
#define GPIO_OUTPUT_PIN_SEL  ((1ULL<<GPIO_OUTPUT_IO_0) | (1ULL<<GPIO_OUTPUT_IO_1))
#define GPIO_INPUT_IO_0     3
#define GPIO_INPUT_IO_1     5
#define GPIO_INPUT_PIN_SEL  ((1ULL<<GPIO_INPUT_IO_0) | (1ULL<<GPIO_INPUT_IO_1))
#define ESP_INTR_FLAG_DEFAULT 0

static xQueueHandle gpio_evt_queue = NULL;
/**
 * @brief GPIO中断回调函数 IRAM_ATTR中断存储在iram1中的
 * @param arg 
 */
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
    uint32_t gpio_num = (uint32_t) arg;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL); //中断队列发送
}
/**
 * @brief gpio任务
 * @param arg 
 */
static void gpio_task_example(void* arg)
{
    uint32_t io_num;
    for(;;) {
        if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) { //接收队列
            printf("GPIO[%d] intr, val: %d\n", io_num, gpio_get_level(io_num));
        }
    }
}

void app_main(void)
{
    
    gpio_config_t io_conf = {};                             //零初始化结构体
    io_conf.intr_type = GPIO_INTR_DISABLE;                  //禁用中断
    io_conf.mode = GPIO_MODE_OUTPUT;                        //设置为输出模式
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;             //要设置的引脚的位掩码,e.g.GPIO18/19
    io_conf.pull_down_en = 0;                               //禁用下拉模式
    io_conf.pull_up_en = 0;                                 //禁用上拉模式
    gpio_config(&io_conf);                                  //配置GPIO结构体参数

    io_conf.intr_type = GPIO_INTR_POSEDGE;                  //上升沿中断
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;              //引脚的位掩码,此处使用 GPIO4/5
    io_conf.mode = GPIO_MODE_INPUT;                         //设置为输入模式
    io_conf.pull_up_en = 1;                                 //开启上拉模式
    gpio_config(&io_conf);

    gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_ANYEDGE); //改变一个引脚的gpio中断类型
    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));    //创建一个队列来处理来自isr的gpio事件
    //开启gpio任务
    xTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, 10, NULL);
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);        //安装gpio isr服务
    gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);//挂钩特定gpio pin的isr处理程序
    gpio_isr_handler_add(GPIO_INPUT_IO_1, gpio_isr_handler, (void*) GPIO_INPUT_IO_1);//挂钩特定gpio pin的isr处理程
    gpio_isr_handler_remove(GPIO_INPUT_IO_0);               //删除gpio编号的isr处理程序。
    gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);//再次挂钩特定gpio pin的isr处理程序
    printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size());
    int cnt = 0;
    while(1) {
        printf("cnt: %d\n", cnt++);
        vTaskDelay(1000 / portTICK_RATE_MS);
        gpio_set_level(GPIO_OUTPUT_IO_0, cnt % 2);
        gpio_set_level(GPIO_OUTPUT_IO_1, cnt % 2);
    }
}

四、演示结果

在这里插入图片描述

  值得注意的是初始化好了ESP32会在串口显示GPIO的配置信息,如果配置了ESP32的IO但是没有出现初始化配置信息的输出,这个时候检查下是否是位置掩码设置太多,可以分批次注册下。
在这里插入图片描述

五、ESP32 GPIO函数API

5.1、gpio_types.h文件中的内容的API

  在API文件中的内容基本上实现的是一些GPIO设置结构体,
1、中断类型
•上升沿中断
•下降沿中断
•上升沿和下降沿中断(边沿中断)
•输入低电平触发
•输入高电平出发
2、GPIO模式
•禁用输入输出
•仅输入
•输出模式
•只输出开漏模式
•输出输入开漏模式
•输出和输入模式
3、IO上拉电阻和下拉电阻的禁用和使能

typedef enum {
    Gpio_intr_disable       = 0,        /*!< Disable GPIO interrupt */
    Gpio_intr_posedge       = 1,        /*!< GPIO中断类型:上升边缘*/
    Gpio_intr_negedge       = 2,        /*!< GPIO中断类型:下降沿*/
    gpio_intr_anyyedge      = 3,        /*!< GPIO中断类型:上升沿和下降沿*/
    Gpio_intr_low_level     = 4,        /*!< GPIO中断类型:输入低电平触发*/
    Gpio_intr_high_level    = 5,        /*!< GPIO中断类型:输入高电平触发*/
    GPIO_INTR_MAX,
} gpio_int_type_t;

#define GPIO_MODE_DEF_DISABLE   ( 0)
#define GPIO_MODE_DEF_INPUT     (BIT0) ///<输入位掩码
#define GPIO_MODE_DEF_OUTPUT    (BIT1) ///<输出位掩码
#define GPIO_MODE_DEF_OD        (BIT2) ///< OD模式的位掩码

typedef enum {
    GPIO_MODE_DISABLE = GPIO_MODE_DEF_DISABLE,                                                          /*!< GPIO模式:禁用输入输出*/
    GPIO_MODE_INPUT = GPIO_MODE_DEF_INPUT,                                                              /*!< GPIO模式:仅输入*/
    GPIO_MODE_OUTPUT = GPIO_MODE_DEF_OUTPUT,                                                            /*!< GPIO模式:输出模式*/
    GPIO_MODE_OUTPUT_OD = ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)),                                /*!< GPIO模式:只输出开漏模式*/
    GPIO_MODE_INPUT_OUTPUT_OD = ((GPIO_MODE_DEF_INPUT) | (GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)),  /*!< GPIO模式:输出输入开漏模式*/
    GPIO_MODE_INPUT_OUTPUT = ((GPIO_MODE_DEF_INPUT) | (GPIO_MODE_DEF_OUTPUT)),                          /*!< GPIO模式:输出和输入模式*/
} gpio_mode_t;

typedef enum {
    GPIO_PULLUP_DISABLE = 0x0,       /*!<禁用GPIO上拉电阻*/
    GPIO_PULLUP_ENABLE  = 0x1,       /*!<使能GPIO上拉电阻*/
} gpio_pullup_t;

typedef enum {
    GPIO_PULLDOWN_DISABLE   = 0x0,   /*!<禁用GPIO下拉电阻*/
    GPIO_PULLDOWN_ENABLE    = 0x1,   /*!<使能GPIO下拉电阻*/
} gpio_pulldown_t;

//gpio_config功能的GPIO板配置参数
typedef struct {
    uint64_t pin_bit_mask;           /* !< GPIO引脚:设置位掩码,每位映射一个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中断类型*/
} gpio_config_t;

typedef enum {
    GPIO_PULLUP_ONLY ,               /*!< Pad上拉*/
    GPIO_PULLDOWN_ONLY ,             /*!< Pad下拉*/
    GPIO_PULLUP_PULLDOWN ,           /*!< Pad上拉+下拉*/
    GPIO_FLOATING ,                  /*!< Pad浮动*/
} gpio_pull_mode_t;

typedef enum {
    GPIO_DRIVE_CAP_0       = 0,      /*!< Pad驱动能力:弱*/
    GPIO_DRIVE_CAP_1       = 1,      /*!< Pad驱动能力:更强*/
    GPIO_DRIVE_CAP_2       = 2,      /*!< Pad驱动能力:中等 */
    GPIO_DRIVE_CAP_DEFAULT = 2,      /*!< Pad驱动能力:中等默认*/
    GPIO_DRIVE_CAP_3       = 3,      /*!< Pad驱动能力:最强*/
    GPIO_DRIVE_CAP_MAX,
} gpio_drive_cap_t;

5.2、在gpio.h文件中的内容的API

  在gpio.h文件中的API基本上就是对于GPIO的一些设置API,这里是一些简约的,没有对参数说明的,参数说明的我放在后面前面太长。

// GPIO通用配置配置GPIO的Mode, pullup,PullDown,IntrTypepGPIOConfig指向GPIO配置结构体的指针
esp_err_t gpio_config(const gpio_config_t *pGPIOConfig);
//重置gpio为默认状态(选择gpio功能,开启上拉,关闭输入输出)。
esp_err_t gpio_reset_pin (gpio_num_t gpio_num);
//GPIO设置中断触发类型
esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type);
/*使能GPIO模块中断信号
* @注意:当使用ADC或Wi-Fi休眠模式时,请不要使用GPIO36和GPIO39的中断。
* 请参阅“adc1_get_raw”的注释。
* 关于这个问题的描述,请参考'ECO_and_Workarounds_for_Bugs_in_ESP32'章节3.11。
* 作为一种变通方法,在应用程序中调用adc_power_acquire()。这将导致更高的功耗(约1mA),
* 但将消除GPIO36和GPIO39上的故障。
*/
esp_err_t gpio_intr_enable (gpio_num_t gpio_num);
//关闭GPIO模块中断信号
esp_err_t gpio_intr_disable (gpio_num_t gpio_num);
//设置GPIO输出电平
esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level);
//GPIO获取输入电平如果pad没有配置为输入(或输入和输出),返回值总是0。
int gpio_get_level (gpio_num_t gpio_num);
//gpio设置方向配置GPIO方向,如output_only、input_only、output_and_input
esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode);
//配置GPIO上拉/下拉电阻只有同时支持输入和输出的引脚集成了上拉和下拉电阻。只有输入的GPIOs 34-39则没有。
esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull);
//开启GPIO唤醒功能。GPIO唤醒类型。只能使用GPIO_INTR_LOW_LEVEL或GPIO_INTR_HIGH_LEVEL。
esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type);
//关闭GPIO唤醒功能。
esp_err_t gpio_wakeup_disable (gpio_num_t gpio_num);
//注册GPIO中断处理器,这个处理器是一个ISR。处理程序将被附加到该函数运行的同一个CPU核心上。
//这个ISR函数在任何GPIO中断发生时被调用。看到替代gpio_install_isr_service()和
//gpio_isr_handler_add() API,以获得驱动程序支持per-GPIO ISRs。
esp_err_t gpio_isr_register(void (*fn)(void *)void *arg, int intr_alloc_flags, gpio_isr_handle_t *handle);
//开启GPIO上拉。
esp_err_t gpio_pullup_en (gpio_num_t gpio_num);
//关闭GPIO上拉菜单。
esp_err_t gpio_pullup_dis (gpio_num_t gpio_num);
//开启GPIO下拉功能。
esp_err_t gpio_pulldown_en (gpio_num_t gpio_num);
//关闭GPIO下拉功能。
esp_err_t gpio_pulldown_dis (gpio_num_t gpio_num);
//安装驱动程序的GPIO ISR处理程序服务,它允许单针GPIO中断处理程序。
//这个函数与gpio_isr_register()不兼容——如果使用了gpio_isr_register(),则会为所有GPIO中断注册一个全局ISR。如果使用了这个函数,ISR服务提供了一个全局GPIO ISR,各个pin句柄是通过gpio_isr_handler_add()函数注册的。
esp_err_t gpio_install_isr_service (int intr_alloc_flags);
//卸载驱动的GPIO ISR服务,释放相关资源。
void gpio_uninstall_isr_service(void);
/*
* 为相应的GPIO管脚添加ISR处理程序。使用gpio_install_isr_service()后调用此函数
* 安装驱动程序的GPIO ISR处理程序服务。引脚ISR处理程序不再需要使用IRAM_ATTR声明
* 除非你在分配时传递ESP_INTR_FLAG_IRAM标志,ISR在gpio_install_isr_service()中。
* 这个ISR处理器将被ISR调用。这是一个堆栈大小限制(可在menuconfig中配置为“ISR堆栈大小”)。这
* 与全局GPIO中断处理程序相比,limit更小过渡到额外的间接层面。
*/
esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void *args);
//删除对应GPIO管脚的ISR处理程序。
esp_err_t gpio_isr_handler_remove (gpio_num_t gpio_num);
//设置GPIO板驱动能力
esp_err_t gpio_set_drive_capability(gpio_num_t gpio_num, gpio_drive_cap_t strength);
//获得GPIO板驱动能力
esp_err_t gpio_get_drive_capability(gpio_num_t gpio_num, gpio_drive_cap_t * strength);
/*
* 开启gpio pad保持功能。
* gpio pad保持功能可以在输入和输出两种模式下工作,但必须是有输出能力的gpio。
* 如果pad按住enabled:在输出模式:pad的输出电平将被强制锁定,不能改变。
* 在输入模式下:无论输入信号的变化,读取的输入值都不会改变。数字gpio在深度睡
* 眠时不能保持状态,会恢复保持功能当芯片从深度睡眠中醒来时。如果数字
* gpio也需要在深度睡眠时保持,' gpio_deep_sleep_hold_en '也应该被调用。
* 关闭电源或调用gpio_hold_dis将禁用此功能。
*/
esp_err_t gpio_hold_en (gpio_num_t gpio_num);
/*
* 关闭gpio pad保持功能。
* 当芯片从深度睡眠中唤醒时,gpio将被设置为默认模式,因此,gpio将输出
* 如果调用此函数,则为默认级别。如果你不想改变级别,gpio应该配置为
* 函数被调用前的已知状态。
* 如。
* 如果你在深度睡眠时保持gpio18高,在芯片被唤醒并' gpio_hold_dis '被调用后,
* gpio18将输出低电平(因为gpio18默认是输入模式)。如果你不想要这种行为,
* 你应该将gpio18设置为输出模式,并在调用' gpio_hold_dis '之前将其设置为高电平。
*/
esp_err_t gpio_hold_dis (gpio_num_t gpio_num);

//在深度睡眠时启用所有数字gpio板保持功能。
* 当芯片处于深度睡眠模式时,所有数字gpio将保持睡眠前的状态,当芯片被唤醒时,
* 数字gpio的状态将不会被保持。请注意,pad hold功能仅在芯片处于深度睡眠模式时有效,
* 当不处于睡眠模式时,数字gpio状态可以改变,即使你已经调用了这个函数。
* 关闭电源或调用gpio_hold_dis将禁用该功能,否则,数字gpio保持功能,只要芯片进入深度睡眠。
*/
void gpio_deep_sleep_hold_en(void);
//在深度睡眠时禁用所有数字gpio板保持功能。
void gpio_deep_sleep_hold_dis(void);
//通过IOMUX将pad输入设置为外设信号。
void gpio_iomux_in(uint32_t gpio_num, uint32_t signal_idx);
//通过IOMUX设置外设输出到GPIO板。
void gpio_iomux_out(uint8_t gpio_num, int func, bool oen_inv);
#if SOC_GPIO_SUPPORT_FORCE_HOLD
//强制保持数字和rtc gpio pad。GPIO强制保持,无论芯片处于休眠模式还是唤醒模式。
esp_err_t gpio_force_hold_all(void);
// 强制不保持数字和rtc gpio pad。无论芯片处于休眠模式还是唤醒模式。
esp_err_t gpio_force_unhold_all(void);
# endif
#if SOC_GPIO_SUPPORT_SLP_SWITCH
//使能SLP_SEL在轻睡状态下自动改变GPIO状态。
esp_err_t gpio_sleep_sel_en (gpio_num_t gpio_num);
//在轻睡状态下,关闭SLP_SEL自动改变GPIO状态。
esp_err_t gpio_sleep_sel_dis (gpio_num_t gpio_num);
//gpio在睡眠时设置方向 配置GPIO方向,如output_only、input_only、output_and_input
esp_err_t gpio_sleep_set_direction(gpio_num_t gpio_num, gpio_mode_t模式);
//在休眠时配置GPIO上拉/下拉电阻只有同时支持输入和输出的引脚集成了上拉和下拉电阻。只有输入的GPIOs 34-39则没有。
esp_err_t gpio_sleep_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull);
# endif
#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
#define gpio_is_deep_sleep_wakeup_valid_gpio_mask ((gpio_num & ~SOC_GPIO_DEEP_SLEEP_WAKEUP_VALID_GPIO_MASK) == 0)
//开启GPIO深度睡眠唤醒功能。
esp_err_t gpio_deep_sleep_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type);
//关闭GPIO深度休眠唤醒功能。
esp_err_t gpio_deep_sleep_wakeup_disable (gpio_num_t gpio_num);

  在gpio.h文件中含有参数的GPIO的参数。

/*
* @brief GPIO通用配置
* 配置GPIO的Mode, pullup,PullDown,IntrType
* pGPIOConfig指向GPIO配置结构体的指针
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
*/
esp_err_t gpio_config(const gpio_config_t *pGPIOConfig);

/*
* @brief重置gpio为默认状态(选择gpio功能,开启上拉,关闭输入输出)。
* @param gpio_num GPIO编号。
* 这个函数也将这个引脚的IOMUX配置到GPIO
* 功能,并断开任何通过GPIO配置的其他外设输出
* 矩阵。
* @return总是返回ESP_OK。
*/
esp_err_t gpio_reset_pin (gpio_num_t gpio_num);

/*
* @brief GPIO设置中断触发类型
* @param gpio_num GPIO编号。如果你想设置触发器类型,例如GPIO16, gpio_num应该是GPIO_NUM_16 (16);
* @param intr_type中断类型,选择gpio_int_type_t
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
*/
esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type);

/*
* @brief使能GPIO模块中断信号
* @注意:当使用ADC或Wi-Fi休眠模式时,请不要使用GPIO36和GPIO39的中断。
* 请参阅“adc1_get_raw”的注释。
* 关于这个问题的描述,请参考'ECO_and_Workarounds_for_Bugs_in_ESP32'章节3.11。
* 作为一种变通方法,在应用程序中调用adc_power_acquire()。这将导致更高的功耗(约1mA),
* 但将消除GPIO36和GPIO39上的故障。
* @param gpio_num GPIO编号。如果你想在GPIO16上启用一个中断,gpio_num应该是GPIO_NUM_16 (16);
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
*/
esp_err_t gpio_intr_enable (gpio_num_t gpio_num);

/*
* @brief关闭GPIO模块中断信号
* @param gpio_num GPIO编号。如果你想禁用中断,例如GPIO16, gpio_num应该是GPIO_NUM_16 (16);
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
*/
esp_err_t gpio_intr_disable (gpio_num_t gpio_num);

/*
* 设置GPIO输出电平
* @param gpio_num GPIO编号。如果你想设置输出电平,例如GPIO16, gpio_num应该是GPIO_NUM_16 (16);
* @param level输出级别。0:低;1:高
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG GPIO编号错误
*/
esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level);

/*
* @brief GPIO获取输入电平
* @warning如果pad没有配置为输入(或输入和输出),返回值总是0。
* @param gpio_num GPIO编号。如果你想要得到pin GPIO16的逻辑级别,gpio_num应该是GPIO_NUM_16 (16);
* @return
* - 0 GPIO输入电平为0
* - 1 GPIO输入电平为1
*/
int gpio_get_level (gpio_num_t gpio_num);

/*
* @brief gpio设置方向
* 配置GPIO方向,如output_only、input_only、output_and_input
* @param gpio_num配置GPIO引脚编号,它应该是GPIO编号。如果你想设置方向,例如GPIO16, gpio_num应该是GPIO_NUM_16 (16);
* @param模式GPIO方向
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG GPIO错误
*/
esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode);

/*
* 配置GPIO上拉/下拉电阻
* 只有同时支持输入和输出的引脚集成了上拉和下拉电阻。只有输入的GPIOs 34-39则没有。
* @param gpio_num GPIO编号。如果你想设置下拉模式,例如GPIO16, gpio_num应该设置为GPIO_NUM_16 (16);
* @param拉GPIO拉上/下模式。
* @return
* - ESP_OK成功
*—ESP_ERR_INVALID_ARG:参数错误
*/
esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull);

/*
* @brief开启GPIO唤醒功能。
* @param gpio_num GPIO编号。
* @param intr_type GPIO唤醒类型。只能使用GPIO_INTR_LOW_LEVEL或GPIO_INTR_HIGH_LEVEL。
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
*/
esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type);

/*
* @brief关闭GPIO唤醒功能。
* @param gpio_num GPIO编号
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
*/
esp_err_t gpio_wakeup_disable (gpio_num_t gpio_num);

/*
* 注册GPIO中断处理器,这个处理器是一个ISR。
* 处理程序将被附加到该函数运行的同一个CPU核心上。
* 这个ISR函数在任何GPIO中断发生时被调用。看到
* 替代gpio_install_isr_service()和
* gpio_isr_handler_add() API,以获得驱动程序支持
* per-GPIO ISRs。
* @param fn中断处理函数。
* @param arg处理函数的参数
* @param intr_alloc_flags用于分配中断的标志。一个或多个(ORred)
*            ESP_INTR_FLAG_ *值。更多信息参见esp_intr_alloc.h。
* @param handle返回句柄的指针。如果非null,将返回一个中断句柄。
* \逐字嵌入:rst:星号
* 要禁用或删除ISR,将返回的句柄传递给:doc: '中断分配函数 '。
* \ endverbatim
* @return
* - ESP_OK Success;
* - ESP_ERR_INVALID_ARG GPIO错误
* - ESP_ERR_NOT_FOUND没有发现带有指定标志的空闲中断
*/
esp_err_t gpio_isr_register(void (*fn)(void *)void *arg, int intr_alloc_flags, gpio_isr_handle_t *handle);

/*
* @brief开启GPIO上拉。
* @param gpio_num GPIO编号
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
*/
esp_err_t gpio_pullup_en (gpio_num_t gpio_num);

/*
* @brief关闭GPIO上拉菜单。
* @param gpio_num GPIO编号
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
*/
esp_err_t gpio_pullup_dis (gpio_num_t gpio_num);

/*
* 开启GPIO下拉功能。
* @param gpio_num GPIO编号
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
*/
esp_err_t gpio_pulldown_en (gpio_num_t gpio_num);

/*
* @brief关闭GPIO下拉功能。
* @param gpio_num GPIO编号
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
*/
esp_err_t gpio_pulldown_dis (gpio_num_t gpio_num);

/*
* 安装驱动程序的GPIO ISR处理程序服务,它允许单针GPIO中断处理程序。
* 这个函数与gpio_isr_register()不兼容——如果使用了gpio_isr_register(),则会为所有GPIO中断注册一个全局ISR。如果使用了这个函数,ISR服务提供了一个全局GPIO ISR,各个pin句柄是通过gpio_isr_handler_add()函数注册的。
* @param intr_alloc_flags用于分配中断的标志。一个或多个(ORred)
*            ESP_INTR_FLAG_ *值。更多信息参见esp_intr_alloc.h。
* @return
* - ESP_OK成功
* - ESP_ERR_NO_MEM没有内存来安装该服务
* - ESP_ERR_INVALID_STATE ISR服务已经安装。
* - ESP_ERR_NOT_FOUND没有发现带有指定标志的空闲中断
* - ESP_ERR_INVALID_ARG GPIO错误
*/
esp_err_t gpio_install_isr_service (int intr_alloc_flags);

/*
* @brief卸载驱动的GPIO ISR服务,释放相关资源。
*/
void gpio_uninstall_isr_service(void);

/*
* 为相应的GPIO管脚添加ISR处理程序。
* 使用gpio_install_isr_service()后调用此函数
* 安装驱动程序的GPIO ISR处理程序服务。
* 引脚ISR处理程序不再需要使用IRAM_ATTR声明
* 除非你在分配时传递ESP_INTR_FLAG_IRAM标志
* ISR在gpio_install_isr_service()中。
* 这个ISR处理器将被ISR调用。这是一个堆栈
* 大小限制(可在menuconfig中配置为“ISR堆栈大小”)。这
* 与全局GPIO中断处理程序相比,limit更小
* 过渡到额外的间接层面。
* @param gpio_num GPIO编号
* @param isr_handler对应GPIO编号的ISR处理函数。
* @param参数为ISR处理程序。
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_STATE错误状态,ISR服务没有初始化。
* - ESP_ERR_INVALID_ARG参数错误
*/
esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void *args);

/*
* 删除对应GPIO管脚的ISR处理程序。
* @param gpio_num GPIO编号
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_STATE错误状态,ISR服务没有初始化。
* - ESP_ERR_INVALID_ARG参数错误
*/
esp_err_t gpio_isr_handler_remove (gpio_num_t gpio_num);

/*
* 设置GPIO板驱动能力
* @param gpio_num仅支持输出GPIO数
* @param strength pad的驱动能力
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
*/
esp_err_t gpio_set_drive_capability(gpio_num_t gpio_num, gpio_drive_cap_t strength);

/*
* @brief获得GPIO板驱动能力
* @param gpio_num仅支持输出GPIO数
* @param strength指针接受pad的驱动能力
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
*/
es p_err_t gpio_get_drive_capability(gpio_num_t gpio_num, gpio_drive_cap_t * strength);

/*
* @brief开启gpio pad保持功能。
* gpio pad保持功能可以在输入和输出两种模式下工作,但必须是有输出能力的gpio。
* 如果pad按住enabled:
* 在输出模式:pad的输出电平将被强制锁定,不能改变。
* 在输入模式下:无论输入信号的变化,读取的输入值都不会改变。
* 数字gpio在深度睡眠时不能保持状态,会恢复保持功能
* 当芯片从深度睡眠中醒来时。如果数字gpio也需要在深度睡眠时保持,
* ' gpio_deep_sleep_hold_en '也应该被调用。
* 关闭电源或调用gpio_hold_dis将禁用此功能。
* @param gpio_num GPIO编号,只支持有输出的GPIO
* @return
* - ESP_OK成功
* - ESP_ERR_NOT_SUPPORTED不支持pad hold功能
*/
esp_err_t gpio_hold_en (gpio_num_t gpio_num);

/*
* @brief关闭gpio pad保持功能。
* 当芯片从深度睡眠中唤醒时,gpio将被设置为默认模式,因此,gpio将输出
* 如果调用此函数,则为默认级别。如果你不想改变级别,gpio应该配置为
* 函数被调用前的已知状态。
* 如。
* 如果你在深度睡眠时保持gpio18高,在芯片被唤醒并' gpio_hold_dis '被调用后,
* gpio18将输出低电平(因为gpio18默认是输入模式)。如果你不想要这种行为,
* 你应该将gpio18设置为输出模式,并在调用' gpio_hold_dis '之前将其设置为高电平。
* @param gpio_num GPIO编号,只支持有输出的GPIO
* @return
* - ESP_OK成功
* - ESP_ERR_NOT_SUPPORTED不支持pad hold功能
*/
esp_err_t gpio_hold_dis (gpio_num_t gpio_num);

/*
* @brief在深度睡眠时启用所有数字gpio板保持功能。
* 当芯片处于深度睡眠模式时,所有数字gpio将保持睡眠前的状态,当芯片被唤醒时,
* 数字gpio的状态将不会被保持。请注意,pad hold功能仅在芯片处于深度睡眠模式时有效,
* 当不处于睡眠模式时,数字gpio状态可以改变,即使你已经调用了这个函数。
* 关闭电源或调用gpio_hold_dis将禁用该功能,否则,数字gpio保持功能,只要芯片进入深度睡眠。
*/
void gpio_deep_sleep_hold_en(void);

/*
* @brief在深度睡眠时禁用所有数字gpio板保持功能。
*/
void gpio_deep_sleep_hold_dis(void);

/*
* 通过IOMUX将pad输入设置为外设信号。
* @param gpio_num pad GPIO编号。
* @param signal_idx要输入的外围信号id。' ' soc/gpio_sig_map.h ' '中的' *_IN_IDX ' '信号之一。
*/
void gpio_iomux_in(uint32_t gpio_num, uint32_t signal_idx);

/*
* 通过IOMUX设置外设输出到GPIO板。
* @param gpio_num gpio_num pad的GPIO编号。
* @param func外部引脚到输出引脚的函数号。
* 在' ' soc/io_mux_reg.h ' '中指定pin (X)的' ' FUNC_X_* ' '。
* @param oen_inv如果输出enable需要反转则为True,否则为False。
*/
void gpio_iomux_out(uint8_t gpio_num, int func, bool oen_inv);

#if SOC_GPIO_SUPPORT_FORCE_HOLD
/*
* @brief强制保持数字和rtc gpio pad。
* @note GPIO强制保持,无论芯片处于休眠模式还是唤醒模式。
*/
esp_err_t gpio_force_hold_all(void);

/*
* @brief 强制不保持数字和rtc gpio pad。
* @note GPIO force unhold,无论芯片处于休眠模式还是唤醒模式。
*/
esp_err_t gpio_force_unhold_all(void);
# endif

#if SOC_GPIO_SUPPORT_SLP_SWITCH
/*
* @brief使能SLP_SEL在轻睡状态下自动改变GPIO状态。
* @param gpio_num pad GPIO编号。
* @return
* - ESP_OK成功
*/
esp_err_t gpio_sleep_sel_en (gpio_num_t gpio_num);

/*
* @brief在轻睡状态下,关闭SLP_SEL自动改变GPIO状态。
* @param gpio_num pad GPIO编号。
* @return
* - ESP_OK成功
*/
esp_err_t gpio_sleep_sel_dis (gpio_num_t gpio_num);

/*
* @brief gpio在睡眠时设置方向
* 配置GPIO方向,如output_only、input_only、output_and_input
* @param gpio_num配置GPIO引脚编号,它应该是GPIO编号。如果你想设置方向,例如GPIO16, gpio_num应该是GPIO_NUM_16 (16);
* @param模式GPIO方向
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG GPIO错误
*/
esp_err_t gpio_sleep_set_direction(gpio_num_t gpio_num, gpio_mode_t模式);

/*
* 在休眠时配置GPIO上拉/下拉电阻
* 只有同时支持输入和输出的引脚集成了上拉和下拉电阻。只有输入的GPIOs 34-39则没有。
* @param gpio_num GPIO编号。如果你想设置下拉模式,例如GPIO16, gpio_num应该设置为GPIO_NUM_16 (16);
* @param拉GPIO拉上/下模式。
* @return
* - ESP_OK成功
*—ESP_ERR_INVALID_ARG:参数错误
*/
esp_err_t gpio_sleep_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull);
# endif

#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
#define gpio_is_deep_sleep_wakeup_valid_gpio_mask ((gpio_num & ~SOC_GPIO_DEEP_SLEEP_WAKEUP_VALID_GPIO_MASK) == 0)
/*
* @brief开启GPIO深度睡眠唤醒功能。
* @param gpio_num GPIO编号。
* @param intr_type GPIO唤醒类型。只能使用GPIO_INTR_LOW_LEVEL或GPIO_INTR_HIGH_LEVEL。
* @note由SDK调用。用户不应该在APP中直接调用它。
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
*/
esp_err_t gpio_deep_sleep_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type);
/*
* @brief关闭GPIO深度休眠唤醒功能。
* @param gpio_num GPIO编号
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
*/
esp_err_t gpio_deep_sleep_wakeup_disable (gpio_num_t gpio_num);
  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值