1. 项目概述与核心价值手头是不是总有几个闲置的旧遥控器可能是换电视后留下的也可能是旧空调、旧DVD机的。它们通常被遗忘在抽屉角落食之无味弃之可惜。但你知道吗这些看似过时的“电子垃圾”其实是一个个现成的、功能完好的无线控制器。今天我们就来聊聊如何用一块最常见的Arduino开发板配合一个不到两块钱的红外接收头把这些旧遥控器“复活”变成你智能家居项目或者电子制作中的得力助手。红外遥控技术本质上是一种利用红外光脉冲进行编码通信的无线技术。它成本极低、实现简单并且拥有海量的现成硬件就是你家各种电器的遥控器。对于嵌入式系统开发、物联网原型验证或者智能家居DIY来说掌握红外遥控的解码与应用等于打开了一扇通往低成本无线控制的大门。你不再需要为了一个简单的无线开关而去研究复杂的蓝牙或Wi-Fi模块一个旧遥控器加一个接收头就能搞定。本文将以最经典的Arduino Uno为例手把手带你完成从红外信号解码到实际控制应用的全过程。我们会使用一个名为IRremote的成熟开源库它能帮你处理复杂的信号解析让你专注于实现自己的控制逻辑。最终你将学会如何让一个旧的三星电视遥控器变身成为控制三色LED灯组的无线开关。这个项目本身是一个绝佳的起点掌握了核心方法后你可以轻松地将控制对象从LED扩展到继电器、舵机、电机甚至智能插座实现真正的“旧物改造变废为宝”。2. 红外遥控技术原理与硬件选型2.1 红外通信的基本原理红外遥控听起来高大上其实原理非常直观。你可以把它想象成一种特殊的“闪光灯语言”。遥控器内部有一个红外发光二极管IR LED当我们按下按键时单片机遥控器里的“大脑”会驱动这个LED以一种特定的规律快速闪烁发出人眼看不见的红外光。这个“闪烁规律”就是通信协议。不同的厂商比如NEC、Sony、Samsung都有自己的“方言”。但它们核心的思想类似通过调制Modulation和编码Encoding来传递信息。调制为了防止环境光如日光灯的干扰红外信号不是持续亮灭而是以一个固定的载波频率通常是38kHz进行开关。这就好比用38kHz的“哨音”来承载信息接收器只“听”这个频率的声音从而过滤掉大部分噪音。编码信息比如“电源键被按下了”被编码成一系列长短不同的脉冲。最常见的NEC协议使用脉冲间隔编码一个560微秒的引导码开始接着是32位的数据包括地址码、命令码和反码用脉冲之间的间隔长短来区分逻辑“0”和逻辑“1”。接收端是一个红外接收头如VS1838、HS0038等它内部集成了光电二极管、前置放大器、带通滤波器和解调电路。它的任务就是“监听”38kHz的信号把调制过的红外脉冲还原成干净的数字电平信号输出给Arduino。这样一来Arduino只需要读取这个引脚的高低电平变化再通过IRremote库去解析这个变化序列就能知道遥控器发送了什么命令。2.2 核心硬件清单与选型要点这个项目的硬件需求非常简单大部分零件在任意一个Arduino入门套件里都能找到。必需硬件Arduino开发板一块Arduino Uno或其兼容板如Elegoo Uno R3。这是项目的大脑负责解码和执行命令。红外接收头这是关键传感器。推荐使用VS1838B或HS0038这类三引脚的一体化接收模块。它们非常常见价格通常在0.5-2元人民币之间。注意要区分接收头接收信号和发射管发射信号本项目解码只需要接收头。红外遥控器任意一个你家闲置的电视、空调、机顶盒遥控器都可以。如果实在没有可以花几块钱在网上购买一个通用的“迷你红外遥控器”常随传感器套件附送。被控对象示例3个不同颜色的LED灯红、黄、绿以及3个对应的220Ω限流电阻。用LED演示最直观。连接线若干杜邦线公对公或公对母用于连接电路。面包板一块用于免焊接搭建电路非常方便实验。硬件选型与连接注意事项接收头引脚识别一体化红外接收头通常有三个引脚。虽然不同型号排列可能不同但功能一致GND接地接Arduino的GND引脚。VCC或Vout电源接Arduino的5V引脚。OUT或Data数据信号输出接Arduino的任意数字引脚如示例中的D6。重要提示接线前务必查阅接收头的资料或观察板子上的丝印接反VCC和GND极有可能瞬间烧毁接收头。通常接收头有弧面透镜的一面朝向遥控器方向引脚顺序从左到右多为“OUT - GND - VCC”但并非绝对。遥控器测试在编写代码前可以用手机摄像头快速测试遥控器是否工作。打开手机的相机APP将遥控器的发射头对准摄像头按下任意键。在手机屏幕上你应该能看到发射头处有白色的闪烁光点因为手机摄像头没有红外滤光片。这是一个快速验证遥控器电池是否有电、红外管是否完好的好方法。LED与电阻LED是电流驱动器件必须串联限流电阻否则会因电流过大而烧毁。对于Arduino的5V输出串联一个220Ω到1kΩ的电阻都是安全的。电阻值越小LED越亮。我们选择220Ω是为了获得较好的亮度。3. 开发环境搭建与IRremote库详解3.1 Arduino IDE配置与库安装首先确保你的电脑上安装了Arduino IDE集成开发环境。如果没有可以去Arduino官网下载安装。安装后我们需要引入本次项目的核心——IRremote库。打开库管理器启动Arduino IDE点击顶部菜单栏的“工具” - “管理库…”。搜索库在弹出的“库管理器”窗口中在搜索框内输入“IRremote”。安装库在搜索结果中找到由“Arduino-IRremote”或“Shirriff”维护的库本文示例基于较老的Shirriff版本但Arduino-IRremote是当前更活跃的维护分支两者核心API兼容。点击该库然后点击“安装”按钮。IDE会自动下载并安装库及其依赖。注意网络上存在多个同名或相似的IR库。请务必确认你安装的是上述主流库。安装错误的库可能导致编译错误或无法解码信号。3.2 IRremote库核心对象与函数解析安装好库后我们来深入理解一下代码中将要使用的几个核心元素。理解它们你才能举一反三而不仅仅是照抄代码。#include IRremote.h这行代码告诉编译器我们要使用IRremote库的功能。 表示这是一个系统/库头文件。IRrecv类与接收对象IRrecv是一个类可以理解为一种数据类型用于创建红外接收对象。IRrecv irrecv(receiverPin);这行代码创建了一个名为irrecv的红外接收对象并告诉它红外接收头的信号线连接在receiverPin例如数字引脚6这个引脚上。你可以把irrecv这个名字改成任何你喜欢的比如myReceiver。decode_results结构体这是一个用来存储解码结果的结构体。当接收到一个完整的红外信号并成功解码后所有的信息都会存放在这个结构体类型的变量里比如信号协议类型、原始数据、数据位数等。decode_results results;irrecv.enableIRIn()这是接收对象的一个方法函数。必须在setup()函数中调用一次它的作用是启动红外信号接收的中断。调用后Arduino就会在后台开始监听指定引脚上的红外信号。irrecv.decode(results)这是最关键的解码函数。它检查是否有一个完整的红外信号被接收并解码。如果解码成功函数返回true并将解码结果存入我们传入的results变量中符号表示传递变量的地址。如果尚未收到或解码未完成则返回false。通常我们在loop()函数中用if(irrecv.decode(results)) { ... }来判断是否有新指令。results.value这是decode_results结构体中最常用的成员它是一个unsigned long类型的变量存储了解码出来的按键值。例如按下遥控器的“电源”键results.value可能等于0xFFA25D十六进制。这个值对于同一个遥控器上的同一个按键是唯一的。irrecv.resume()在成功解码并处理完一次信号后必须调用此函数。它的作用是重置接收器使其准备好接收下一个红外信号。如果忘记调用接收器将一直停留在“已解码”状态无法接收新指令。4. 实战第一步解码你的遥控器现在让我们开始动手。第一步是“侦听”即弄清楚你的遥控器每个按键发出的“密码”是什么。4.1 电路连接按照下图在面包板上搭建电路将红外接收头的VCC引脚连接到 Arduino 的5V。将红外接收头的GND引脚连接到 Arduino 的GND。将红外接收头的OUT引脚连接到 Arduino 的数字引脚 6。暂时不需要连接LED。4.2 解码程序编写与上传打开Arduino IDE新建一个项目复制粘贴以下代码。这段代码是一个通用的红外解码器能识别多种协议并打印出按键值。/* * 红外遥控器按键解码器 * 作者你的名字 * 功能读取红外接收头信号并在串口监视器显示按键的十进制、十六进制和二进制值 */ #include IRremote.h // 引入IRremote库 const int RECV_PIN 6; // 红外接收头连接至数字引脚6 IRrecv irrecv(RECV_PIN); // 创建红外接收对象 decode_results results; // 用于存储解码结果的结构体 void setup() { Serial.begin(9600); // 启动串口通信波特率9600 irrecv.enableIRIn(); // 启动红外接收 Serial.println(红外解码器已启动请按下遥控器按键...); } void loop() { if (irrecv.decode(results)) { // 如果成功解码到一个信号 // 打印协议类型便于调试 Serial.print(协议类型: ); switch (results.decode_type) { case NEC: Serial.println(NEC); break; case SONY: Serial.println(SONY); break; case RC5: Serial.println(RC5); break; case RC6: Serial.println(RC6); break; case DISH: Serial.println(DISH); break; case SHARP: Serial.println(SHARP); break; case JVC: Serial.println(JVC); break; case SAMSUNG: Serial.println(SAMSUNG); break; case LG: Serial.println(LG); break; case WHYNTER: Serial.println(WHYNTER); break; case PANASONIC: Serial.println(PANASONIC); break; case DENON: Serial.println(DENON); break; case BOSEWAVE: Serial.println(BOSE); break; case LEGO_PF: Serial.println(LEGO Power Functions); break; case UNKNOWN: default: Serial.println(未知协议); break; } // 打印按键值三种进制 Serial.print(按键值 (十进制): ); Serial.println(results.value, DEC); // 十进制显示 Serial.print(按键值 (十六进制): 0x); Serial.println(results.value, HEX); // 十六进制显示更常用 Serial.print(按键值 (二进制): ); Serial.println(results.value, BIN); // 二进制显示 Serial.println(-----------------------------------); irrecv.resume(); // 至关重要准备接收下一个信号 } }上传与测试在IDE中选择正确的板卡如 Arduino Uno和端口。点击上传按钮将代码烧录到Arduino。上传成功后打开IDE的“工具” - “串口监视器”或使用快捷键 CtrlShiftM。确保串口监视器右下角的波特率设置为9600。将你的遥控器对准红外接收头距离20厘米以内按下任意按键。你会在串口监视器中看到类似下面的输出红外解码器已启动请按下遥控器按键... 协议类型: SAMSUNG 按键值 (十进制): 3772784863 按键值 (十六进制): 0xE0E020DF 按键值 (二进制): 11100000111000000010000011011111 -----------------------------------4.3 记录关键按键值拿出纸笔或打开一个文本编辑器记录下你计划使用的几个按键对应的十六进制值。例如我记录了我的三星遥控器按键1:0xE0E020DF按键2:0xE0E0A05F按键3:0xE0E0609F按键4:0xE0E010EF(这是我额外解码的)实操心得解码中的常见问题收不到信号/值全是0xFFFFFFFF首先检查接线特别是VCC和GND是否接反。其次确保遥控器对准接收头距离和角度。有些接收头视角较窄。最后尝试按下按键时间长一点1-2秒有些协议需要较长的引导码。每次按键出现多个值这是正常的。许多遥控器在长按时会先发送一个“按下”指令然后重复发送“重复”指令通常是0xFFFFFFFF。我们的代码会分别显示它们。在控制逻辑中我们通常只响应非重复码。解码出的协议是UNKNOWN你的遥控器可能使用了IRremote库不支持的私有协议。可以尝试更新到最新版本的IRremote库或者尝试用results.rawlen和results.rawbuf来获取原始脉冲数据进行更底层的分析这属于进阶内容。值不稳定偶尔变化可能是环境光干扰如强烈的日光灯。尝试遮挡一下环境光或让接收头远离强光源。5. 实战第二步用遥控器无线控制LED拿到“密码本”后我们就可以编写控制程序了。接下来我们将用遥控器的1、2、3、4键分别控制红、黄、绿LED的单独点亮以及全部点亮。5.1 扩展电路连接在之前解码电路的基础上增加LED控制部分将红色LED的长脚阳极通过一个220Ω电阻连接到 Arduino数字引脚 8。短脚阴极接GND。将黄色LED的长脚通过一个220Ω电阻连接到 Arduino数字引脚 9。短脚接GND。将绿色LED的长脚通过一个220Ω电阻连接到 Arduino数字引脚 10。短脚接GND。红外接收头连接保持不变VCC-5V, GND-GND, OUT-D6。5.2 控制程序编写与解析新建一个项目复制粘贴以下代码。请务必将代码中if语句里的十六进制值0x...替换成你在上一步中记录下来的、你自己遥控器的实际值/* * 红外遥控无线LED控制器 * 作者你的名字 * 功能使用红外遥控器控制三个LED * 按键1: 点亮红色LED 2秒 * 按键2: 点亮黄色LED 2秒 * 按键3: 点亮绿色LED 2秒 * 按键4: 同时点亮所有LED 2秒 */ #include IRremote.h // 引脚定义 const int RECV_PIN 6; // 红外接收头信号引脚 const int RED_PIN 8; // 红色LED控制引脚 const int YELLOW_PIN 9; // 黄色LED控制引脚 const int GREEN_PIN 10; // 绿色LED控制引脚 const long ON_DURATION 2000; // LED点亮持续时间毫秒 // 创建红外接收对象和解码结果变量 IRrecv irrecv(RECV_PIN); decode_results results; // 重要请用你自己的遥控器按键值替换下面的值 const unsigned long KEY_1 0xE0E020DF; // 替换为你的按键1的十六进制值 const unsigned long KEY_2 0xE0E0A05F; // 替换为你的按键2的十六进制值 const unsigned long KEY_3 0xE0E0609F; // 替换为你的按键3的十六进制值 const unsigned long KEY_4 0xE0E010EF; // 替换为你的按键4的十六进制值 void setup() { // 初始化串口用于调试输出 Serial.begin(9600); Serial.println(红外LED控制器初始化...); // 设置LED引脚为输出模式 pinMode(RED_PIN, OUTPUT); pinMode(YELLOW_PIN, OUTPUT); pinMode(GREEN_PIN, OUTPUT); // 初始状态关闭所有LED allLEDsOff(); // 启动红外接收 irrecv.enableIRIn(); Serial.println(就绪等待遥控指令...); } void loop() { // 检查是否收到红外信号 if (irrecv.decode(results)) { // 打印接收到的值便于调试 Serial.print(收到红外码: 0x); Serial.println(results.value, HEX); // 根据接收到的值执行相应动作 // 注意这里使用 进行比较因为我们只关心特定按键 if (results.value KEY_1) { Serial.println(指令点亮红色LED); controlLED(RED_PIN); } else if (results.value KEY_2) { Serial.println(指令点亮黄色LED); controlLED(YELLOW_PIN); } else if (results.value KEY_3) { Serial.println(指令点亮绿色LED); controlLED(GREEN_PIN); } else if (results.value KEY_4) { Serial.println(指令点亮所有LED); allLEDsOn(); delay(ON_DURATION); allLEDsOff(); } else { // 可以在这里处理其他按键或重复码0xFFFFFFFF // 对于重复码通常我们忽略它避免长按导致动作重复执行 if (results.value ! 0xFFFFFFFF) { Serial.println(未知指令已忽略。); } } // 准备接收下一个信号 irrecv.resume(); } // 这里可以添加其他非阻塞的任务 } // 控制单个LED点亮指定时间的函数 void controlLED(int ledPin) { digitalWrite(ledPin, HIGH); // 点亮LED delay(ON_DURATION); // 保持点亮状态 digitalWrite(ledPin, LOW); // 关闭LED } // 关闭所有LED的函数 void allLEDsOff() { digitalWrite(RED_PIN, LOW); digitalWrite(YELLOW_PIN, LOW); digitalWrite(GREEN_PIN, LOW); } // 点亮所有LED的函数 void allLEDsOn() { digitalWrite(RED_PIN, HIGH); digitalWrite(YELLOW_PIN, HIGH); digitalWrite(GREEN_PIN, HIGH); }代码解析与优化点常量定义将引脚、按键值和延时时间定义为const常量放在程序开头。这样做的优点是提高代码可读性并且未来修改参数比如换引脚、改延时时只需修改一处非常方便。函数封装将allLEDsOff()、allLEDsOn()和controlLED()这些重复操作封装成函数。这使得主循环loop()非常清晰也便于代码复用和维护。重复码处理在else分支中我们特别判断了results.value ! 0xFFFFFFFF。0xFFFFFFFF是大多数协议中的“重复码”表示按键被持续按住。在简单的开关控制中我们通常忽略它以避免长按时LED不停闪烁。如果你需要实现“长按加速”等功能则可以在这里做特殊处理。非阻塞设计思考当前的代码使用delay(ON_DURATION)来保持LED亮起。这会导致在这2秒内Arduino无法响应新的红外指令或其他任务。对于简单的演示没问题但在更复杂的项目中可以考虑使用millis()函数进行非阻塞延时实现多任务处理。5.3 上传测试与功能验证将修改好按键值的代码上传到Arduino。打开串口监视器。用遥控器分别按下1、2、3、4键观察串口监视器是否打印出对应的指令信息。对应的LED是否被点亮2秒后自动熄灭。按下按键4时是否所有LED同时点亮2秒。如果一切正常恭喜你你已经成功将旧遥控器改造为一个三通道无线开关控制器。6. 项目扩展与高级应用思路掌握了基础的红外解码与控制后这个项目的潜力远不止控制几个LED。下面分享几个实用的扩展方向和我个人实践中的一些心得。6.1 控制更复杂的设备继电器与家电控制LED是小试牛刀真正的威力在于控制交流电器。你需要一个继电器模块建议使用带光耦隔离和续流二极管的5V驱动模块更安全。连接与代码调整硬件将继电器的控制引脚IN接Arduino的某个数字引脚如D7VCC和GND分别接5V和GND。继电器的常开触点NO和公共端COM串联到你想控制的电器如台灯的电源线中注意高压危险操作前务必断电。软件代码逻辑和LED控制完全一样。只需将digitalWrite(ledPin, HIGH/LOW)改为控制继电器的引脚即可。例如digitalWrite(RELAY_PIN, HIGH)吸合继电器电器通电LOW则断开。这样你就可以用旧遥控器控制台灯、风扇、加湿器等任何220V电器实现基础的智能开关功能。你可以为不同的按键分配不同的电器或者用“开”、“关”、“模式”等键实现更复杂的逻辑。6.2 实现状态切换Toggle与长按功能前面的例子是“点按触发延时关闭”。更常用的可能是“点按开关”。这需要程序能记住LED的当前状态。实现思路bool redLedState false; // 记录红色LED状态false为关 if (results.value KEY_1) { redLedState !redLedState; // 状态取反 digitalWrite(RED_PIN, redLedState ? HIGH : LOW); Serial.println(redLedState ? 红色LED已打开 : 红色LED已关闭); }对于长按功能可以在解码时判断results.value。如果是重复码0xFFFFFFFF并且距离上次有效按键时间很短则可以执行长按动作如调节亮度、连续增加数值等。6.3 构建红外学习与转发器万能遥控一个更有趣的项目是制作一个“红外学习转发器”。它需要两个核心部件一个红外接收头用于学习和一个红外发射管用于转发。工作流程学习模式按下学习键设备进入学习状态。用原装遥控器对准接收头按下按键Arduino记录下该按键的原始脉冲时序results.rawbuf和results.rawlen并存储到EEPROMArduino的永久存储器中。转发模式按下转发键Arduino从EEPROM中读取脉冲时序驱动红外发射管原样发送出去从而控制目标设备。这相当于自制了一个可学习的万能遥控器。网上有成熟的IRremote库示例代码实现了此功能核心是使用irsend.sendRaw(rawCodes, codeLen, frequency)函数来发送学习到的原始数据。6.4 集成到智能家居平台如果你玩Home Assistant、OpenHAB等开源智能家居平台可以让Arduino通过串口、Wi-Fi如ESP8266或以太网与服务器通信。Arduino作为红外收发节点接收来自智能家居平台的指令转发红外信号控制空调、电视等非智能家电同时它也可以将遥控器按键动作上报给平台作为触发自动化场景的输入。例如你可以设置“晚上10点按下遥控器睡眠键自动关闭客厅灯、空调调至26度、打开卧室空气净化器”这样的场景。7. 常见问题排查与调试技巧实录在折腾红外项目的过程中我踩过不少坑。这里把最常见的问题和解决方法整理出来希望能帮你节省时间。问题现象可能原因排查步骤与解决方案完全无反应串口无输出1. 电源问题2. 接收头接线错误3. 代码未上传成功4. 串口监视器设置错误1. 检查Arduino是否通过USB正常供电板载电源指示灯是否亮起。2.重点检查红外接收头VCC、GND是否接反信号线是否接对引脚用万用表测量接收头VCC与GND之间是否有5V电压。3. 重新编译上传代码观察IDE下方是否有错误提示。4. 确认串口监视器波特率设置为9600并选择了正确的COM端口。串口有输出但results.value始终为0或固定值1. 遥控器没电或损坏2. 接收头型号不匹配或损坏3. 环境光干扰太强4. 遥控器协议不支持1. 用手机摄像头检查遥控器发射管是否闪烁方法见前文。2. 尝试更换一个已知好用的接收头如VS1838。3. 移至室内光线较暗处或遮挡接收头。4. 尝试用Serial.println(results.decode_type)查看协议类型如果是UNKNOWN可能需寻找专用库或解析原始信号。按键一次串口打印多次不同值1. 接收到重复码2. 按键抖动或信号反射1. 这是正常现象。第一个值是有效键值后续的0xFFFFFFFF是重复码。在控制逻辑中应过滤掉重复码如if(results.value ! 0xFFFFFFFF)。2. 确保遥控器与接收头之间没有强反射面短按按键。控制不稳定时灵时不灵1. 距离或角度问题2. 电源噪声3. 程序逻辑有冲突1. 红外是直线传播确保发射头与接收头透镜对准距离建议在5米内无遮挡。2. 如果使用电机等大电流设备可能引起电源波动。尝试给Arduino和接收头单独供电或在VCC与GND间加一个10-100μF的电解电容滤波。3. 检查代码中是否有长时间的delay()阻塞了红外接收。考虑改用非阻塞编程模式。能解码但不能控制设备如LED不亮1. LED/继电器接线错误2. 控制引脚定义错误3. LED或电阻损坏1. 确认LED长脚阳极通过电阻接控制引脚短脚接GND。继电器模块注意控制引脚、高低电平触发方式。2. 检查代码中pinMode和digitalWrite使用的引脚号是否与实际接线一致。3. 用一段导线直接将LED两端接5V和GND串联电阻测试LED本身是否完好。调试进阶技巧使用Serial.print进行“printf调试”在代码关键位置如进入if判断、调用函数前打印信息是追踪程序流程最直接的方法。监听原始信号如果标准协议解码失败可以尝试让IRremote库输出原始脉冲宽度数据。这有助于判断是信号根本没收到还是协议不匹配。if (irrecv.decode(results)) { Serial.print(Raw len: ); Serial.println(results.rawlen); for (int i 1; i results.rawlen; i) { Serial.print(results.rawbuf[i] * USECPERTICK, DEC); Serial.print( ); } Serial.println(); irrecv.resume(); }供电隔离当项目涉及电机、舵机等感性负载时强烈建议使用独立的电源为Arduino逻辑部分和动力部分供电并共地。这能极大提高系统稳定性。红外遥控是一个入门简单、但深度可挖的领域。从让一个旧遥控器重新发光发热开始你可以逐步深入到协议分析、信号模拟、智能联动等更有趣的应用。最重要的是动手去做在调试和解决问题的过程中你对硬件和嵌入式编程的理解会深刻得多。
Arduino红外遥控解码实战:旧遥控器变智能无线控制器
发布时间:2026/6/2 13:18:09
1. 项目概述与核心价值手头是不是总有几个闲置的旧遥控器可能是换电视后留下的也可能是旧空调、旧DVD机的。它们通常被遗忘在抽屉角落食之无味弃之可惜。但你知道吗这些看似过时的“电子垃圾”其实是一个个现成的、功能完好的无线控制器。今天我们就来聊聊如何用一块最常见的Arduino开发板配合一个不到两块钱的红外接收头把这些旧遥控器“复活”变成你智能家居项目或者电子制作中的得力助手。红外遥控技术本质上是一种利用红外光脉冲进行编码通信的无线技术。它成本极低、实现简单并且拥有海量的现成硬件就是你家各种电器的遥控器。对于嵌入式系统开发、物联网原型验证或者智能家居DIY来说掌握红外遥控的解码与应用等于打开了一扇通往低成本无线控制的大门。你不再需要为了一个简单的无线开关而去研究复杂的蓝牙或Wi-Fi模块一个旧遥控器加一个接收头就能搞定。本文将以最经典的Arduino Uno为例手把手带你完成从红外信号解码到实际控制应用的全过程。我们会使用一个名为IRremote的成熟开源库它能帮你处理复杂的信号解析让你专注于实现自己的控制逻辑。最终你将学会如何让一个旧的三星电视遥控器变身成为控制三色LED灯组的无线开关。这个项目本身是一个绝佳的起点掌握了核心方法后你可以轻松地将控制对象从LED扩展到继电器、舵机、电机甚至智能插座实现真正的“旧物改造变废为宝”。2. 红外遥控技术原理与硬件选型2.1 红外通信的基本原理红外遥控听起来高大上其实原理非常直观。你可以把它想象成一种特殊的“闪光灯语言”。遥控器内部有一个红外发光二极管IR LED当我们按下按键时单片机遥控器里的“大脑”会驱动这个LED以一种特定的规律快速闪烁发出人眼看不见的红外光。这个“闪烁规律”就是通信协议。不同的厂商比如NEC、Sony、Samsung都有自己的“方言”。但它们核心的思想类似通过调制Modulation和编码Encoding来传递信息。调制为了防止环境光如日光灯的干扰红外信号不是持续亮灭而是以一个固定的载波频率通常是38kHz进行开关。这就好比用38kHz的“哨音”来承载信息接收器只“听”这个频率的声音从而过滤掉大部分噪音。编码信息比如“电源键被按下了”被编码成一系列长短不同的脉冲。最常见的NEC协议使用脉冲间隔编码一个560微秒的引导码开始接着是32位的数据包括地址码、命令码和反码用脉冲之间的间隔长短来区分逻辑“0”和逻辑“1”。接收端是一个红外接收头如VS1838、HS0038等它内部集成了光电二极管、前置放大器、带通滤波器和解调电路。它的任务就是“监听”38kHz的信号把调制过的红外脉冲还原成干净的数字电平信号输出给Arduino。这样一来Arduino只需要读取这个引脚的高低电平变化再通过IRremote库去解析这个变化序列就能知道遥控器发送了什么命令。2.2 核心硬件清单与选型要点这个项目的硬件需求非常简单大部分零件在任意一个Arduino入门套件里都能找到。必需硬件Arduino开发板一块Arduino Uno或其兼容板如Elegoo Uno R3。这是项目的大脑负责解码和执行命令。红外接收头这是关键传感器。推荐使用VS1838B或HS0038这类三引脚的一体化接收模块。它们非常常见价格通常在0.5-2元人民币之间。注意要区分接收头接收信号和发射管发射信号本项目解码只需要接收头。红外遥控器任意一个你家闲置的电视、空调、机顶盒遥控器都可以。如果实在没有可以花几块钱在网上购买一个通用的“迷你红外遥控器”常随传感器套件附送。被控对象示例3个不同颜色的LED灯红、黄、绿以及3个对应的220Ω限流电阻。用LED演示最直观。连接线若干杜邦线公对公或公对母用于连接电路。面包板一块用于免焊接搭建电路非常方便实验。硬件选型与连接注意事项接收头引脚识别一体化红外接收头通常有三个引脚。虽然不同型号排列可能不同但功能一致GND接地接Arduino的GND引脚。VCC或Vout电源接Arduino的5V引脚。OUT或Data数据信号输出接Arduino的任意数字引脚如示例中的D6。重要提示接线前务必查阅接收头的资料或观察板子上的丝印接反VCC和GND极有可能瞬间烧毁接收头。通常接收头有弧面透镜的一面朝向遥控器方向引脚顺序从左到右多为“OUT - GND - VCC”但并非绝对。遥控器测试在编写代码前可以用手机摄像头快速测试遥控器是否工作。打开手机的相机APP将遥控器的发射头对准摄像头按下任意键。在手机屏幕上你应该能看到发射头处有白色的闪烁光点因为手机摄像头没有红外滤光片。这是一个快速验证遥控器电池是否有电、红外管是否完好的好方法。LED与电阻LED是电流驱动器件必须串联限流电阻否则会因电流过大而烧毁。对于Arduino的5V输出串联一个220Ω到1kΩ的电阻都是安全的。电阻值越小LED越亮。我们选择220Ω是为了获得较好的亮度。3. 开发环境搭建与IRremote库详解3.1 Arduino IDE配置与库安装首先确保你的电脑上安装了Arduino IDE集成开发环境。如果没有可以去Arduino官网下载安装。安装后我们需要引入本次项目的核心——IRremote库。打开库管理器启动Arduino IDE点击顶部菜单栏的“工具” - “管理库…”。搜索库在弹出的“库管理器”窗口中在搜索框内输入“IRremote”。安装库在搜索结果中找到由“Arduino-IRremote”或“Shirriff”维护的库本文示例基于较老的Shirriff版本但Arduino-IRremote是当前更活跃的维护分支两者核心API兼容。点击该库然后点击“安装”按钮。IDE会自动下载并安装库及其依赖。注意网络上存在多个同名或相似的IR库。请务必确认你安装的是上述主流库。安装错误的库可能导致编译错误或无法解码信号。3.2 IRremote库核心对象与函数解析安装好库后我们来深入理解一下代码中将要使用的几个核心元素。理解它们你才能举一反三而不仅仅是照抄代码。#include IRremote.h这行代码告诉编译器我们要使用IRremote库的功能。 表示这是一个系统/库头文件。IRrecv类与接收对象IRrecv是一个类可以理解为一种数据类型用于创建红外接收对象。IRrecv irrecv(receiverPin);这行代码创建了一个名为irrecv的红外接收对象并告诉它红外接收头的信号线连接在receiverPin例如数字引脚6这个引脚上。你可以把irrecv这个名字改成任何你喜欢的比如myReceiver。decode_results结构体这是一个用来存储解码结果的结构体。当接收到一个完整的红外信号并成功解码后所有的信息都会存放在这个结构体类型的变量里比如信号协议类型、原始数据、数据位数等。decode_results results;irrecv.enableIRIn()这是接收对象的一个方法函数。必须在setup()函数中调用一次它的作用是启动红外信号接收的中断。调用后Arduino就会在后台开始监听指定引脚上的红外信号。irrecv.decode(results)这是最关键的解码函数。它检查是否有一个完整的红外信号被接收并解码。如果解码成功函数返回true并将解码结果存入我们传入的results变量中符号表示传递变量的地址。如果尚未收到或解码未完成则返回false。通常我们在loop()函数中用if(irrecv.decode(results)) { ... }来判断是否有新指令。results.value这是decode_results结构体中最常用的成员它是一个unsigned long类型的变量存储了解码出来的按键值。例如按下遥控器的“电源”键results.value可能等于0xFFA25D十六进制。这个值对于同一个遥控器上的同一个按键是唯一的。irrecv.resume()在成功解码并处理完一次信号后必须调用此函数。它的作用是重置接收器使其准备好接收下一个红外信号。如果忘记调用接收器将一直停留在“已解码”状态无法接收新指令。4. 实战第一步解码你的遥控器现在让我们开始动手。第一步是“侦听”即弄清楚你的遥控器每个按键发出的“密码”是什么。4.1 电路连接按照下图在面包板上搭建电路将红外接收头的VCC引脚连接到 Arduino 的5V。将红外接收头的GND引脚连接到 Arduino 的GND。将红外接收头的OUT引脚连接到 Arduino 的数字引脚 6。暂时不需要连接LED。4.2 解码程序编写与上传打开Arduino IDE新建一个项目复制粘贴以下代码。这段代码是一个通用的红外解码器能识别多种协议并打印出按键值。/* * 红外遥控器按键解码器 * 作者你的名字 * 功能读取红外接收头信号并在串口监视器显示按键的十进制、十六进制和二进制值 */ #include IRremote.h // 引入IRremote库 const int RECV_PIN 6; // 红外接收头连接至数字引脚6 IRrecv irrecv(RECV_PIN); // 创建红外接收对象 decode_results results; // 用于存储解码结果的结构体 void setup() { Serial.begin(9600); // 启动串口通信波特率9600 irrecv.enableIRIn(); // 启动红外接收 Serial.println(红外解码器已启动请按下遥控器按键...); } void loop() { if (irrecv.decode(results)) { // 如果成功解码到一个信号 // 打印协议类型便于调试 Serial.print(协议类型: ); switch (results.decode_type) { case NEC: Serial.println(NEC); break; case SONY: Serial.println(SONY); break; case RC5: Serial.println(RC5); break; case RC6: Serial.println(RC6); break; case DISH: Serial.println(DISH); break; case SHARP: Serial.println(SHARP); break; case JVC: Serial.println(JVC); break; case SAMSUNG: Serial.println(SAMSUNG); break; case LG: Serial.println(LG); break; case WHYNTER: Serial.println(WHYNTER); break; case PANASONIC: Serial.println(PANASONIC); break; case DENON: Serial.println(DENON); break; case BOSEWAVE: Serial.println(BOSE); break; case LEGO_PF: Serial.println(LEGO Power Functions); break; case UNKNOWN: default: Serial.println(未知协议); break; } // 打印按键值三种进制 Serial.print(按键值 (十进制): ); Serial.println(results.value, DEC); // 十进制显示 Serial.print(按键值 (十六进制): 0x); Serial.println(results.value, HEX); // 十六进制显示更常用 Serial.print(按键值 (二进制): ); Serial.println(results.value, BIN); // 二进制显示 Serial.println(-----------------------------------); irrecv.resume(); // 至关重要准备接收下一个信号 } }上传与测试在IDE中选择正确的板卡如 Arduino Uno和端口。点击上传按钮将代码烧录到Arduino。上传成功后打开IDE的“工具” - “串口监视器”或使用快捷键 CtrlShiftM。确保串口监视器右下角的波特率设置为9600。将你的遥控器对准红外接收头距离20厘米以内按下任意按键。你会在串口监视器中看到类似下面的输出红外解码器已启动请按下遥控器按键... 协议类型: SAMSUNG 按键值 (十进制): 3772784863 按键值 (十六进制): 0xE0E020DF 按键值 (二进制): 11100000111000000010000011011111 -----------------------------------4.3 记录关键按键值拿出纸笔或打开一个文本编辑器记录下你计划使用的几个按键对应的十六进制值。例如我记录了我的三星遥控器按键1:0xE0E020DF按键2:0xE0E0A05F按键3:0xE0E0609F按键4:0xE0E010EF(这是我额外解码的)实操心得解码中的常见问题收不到信号/值全是0xFFFFFFFF首先检查接线特别是VCC和GND是否接反。其次确保遥控器对准接收头距离和角度。有些接收头视角较窄。最后尝试按下按键时间长一点1-2秒有些协议需要较长的引导码。每次按键出现多个值这是正常的。许多遥控器在长按时会先发送一个“按下”指令然后重复发送“重复”指令通常是0xFFFFFFFF。我们的代码会分别显示它们。在控制逻辑中我们通常只响应非重复码。解码出的协议是UNKNOWN你的遥控器可能使用了IRremote库不支持的私有协议。可以尝试更新到最新版本的IRremote库或者尝试用results.rawlen和results.rawbuf来获取原始脉冲数据进行更底层的分析这属于进阶内容。值不稳定偶尔变化可能是环境光干扰如强烈的日光灯。尝试遮挡一下环境光或让接收头远离强光源。5. 实战第二步用遥控器无线控制LED拿到“密码本”后我们就可以编写控制程序了。接下来我们将用遥控器的1、2、3、4键分别控制红、黄、绿LED的单独点亮以及全部点亮。5.1 扩展电路连接在之前解码电路的基础上增加LED控制部分将红色LED的长脚阳极通过一个220Ω电阻连接到 Arduino数字引脚 8。短脚阴极接GND。将黄色LED的长脚通过一个220Ω电阻连接到 Arduino数字引脚 9。短脚接GND。将绿色LED的长脚通过一个220Ω电阻连接到 Arduino数字引脚 10。短脚接GND。红外接收头连接保持不变VCC-5V, GND-GND, OUT-D6。5.2 控制程序编写与解析新建一个项目复制粘贴以下代码。请务必将代码中if语句里的十六进制值0x...替换成你在上一步中记录下来的、你自己遥控器的实际值/* * 红外遥控无线LED控制器 * 作者你的名字 * 功能使用红外遥控器控制三个LED * 按键1: 点亮红色LED 2秒 * 按键2: 点亮黄色LED 2秒 * 按键3: 点亮绿色LED 2秒 * 按键4: 同时点亮所有LED 2秒 */ #include IRremote.h // 引脚定义 const int RECV_PIN 6; // 红外接收头信号引脚 const int RED_PIN 8; // 红色LED控制引脚 const int YELLOW_PIN 9; // 黄色LED控制引脚 const int GREEN_PIN 10; // 绿色LED控制引脚 const long ON_DURATION 2000; // LED点亮持续时间毫秒 // 创建红外接收对象和解码结果变量 IRrecv irrecv(RECV_PIN); decode_results results; // 重要请用你自己的遥控器按键值替换下面的值 const unsigned long KEY_1 0xE0E020DF; // 替换为你的按键1的十六进制值 const unsigned long KEY_2 0xE0E0A05F; // 替换为你的按键2的十六进制值 const unsigned long KEY_3 0xE0E0609F; // 替换为你的按键3的十六进制值 const unsigned long KEY_4 0xE0E010EF; // 替换为你的按键4的十六进制值 void setup() { // 初始化串口用于调试输出 Serial.begin(9600); Serial.println(红外LED控制器初始化...); // 设置LED引脚为输出模式 pinMode(RED_PIN, OUTPUT); pinMode(YELLOW_PIN, OUTPUT); pinMode(GREEN_PIN, OUTPUT); // 初始状态关闭所有LED allLEDsOff(); // 启动红外接收 irrecv.enableIRIn(); Serial.println(就绪等待遥控指令...); } void loop() { // 检查是否收到红外信号 if (irrecv.decode(results)) { // 打印接收到的值便于调试 Serial.print(收到红外码: 0x); Serial.println(results.value, HEX); // 根据接收到的值执行相应动作 // 注意这里使用 进行比较因为我们只关心特定按键 if (results.value KEY_1) { Serial.println(指令点亮红色LED); controlLED(RED_PIN); } else if (results.value KEY_2) { Serial.println(指令点亮黄色LED); controlLED(YELLOW_PIN); } else if (results.value KEY_3) { Serial.println(指令点亮绿色LED); controlLED(GREEN_PIN); } else if (results.value KEY_4) { Serial.println(指令点亮所有LED); allLEDsOn(); delay(ON_DURATION); allLEDsOff(); } else { // 可以在这里处理其他按键或重复码0xFFFFFFFF // 对于重复码通常我们忽略它避免长按导致动作重复执行 if (results.value ! 0xFFFFFFFF) { Serial.println(未知指令已忽略。); } } // 准备接收下一个信号 irrecv.resume(); } // 这里可以添加其他非阻塞的任务 } // 控制单个LED点亮指定时间的函数 void controlLED(int ledPin) { digitalWrite(ledPin, HIGH); // 点亮LED delay(ON_DURATION); // 保持点亮状态 digitalWrite(ledPin, LOW); // 关闭LED } // 关闭所有LED的函数 void allLEDsOff() { digitalWrite(RED_PIN, LOW); digitalWrite(YELLOW_PIN, LOW); digitalWrite(GREEN_PIN, LOW); } // 点亮所有LED的函数 void allLEDsOn() { digitalWrite(RED_PIN, HIGH); digitalWrite(YELLOW_PIN, HIGH); digitalWrite(GREEN_PIN, HIGH); }代码解析与优化点常量定义将引脚、按键值和延时时间定义为const常量放在程序开头。这样做的优点是提高代码可读性并且未来修改参数比如换引脚、改延时时只需修改一处非常方便。函数封装将allLEDsOff()、allLEDsOn()和controlLED()这些重复操作封装成函数。这使得主循环loop()非常清晰也便于代码复用和维护。重复码处理在else分支中我们特别判断了results.value ! 0xFFFFFFFF。0xFFFFFFFF是大多数协议中的“重复码”表示按键被持续按住。在简单的开关控制中我们通常忽略它以避免长按时LED不停闪烁。如果你需要实现“长按加速”等功能则可以在这里做特殊处理。非阻塞设计思考当前的代码使用delay(ON_DURATION)来保持LED亮起。这会导致在这2秒内Arduino无法响应新的红外指令或其他任务。对于简单的演示没问题但在更复杂的项目中可以考虑使用millis()函数进行非阻塞延时实现多任务处理。5.3 上传测试与功能验证将修改好按键值的代码上传到Arduino。打开串口监视器。用遥控器分别按下1、2、3、4键观察串口监视器是否打印出对应的指令信息。对应的LED是否被点亮2秒后自动熄灭。按下按键4时是否所有LED同时点亮2秒。如果一切正常恭喜你你已经成功将旧遥控器改造为一个三通道无线开关控制器。6. 项目扩展与高级应用思路掌握了基础的红外解码与控制后这个项目的潜力远不止控制几个LED。下面分享几个实用的扩展方向和我个人实践中的一些心得。6.1 控制更复杂的设备继电器与家电控制LED是小试牛刀真正的威力在于控制交流电器。你需要一个继电器模块建议使用带光耦隔离和续流二极管的5V驱动模块更安全。连接与代码调整硬件将继电器的控制引脚IN接Arduino的某个数字引脚如D7VCC和GND分别接5V和GND。继电器的常开触点NO和公共端COM串联到你想控制的电器如台灯的电源线中注意高压危险操作前务必断电。软件代码逻辑和LED控制完全一样。只需将digitalWrite(ledPin, HIGH/LOW)改为控制继电器的引脚即可。例如digitalWrite(RELAY_PIN, HIGH)吸合继电器电器通电LOW则断开。这样你就可以用旧遥控器控制台灯、风扇、加湿器等任何220V电器实现基础的智能开关功能。你可以为不同的按键分配不同的电器或者用“开”、“关”、“模式”等键实现更复杂的逻辑。6.2 实现状态切换Toggle与长按功能前面的例子是“点按触发延时关闭”。更常用的可能是“点按开关”。这需要程序能记住LED的当前状态。实现思路bool redLedState false; // 记录红色LED状态false为关 if (results.value KEY_1) { redLedState !redLedState; // 状态取反 digitalWrite(RED_PIN, redLedState ? HIGH : LOW); Serial.println(redLedState ? 红色LED已打开 : 红色LED已关闭); }对于长按功能可以在解码时判断results.value。如果是重复码0xFFFFFFFF并且距离上次有效按键时间很短则可以执行长按动作如调节亮度、连续增加数值等。6.3 构建红外学习与转发器万能遥控一个更有趣的项目是制作一个“红外学习转发器”。它需要两个核心部件一个红外接收头用于学习和一个红外发射管用于转发。工作流程学习模式按下学习键设备进入学习状态。用原装遥控器对准接收头按下按键Arduino记录下该按键的原始脉冲时序results.rawbuf和results.rawlen并存储到EEPROMArduino的永久存储器中。转发模式按下转发键Arduino从EEPROM中读取脉冲时序驱动红外发射管原样发送出去从而控制目标设备。这相当于自制了一个可学习的万能遥控器。网上有成熟的IRremote库示例代码实现了此功能核心是使用irsend.sendRaw(rawCodes, codeLen, frequency)函数来发送学习到的原始数据。6.4 集成到智能家居平台如果你玩Home Assistant、OpenHAB等开源智能家居平台可以让Arduino通过串口、Wi-Fi如ESP8266或以太网与服务器通信。Arduino作为红外收发节点接收来自智能家居平台的指令转发红外信号控制空调、电视等非智能家电同时它也可以将遥控器按键动作上报给平台作为触发自动化场景的输入。例如你可以设置“晚上10点按下遥控器睡眠键自动关闭客厅灯、空调调至26度、打开卧室空气净化器”这样的场景。7. 常见问题排查与调试技巧实录在折腾红外项目的过程中我踩过不少坑。这里把最常见的问题和解决方法整理出来希望能帮你节省时间。问题现象可能原因排查步骤与解决方案完全无反应串口无输出1. 电源问题2. 接收头接线错误3. 代码未上传成功4. 串口监视器设置错误1. 检查Arduino是否通过USB正常供电板载电源指示灯是否亮起。2.重点检查红外接收头VCC、GND是否接反信号线是否接对引脚用万用表测量接收头VCC与GND之间是否有5V电压。3. 重新编译上传代码观察IDE下方是否有错误提示。4. 确认串口监视器波特率设置为9600并选择了正确的COM端口。串口有输出但results.value始终为0或固定值1. 遥控器没电或损坏2. 接收头型号不匹配或损坏3. 环境光干扰太强4. 遥控器协议不支持1. 用手机摄像头检查遥控器发射管是否闪烁方法见前文。2. 尝试更换一个已知好用的接收头如VS1838。3. 移至室内光线较暗处或遮挡接收头。4. 尝试用Serial.println(results.decode_type)查看协议类型如果是UNKNOWN可能需寻找专用库或解析原始信号。按键一次串口打印多次不同值1. 接收到重复码2. 按键抖动或信号反射1. 这是正常现象。第一个值是有效键值后续的0xFFFFFFFF是重复码。在控制逻辑中应过滤掉重复码如if(results.value ! 0xFFFFFFFF)。2. 确保遥控器与接收头之间没有强反射面短按按键。控制不稳定时灵时不灵1. 距离或角度问题2. 电源噪声3. 程序逻辑有冲突1. 红外是直线传播确保发射头与接收头透镜对准距离建议在5米内无遮挡。2. 如果使用电机等大电流设备可能引起电源波动。尝试给Arduino和接收头单独供电或在VCC与GND间加一个10-100μF的电解电容滤波。3. 检查代码中是否有长时间的delay()阻塞了红外接收。考虑改用非阻塞编程模式。能解码但不能控制设备如LED不亮1. LED/继电器接线错误2. 控制引脚定义错误3. LED或电阻损坏1. 确认LED长脚阳极通过电阻接控制引脚短脚接GND。继电器模块注意控制引脚、高低电平触发方式。2. 检查代码中pinMode和digitalWrite使用的引脚号是否与实际接线一致。3. 用一段导线直接将LED两端接5V和GND串联电阻测试LED本身是否完好。调试进阶技巧使用Serial.print进行“printf调试”在代码关键位置如进入if判断、调用函数前打印信息是追踪程序流程最直接的方法。监听原始信号如果标准协议解码失败可以尝试让IRremote库输出原始脉冲宽度数据。这有助于判断是信号根本没收到还是协议不匹配。if (irrecv.decode(results)) { Serial.print(Raw len: ); Serial.println(results.rawlen); for (int i 1; i results.rawlen; i) { Serial.print(results.rawbuf[i] * USECPERTICK, DEC); Serial.print( ); } Serial.println(); irrecv.resume(); }供电隔离当项目涉及电机、舵机等感性负载时强烈建议使用独立的电源为Arduino逻辑部分和动力部分供电并共地。这能极大提高系统稳定性。红外遥控是一个入门简单、但深度可挖的领域。从让一个旧遥控器重新发光发热开始你可以逐步深入到协议分析、信号模拟、智能联动等更有趣的应用。最重要的是动手去做在调试和解决问题的过程中你对硬件和嵌入式编程的理解会深刻得多。