💡 划重点
- 项目定位:基于 ESP32 的多功能红外遥控器,解决客厅遥控器数量多、易丢失、操作繁琐的问题。
- 核心能力:红外信号学习与回放、按键矩阵直接控制、LCD 菜单指引、Wi‑Fi 联网扩展。
- 成本控制:全部元器件 BOM 成本控制在 45 元以内,利用模块化设计降低焊接难度。
- 接线纪律:IR 接收使用 GPIO15,IR 发射使用 GPIO4,LCD I2C 挂载在 GPIO21/22,按键矩阵占用独立 GPIO,避免冲突。
- 交付物:可编译的 Arduino 骨架代码、接线图、物料表与调试说明书。
需求洞察
目标用户
客厅中拥有电视机、机顶盒、空调、音响等 3 个以上红外家电的家庭用户,尤其适合老年用户、租房青年以及不愿反复找遥控器的人群。
真实痛点
- 遥控器泛滥:每个家电至少一个遥控器,茶几上堆积多个遥控器,外观相似、功能交叉,家人经常拿错。
- 操作割裂:开关电视要分别用电视、机顶盒、音响遥控器,切换信号源效率低。
- 学习成本高:老人记不住复杂按键组合,普通万能遥控器设置步骤繁琐,难以二次配置。
- 物理丢失:小遥控器极易滑入沙发缝或床底,关键时刻找不到。
为什么值得做
硬件成本仅需 40 多元,却能集中管理 5‑8 个红外设备。利用 ESP32 的 Wi‑Fi 能力,后期可接入智能家居系统,实现手机远程遥控、语音联动,远比购买多个官方替代遥控器经济。项目完全开源,可以按家庭需求定制按键布局和宏命令,用户粘性极高。
方案设计
感知层
- IR 接收模块:使用 VS1838B 一体红外接收管,连接至 GPIO15,负责捕获各类遥控器发出的红外编码,实现“学习”功能。
- 4×4 薄膜按键矩阵:8 个数字引脚扫描,提供 16 个物理按键,用于设备选择、功能直达和学习模式触发。
控制层
- 主控 ESP32‑WROOM‑32E:双核 240 MHz,内置 520 KB SRAM 与 448 KB ROM,运行 Arduino 框架,负责红外协议解析(NEC、Sony、RC5 等)、按键消抖、LCD 菜单逻辑以及 MQTT/HTTP 数据交换。
- 非易失存储:利用 ESP32 的 NVS 分区存储已学习的红外码和宏命令,掉电保留。
执行层
- IR 发射电路:GPIO4 输出 38 kHz 载波驱动 5 mm 红外发射管,通过 NPN 三极管放大电流,有效遥控距离≥8 米。
- I2C LCD1602 字符屏:地址 0x27,显示当前所选设备、按键功能说明、学习状态以及信号发送确认。
日志/联网层
- Wi‑Fi 连接:在 setup 中自动连接预配置的 2.4 GHz 网络,失败后降级为本地独立遥控器模式。
- 数据上报:通过 MQTT 协议向 Home Assistant 或私有 Broker 上报遥控按键事件、学习进度及设备在线状态。
- OTA 更新:保留 2 MB 的 OTA 分区,支持通过 Arduino IDE 无线更新固件,方便功能迭代。
物料清单
| 序号 | 物料名称 | 数量 | 用途 | 估算单价(元) | 小计(元) |
|---|---|---|---|---|---|
| 1 | ESP32‑WROOM‑32E 开发板 | 1 | 主控及 Wi‑Fi | 14.00 | 14.00 |
| 2 | VS1838B 红外接收模块 | 1 | 学习红外信号 | 1.50 | 1.50 |
| 3 | 5 mm 红外发射管 | 1 | 发射控制信号 | 0.50 | 0.50 |
| 4 | 2N2222 NPN 三极管 | 1 | 发射管驱动 | 0.30 | 0.30 |
| 5 | 1 kΩ、100 Ω 电阻各一 | 2 | 基极/限流 | 0.10 | 0.20 |
| 6 | I2C LCD1602 液晶屏 | 1 | 显示交互界面 | 9.50 | 9.50 |
| 7 | 4×4 薄膜按键矩阵 | 1 | 物理控制输入 | 4.50 | 4.50 |
| 8 | 面包板 + 跳线 | 1 套 | 原型搭建 | 5.00 | 5.00 |
| 9 | Micro USB 电源线 | 1 | 供电 | 2.00 | 2.00 |
| 10 | 旧遥控器 | 1 | 测试学习源 | 0.00 | 0.00 |
| 合计 | 37.50 |
实际成本 37.50 元,在 45 元预算内留出余量用于外壳或扩展。若直接焊接洞洞板,面包板成本可进一步压缩。
接线与结构
接线表
| 组件 | 模块引脚 | ESP32 GPIO | 说明 |
|---|---|---|---|
| IR 接收 | OUT | 15 | 学习红外码,电平触发 |
| IR 接收 | VCC | 3.3V | 接收模块供电 |
| IR 接收 | GND | GND | 共地 |
| IR 发射 | 阳极(串电阻后) | 4 | 经三极管驱动 |
| 三极管基极 | 串 1kΩ 电阻 → | 4 | GPIO4 输出 38 kHz 载波 |
| LCD I2C | SDA | 21 | I2C 数据线 |
| LCD I2C | SCL | 22 | I2C 时钟线 |
| LCD I2C | VCC | 5V | 液晶屏供电 |
| LCD I2C | GND | GND | 共地 |
| 按键矩阵 | 行 1‑4 | 25, 26, 27, 14 | 行扫描输出 |
| 按键矩阵 | 列 1‑4 | 12, 13, 32, 33 | 列扫描输入 |
微调理由:IR 接收使用 GPIO15 以避开 ADC2 和常用 JTAG 引脚,确保学习时不干扰 Wi‑Fi;发射使用 GPIO4 可配置内部分频产生精准 38 kHz PWM 载波。按键矩阵占用独立 GPIO,避免与 I2C 和红外功能冲突。结构上将所有模块固定在一块 8×6 cm 洞洞板上,按键矩阵贴在正面,LCD 屏竖起,红外收发窗口朝向前方,形成握持舒适的手持遥控器形态。
核心代码
以下给出 Arduino 骨架,基于 PlatformIO 或 Arduino IDE 均可编译。
#include <Arduino.h>
#include <IRremote.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <Preferences.h>
// 红外引脚
#define IR_RECEIVE_PIN 15
#define IR_SEND_PIN 4
// LCD
// 按键矩阵
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {25, 26, 27, 14};
byte colPins[COLS] = {12, 13, 32, 33};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// 红外对象
IRrecv irrecv(IR_RECEIVE_PIN);
IRsend irsend(IR_SEND_PIN);
// 存储
Preferences prefs;
// WiFi 及 MQTT
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASS";
WiFiClient espClient;
// 当前设备索引
int currentDevice = 0;
bool learningMode = false;
void setup() {
Serial.begin(115200);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("IR Controller");
irrecv.enableIRIn();
prefs.begin("ircodes", false);
// 连接 WiFi
WiFi.begin(ssid, password);
int retry = 0;
while (WiFi.status() != WL_CONNECTED && retry < 20) {
delay(500);
retry++;
}
if (WiFi.status() == WL_CONNECTED) {
client.connect("ESP32_IR");
}
}
void loop() {
// 按键处理
char key = keypad.getKey();
if (key) {
handleKey(key);
}
// 红外学习
if (learningMode && irrecv.decode()) {
irrecv.resume();
learningMode = false;
lcd.clear();
lcd.print("Code Saved");
delay(1000);
}
// MQTT 保活
if (client.connected()) {
client.loop();
}
}
void handleKey(char key) {
switch (key) {
case 'A': // 学习键
learningMode = true;
lcd.clear();
lcd.print("Learning...");
break;
case 'B': // 发送测试
sendIR(currentDevice, '1');
break;
case 'C': // 设备切换
currentDevice = (currentDevice + 1) % 3;
lcd.clear();
lcd.print("Device:");
lcd.print(currentDevice);
break;
case 'D': // 上报
if (client.connected()) {
client.publish("ir/status", "online");
}
break;
default: // 直接发射对应码
sendIR(currentDevice, key);
break;
}
}
void storeIRCode(int dev, char btn, IRData data) {
String key = String(dev) + "_" + String(btn);
prefs.putBytes(key.c_str(), &data;, sizeof(IRData));
lcd.setCursor(0, 1);
lcd.print("Stored ");
lcd.print(key);
}
void sendIR(int dev, char btn) {
String key = String(dev) + "_" + String(btn);
IRData data;
if (prefs.getBytes(key.c_str(), &data;, sizeof(IRData)) == sizeof(IRData)) {
irsend.write(&data;);
lcd.clear();
lcd.print("Sent ");
lcd.print(btn);
}
}
调试步骤
- 基础测试
上传 Blink 例程,确认 ESP32 工作正常,串口监视器输出无乱码。
- LCD 及 I2C 验证
烧录 I2C 扫描程序,确认地址 0x27 被检测到,观察 LCD 背光亮起并打印 hello world。
- 红外接收测试
使用电视或空调遥控器对准 VS1838B 按下,串口打印出 NEC 或 RC5 原始码,确保中断响应无遗漏。
- 发射电路调试
在 sendIR 函数中直接发送预置 NEC 码,用手机摄像头观察发射管是否发出紫红色光晕,配合电视验证开关机功能。
- 按键矩阵标定
逐键按压,在串口打印对应字符,确认行列映射正确,接触不良按键进行替换。
- 学习‑发射联调
长按 A 键进入学习模式,对着接收头按原遥控器任意键,LCD 显示 “Code Saved”。随后短按对应数字键,家电应正确响应。
- Wi‑Fi 及 MQTT
修改代码中的 SSID 和密码,重启后通过 MQTT 客户端工具监听 ir/status 主题,确认上线报文正常推送。