📡 ESP32 红外遥控实战:VS1838B 接收解码 + 红外发射
📅 2026-05-29 · 📂 硬件编程 · ⏱ 阅读约 7 分钟
📺 B站推荐视频:ESP32单片机教程 第六章23 红外遥控收发使用Arduino开发
📖 概述
红外遥控是嵌入式开发中最实用的技能之一。从家里的空调、电视、机顶盒到小米万能遥控器,红外通信无处不在。掌握 ESP32 的红外收发能力,你就能解码任何遥控器的按键码,也能用 ESP32 发射红外信号控制家电,打造自己的万能遥控器。
本教程使用 VS1838B 红外接收管(几毛钱一个)和红外发射管,搭配 Arduino 生态中最成熟的 IRremote 库。无需理解底层 NEC 协议的每一个 bit,库已经帮你封装好了。今天你将学会:解码遥控器信号 → 用串口打印按键码 → 把按键码存储下来 → 用 ESP32 发射同样的信号去控制电器。
💡 红外通信原理速览:遥控器以 38kHz 载波调制红外光发送数据(常用 NEC 协议),接收管 VS1838B 自动解调、滤除环境光干扰,输出干净的方波信号给 ESP32 解码。
🛒 物料清单
| 物料 | 型号/参数 | 数量 | 参考单价 |
| 开发板 | ESP32-WROOM-32 | 1 | ¥18 |
| 红外接收管 | VS1838B(38kHz,带金属屏蔽) | 1 | ¥0.5 |
| 红外发射管 | 5mm 940nm IR LED | 1 | ¥0.3 |
| NPN 三极管 | S8050 / 2N2222 | 1 | ¥0.2 |
| 电阻 | 100Ω(限流)+ 1kΩ(基极) | 各1 | ¥0.05 |
| 面包板 + 杜邦线 | 830孔 + 公母线若干 | 1套 | ¥8 |
| 任意红外遥控器 | 电视/空调/机顶盒遥控器均可 | 1 | 手边找 |
🔌 接线图
接收部分(VS1838B)
VS1838B 引脚(面向凸面,引脚朝下,从左到右):
┌─────────────────┐
│ ○ OUT ○ GND ○ VCC │
└─────────────────┘
VS1838B OUT → ESP32 GPIO 14
VS1838B GND → ESP32 GND
VS1838B VCC → ESP32 3.3V
发射部分(IR LED — 经三极管驱动)
ESP32 GPIO 4 → 1kΩ 电阻 → S8050 基极 (B)
S8050 集电极 (C) → 100Ω 电阻 → IR LED 正极(+)
IR LED 负极(-) → GND
S8050 发射极 (E) → GND
⚠️ 为什么加三极管?ESP32 引脚最大输出 12mA,不足以驱动
IR LED(需 20~100mA 脉冲电流)。S8050 做开关放大。
💻 基础代码:解码任意遥控器
首先安装库:Arduino IDE → 库管理 → 搜索 IRremote(作者 Armin Joachimsmeyer)→ 安装 4.x 版本。
// ===== ESP32 红外接收解码器 =====
#include <IRremote.hpp>
const int IR_RECV_PIN = 14;
void setup() {
Serial.begin(115200);
IrReceiver.begin(IR_RECV_PIN, false); // false = 不使用板载LED
Serial.println("📡 红外解码就绪 — 请对准遥控器按键");
}
void loop() {
if (IrReceiver.decode()) {
// 🔍 打印原始数据
Serial.print("协议: ");
Serial.println(getProtocolString(IrReceiver.decodedIRData.protocol));
Serial.print("地址: 0x");
Serial.println(IrReceiver.decodedIRData.address, HEX);
Serial.print("命令: 0x");
Serial.println(IrReceiver.decodedIRData.command, HEX);
Serial.println("───────────────");
IrReceiver.resume(); // ⚡ 必须调用,准备接收下一个信号
}
}
🔑 拿到按键码之后:打开串口监视器(115200 波特率),对着遥控器一个键一个键地按,记录下每个按键的「地址+命令」组合。这就是你遥控器的"指纹",后面发射时直接复用。
📤 进阶应用一:红外发射(控制电器)
当你已经解码出目标电器的按键码后,就可以用 ESP32 化身"万能遥控器"了。
// ===== ESP32 红外发射 =====
#include <IRremote.hpp>
const int IR_SEND_PIN = 4;
void setup() {
Serial.begin(115200);
IrSender.begin(IR_SEND_PIN);
Serial.println("🔫 红外发射就绪");
}
void loop() {
// 发送 NEC 协议信号:地址=0x00, 命令=0x45
Serial.println("📤 发送开机键...");
IrSender.sendNEC(0x00, 0x45, 0); // (地址, 命令, 重复次数)
delay(5000); // 每 5 秒发一次
}
⚠️ IR LED 必须经三极管驱动!直接用 GPIO 推 IR LED 亮度太弱、距离不到 30cm。加 S8050 后有效距离可达 3~5 米。发射时注意 IR LED 对准目标电器。
🎯 进阶应用二:红外 + 舵机 = 遥控开门
结合 5月15日学过的 SG90 舵机,用遥控器控制物理动作 — 按「1」开门、按「2」关门。
// ===== 红外遥控 + 舵机联动 =====
#include <IRremote.hpp>
#include <ESP32Servo.h>
const int IR_RECV_PIN = 14;
const int SERVO_PIN = 13;
Servo myServo;
void setup() {
Serial.begin(115200);
IrReceiver.begin(IR_RECV_PIN, false);
myServo.attach(SERVO_PIN);
myServo.write(0); // 初始关门位置
}
void loop() {
if (IrReceiver.decode()) {
uint8_t cmd = IrReceiver.decodedIRData.command;
if (cmd == 0x45) { // 你遥控器的「1」键
myServo.write(90); // 开门
Serial.println("🚪 开门!");
} else if (cmd == 0x46) { // 你遥控器的「2」键
myServo.write(0); // 关门
Serial.println("🔒 关门!");
}
IrReceiver.resume();
}
}
🏗️ 实战场景
场景一:万能遥控器 + Web 控制面板
结合 5月8日学过的 ESP32 Web Server,在手机网页上列出所有家电按钮。点网页按钮 → ESP32 发射红外 → 控制电视/空调/风扇。
物料组合:ESP32 + VS1838B(先解码各设备) + IR LED发射管 + S8050
联动思路:WiFi STA 模式连接路由器 → 启动 Web Server → HTML 按钮触发 IrSender.sendNEC() → 三极管驱动 IR LED → 搞定!一台手机控制全家红外设备。
场景二:红外遥控小车
结合 5月25日学过的 L298N 电机驱动,用遥控器的方向键控制小车前进后退。
物料组合:ESP32 + L298N + 两个 TT 马达 + VS1838B + 任意遥控器
联动思路:遥控器 ↑ 键 → 小车前进(L298N IN1=HIGH, IN2=LOW);↓ 键 → 后退;← → 左转;→ → 右转。小成本打造红外遥控小车!
⚠️ 常见问题
Q1: VS1838B 接好线但完全收不到信号?
🔧 三件事检查:(1) VS1838B 引脚顺序别搞反 — 面向凸面从左到右是 OUT/GND/VCC;(2) 供电必须是 3.3V,接 5V 虽然也能工作但会缩短寿命;(3) 部分廉价 VS1838B 模块自带滤波电容,OUT 脚默认 HIGH,收到信号才拉 LOW,检查逻辑是否反了。
Q2: 解码结果全是 0xFFFFFFFF?
🔧 这是 NEC 协议的「重复码」— 当你长按遥控器按键时,第一个是完整码,后续都是 0xFFFFFFFF。代码里可以用 if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT) 判断并跳过。
Q3: 发射距离不到 30cm,信号太弱?
🔧 两个可能:(1) 没加三极管驱动 — GPIO 直接推 IR LED 电流不够,加 S8050 + 100Ω 限流电阻;(2) IR LED 波长不对 — 确认是 940nm 的红外发射管(不是普通红色 LED!)。正确驱动后距离 3~5 米没问题。
Q4: 发射信号后电视没反应,但串口显示发送成功?
🔧 红外发射有方向性,IR LED 必须对准电器的红外接收窗。另外确认 (1) 协议类型匹配(NEC/Sony/RC5 等),(2) 地址和命令码正确移植了之前解码的结果,(3) 试试 IrSender.sendNEC(address, command, 2) 多发两次。