💡 划重点
- 主控芯片:ESP32,负责红外学习、解码、存储与发射。
- 关键模块:IR 接收头、IR 发射管、LCD1602 I2C、4×4 按键矩阵。
- 使用场景:客厅电视柜,统一管理电视、机顶盒、风扇、空调等红外家电。
- 目标成本:45 元以内,实际物料估算约 34 元。
- 核心体验:一键学习原遥控器红外码,LCD 显示设备与按键状态,支持分类保存和快速发射。
- 可扩展:串口日志、Wi-Fi 上报、MQTT 联动、OTA 升级。
需求洞察
客厅里的红外遥控器往往有三到五个:电视、机顶盒、空调、风扇、投影仪。它们外形相似、按键布局不同,电池没电时还会突然失灵。目标用户包括普通家庭用户、租房年轻人,以及不擅长操作智能设备的老人。真实痛点不是“不能控制”,而是“找不到、分不清、学不会”。传统万能遥控器需要输入品牌代码,匹配率低;手机红外遥控又依赖手机型号和 App 广告。值得做这个项目,是因为 ESP32 能低成本完成红外收发,LCD 与按键矩阵提供离线可用的人机界面,既不需要联网也能工作,还能保留联网扩展空间。对硬件编程学习者来说,它覆盖了 GPIO、I2C、红外时序、状态机、NVS 存储等典型技能,非常适合作为客厅场景的入门到进阶项目。
方案设计
感知层由 IR 接收头和按键矩阵组成。IR 接收头输出解调后的红外波形,ESP32 通过 GPIO15 捕获原始时序;4×4 按键矩阵负责选择设备、学习、发射、翻页和确认。控制层运行在 ESP32 上,采用“待机—学习—保存—发射—设置”状态机。学习时记录原始码或解码后的协议码,用 Preferences 写入 NVS,断电不丢失。执行层包括 IR 发射和 LCD 反馈。IR 发射管经三极管驱动,接 GPIO4,保证发射距离;LCD 通过 I2C 接 GPIO21/22,显示当前设备名、按键编号、学习状态和电池电压提示。日志与联网层先以 115200 串口输出调试信息,预留 Wi-Fi/MQTT 任务,把“今天开了空调”“电视已关”等事件上报到家庭自动化平台,也可通过 OTA 更新红外码库。
物料清单
| 物料 | 数量 | 用途 | 估算单价 | 合计 |
|---|---|---|---|---|
| ESP32 开发板 | 1 | 主控、存储、Wi-Fi | 13 元 | 13 元 |
| IR 接收头 VS1838B | 1 | 学习原遥控器红外码 | 1 元 | 1 元 |
| IR 发射管 940nm | 1 | 发射红外控制信号 | 0.5 元 | 0.5 元 |
| LCD1602 I2C | 1 | 显示设备、按键、状态 | 8.5 元 | 8.5 元 |
| 4×4 薄膜按键矩阵 | 1 | 设备选择与功能输入 | 3 元 | 3 元 |
| S8050 三极管 | 1 | 驱动 IR 发射管 | 0.2 元 | 0.2 元 |
| 电阻 1kΩ/220Ω | 2 | 基极限流、LED 限流 | 0.1 元 | 0.2 元 |
| 洞洞板与杜邦线 | 1 套 | 焊接与连接 | 3 元 | 3 元 |
| USB 数据线 | 1 | 供电与烧录 | 3 元 | 3 元 |
| 简易外壳 | 1 | 客厅桌面放置 | 2 元 | 2 元 |
| 合计 | 34.4 元 |
接线与结构
| 模块 | 引脚 | ESP32 GPIO | 说明 |
|---|---|---|---|
| IR 接收 | OUT | GPIO15 | 使用给定引脚,接收解调信号 |
| IR 发射 | 经三极管基极 | GPIO4 | 使用给定引脚,发射 38kHz 调制波 |
| LCD I2C | SDA | GPIO21 | 默认 I2C 数据 |
| LCD I2C | SCL | GPIO22 | 默认 I2C 时钟 |
| 按键矩阵 | 行 1-4 | GPIO32、33、25、26 | 输入上拉 |
| 按键矩阵 | 列 1-4 | GPIO27、14、13、23 | 输出扫描 |
| 电源 | VCC/GND | 5V/3.3V/GND | LCD 用 5V,IR 接收用 3.3V |
微调说明:矩阵列未使用 GPIO12,因为它是启动模式相关引脚,上电时被拉高可能影响启动;改用 GPIO23 更稳妥。IR 接收接 GPIO15 与其默认下拉特性匹配,IR 发射接 GPIO4 避开启动冲突。结构上建议把 IR 接收头放在外壳正面偏左,IR 发射管放在正面偏右并略向外倾,LCD 居中,按键矩阵在下部,方便客厅单手操作。
核心代码
#include <IRremoteESP8266.h>
#include <IRrecv.h>
#include <IRsend.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <Preferences.h>
const uint16_t kRecvPin = 15;
const uint16_t kIrLed = 4;
IRrecv irrecv(kRecvPin);
IRsend irsend(kIrLed);
const byte ROWS = 4, COLS = 4;
char keys[ROWS][COLS] = {
{'1','2','3','A'}, {'4','5','6','B'},
{'7','8','9','C'}, {'*','0','#','D'}
};
byte rowPins[ROWS] = {32, 33, 25, 26};
byte colPins[COLS] = {27, 14, 13, 23};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
Preferences prefs;
decode_results results;
bool learnMode = false;
uint16_t lastCode = 0;
uint8_t lastBits = 0;
String lastProto = "";
void showIdle() {
lcd.clear();
}
void setup() {
Serial.begin(115200);
irrecv.enableIRIn();
irsend.begin();
lcd.init(); lcd.backlight();
showIdle();
}
void loop() {
char key = keypad.getKey();
if (key == 'A') {
learnMode = true;
}
if (key == 'B' && lastCode != 0) {
delay(300); showIdle();
}
if (irrecv.decode(&results;)) {
if (learnMode) {
lastCode = results.value;
lastBits = results.bits;
lastProto = typeToString(results.decode_type, results.repeat);
lcd.clear();
learnMode = false;
}
irrecv.resume();
}
}
调试步骤
- 供电检查:USB 上电后测 ESP32 3.3V 与 LCD 5V,确认无短路。
- I2C 扫描:运行扫描程序,确认 LCD 地址为 0x27 或 0x3F,并修改代码。
- 红外接收:打开串口 115200,按原遥控器,观察是否打印协议、码值、位数。
- 红外发射:用手机摄像头对准 IR 发射管,按发射键,看到紫色闪烁说明工作。
- 按键矩阵:逐个按键测试,串口打印键值,修正 rowPins/colPins 顺序。
- 学习与保存:按 A 学习,按 B 发射,断电重启后确认码值仍在。
- 客厅实测:在 3 米内对准电视、机顶盒,调整发射管角度与限流电阻。