跳到主要内容

GPIO 使用

在 ESP32 中,GPIO 的作用

GPIO 全称是 "General Purpose Input/Output"(通用输入输出),可以理解为芯片上的"数字引脚"。就像你在软件开发中操作变量一样,GPIO 让你可以操作硬件引脚,控制电平的高低(类似 true/false)。

ESP32 芯片上带有几十个引脚(不同封装型号数量可能不同),其中大多数都可以配置为 GPIO。每个 GPIO 引脚都可以通过软件设定为 输入 或 输出:

  • 输入模式
    可以用来读取外部信号(例如按钮、传感器的数据电平)。
    ESP32 GPIO 还支持上拉、下拉电阻配置,方便读取稳定的逻辑电平。

  • 输出模式
    可以用来驱动外部器件(例如点亮 LED、控制继电器、与外设通信)。

  • 多功能复用
    ESP32 的 GPIO 大部分都可以复用为其他外设功能(UART、I2C、SPI、PWM、ADC、DAC 等),不仅仅是单纯的“高低电平”。

ESP32 GPIO 的一些特点

数量:ESP32 通常提供约 34 个可用的 GPIO(不过并不是每一个封装都会引出全部引脚)。

电压:GPIO 工作在 3.3V 电平,输入电压必须在 0~3.3V 之间,高于这个范围可能烧坏芯片。

  1. 特殊功能引脚:
    • GPIO6 ~ GPIO11:通常用于连接 Flash,不建议用户使用。
    • GPIO34 ~ GPIO39:只支持输入,不支持输出。
  2. 可配置模式:通过软件 API(例如 pinMode() 在 Arduino 框架下,或 ESP-IDF 的 gpio_set_direction())来配置。

简单例子(Arduino 框架下)

int ledPin = 2; // ESP32 开发板上的一般 IO2 引脚接了板载 LED

void setup() {
pinMode(ledPin, OUTPUT); // 设置 GPIO2 为输出
}

void loop() {
digitalWrite(ledPin, HIGH); // 输出高电平,点亮 LED
delay(1000);
digitalWrite(ledPin, LOW); // 输出低电平,熄灭 LED
delay(1000);
}

上拉(Pull-up)和下拉(Pull-down)是什么?

当 GPIO 被配置为 输入 时,它需要去“读取”一个电平(高电平=1,低电平=0)。

但是有时候输入引脚并没有可靠的电压信号接上去(比如一个按钮没按下时,电路是悬空的),此时引脚电压就会处在“不确定状态”(可能受环境杂讯影响),这就会导致读到的数据不稳定。

为了解决这个问题,芯片内部提供了 上拉电阻(pull-up resistor) 和 下拉电阻(pull-down resistor):

  • 上拉(Pull-up):给 GPIO 接一个电阻连到 VCC (3.3V),使得当信号未被外部主动驱动时,GPIO 默认处于 高电平。

  • 下拉(Pull-down):给 GPIO 接一个电阻连到 GND (0V),使得当信号未被外部主动驱动时,GPIO 默认处于 低电平。

ESP32 自带了这些上拉/下拉电阻,可以通过软件配置打开,非常方便。

假设你有一个按钮,想用 GPIO 读取按钮状态:

方案1:上拉模式

  • 按钮一端接 GND,另一端接 GPIO。
  • 把 GPIO 配置为 输入 + 内部上拉。
  • 没按下按钮时 → 电路开路,GPIO 通过内部上拉电阻 = 高电平 → 读到 1
  • 按下按钮时 → GPIO 直接接 GND → 低电平 → 读到 0

方案2:下拉模式

  • 按钮一端接 VCC,另一端接 GPIO。
  • 把 GPIO 配置为 输入 + 内部下拉。
  • 没按按钮时 → GPIO 通过内部下拉电阻接地 = 低电平 → 读到 0
  • 按下按钮时 → GPIO 被拉到 VCC → 高电平 → 读到 1
int buttonPin = 4;

void setup() {
pinMode(buttonPin, INPUT_PULLUP); // 使用内部上拉
Serial.begin(115200);
}

void loop() {
int state = digitalRead(buttonPin);
if (state == LOW) { // 按钮按下
Serial.println("Button Pressed");
} else {
Serial.println("Button Released");
}
delay(200);
}

这里用的是 上拉模式,所以当按钮按下时,读取到的是 低电平。

gpio_config_t 配置

在 ESP-IDF 中,gpio_config_t 是一个结构体,用来集中描述 GPIO 的配置选项,然后通过 gpio_config() 函数一次性完成设置。

https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/api-reference/peripherals/gpio.html#_CPPv413gpio_config_t

#include "driver/gpio.h"

2. 结构体定义

精简版(不同 IDF 版本可能略有差别,但核心一致):

typedef struct {
// GPIO 引脚掩码(哪些引脚要配置)
uint64_t pin_bit_mask;

// GPIO 模式
gpio_mode_t mode;

// 上拉功能(0=关闭,1=开启)
gpio_pullup_t pull_up_en;

// 下拉功能(0=关闭,1=开启)
gpio_pulldown_t pull_down_en;

// 中断类型(例如上升沿触发、下降沿触发)
gpio_int_type_t intr_type;
} gpio_config_t;

3. 各字段解释

pin_bit_mask

  • 采用 位掩码(bit mask)来选择要配置的 GPIO。
  • 比如 1ULL << GPIO_NUM_4 表示选择 GPIO4。
  • 也可以一次配置多个,比如:
    cfg.pin_bit_mask = (1ULL << GPIO_NUM_4) | (1ULL << GPIO_NUM_5);

这里之所以使用掩码是因为可以很方便的选择多个位

mode

  • 引脚的工作模式,类型是 gpio_mode_t
    • GPIO_MODE_DISABLE → 不用该引脚。
    • GPIO_MODE_INPUT → 输入模式。
    • GPIO_MODE_OUTPUT → 输出模式。
    • GPIO_MODE_OUTPUT_OD → 开漏输出。
    • GPIO_MODE_INPUT_OUTPUT → 输入输出都可。
    • GPIO_MODE_INPUT_OUTPUT_OD → 可输入+开漏输出。

pull_up_en

  • 是否启用上拉电阻(GPIO_PULLUP_ENABLE / GPIO_PULLUP_DISABLE)。

pull_down_en

  • 是否启用下拉电阻(GPIO_PULLDOWN_ENABLE / GPIO_PULLDOWN_DISABLE)。

intr_type

  • 中断触发类型,类型是 gpio_int_type_t
    • GPIO_INTR_DISABLE → 不使用中断。
    • GPIO_INTR_POSEDGE → 上升沿触发。
    • GPIO_INTR_NEGEDGE → 下降沿触发。
    • GPIO_INTR_ANYEDGE → 任意边沿触发。
    • GPIO_INTR_LOW_LEVEL → 低电平触发。
    • GPIO_INTR_HIGH_LEVEL → 高电平触发。

输入 + 中断(例如按钮)

#include "driver/gpio.h"

void app_main(void)
{
gpio_config_t io_conf = {};
io_conf.intr_type = GPIO_INTR_NEGEDGE; // 按钮按下 → 下降沿触发中断
io_conf.mode = GPIO_MODE_INPUT; // 输入模式
io_conf.pin_bit_mask = (1ULL << GPIO_NUM_4); // 选择 GPIO4
io_conf.pull_up_en = GPIO_PULLUP_ENABLE; // 启用上拉
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; // 禁用下拉
gpio_config(&io_conf); // 应用配置

// 然后你可以注册 ISR 回调处理按钮事件
}

输出(例如点亮 LED)

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 = (1ULL << GPIO_NUM_2); // 选择 GPIO2
io_conf.pull_up_en = GPIO_PULLUP_DISABLE; // 不启用上拉
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; // 不启用下拉
gpio_config(&io_conf);

// 控制 GPIO2
gpio_set_level(GPIO_NUM_2, 1); // 输出高电平 → LED 亮
gpio_set_level(GPIO_NUM_2, 0); // 输出低电平 → LED 灭
}