ESP32 是一款由乐鑫科技 (Espressif Systems) 开发的低成本、低功耗的 Wi-Fi 和蓝牙双模芯片。它集成了强大的 Tensilica Xtensa LX6 双核处理器、Wi-Fi、蓝牙、以及丰富的周边接口(如 GPIO, ADC, DAC, SPI, I2C, UART, I2S, RMT, TWAI 等),使其成为物联网 (IoT) 应用的理想选择。理解 ESP32 的引脚功能和编号对于任何 ESP32 项目都至关重要。

核心思想:ESP32 芯片提供了大量的通用输入/输出 (GPIO) 引脚,这些引脚除了基本的数字输入/输出功能外,还复用 (multiplexing) 了多种外设功能。正确识别和使用这些引脚是成功开发 ESP32 应用的基础。


一、ESP32 芯片与开发板

在讨论引脚之前,需要明确 ESP32 芯片本身和基于 ESP32 芯片的开发板(如 ESP32-DevKitC, ESP32-WROOM-32D/U 等模组)的区别:

  • ESP32 芯片:指的是裸芯片,例如 ESP32-D0WDQ6。它具有 39 个 GPIO 引脚。
  • ESP32 模组:将 ESP32 芯片与必要的闪存、晶振、天线等元件集成在一起,形成一个易于使用的模块,如 ESP32-WROOM-32。
  • ESP32 开发板:将 ESP32 模组焊接到一块更大的 PCB 上,引出所有可用的 GPIO 引脚,并添加了 USB 转串口芯片、电源稳压器、复位按钮和启动模式按钮等,方便用户开发。

本文主要以 ESP32 开发板上常见的引脚编号为基础进行讲解。

二、ESP32 GPIO 引脚编号规则

ESP32 芯片有 39 个 GPIO 引脚(GPIO0 ~ GPIO39),但并非所有引脚都暴露在开发板上,也并非所有引脚都适合所有用途。在编程时,我们通常直接使用 GPIO 编号 (例如 GPIO_NUM_2 或直接使用 2)。

关键点:

  • GPIO 编号 (GPIO Number):这是乐鑫科技官方定义的引脚序号,在代码中直接使用。
  • 开发板丝印 (Pin Label):开发板 PCB 上通常会有丝印,有些直接写 GPIO 编号 (如 GND, 3V3, D2, D4),有些则可能使用 TX0, RX0, SDA, SCL 等功能名称。在编程时,应始终以 GPIO 编号为准。

2.1 GPIO0-GPIO39 概览

GPIO 编号 常用丝印/功能 特性/注意事项
GPIO0 BOOT, D0 上电时低电平会进入固件下载模式,高电平正常启动。内部上拉。不建议作为普通输入。
GPIO1 TX0 默认 UART0 TXD。内部上拉。不建议用作输入。
GPIO2 D2 内部下拉。上电时不能为高电平,否则启动失败 (若连接到外部上拉电阻)。不建议作为启动引脚。
GPIO3 RX0 默认 UART0 RXD。内部上拉。不建议用作输入。
GPIO4 D4 通用 GPIO,支持 ADC2_CH0。
GPIO5 D5 通用 GPIO,SPI SS 引脚。
GPIO6-GPIO11 SPI_CLK, SPI_MISO, SPI_MOSI, SPI_SS 连接到板载 SPI 闪存,通常不建议作为通用 GPIO 使用。
GPIO12 D12 上电时需保持低电平,否则导致启动失败。内部下拉。支持 ADC2_CH5。
GPIO13 D13 通用 GPIO,支持 ADC2_CH4。
GPIO14 D14 通用 GPIO,SPI CLK 引脚。支持 ADC2_CH6。
GPIO15 D15 上电时需保持低电平,否则可能导致启动失败。内部上拉。SPI SS 引脚。支持 ADC2_CH7。
GPIO16 D16 通用 GPIO。通常用于 PSRAM (外部 RAM)。
GPIO17 D17 通用 GPIO。通常用于 PSRAM (外部 RAM)。
GPIO18 D18 通用 GPIO,SPI CLK 引脚。
GPIO19 D19 通用 GPIO,SPI MISO 引脚。
GPIO20 - 不暴露在 WROOM 系列模组上
GPIO21 SDA 通用 GPIO,I2C SDA 引脚。
GPIO22 SCL 通用 GPIO,I2C SCL 引脚。
GPIO23 D23 通用 GPIO,SPI MOSI 引脚。
GPIO24 - 不暴露在 WROOM 系列模组上
GPIO25 D25 通用 GPIO,支持 DAC1, ADC2_CH8。
GPIO26 D26 通用 GPIO,支持 DAC2, ADC2_CH9。
GPIO27 D27 通用 GPIO,支持 ADC2_CH7。
GPIO28-GPIO31 - 不暴露在 WROOM 系列模组上
GPIO32 D32 通用 GPIO,支持 ADC1_CH4。
GPIO33 D33 通用 GPIO,支持 ADC1_CH5。
GPIO34 VIN, SENSOR_VP 只能作输入,无内部上拉/下拉。支持 ADC1_CH6。
GPIO35 SENSOR_VN 只能作输入,无内部上拉/下拉。支持 ADC1_CH7。
GPIO36 SENSOR_VP (ESP32-S系列有所不同) 只能作输入,无内部上拉/下拉。支持 ADC1_CH0。
GPIO37-GPIO38 - 只能作输入,无内部上拉/下拉。GPIO37/38 不暴露在 WROOM 系列模组上
GPIO39 SENSOR_VN (ESP32-S系列有所不同) 只能作输入,无内部上拉/下拉。支持 ADC1_CH3。

重要说明:

  • ADC1 和 ADC2
    • ADC1 (GPIO32-39) 可用于自由 ADC 转换。
    • ADC2 (GPIO0, 2, 4, 12-15, 25-27) 在 Wi-Fi 启动时会被 Wi-Fi 驱动程序占用,此时无法使用。
  • 输入专用引脚:GPIO34, 35, 36, 39 只能作为输入引脚,不能设置为输出。它们也没有内部上拉/下拉电阻。
  • 启动模式引脚:GPIO0, GPIO2, GPIO4, GPIO5, GPIO12, GPIO15 在芯片启动时会读取其电平,以决定启动模式。不当使用这些引脚可能会导致 ESP32 无法正常启动或进入下载模式。
    • GPIO0:外部上拉,低电平进入下载模式
    • GPIO2:外部下拉,高电平启动失败
    • GPIO12:外部下拉,高电平启动失败
    • GPIO15:外部上拉,低电平启动失败
    • 建议在这些引脚上避免连接可能影响其启动电平的设备,特别是那些在启动时就产生高/低电平的传感器或模块。如果必须使用,请确保在启动时这些引脚处于正确的电平状态。
  • 闪存/PSRAM 引脚:GPIO6-GPIO11 和 GPIO16-GPIO17 通常用于连接外部 SPI 闪存和 PSRAM,强烈不建议作为通用 GPIO 使用,否则可能导致程序崩溃或闪存访问异常。

三、开发板引脚布局示例 (以 ESP32-DevKitC 为例)

不同的开发板型号可能会有不同的引脚布局和丝印,但其背后的 GPIO 编号是固定的。以下是一个典型的 ESP32-DevKitC (ESP32-WROOM-32 模组) 引脚布局示意图及说明:

引脚功能总结 (针对上图所示的典型开发板):

  • 电源引脚
    • 3V3:3.3V 输出 (由板载稳压器提供)。
    • VIN / 5V:5V 输入(通过 USB 供电或外部 5V 适配器)。
    • GND:接地。
  • 专用功能引脚
    • EN (Enable):芯片使能引脚,低电平复位 ESP32。
    • TX0, RX0 (GPIO1, GPIO3):默认 UART0 串口通信引脚,用于烧录和调试输出。
    • SDA, SCL (GPIO21, GPIO22):默认 I2C 通信引脚。
    • D0, D2, D12, D15:这些是启动模式引脚,需特别注意其电平。
  • 通用 GPIO:其余大部分引脚都可以用作数字输入/输出。
  • ADC (模拟数字转换):ESP32 内置 12 位 ADC,支持多个通道。
    • ADC1 (通道 0-7): GPIO36, GPIO39, GPIO34, GPIO35, GPIO32, GPIO33, GPIO25, GPIO26
    • ADC2 (通道 0-9): GPIO4, GPIO0, GPIO2, GPIO15, GPIO13, GPIO12, GPIO14, GPIO27, GPIO25, GPIO26
  • DAC (数字模拟转换):ESP32 内置 8 位 DAC。
    • DAC1: GPIO25
    • DAC2: GPIO26
  • SPI (串行外设接口):ESP32 有多个 SPI 控制器。
    • VSPI (通用 SPI): 默认 CLK=GPIO18, MISO=GPIO19, MOSI=GPIO23, CS0=GPIO5。
    • HSPI (高速 SPI): 默认 CLK=GPIO14, MISO=GPIO12, MOSI=GPIO13, CS0=GPIO15。
  • I2C (集成电路互联):ESP32 有两个 I2C 控制器。
    • I2C_NUM_0: 默认 SDA=GPIO21, SCL=GPIO22。
    • I2C_NUM_1: 默认 SDA=GPIO25, SCL=GPIO26。
  • UART (通用异步收发器):ESP32 有三个 UART 接口。
    • UART0: 默认 RX=GPIO3, TX=GPIO1 (用于串口调试和烧录)。
    • UART1: 默认 RX=GPIO9, TX=GPIO10 (通常连接到闪存,不建议使用)。
    • UART2: 默认 RX=GPIO16, TX=GPIO17。
  • PWM (脉冲宽度调制):所有支持输出的 GPIO 引脚都可以通过 LEDC 模块实现 PWM 功能。
  • 触摸传感器:ESP32 有 10 个电容式触摸传感器引脚 (GPIO0, 2, 4, 12, 13, 14, 15, 27, 32, 33)。

四、编程中如何使用引脚

在 Arduino IDE 或 ESP-IDF 中,我们通常直接使用 GPIO 编号来操作引脚。

4.1 Arduino IDE 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const int ledPin = 2; // 使用 GPIO2 连接一个 LED
const int buttonPin = 0; // 使用 GPIO0 连接一个按钮 (注意启动模式)

void setup() {
Serial.begin(115200);
pinMode(ledPin, OUTPUT); // 将 GPIO2 设置为输出模式
pinMode(buttonPin, INPUT_PULLUP); // 将 GPIO0 设置为输入带上拉模式

// 初始化 I2C (SDA=GPIO21, SCL=GPIO22 是默认值)
Wire.begin();

// 初始化 SPI (SCK=GPIO18, MISO=GPIO19, MOSI=GPIO23 是默认值)
// SPI.begin();
}

void loop() {
// 控制 LED
digitalWrite(ledPin, HIGH); // 点亮 LED
delay(1000);
digitalWrite(ledPin, LOW); // 关闭 LED
delay(1000);

// 读取按钮状态
if (digitalRead(buttonPin) == LOW) { // 按钮按下
Serial.println("Button Pressed!");
}

// 读取模拟值 (例如 GPIO34)
int sensorValue = analogRead(34);
Serial.print("Analog Value: ");
Serial.println(sensorValue);
}

4.2 ESP-IDF 示例 (Go 语言伪代码)

虽然 ESP-IDF 主要使用 C/C++,但为了演示 Go 的风格,这里使用伪代码。实际上 Go 语言也有 tinygo 等项目支持 ESP32。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package main

import (
"machine"
"time"
)

func main() {
// 定义 GPIO 引脚
ledPin := machine.GPIO{machine.GPIO2}
buttonPin := machine.GPIO{machine.GPIO0} // 注意启动模式

// 设置引脚模式
ledPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
buttonPin.Configure(machine.PinConfig{Mode: machine.PinInputPullup})

// 初始化串口 (类似 Serial.begin)
// machine.UART0.Configure(machine.UARTConfig{BaudRate: 115200})

// 初始化 I2C
// machine.I2C0.Configure(machine.I2CConfig{SCL: machine.GPIO22, SDA: machine.GPIO21})

for {
// 控制 LED
ledPin.High() // 点亮 LED
time.Sleep(time.Second)
ledPin.Low() // 关闭 LED
time.Sleep(time.Second)

// 读取按钮状态
if buttonPin.Get() == false { // false 表示低电平,按钮按下
// machine.UART0.Write([]byte("Button Pressed!\r\n"))
}

// 读取模拟值 (假设 machine 库支持 analogRead)
// adcPin := machine.ADC{machine.GPIO34}
// adcPin.Configure(machine.PinConfig{Mode: machine.PinInput})
// sensorValue := adcPin.Read()
// machine.UART0.Write([]byte(fmt.Sprintf("Analog Value: %d\r\n", sensorValue)))
}
}

五、重要注意事项与最佳实践

  1. 参考官方文档始终以乐鑫科技的官方数据手册 (Datasheet) 和技术参考手册 (Technical Reference Manual) 为准。它们提供了最准确和详细的引脚信息。
  2. 避免使用启动模式引脚:如果可能,尽量避免将重要功能连接到 GPIO0, GPIO2, GPIO12, GPIO15。如果必须使用,请确保外部电路在 ESP32 启动期间不会将它们拉到不期望的电平。
  3. 注意输入专用引脚:GPIO34, 35, 36, 39 只能作为输入,并且没有内部上拉/下拉。如果需要上拉/下拉,必须在外部添加电阻。
  4. 注意闪存/PSRAM 引脚:GPIO6-GPIO11 和 GPIO16-GPIO17 绝不应作为通用 GPIO 使用。
  5. I2C/SPI/UART 引脚复用:ESP32 的所有外设引脚都是可编程的。虽然有默认引脚,但你可以通过代码将其映射到其他可用的 GPIO 上(例如,将 I2C 映射到 GPIO18/19)。这提供了极大的灵活性,但也增加了配置的复杂性。
  6. GPIO 的内部上拉/下拉:ESP32 的大部分 GPIO 都有内部可编程的上拉/下拉电阻。在 pinMode() 中使用 INPUT_PULLUPINPUT_PULLDOWN 可以启用它们。
  7. 3.3V 逻辑电平:ESP32 的 GPIO 均采用 3.3V 逻辑电平。直接连接 5V 设备可能会损坏芯片,需要使用逻辑电平转换器。
  8. 电流限制:单个 GPIO 引脚的输出电流有限(通常最大 40mA,建议在 20mA 以内)。如果需要驱动大功率负载,请使用外部驱动电路(如晶体管或继电器)。

六、总结

ESP32 拥有丰富的 GPIO 资源,支持多种外设功能复用,这使其在物联网和嵌入式开发中具有极高的灵活性。然而,由于某些引脚在芯片启动时扮演特殊角色,或仅支持输入功能,因此在使用前务必仔细查阅开发板原理图和官方文档,了解每个引脚的详细特性和限制。正确理解和利用 ESP32 的引脚特性,是构建稳定、高效嵌入式系统的关键。