2. GPIO基础与LED控制:数字输出、GPIO库函数、LED闪烁、呼吸灯效果实现

各位同学,欢迎来到第二章。这一章我们直接上手硬件控制——GPIO。说白了,就是让ESP32的引脚听话,输出高电平或低电平,去点亮或熄灭一个LED。

我刚开始学单片机时,第一个实验就是点灯。别小看这个动作,它背后藏着数字输出的全部逻辑。你搞懂了GPIO,后面控制继电器、蜂鸣器、电机,甚至通信协议,都是这个思路的延伸。

2.1 什么是GPIO?

GPIO,全称General-Purpose Input/Output,通用输入输出口。你可以把它想象成芯片伸出来的“触手”。

  • 输出模式:芯片主动拉高(3.3V)或拉低(0V),驱动外部设备。
  • 输入模式:读取外部电平,比如按键按下还是松开。

ESP32有34个GPIO引脚,但不是所有引脚都能随便用。有些引脚内部接了Flash,有些有特殊功能。我踩过这个坑——第一次用GPIO6去点灯,死活不亮,查了半天才发现它被Flash占用了。

⚠️ 避坑指南: ESP32的GPIO6-11默认用于连接外部Flash,不要把它们当普通IO用。GPIO34-39只能输入,不能输出。GPIO0、2、12、15在启动时有特殊功能,使用时要注意上拉/下拉状态。

2.2 数字输出:点亮一个LED

先看最简单的电路。一个LED,一个220Ω限流电阻,串联到GPIO和GND之间。LED长脚接GPIO,短脚接电阻再到GND。

代码怎么写?我习惯用Arduino框架,因为上手快,生态好。ESP-IDF当然也行,但咱们课程先以Arduino为主,后面再深入IDF。

// 点亮LED示例
#define LED_PIN 2   // 大多数ESP32开发板,板载LED接在GPIO2

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

void loop() {
  // 什么都不做,LED一直亮
}

这里有两个核心函数:pinMode() 和 digitalWrite()。前者配置引脚方向,后者设置电平状态。HIGH是3.3V,LOW是0V。

💡 我的习惯: 定义引脚时用宏或const变量,别直接写数字。万一要换引脚,改一处就行。我在项目里吃过“魔法数字”的亏,后来就老实了。

2.3 GPIO库函数详解

Arduino框架的GPIO函数不多,但每个都很重要。我整理了一张表,方便你对照查阅。

函数 功能 参数说明
pinMode(pin, mode) 设置引脚模式 mode: OUTPUT, INPUT, INPUT_PULLUP, INPUT_PULLDOWN
digitalWrite(pin, value) 输出数字电平 value: HIGH (3.3V) 或 LOW (0V)
digitalRead(pin) 读取引脚电平 返回 HIGH 或 LOW
analogWrite(pin, value) 输出PWM模拟信号 value: 0-255(ESP32需用ledc库)

注意最后一行。ESP32的analogWrite()和Arduino Uno不一样,它底层用的是LEDC(LED Control)外设。我们做呼吸灯时会详细讲。

2.4 LED闪烁:经典入门实验

闪烁就是让LED亮一段时间,灭一段时间,循环往复。核心是delay()函数,但我要提醒你——delay会阻塞程序,后面学多任务时你就知道它的坏处了。不过初学阶段,先用它理解逻辑。

#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
}

上传代码后,LED会以1秒周期闪烁(0.5秒亮,0.5秒灭)。你可以改delay的值,调整闪烁频率。

🔑 关键点: 闪烁的本质是“状态切换 + 时间控制”。后面所有时序控制,包括PWM、通信协议,都是这个思路的变体。

2.5 呼吸灯效果:PWM与LEDC

呼吸灯,就是LED从暗到亮,再从亮到暗,像呼吸一样平滑变化。这需要PWM(脉冲宽度调制)。

PWM的原理很简单:快速切换高低电平,通过改变高电平占整个周期的比例(占空比),来模拟不同的电压。占空比0%就是灭,100%就是最亮,50%就是半亮。

ESP32用LEDC外设实现PWM。它比Arduino Uno的analogWrite()灵活得多——你可以设置频率、分辨率、通道数。

#define LED_PIN 2
#define LEDC_CHANNEL 0
#define LEDC_RESOLUTION 8   // 8位分辨率,占空比0-255
#define LEDC_FREQ 5000      // 5kHz PWM频率

void setup() {
  ledcSetup(LEDC_CHANNEL, LEDC_FREQ, LEDC_RESOLUTION);
  ledcAttachPin(LED_PIN, LEDC_CHANNEL);
}

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

这段代码里,ledcSetup()配置PWM参数,ledcAttachPin()把通道绑定到引脚,ledcWrite()设置占空比。两个for循环分别实现渐亮和渐暗,delay(5)控制变化速度。

💡 经验之谈: 呼吸灯的平滑度取决于两个因素:PWM分辨率和步进延时。8位分辨率(0-255)已经够用,延时5-10ms效果最好。太快会闪烁,太慢就不像呼吸了。你可以自己调调看。

2.6 本章知识结构图

下面这张SVG图,把本章的核心知识点串起来了。从GPIO基础出发,分支出数字输出和PWM输出两条线,最后汇聚到LED控制这个实战目标。

第二章知识结构图:GPIO与LED控制 第二章 知识结构:GPIO与LED控制 GPIO 基础 数字输出 PWM 输出 pinMode() digitalWrite() LED 闪烁 ledcSetup() ledcAttachPin() 呼吸灯效果 实战目标:从点亮LED到呼吸灯,掌握GPIO全部输出能力

2.7 常见问题与调试技巧

写代码容易,调硬件难。我总结几个新手常遇到的问题,你遇到了可以对照排查。

  • LED不亮:先检查接线,正负极有没有反?电阻有没有接?再用万用表量GPIO引脚电压,如果没输出,检查代码里引脚号对不对。
  • LED微亮但不闪烁:可能是引脚模式没设对,或者代码里只写了一次digitalWrite,没有在loop里切换。
  • 呼吸灯闪烁不均匀:PWM频率太低。LEDC频率建议设在1kHz以上,人眼就感觉不到闪烁了。
  • 上传失败:按住开发板上的BOOT键,再点上传。ESP32进入下载模式需要这个操作。
⚠️ 硬件安全提醒: 不要直接用GPIO驱动大功率负载(如电机、继电器线圈)。ESP32的GPIO最大输出电流约12mA,超出会烧引脚。驱动大负载必须加三极管或MOS管做开关。

好了,这一章的内容就到这里。你学会了GPIO的数字输出和PWM输出,从简单的点灯到呼吸灯,算是迈出了硬件控制的第一步。这些基础打牢了,后面学传感器读取、外设驱动就会轻松很多。