【ESP32】ESP-IDF开发 | GPIO通用输入输出+LED点灯和按键输入例程

发布于:2024-09-17 ⋅ 阅读:(74) ⋅ 点赞:(0)

1. 简介

        ESP32芯片有34个物理GPIO pad,每个GPIO pad都可用作一个通用IO或连接一个内部的外设信号。IO_MUX、RTC IO_MUX和GPIO交换矩阵用于将信号从外设传输至GPIO pad。

        从上面看到,每个pad可以配置成GPIO功能(连接GPIO交换矩阵)或者直连功能(旁路GPIO交换矩阵),功能的切换通过IO_MUX来实现。

        ESP32一共有162个外设输入信号和176个外设输出信号,要使用某个外设,就要把外设信号连接到对应的GPIO pad上,这个功能就是由GPIO交换矩阵来实现的。

        直连功能和GPIO功能有什么不同呢?快速信号如以太网、SDIO、SPI、JTAG、UART 等,通过旁路 GPIO 交换矩阵可以实现更好的高频数字特性,所以高速信号会直接通过 IO_MUX 输入和输出。

        ESP32除了有物理pad还有RTC pad,这些pads通过RTC IO_MUX可以配置成RTC GPIO功能,这些管脚主要在低功耗的模式下工作,实现低功耗功能。

        但要注意的是,虽然ESP32有34个物理pad,但并不是所有的pad都能任由用户控制或全功能的,下面列出一些开发时要注意的管脚:

  1. GPIO34-39,这几个管脚只有输入功能,没有输出功能,而且没有上下拉配置;
  2. GPIO6-11,如果你的模组带NOR Flash的话,这几个管脚是负责Flash的通信的,不能使用;
  3. GPIO12-15,这几个是JTAG的调试管脚,GPIO12是默认下拉的,GPIO15是默认上拉的,使用时要注意;
  4. GPIO1和GPIO3,这两个是芯片的调试串口和下载串口,不能用作其他使用;
  5. GPIO0、GPIO2和GPIO5,这几个是芯片的strapping管脚,GPIO0默认上拉,GPIO2默认下拉,GPIO5默认上拉,使用时要注意。

2. 例程

2.1 LED点灯

        这个例程实现一个点灯的代码,LED灯每隔一秒改变一次状态。

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

void app_main()
{
    gpio_config_t gpio_cfg = {0};

    gpio_cfg.mode = GPIO_MODE_OUTPUT;
    gpio_cfg.pull_down_en = GPIO_PULLDOWN_DISABLE;
    gpio_cfg.pull_up_en = GPIO_PULLUP_DISABLE;
    gpio_cfg.intr_type = GPIO_INTR_DISABLE;
    gpio_cfg.pin_bit_mask = (1 << GPIO_NUM_2);
    gpio_config(&gpio_cfg);

    while (1)
    {
        gpio_set_level(GPIO_NUM_2, 1);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        gpio_set_level(GPIO_NUM_2, 0);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

         GPIO的初始化使用gpio_config一个函数即可,结构体里面配置模式(mode)、下拉(pull_down_en)、上拉(pull_up_en)、中断使能(intr_type)、管脚映射(pin_bit_mask)。

        管脚映射是用一个uint64_t实现的,每个bit代表一个管脚,所以要将管脚号左移对应位数来使能对应管脚。

        主循环里面使用gpio_set_level函数来控制GPIO输出,因为IDF框架是基于FreeRTOS的,所以延时可以直接调用vTaskDelay实现。

        系统启动后的打印如下,可以看到最后一行打印了我们管脚的配置信息,此时开发板上的LED灯就在闪烁了。

2.2 按键输入

        这个例程配置管脚为输入模式,接收按键的输入信号。例程使用的是开发板的IO0管脚作为按键输入。

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

#define TAG "app"

void app_main()
{
    gpio_config_t gpio_cfg = {0};

    gpio_cfg.mode = GPIO_MODE_INPUT;
    gpio_cfg.pull_down_en = GPIO_PULLDOWN_DISABLE;
    gpio_cfg.pull_up_en = GPIO_PULLUP_ENABLE;
    gpio_cfg.intr_type = GPIO_INTR_DISABLE;
    gpio_cfg.pin_bit_mask = (1 << GPIO_NUM_0);
    gpio_config(&gpio_cfg);

    while (1) {
        if (0 == gpio_get_level(GPIO_NUM_0)) {

            /* 软件去抖 */
            while (0 == gpio_get_level(GPIO_NUM_0)) {
                vTaskDelay(20 / portTICK_PERIOD_MS);
            }
            
            ESP_LOGI(TAG, "Key pressed");
        }

        vTaskDelay(10 / portTICK_PERIOD_MS);
    }
}

        GPIO的配置和前面差不多,只是模式改成输入即可,上下拉可以根据自己的开发板设置,我这里设置为上拉。

        主循环使用gpio_get_level不断查看按键状态,检测到按键按下后会经过一个软件去抖处理,防止多次触发,最后就是打印一个log信息。

        需要注意主循环最后的这个延时必须要有!!!因为IDF是默认开启看门狗的,看门狗的喂狗函数在空闲任务里面,而主任务的优先级是高于空闲任务的;如果不加延时,空闲任务会一直运行不了,导致看门狗超时,系统重启。


网站公告

今日签到

点亮在社区的每一天
去签到