GPIO基础与LED控制:数字输出、GPIO模式配置、LED闪烁实验、PWM调光原理

各位同学,欢迎来到第二章。上一章我们把ESP32的开发环境搭好了,也跑了第一个Hello World。这一章咱们来点看得见摸得着的东西——控制LED。

别小看LED,它背后藏着嵌入式开发最核心的概念:GPIO。说白了,GPIO就是芯片伸出来的那些“手脚”,你可以让它们输出高电平、低电平,或者读取外部信号。我做了这么多年硬件,可以说90%的传感器交互,底层都是GPIO在干活。

2.1 认识ESP32的GPIO

ESP32有34个GPIO引脚,但不是所有引脚都能随便用。嗯,这里要注意:有些引脚有特殊功能,比如接Flash、接晶振,你拿来当普通IO用可能会出问题。

引脚范围 可用性 注意事项
GPIO0-19 大部分可用 GPIO6-11用于Flash,不建议使用
GPIO21-23 完全可用 常用作I2C、SPI
GPIO25-27 完全可用 内置DAC,也可做普通IO
GPIO32-39 完全可用 GPIO34-39只能输入,不能输出

我个人习惯,做实验时优先用GPIO2、GPIO4、GPIO5、GPIO18、GPIO19这几个。它们没有特殊限制,接个LED、按键什么的很稳。

2.2 数字输出与GPIO模式配置

要让GPIO输出高低电平,你得先做两件事:

  1. 设置引脚模式:告诉芯片这个引脚是输出还是输入。
  2. 写入电平值:输出高电平(3.3V)或低电平(0V)。

在Arduino框架下,代码极其简单:

void setup() {
    pinMode(2, OUTPUT);      // 设置GPIO2为输出模式
    digitalWrite(2, HIGH);   // 输出高电平,LED亮
}

void loop() {
    // 暂时空着
}

你想想看,这背后芯片干了什么?它其实配置了GPIO内部的推挽输出电路。高电平时,上拉MOS管导通,引脚被拉到VCC;低电平时,下拉MOS管导通,引脚被拉到GND。

小技巧: 我建议你在写代码时,把引脚号定义成常量,别直接写数字。比如 #define LED_PIN 2,后期改硬件时改一行就行。

2.3 LED闪烁实验

闪烁实验就是让LED交替亮灭。核心逻辑是:输出高电平→延时→输出低电平→延时→循环。

代码示例:

#define LED_PIN 2

void setup() {
    pinMode(LED_PIN, OUTPUT);
}

void loop() {
    digitalWrite(LED_PIN, HIGH);   // 亮
    delay(500);                    // 保持500ms
    digitalWrite(LED_PIN, LOW);    // 灭
    delay(500);                    // 保持500ms
}

上传到ESP32,你应该能看到板载LED(通常接GPIO2)以0.5秒间隔闪烁。

避坑指南: 我曾经遇到过一个问题——LED不亮。查了半天发现是LED接反了。LED有正负极,长脚是正极(阳极),短脚是负极(阴极)。正极接GPIO,负极接GND,别忘了串一个220Ω~330Ω的限流电阻,否则电流过大可能烧坏GPIO。

2.4 从闪烁到呼吸:PWM调光原理

闪烁实验只能让LED全亮或全灭。那怎么让LED半亮呢?你可能会想:输出一个中间电压,比如1.65V。但ESP32的数字GPIO只能输出0V或3.3V,没有中间值。

这时候就要请出PWM了。

PWM(脉冲宽度调制),说白了就是快速开关。开关速度快到人眼反应不过来,LED看起来就像在“半亮”。

PWM有三个关键参数:

参数 说明 常见值
频率 每秒开关次数 5000Hz(5kHz)
占空比 高电平时间占整个周期的比例 0%~100%
分辨率 占空比可调节的精细程度 8位(0-255)或16位(0-65535)

举个例子:频率5000Hz,周期就是200微秒。如果占空比50%,就是高电平100微秒、低电平100微秒。人眼看到的亮度大约是最大亮度的一半。

ESP32的PWM实现代码:

#define LED_PIN 2
#define PWM_CH 0       // PWM通道
#define PWM_FREQ 5000  // 5kHz
#define PWM_RES 8      // 8位分辨率

void setup() {
    ledcSetup(PWM_CH, PWM_FREQ, PWM_RES);
    ledcAttachPin(LED_PIN, PWM_CH);
}

void loop() {
    // 从暗到亮
    for (int duty = 0; duty <= 255; duty++) {
        ledcWrite(PWM_CH, duty);
        delay(5);
    }
    // 从亮到暗
    for (int duty = 255; duty >= 0; duty--) {
        ledcWrite(PWM_CH, duty);
        delay(5);
    }
}

这段代码会让LED像呼吸一样慢慢变亮再慢慢变暗,这就是“呼吸灯”效果。

核心理解: PWM不是真的输出模拟电压,而是用数字信号“模拟”出模拟效果。频率要足够高(人眼临界约50Hz),占空比要足够精细(8位以上),效果才平滑。

2.5 本章知识体系

下面这张图把本章的核心逻辑串起来了:

第二章:GPIO基础与LED控制 知识体系 GPIO基础概念 数字输出模式 PWM输出模式 pinMode() 配置 digitalWrite() 输出 LED闪烁实验 频率 / 占空比 / 分辨率 ledcSetup() 配置 呼吸灯实验

这张图把本章内容分成了两条主线:左边是数字输出,右边是PWM输出。数字输出只能控制亮灭,PWM能控制亮度。两条线最终都服务于同一个目标——控制LED。

2.6 动手实验:组合挑战

学完理论,我建议你动手做个小实验:用两个LED,一个做闪烁(数字输出),一个做呼吸(PWM输出)。看看它们同时运行的效果。

接线图很简单:

  • LED1:正极接GPIO2(串220Ω电阻),负极接GND
  • LED2:正极接GPIO4(串220Ω电阻),负极接GND

代码思路:

#define LED_BLINK 2
#define LED_BREATHE 4
#define PWM_CH 0
#define PWM_FREQ 5000
#define PWM_RES 8

void setup() {
    pinMode(LED_BLINK, OUTPUT);
    ledcSetup(PWM_CH, PWM_FREQ, PWM_RES);
    ledcAttachPin(LED_BREATHE, PWM_CH);
}

void loop() {
    // LED1闪烁
    digitalWrite(LED_BLINK, HIGH);
    delay(300);
    digitalWrite(LED_BLINK, LOW);
    delay(300);
    
    // LED2呼吸一次
    for (int d = 0; d <= 255; d++) {
        ledcWrite(PWM_CH, d);
        delay(3);
    }
    for (int d = 255; d >= 0; d--) {
        ledcWrite(PWM_CH, d);
        delay(3);
    }
}
调试建议: 如果LED不亮,先检查GPIO引脚号对不对。ESP32开发板上的LED通常标有“LED”字样,但不同厂家可能接在不同引脚。我习惯先跑个简单的digitalWrite测试,确认引脚能输出,再上PWM。

好了,这一章的内容就到这里。GPIO是嵌入式开发的基石,数字输出和PWM是控制外设最常用的两种手段。你把这些搞明白了,后面接传感器、控制电机都会轻松很多。