Arduino Mega 按键 PWM 调光:三阶段渐变 LED 实战教程
项目简介
本教程循序渐进演示如何用 Arduino Mega 实现 LED 呼吸灯效果,共分三个阶段:
- 基础自动渐变(红→黄→绿→黄循环)
- 按键触发单次渐变序列
- 按键按住时渐变、松开即刻复位(非阻塞消抖)
适合初学者理解 analogWrite()、PWM 占空比、非阻塞定时与按键消抖等核心概念。
硬件清单
| 器件 | 数量 | 备注 |
|---|---|---|
| Arduino Mega 2560 | 1 | Uno/Nano 亦可,仅需修改引脚定义 |
| 面包板 | 1 | |
| LED(红/黄/绿) | 各 1 | 共阴极,接 330 Ω 限流电阻 |
| 12 mm 轻触开关 | 1 | 接数字引脚 7,内部上拉 |
| 330 Ω 电阻 | 4 | 3 颗 LED + 1 颗备用 |
| 杜邦线若干 | 1 包 |
电路原理图


LED 阳极分别接 D9(红)、D6(黄)、D3(绿) —— 均为 Mega 上的 PWM 引脚;按键一端接 D7,另一端接 GND,代码中启用 INPUT_PULLUP 省去外部上拉电阻。
阶段一:自动循环渐变
核心代码
const int LED_R = 9, LED_Y = 6, LED_G = 3;
const int FADE_DELAY = 10; // 统一延时常量,易于调整速度
void setup() {
pinMode(LED_R, OUTPUT);
pinMode(LED_Y, OUTPUT);
pinMode(LED_G, OUTPUT);
}
void loop() {
fadeSingle(LED_R);
fadeSingle(LED_Y);
fadeSingle(LED_G);
fadeSingle(LED_Y); // 红→黄→绿→黄 循环
}
void fadeSingle(int pin) {
for (int i = 0; i <= 255; i++) { analogWrite(pin, i); delay(FADE_DELAY); }
for (int i = 255; i >= 0; i--) { analogWrite(pin, i); delay(FADE_DELAY); }
}
要点:将延时提取为常量 FADE_DELAY,修改一处即可改变全局速度;封装 fadeSingle() 避免重复代码。
阶段二:按键触发单次序列
改进点
setup()中初始化绿灯常亮作为待机状态loop()检测按键按下(含 15 ms 软件消抖),调用fadeSequence()执行完整渐变流程- 按键未按下时保持绿灯常亮
关键代码片段
const int BTN = 7;
void setup() {
// ... 初始化 LED ...
pinMode(BTN, INPUT_PULLUP);
digitalWrite(LED_G, HIGH); // 待机绿灯亮
}
void loop() {
if (digitalRead(BTN) == LOW) { // 按下为低电平
delay(15);
if (digitalRead(BTN) == LOW) fadeSequence();
} else {
digitalWrite(LED_R, LOW);
digitalWrite(LED_Y, LOW);
digitalWrite(LED_G, HIGH);
}
}
void fadeSequence() {
// 绿→黄→红→黄→绿 完整渐变序列
fadeDown(LED_G);
fadeUpDown(LED_Y);
fadeUpDown(LED_R);
fadeUpDown(LED_Y);
fadeUp(LED_G);
}
阶段三:非阻塞实时响应(按住渐变、松手复位)
阶段二的缺陷:delay() 阻塞导致按键释放无法即时检测。解决方案:用空循环计数替代 delay(),每微步检测一次按键状态。
改进后的渐变函数
void fadeUpDownNonBlocking(int pin, int stepsPerCheck) {
for (int i = 0; i <= 255; i++) {
analogWrite(pin, i);
if (!checkButtonHeld()) return; // 松手即返回
}
for (int i = 255; i >= 0; i--) {
analogWrite(pin, i);
if (!checkButtonHeld()) return;
}
}
bool checkButtonHeld() {
for (int y = 0; y < 1000; y++) { // 空循环约 10 µs,累计 ~10 ms
if (digitalRead(BTN) == HIGH) return false; // 松手
}
return true; // 仍按住
}
原理:for (int y=0; y<1000; y++) 空循环替代 delay(10),期间反复轮询按键。若检测到释放(HIGH),return 直接跳出整个渐变流程,回到 loop() 待机分支,实现“松手即停”。
进阶优化建议
- 使用
millis()非阻塞定时器彻底消除空循环,适配更复杂多任务场景。 - 引入
Bounce2库实现硬件无关的专业消抖。 - 扩展为电位器调速、串口指令控制、多通道同步渐变等。
完整代码下载
本文 Code 章节提供三个版本完整 .ino 文件,可直接上传验证。
制造工艺
- Arduino Nano 与 MPU-6050 构建实时陀螺仪游戏
- 基于 Arduino 与 Python 的可靠 RFID 考勤系统
- DHT11 温湿度传感器项目:LED 指示与压电蜂鸣器报警
- 用 Arduino 制作超声波悬浮装置:分步指南
- Unopad:基于 Arduino 的无缝 Ableton Live MIDI 控制器
- Arduino 自动浇水系统:定时 + 土壤湿度双模式,轻松养护盆栽
- 自制简易红外避障传感器:IR LED + 光电二极管 + Arduino
- Find Me:基于 Arduino 与蓝牙的智能寻物器制作指南
- 用 Arduino 测量地球质量:DIY 分步指南
- Arduino 声纳实时测距与 Processing 可视化
- 智能停车计数系统:Arduino + Processing + PHP 实时车位追踪上云
- Arduino Uno 控制 25kHz 4 针 PWM 风扇 - 硬件、代码与测试