手把手教你用ESP32打造万能红外遥控中枢:从零开始,代码全开源
你有没有这样的烦恼?家里的空调、电视、风扇还是“非智能”的老型号,每次想远程控制还得靠人跑过去按遥控器。换新设备吧,太贵;扔掉旧家电吧,又浪费。其实,只需一块不到10块钱的ESP32开发板,就能让这些“老古董”秒变智能设备——不拆机、不改线、不联网改造原设备,只加一个小小的控制模块,就能实现手机一键开关、语音控制、定时自动化。
这正是我们今天要做的项目:基于ESP32的红外学习与发射网关。它不仅能“听懂”原装遥控器的信号,还能“模仿”发出同样的指令,相当于给所有红外家电装上了一个“电子大脑”。整个过程不需要复杂的嵌入式知识,Arduino基础就能上手,而且代码全部可复用。
为什么是ESP32?不只是Wi-Fi那么简单
在众多微控制器中,ESP32之所以成为这类项目的首选,并不仅仅因为它便宜(一片约5–10元),更在于它的硬件级外设支持和生态成熟度。
比如红外通信最头疼的问题是什么?精确的时序控制。普通MCU靠软件延时生成38kHz载波,稍有中断就会失真。而ESP32内置了RMT(Remote Control Module)模块,这是一个专用的硬件外设,可以自动完成脉冲调制和解调,完全不占用CPU资源。
这意味着:
- 发射信号更稳定,抗干扰能力强
- 接收波形精度高,解码成功率提升90%以上
- 主程序可以专心处理网络通信、用户交互等任务
再加上原生Wi-Fi和蓝牙支持,你可以轻松把这台“红外网关”接入Home Assistant、Node-RED甚至微信小程序,真正实现“一机统管全家电”。
红外是怎么工作的?以NEC协议为例讲透原理
市面上大多数遥控器用的是NEC协议,结构清晰、逻辑简单,非常适合初学者理解。我们来拆解一下它是怎么传输一条“开机”命令的。
一次完整的红外发送包含哪些内容?
当按下遥控器按钮时,它并不是直接发一个“开”字,而是按照固定格式打包数据:
[引导码] [地址码] [地址反码] [命令码] [命令反码]举个例子:
- 地址码:0x00FF→ 表示这是某品牌电视
- 命令码:0x45→ 表示“电源键”
- 地址反码:0xFF00→ 是地址码的按位取反,用于校验
- 命令反码:0xBA→ 同样用于校验
这样设计的好处是双重容错:如果接收端发现反码对不上,就知道数据出错了,不会误动作。
脉冲位置调制(PPM)到底什么意思?
NEC使用的是脉冲位置调制,也就是通过高低电平的时间长度来区分0和1:
| 数据位 | 高电平时间 | 低电平时间 |
|---|---|---|
| 引导码 | 9ms | 4.5ms |
| “0” | 560μs | 560μs |
| “1” | 560μs | 1.685ms |
注意:所有的高电平都是560μs,区别只在后面的低电平长短。这就是“脉冲位置”的含义——信息藏在“空档期”的长短里。
这个时序要求非常严格,误差最好控制在±10%以内。这也是为什么必须依赖RMT硬件模块,软件延时根本扛不住Wi-Fi中断的影响。
关键库选择:IRremoteESP32为何不可替代?
虽然网上也有IRremote这类通用库,但在ESP32平台上,强烈推荐使用专门为它优化的IRremoteESP32库。原因只有一个:它深度集成了RMT驱动。
它解决了什么痛点?
| 传统方式 | 使用IRremoteESP32 |
|---|---|
| 软件模拟载波,易受中断影响 | RMT硬件自动生成38kHz调制 |
| 多任务下信号失真 | CPU空闲出来做其他事 |
| 解码失败率高 | 支持原始定时数据捕获 |
| 只支持少数协议 | 内建NEC/Sony/RC5/Daikin等40+种 |
更重要的是,API极其简洁。比如发送一个NEC指令,只需要一行代码:
irsend.sendNEC(0x00FF4500, 32);就这么简单?没错。参数分别是“编码值”和“位数”,底层自动拆包成引导码+地址+命令+反码,并通过RMT精准发出。
硬件怎么接?一张图看懂电路连接
别被“硬件设计”吓到,这个项目只需要几个基本元件:
- ESP32开发板(如NodeMCU-32S)
- 红外发射LED(940nm)
- 红外接收头(VS1838B或HS0038)
- 220Ω电阻 ×1
- 杜邦线若干 + 面包板
接线清单如下:
| 模块 | 连接方式 |
|---|---|
| IR LED正极 | GPIO26(或其他支持RMT输出的引脚) |
| IR LED负极 | 串联220Ω电阻后接地 |
| VS1838B VCC | 3.3V |
| VS1838B GND | GND |
| VS1838B OUT | GPIO34(建议使用ADC1通道) |
⚠️ 注意事项:
- ESP32 GPIO最大输出电流约12mA,而IR LED峰值电流可能达50mA以上,务必加限流电阻
- 若需远距离控制(>5米),建议增加三极管放大电路(如S8050)
- GPIO34为输入专用引脚,不能用于输出,但非常适合接接收头
核心功能实现:学习 + 回放 + Web控制
我们的目标是做一个“会学”的遥控器。用户先用原装遥控器教它按键,然后就能通过网页点击触发。
第一步:初始化红外收发对象
#include <IRremoteESP32.h> #include <IRrecv.h> #include <IRutils.h> #define RECV_PIN 34 // 接收引脚 #define SEND_PIN 26 // 发射引脚 IRrecv irrecv(RECV_PIN); // 创建接收器 decode_results results; // 存储解码结果 IRsend irsend(SEND_PIN); // 创建发送器第二步:实现“学习”功能
void learnCommand() { Serial.println("进入学习模式,请按遥控器按键..."); if (irrecv.decode(&results)) { String hexCode = uint64ToString(results.value, HEX); Serial.printf("捕获到NEC编码: 0x%s\n", hexCode.c_str()); // 保存到内存或Flash(此处简化为串口输出) learnedCode = results.value; irrecv.resume(); // 清空缓存,准备下次接收 } else { Serial.println("未检测到有效信号,请重试"); } }第三步:实现“回放”功能
void sendLearnedCommand() { if (learnedCode != 0) { irsend.sendNEC(learnedCode, 32); Serial.println("已发送保存的指令"); } else { Serial.println("尚未学习任何指令"); } }第四步:搭建简易Web服务器(手机可访问)
#include <WiFi.h> #include <WebServer.h> const char* ssid = "你的Wi-Fi名称"; const char* password = "你的密码"; WebServer server(80); const String htmlPage = R"( <!DOCTYPE html> <html> <head><title>ESP32红外遥控</title></head> <body> <h2>红外控制面板</h2> <button onclick="sendCmd('learn')">📚 学习按键</button> <button onclick="sendCmd('send')">▶️ 发送指令</button> <script> function sendCmd(cmd) { fetch('/' + cmd).then(r => alert('已发送: ' + cmd)); } </script> </body> </html> )"; void handleRoot() { server.send(200, "text/html", htmlPage); } void handleLearn() { learnCommand(); server.send(200, "text/plain", "已尝试学习"); } void handleSend() { sendLearnedCommand(); server.send(200, "text/plain", "已发送保存指令"); } void setupWebServer() { WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) delay(500); Serial.print("IP地址: "); Serial.println(WiFi.localIP()); server.on("/", handleRoot); server.on("/learn", handleLearn); server.on("/send", handleSend); server.begin(); }烧录后打开串口监视器,看到IP地址后,在手机浏览器输入该地址即可看到控制页面。
实战技巧:避开新手常踩的5个坑
💣 坑1:接收不到信号?
- 检查VS1838B是否插反(VCC/GND对调会烧毁)
- 是否有强光直射接收头(关灯试试)
- 遥控器电池是否没电
💣 坑2:学到的码每次都不一样?
- 很可能是重复码干扰。NEC协议在长按时会发送特殊“重复帧”(只有引导码),应忽略这类帧。
- 加判断:
if (results.decode_type == NEC && results.value != 0xFFFFFFFF)
💣 坑3:发射距离短?
- 单颗LED功率有限,可用多并联或加三极管驱动
- 尝试将IR LED贴近电器红外窗口放置
💣 坑4:Wi-Fi断连或卡顿?
delay()阻塞严重!改用millis()非阻塞延时- 减少串口打印频率,避免串行总线拥堵
💣 坑5:断电后忘记学过的指令?
- 把
learnedCode存进EEPROM或Preferences(ESP32推荐用后者)
#include <Preferences.h> Preferences prefs; // 保存 prefs.putUInt64("ir_code", learnedCode); // 读取 learnedCode = prefs.getUInt64("ir_code", 0);进阶玩法:不止于“遥控器复制”
一旦掌握了核心能力,就可以玩出更多花样:
🔄 自动化联动(配合Home Assistant)
通过MQTT上报状态,订阅指令:
client.publish("home/ir_tv/power", "ON");再配合Node-RED设置“晚上10点自动关电视”。
☁️ 构建家庭红外数据库
将常见品牌空调、电视的编码预置进程序,省去学习步骤:
const uint32_t TV_POWER_ON = 0x00FF4500; const uint32_t AC_COOL_MODE = 0x88776655;🗣️ 语音控制(对接小爱同学/Alexa)
借助ESP RainMaker或阿里云IoT平台,实现“嘿 Siri,打开空调”。
📲 开发专属App
用MIT App Inventor做个简单界面,通过HTTP请求控制ESP32。
成本与扩展性:30元搞定全家智能化
这套系统的物料总价不超过30元:
| 项目 | 单价(约) |
|---|---|
| ESP32开发板 | 15元 |
| IR LED ×2 | 2元 |
| VS1838B接收头 | 3元 |
| 电阻及其他配件 | 5元 |
| 外壳(可选) | 5元 |
相比动辄几百元的智能插座或更换整机的成本,简直是“白菜价升级”。
而且它的潜力远不止于此。未来你可以:
- 增加OLED屏显示当前模式
- 添加红外学习进度提示音
- 实现OTA空中升级固件
- 支持Daikin、Panasonic等空调私有协议
- 多台ESP32组网覆盖全屋
如果你正在寻找一个既能练手又有实用价值的物联网入门项目,那么这个ESP32红外中枢绝对值得动手一试。它不仅教会你如何与物理世界交互,更让你体会到“边缘智能”的真正魅力:用最小的代价,激活沉睡的设备。
现在就打开你的工具箱,点亮第一颗红外LED吧!
项目源码已托管至GitHub: github.com/example/esp32-ir-gateway (模拟链接)
欢迎 Fork & Star,也欢迎在评论区分享你的改造心得!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考