ESP8266笔记-04.ESP8266 GPIO的输入 - RISC-V MCU技术社区 - 电子技术论坛 - 广受欢迎的专业电子论坛
分享 收藏 返回

[文章]

ESP8266笔记-04.ESP8266 GPIO的输入

GPIO的输入有很多的类型,当初51单片机还得加上拉和下拉电阻,现在大部分都可以直接用代码就可以配置了,这次主要记录一下ESP8266的三种输入模式分别是:上拉输入、下拉输入和中断函数。
再介绍一下我自己画的板子,输出我用了一个三色灯,而对于输入我只有启动按钮和复位按钮两种,没有其他输入按钮,好在启动按钮在启动后就不再需要了,我们就可以配置为输入按钮了,但是我再启动按钮上面增加了上拉电阻,在这里还得提醒一句,非常重要:
数字引脚0-15可设置为INPUT、OUTPUT、INPUT_PULLUP模式(输入、输出、上拉输入);数字引脚16可设置为INPUT、OUTPUT、INPUT_PULLDOWN_16模式(输入、输出、下拉输入);启动时,这些引脚默认配置为INPUT模式;
所以说,在ESP8266中除了特殊的需求外,该接上拉电阻还是下拉电阻都是需要接入的。其实,在其他的芯片中也理当如此,方便接入还是需要接入的。

无中断输入

再次进行修改预定义

#define GPIO_INPUT_IO 0
#define GPIO_INPUT_PIN_SEL (1ULL << GPIO_INPUT_IO)

配置输入模式:

    //首先定义GPIO设置的结构体:
    gpio_config_t io_input_conf;
    //然后关闭中断
    io_input_conf.intr_type = GPIO_INTR_DISABLE;
    //设置GPIO模式为输入模式
    io_input_conf.mode = GPIO_MODE_INPUT;
    //选择GPIO PIN
    io_input_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    //关闭下拉模式 GPIO0就算想打开也打不开
    io_input_conf.pull_down_en = 0;
    //打开上拉模式
    io_input_conf.pull_up_en = 1;
    //最后写入设置
    gpio_config(&io_input_conf);

完整代码在下面:

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

#define GPIO_INPUT_IO 0
#define GPIO_INPUT_PIN_SEL (1ULL << GPIO_INPUT_IO)

#define GPIO_OUTPUT_IO_0    2
#define GPIO_OUTPUT_IO_1    4
#define GPIO_OUTPUT_IO_2    5
#define GPIO_OUTPUT_PIN_SEL  ((1ULL<<GPIO_OUTPUT_IO_0) | (1ULL<<GPIO_OUTPUT_IO_1) | (1ULL<<GPIO_OUTPUT_IO_2))

void app_main()
{
    uart_set_baudrate(0, 74880);
    printf("Esp8266 Hello world!\n");

    gpio_config_t io_conf;
    //disable interrupt
    io_conf.intr_type = GPIO_INTR_DISABLE;
    //set as output mode
    io_conf.mode = GPIO_MODE_OUTPUT;
    //bit mask of the pins that you want to set
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
    //disable pull-down mode
    io_conf.pull_down_en = 0;
    //disable pull-up mode
    io_conf.pull_up_en = 0;
    //configure GPIO with the given settings
    gpio_config(&io_conf);

    gpio_config_t io_input_conf;
    io_input_conf.intr_type = GPIO_INTR_DISABLE;
    io_input_conf.mode = GPIO_MODE_INPUT;
    io_input_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    io_input_conf.pull_down_en = 0;
    io_input_conf.pull_up_en = 1;
    gpio_config(&io_input_conf);

    /* Print chip information */
    esp_chip_info_t chip_info;
    esp_chip_info(&chip_info);
    printf("This is ESP8266 chip with %d CPU cores, WiFi, ",
            chip_info.cores);

    printf("silicon revision %d, ", chip_info.revision);

    printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
            (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");

    while(true) {
        printf("gpio %d.\n", gpio_get_level(GPIO_INPUT_IO));
        gpio_set_level(GPIO_OUTPUT_IO_0, 1);
        vTaskDelay(500 / portTICK_PERIOD_MS);
        gpio_set_level(GPIO_OUTPUT_IO_0, 0);
        gpio_set_level(GPIO_OUTPUT_IO_1, 1);
        vTaskDelay(500 / portTICK_PERIOD_MS);
        gpio_set_level(GPIO_OUTPUT_IO_1, 0);
        gpio_set_level(GPIO_OUTPUT_IO_2, 1);
        vTaskDelay(500 / portTICK_PERIOD_MS);
        gpio_set_level(GPIO_OUTPUT_IO_2, 0);
        vTaskDelay(500 / portTICK_PERIOD_MS);
    }
    fflush(stdout);
    esp_restart();
}

我们可以查看串口的输出内容:
2024-08-29_163541.png

如果我们按下,那么GPIO处就显示为0,否则就是1.
接下来我们继续进行讨论,使用轮询的方式去读取GPIO的输入有2个问题:
1.轮询会占用不少的CPU
2.轮询的方式会因为CPU处理其他内容而导致实时性降低
所以,在很多情况下使用中断输入模式会更加好一些。

中断输入

也一样需要把预定义修改为非中断输入一样的,然后我们需要中断函数。

static xQueueHandle gpio_evt_queue = NULL;

static void 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[%d] intr, val: %d\n", io_num, gpio_get_level(io_num));
        }
    }
}

接下来,我们还需要对GPIO进行配置:

    //首先定义GPIO设置的结构体:
    gpio_config_t io_input_conf;
    //修改中断模式为下降沿模式 因为我用的是上拉电阻
    io_input_conf.intr_type = GPIO_INTR_NEGEDGE;
    //设置GPIO模式为输入模式
    io_input_conf.mode = GPIO_MODE_INPUT;
    //选择GPIO PIN
    io_input_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    //开启上拉模式
    io_input_conf.pull_up_en = 1;
    //最后写入设置
    gpio_config(&io_input_conf);

然后粘贴完整代码:

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

#define GPIO_INPUT_IO 0
#define GPIO_INPUT_PIN_SEL (1ULL << GPIO_INPUT_IO)

#define GPIO_OUTPUT_IO_0    2
#define GPIO_OUTPUT_IO_1    4
#define GPIO_OUTPUT_IO_2    5
#define GPIO_OUTPUT_PIN_SEL  ((1ULL<<GPIO_OUTPUT_IO_0) | (1ULL<<GPIO_OUTPUT_IO_1) | (1ULL<<GPIO_OUTPUT_IO_2))

static xQueueHandle gpio_evt_queue = NULL;

static void 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[%d] intr, val: %d\n", io_num, gpio_get_level(io_num));
        }
    }
}

void app_main()
{
    uart_set_baudrate(0, 74880);
    printf("Esp8266 Hello world!\n");

    gpio_config_t io_conf;
    //disable interrupt
    io_conf.intr_type = GPIO_INTR_DISABLE;
    //set as output mode
    io_conf.mode = GPIO_MODE_OUTPUT;
    //bit mask of the pins that you want to set
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
    //disable pull-down mode
    io_conf.pull_down_en = 0;
    //disable pull-up mode
    io_conf.pull_up_en = 0;
    //configure GPIO with the given settings
    gpio_config(&io_conf);

    //gpio_config_t io_input_conf;
    //io_input_conf.intr_type = GPIO_INTR_DISABLE;
    //io_input_conf.mode = GPIO_MODE_INPUT;
    //io_input_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    //io_input_conf.pull_down_en = 0;
    //io_input_conf.pull_up_en = 1;
    //gpio_config(&io_input_conf);

    //首先定义GPIO设置的结构体:
    gpio_config_t io_input_conf;
    //修改中断模式为下降沿模式 因为我用的是上拉电阻
    io_input_conf.intr_type = GPIO_INTR_NEGEDGE;
    //设置GPIO模式为输入模式
    io_input_conf.mode = GPIO_MODE_INPUT;
    //选择GPIO PIN
    io_input_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    //开启上拉模式
    io_input_conf.pull_up_en = 1;
    //最后写入设置
    gpio_config(&io_input_conf);

    /* Print chip information */
    esp_chip_info_t chip_info;
    esp_chip_info(&chip_info);
    printf("This is ESP8266 chip with %d CPU cores, WiFi, ",
            chip_info.cores);

    printf("silicon revision %d, ", chip_info.revision);

    printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
            (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");

    //create a queue to handle gpio event from isr
    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
    //start gpio task
    xTaskCreate(gpio_task_example, "gpio_task_example", 1024, NULL, 10, NULL);

    //install gpio isr service
    gpio_install_isr_service(0);
    //hook isr handler for specific gpio pin
    gpio_isr_handler_add(GPIO_INPUT_IO, gpio_isr_handler, (void *) GPIO_INPUT_IO);
    //remove isr handler for gpio number.
    //gpio_isr_handler_remove(GPIO_INPUT_IO);

    while(true) {
        gpio_set_level(GPIO_OUTPUT_IO_0, 1);
        vTaskDelay(500 / portTICK_PERIOD_MS);
        gpio_set_level(GPIO_OUTPUT_IO_0, 0);
        gpio_set_level(GPIO_OUTPUT_IO_1, 1);
        vTaskDelay(500 / portTICK_PERIOD_MS);
        gpio_set_level(GPIO_OUTPUT_IO_1, 0);
        gpio_set_level(GPIO_OUTPUT_IO_2, 1);
        vTaskDelay(500 / portTICK_PERIOD_MS);
        gpio_set_level(GPIO_OUTPUT_IO_2, 0);
        vTaskDelay(500 / portTICK_PERIOD_MS);
    }
    fflush(stdout);
    esp_restart();
}

最后查看一下实际运行图:
2024-08-29_164755.png

每按下一次,就输出一次,其实不光可以下降沿输出,还可以上升沿输入和边缘沿输入,在这里就不再赘述了,可以直接查看官方的API文档:GPIO API文档;还参考了半颗心脏的博客。下一次,我应该会开始学习WIFI的使用了。

回帖(1)

熊治坤

2024-9-18 08:39:51
厉害,学习了。都是大佬

更多回帖

×
发帖