ESP32 GPIO基本使用

关于ESP32-C3工程的建立

​ 目前为止,我仍然采用的ESPIDF中的example作为一个最基本的工程,然后在此基础上在加以修改(比较笨,之后找到好的办法再说)

Ctrl + shift + p可以打开VSCODE的交互界面

之后便可以在这其中选择一个作为工程来创建如图

GPIO接口的使用

概述

​ ESP32-C3 芯片有22 个物理通用输入输出管脚(GPIO Pin)。每个管脚都可用作一个通用IO,或连接一个内部的外设信号。利用GPIO 交换矩阵和IO MUX,可配置外设模块的输入信号来源于任何的IO 管脚,并且外设模块的输出信号也可连接到任意IO 管脚。这些模块共同组成了芯片的IO 控制。

关于IO MUX 以及GPIO 交换矩阵的理解

结合IO MUX 以及 GPIO交换矩阵的主要特性,配合着二者的工作流程图不难看出

GPIO交换矩阵主要起一个中继的作用,外部的输入信号,以及内部的输出信号可以通过GPIO交换矩阵来配置,从而达到外设模块的输入信号可以来源于任何的IO管脚,通过内部信号也可以通过交换矩阵配置从而可以从任意一个PIN脚输出。十分灵活(不同于STM32这类,硬件I2C或者硬件SPI就必须是某几个固定的PIN脚)?

IO MUX的主要作用就是为每个GPIO管脚提供一个寄存器的作用,用来配置各个管脚功能。

并且为了实现更好的高频特性,SPI,UART等相关外设也可以不通过GPIO交换矩阵,直接通过IO MUX与PIN脚相连接。

关于GPIO的电源域

即GPIO0~5都可以作为唤醒引脚

利用GPIO输出点亮一个LED灯

我的板子上是利用这么几个IO口来控制LED灯的。可以很明显的看出,当GPIO为高电平的时候,LED灯会被点亮。

GPIO输出模式的配置过程

利用ESPIDF配置GPIO口是很简单的。

过程如下(最简单的方法)

gpio_pad_select_gpio(GPIO_NUM_5);                   // 选择一个GPIO
gpio_set_direction(GPIO_NUM_5, GPIO_MODE_OUTPUT);    // 把这个GPIO作为输出
gpio_set_level(GPIO_NUM_5, 0);                        // 设置这个GPIO的高低电平

使LED灯闪烁的方法

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

void app_main(void)
&#123;
    gpio_pad_select_gpio(GPIO_NUM_5);                // 选择一个GPIO
    gpio_set_direction(GPIO_NUM_5, GPIO_MODE_OUTPUT);// 把这个GPIO作为输出

    while(1)
    &#123;
        gpio_set_level(GPIO_NUM_5, 1);                   // 把这个GPIO输出低电平
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        gpio_set_level(GPIO_NUM_5, 0);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    &#125;
&#125;

以上涉及了一些FreeRTOS操作系统的相关函数和库,暂时先不用管,之后会做详细记录

只需知道vTaskDelay(1000 / portTICK_PERIOD_MS)这个函数是延迟1s就完事了。并且这个函数的使用需要FreeRTOS.h,task.h,这两个库的支持


测试

VID_20210908_160947.gif


利用GPIO的输入功能来检测按键是否按下

我的板子上是使用这么两个IO口来检测按键的输入的。

GPIO9可以正常作为按键输入的检测。但是CHIP_EN脚是用作于ESP32的使能,失能脚,起到的是复位ESP32的作用。

所以这里选择的是GPIO9脚来作为按键输入的判断。(检测到低电平为按键按下)

GPIO输入模式的配置过程

同理,过程如下(简单方法)

gpio_pad_select_gpio(GPIO_NUM_9);                     // 选择一个GPIO
gpio_set_direction(GPIO_NUM_9, GPIO_MODE_INPUT);      // 把这个GPIO作为输入
gpio_get_level(GPIO_NUM_9);                            //获取GPIO的电平

获取按键是否按下的代码

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

void app_main(void)
&#123;
    gpio_pad_select_gpio(GPIO_NUM_9);
    gpio_set_direction(GPIO_NUM_9, GPIO_MODE_INPUT);

    while(1)
    &#123;
        printf(" Current Gpio9 Level is : %d \r\n\r\n",
                gpio_get_level(GPIO_NUM_9));        //获取一次GPIO_NUM_9的电平

        vTaskDelay(500 / portTICK_PERIOD_MS);       //每500ms检测一次是否有输入
    &#125;

&#125;

测试

VID_20210908_170948.gif


配置GPIO来检测中断

首先要注意这几个函数

esp_err_t gpio_isr_register(void (*fn)(void *), 
                            void *arg, 
                            int intr_alloc_flags, 
                            gpio_isr_handle_t *handle, )

这个函数是为GPIO中断注册中断处理程序,这个中断程序会在任何GPIO发生中断的时候被调用。(一般情况下就不用这个函数,用下面的方法来配置GPIO的中断)

  • Parameters
  • fn: 需要调用的中断函数
    • intr_alloc_flags: 用于分配中断的标志。
  • arg: 传入中断函数的参数
    • handle: 指向中断函数返回的句柄
esp_err_t gpio_install_isr_service(int intr_alloc_flags)

这个函数用来为GPIO驱动注册中断服务,相当于GPIO中断的总开关。但是这个函数与gpio_isr_register不兼容。这个函数常常与gpio_isr_handler_add 这个函数配合着使用。

其中的参数intr_alloc_flags相当于中断的优先级等级。也就是说,整个GPIO的外部输入中断的优先级都一样。不过仍然可以在GPIO中断处理函数中进行判断其优先级

esp_err_t gpio_isr_handler_add(gpio_num_tgpio_num, 
                               gpio_isr_tisr_handler, 
                               void *args)

这个函数的作用是为某个GPIO口来绑定一个中断回调函数。

对于中断回调函数而言,不再需要为其声明IRAM_ATTR标志。 除非在gpio_install_isr_service()中分配ISR时传递ESP_INTR_FLAG_IRAM标志。

  • Parameters
    • gpio_num: GPIO标号
    • isr_handler: GPIO口的中断回调函数名
    • args: 传入GPIO口的参数

GPIO中断配置的过程

首先选定一个GPIO口

设置其输入/输出方向

使能其中断

设置中断的触发类型(见下表)

GPIO_INTR_DISABLE //禁用GPIO中断
GPIO_INTR_POSEDGE //GPIO中断类型:上升沿
GPIO_INTR_NEGEDGE //下降沿
GPIO_INTR_ANYEDGE //上升沿和下降沿
GPIO_INTR_LOW_LEVEL //输入低电平触发
GPIO_INTR_HIGH_LEVEL //输入高电平触发

可选:设置GPIO的上下拉是否使能(上拉后,ESP32可以检测到GPIO的下降沿)。

相关函数如下

gpio_pad_select_gpio(GPIO_NUM_36);
gpio_set_direction(GPIO_NUM_36, GPIO_MODE_INPUT);
gpio_intr_enable(GPIO_NUM_36);
gpio_set_intr_type(GPIO_NUM_36, GPIO_INTR_NEGEDGE);
gpio_pullup_en(GPIO_NUM_36);

目的:

​ 利用一个按键通过中断的方式来控制LED的亮灭

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

uint8_t flag;//按键按下标志位

void IRAM_ATTR gpio_isr_handler(void* arg)    //GPIO中断回调函数
&#123;   
    flag = ~flag;
    gpio_set_level(GPIO_NUM_5,flag);//使GPIO5的电平翻转一次
&#125;

void app_main(void)
&#123;
    //GPIO5------蓝色LED
    gpio_pad_select_gpio(GPIO_NUM_5);
    gpio_set_direction(GPIO_NUM_5, GPIO_MODE_OUTPUT);

    //GPIO9------按键输入中断配置
    gpio_pad_select_gpio(GPIO_NUM_9);
    gpio_set_direction(GPIO_NUM_9, GPIO_MODE_INPUT);
    gpio_intr_enable(GPIO_NUM_9);                       //使能GPIO9 上的中断
    gpio_set_intr_type(GPIO_NUM_9, GPIO_INTR_NEGEDGE);  //配置GPIO9 上中断触发源(下降沿)
    gpio_pullup_en(GPIO_NUM_9);                         //对GPIO9   上拉以便于检测到下降沿或者说低电平

    //注册中断服务
    gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1);
    //设置GPIO的中断回调函数
    gpio_isr_handler_add(GPIO_NUM_9,gpio_isr_handler,NULL);

    while(1)
    &#123;
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    &#125;

&#125;

具体的整个流程就是

  1. 配置GPIO为输入模式
  2. 开启GPIO口中断
  3. 设置其中断触发源
  4. 配置其为上拉模式,以便于检测按键的下降沿
  5. 为GPIO驱动注册中断服务
  6. 编写GPIO的中断回调函数
  7. 设置GPIO的中断回调函数与GPIO口中断绑定

测试

VID_20210908_220746.gif


函数总结(便于查阅)

gpio_pad_select_gpio();            用于选择需要配置的GPIO口

gpio_set_direction();            用于设置GPIO的输入输出等模式

gpio_set_level();                用于设置GPIO口的电平

gpio_get_level();                用于获取指定GPIO口的电平

gpio_intr_enable();                使能选中的GPIO中断

gpio_set_intr_type();            用于配置选定的GPIO口的中断触发方式

gpio_pullup_en();                用于使能GPIO口的上拉

gpio_isr_register();            用于为GPIO口注册中断(不常用)

gpio_install_isr_service();        用于为GPIO驱动注册中断

gpio_isr_handler_add();            用于为GPIO口注册中断回调函数

更多详细的GPIO相关函数还请参考:https://docs.espressif.com/projects/esp-idf/zh_CN/release-v4.3/esp32c3/api-reference/peripherals/gpio.html?highlight=gpio#gpio-rtc-gpio