红外遥控信号解码与回放:空调码型采集及通用控制方案

📅 发布时间:2026/9/19 18:48:02
红外遥控信号解码与回放:空调码型采集及通用控制方案
1. 红外遥控信号解码技术整体设计思路拆解1.1 为什么选择红外遥控作为空调控制的切入点空调遥控器本质上是一个单向的红外编码发射器它把按键信息调制成一串特定时序的脉冲通过940nm左右的近红外光发射出去。空调室内机收到这串脉冲后按约定协议解析出温度、模式、风速、扫风等状态再驱动压缩机、风机执行动作。整个链路里没有握手、没有应答、没有加密这意味着只要我们能完整复现那串脉冲就能让空调执行任意合法指令。我最初接触这个方向是因为家里三台空调品牌各不相同遥控器经常找不到手机红外发射器又只能覆盖少数几个品牌。市面上的万能遥控码库要么收费要么码型不全尤其是老款机型和一些冷门品牌根本查不到。与其到处找码不如自己把原遥控器的码型采下来存成自己的码库想怎么回放就怎么回放。这个思路一旦跑通不仅能控制空调还能扩展到红外遥控电机控制、红外遥控报警器这类场景——本质上都是“采码—存码—发码”三件事。适合读这篇内容的人我大致分三类一是做智能家居DIY的爱好者手里有开发板想接红外收发二是嵌入式方向的学生或工程师需要理解红外编解码的时序细节三是做红外遥控电机控制、红外遥控报警器这类小产品的开发者需要一套可复用的码型采集与回放方案。不管你是哪一类只要跟着把采集和回放两条链路走通后面换任何红外设备都只是换码型数据的事。1.2 采集与回放两条链路的整体架构整套方案我拆成两条独立但对称的链路。采集链路负责“听懂”遥控器在说什么回放链路负责“模仿”遥控器说话。两条链路共用同一套码型存储格式这样采完就能直接回放中间不需要人工转换。采集链路的硬件部分是一个红外接收头常见的是VS1838B、HS0038这类一体化接收解调模块它内部已经把38kHz载波解调掉了输出的是干净的基带脉冲序列。接收头输出接到单片机的GPIO或者外部中断引脚用定时器记录每个电平跳变的时刻得到一串“高电平持续时间低电平持续时间”的数组。这个数组就是原始码型也叫时序码。回放链路的硬件部分是一个红外发射管通常配一个三极管做驱动因为单片机IO口的驱动电流一般只有十几毫安直接推红外管亮度不够发射距离会很短。发射时用定时器产生38kHz的PWM载波再用码型数组去调制这个载波的开启和关闭就能还原出和原遥控器几乎一致的脉冲串。这里有个关键设计取舍采集时记录的是“解调后的基带时序”回放时再“重新调制到38kHz载波上”。为什么不直接采原始带载波的信号因为原始信号频率高、数据量大普通单片机采样会非常吃力而且不同遥控器的载波频率可能有偏差37.9kHz、38kHz、40kHz都有解调后再调制反而更灵活回放时还能微调载波频率去适配不同接收灵敏度的空调。1.3 码型存储格式的设计考量码型存成什么格式直接决定了后面回放方不方便、能不能压缩、能不能跨平台迁移。我试过三种格式最后定下来的是一种折中方案。第一种是纯文本的“微秒对”格式每行一个“高电平微秒数,低电平微秒数”可读性最好调试时一眼就能看出时序对不对但文件体积大一个完整空调码型动辄几百行。第二种是二进制紧凑格式把微秒数按比例缩放到一个字节或两个字节体积小但可读性差调试时得写解析工具。第三种是我现在用的“头部数据段”格式头部用文本记录品牌、型号、载波频率、数据长度、校验和数据段用二进制存缩放后的时序值。这样既能快速识别码型归属又兼顾了体积。缩放比例我一般取1也就是直接存原始微秒数用uint16存最大能表示65535微秒足够覆盖空调码型里最长的电平一般不超过20毫秒。如果遇到超长的引导码就单独用uint32存那一段。提示码型文件一定要带校验和我踩过一次坑SD卡写入时掉电导致文件尾部损坏回放时空调收到半截码型直接死机得断电重启。加了CRC16校验后回放前先验一遍损坏的码型直接拒绝发送安全很多。2. 红外接收与发射硬件选型及电路细节2.1 红外接收头的选型与外围电路接收头我前后用过五六种最后长期留在板子上的是VS1838B。它便宜、好买、灵敏度够用中心频率38kHz接收角度约90度室内几米范围内对准就能稳定收到。HS0038性能更好一些抗干扰强但价格贵一点做产品可以考虑自己做着玩VS1838B完全够。外围电路非常简单但有两个细节必须注意。第一接收头输出是开集电极结构必须接上拉电阻一般取10k到100k之间我习惯用47k兼顾功耗和上升沿速度。第二电源引脚旁边一定要并一个0.1uF的陶瓷电容再并一个10uF的电解电容因为接收头内部有自动增益控制电源纹波会直接影响接收灵敏度我最早没加电容遥控器离半米就收不到了加上之后三米内都很稳。接收头的输出引脚接单片机的外部中断配置成双边沿触发这样高电平变低、低电平变高都能进中断在中断里读定时器计数值和上一次的值相减就得到一个电平的持续时间。这里定时器的分辨率很关键我一般用1微秒计数因为红外码型里最短的电平可能只有几百微秒1微秒分辨率足够精确又不会让计数值溢出太快。2.2 红外发射管的驱动电路与发射距离优化发射部分最容易出问题。红外发射管正向压降约1.2V额定电流一般20mA到100mA峰值电流可以到1A以上。单片机IO口输出高电平一般3.3V或5V直接串个限流电阻接发射管电流只有几毫安发射距离短得可怜我实测只有十几厘米。正确的做法是用NPN三极管做开关驱动比如S8050或者2N3904。单片机IO口通过一个1k电阻接三极管基极发射管串一个限流电阻接在集电极和电源之间三极管发射极接地。这样IO口只需要提供不到1mA的基极电流就能让三极管饱和导通发射管上流过几十到上百毫安的电流。限流电阻我一般取10欧到22欧配合5V电源峰值电流约150mA到300mA发射距离能到五米以上。如果想进一步增加距离可以用两个发射管串联或并联。串联时限流电阻要重新算两个管子压降约2.4V5V电源下电阻取(5-2.4-0.3)/0.15≈15欧。并联时每个管子单独串限流电阻避免电流分配不均。我试过三个管子并联覆盖角度更大但总电流也上去了电池供电的话要权衡。注意发射管和接收头不能同时工作否则自己发的光会被自己收到造成误触发。回放时要么把接收头暂时关闭要么在软件里加一个“发射期间忽略接收”的标志位。我最早没做这个处理回放时接收中断疯狂触发把码型缓冲区冲得乱七八糟。2.3 载波频率的生成与微调38kHz载波用定时器PWM生成最方便。以STM32为例定时器时钟72MHz预分频取0自动重装载值取72M/38k/2≈947占空比设50%就能得到38kHz方波。不同单片机算法一样核心就是让PWM频率落在37kHz到39kHz之间因为接收头的带通特性有一定宽容度偏差太大会导致灵敏度下降。但有些空调的接收窗口比较窄载波频率偏一点就收不到。我遇到过一台老空调38kHz回放没反应把PWM调到37.5kHz就正常了。所以码型文件里我专门留了一个“载波频率”字段采集时虽然接收头已经把载波解调掉了测不到原始频率但回放时可以手动试几个值找到最灵敏的那个记下来。一般37.5kHz、38kHz、38.5kHz、40kHz这四个值覆盖绝大多数设备。3. 空调码型采集的完整实操流程3.1 采集前的环境准备与干扰排查采集环境比想象中重要。我第一次采码是在客厅旁边开着日光灯采出来的码型乱七八糟后来才发现是日光灯的红外成分干扰了接收头。正确的做法是找一个没有强光源直射接收头的角落关掉可能发出红外光的设备比如某些白炽灯、加热器、部分摄像头的红外补光灯。遥控器电池要保证电量充足电压不足时发射功率下降码型边沿会变缓采出来的时序可能偏差。我一般用新电池或者稳压电源供电。遥控器和接收头的距离控制在10厘米到30厘米之间太近可能饱和太远信号弱都会导致误码。采集前还要确认接收头输出空闲时是高电平。如果空闲时就是低电平说明接收头坏了或者接线错了得先排查硬件。我习惯在采集程序里加一个“空闲检测”上电后先读一秒接收头状态如果一直是低电平就报错避免后面白忙活。3.2 原始时序数据的抓取与预处理抓取逻辑不复杂但细节决定成败。我用外部中断加定时器的方式中断里记录当前定时器计数值和上一次的值相减得到电平持续时间存进一个数组。数组长度要留够空调码型一般有100到300个电平跳变我留512个uint16的空间足够覆盖绝大多数机型。抓取完成后要做预处理主要是三件事。第一去掉尾部多余的空闲电平因为遥控器发完码后会保持空闲高电平这段不计入有效码型。第二把持续时间按阈值分类红外码型里电平宽度通常分几档比如引导码的9ms高电平、4.5ms低电平数据位的0.56ms高电平、0.56ms或1.69ms低电平。分类后可以压缩存储也方便后面做码型比对。第三计算校验和存进码型头部。预处理里最容易出错的是阈值设定。不同品牌的空调码型时间基准不一样有的用0.56ms做单位有的用0.6ms有的用0.42ms。我一般先统计所有电平持续时间的分布找出几个明显的聚类中心再按聚类中心之间的中点设阈值。这样自适应出来的阈值比固定值靠谱得多。3.3 多品牌空调码型的分类与存储策略采了十几台空调之后我发现码型可以按结构分成几类。一类是“固定长度帧”每次按键发同样长度的码状态信息编码在数据位里比如格力、美的的部分机型。另一类是“变长帧”不同按键发的码长度不同比如某些日系品牌。还有一类是“重复帧”一次按键连续发好几遍同样的码接收端只要收到一遍就执行比如一些老款空调。存储时我按“品牌/型号/按键”三级目录组织每个码型文件独立存放。文件名里带上采集日期和载波频率方便回溯。比如gree_kfr35_26cool_38k_20240512.ir一看就知道是格力KFR-35机型、26度制冷、38kHz载波、2024年5月12日采集的。对于重复帧我只存一遍有效码型在头部里标记“重复次数”回放时按次数循环发送。这样既节省空间又保留了原始行为特征。有些空调对重复次数敏感发少了不响应发多了可能触发保护所以这个字段不能省。4. 码型回放与空调响应验证4.1 回放程序的时序精度控制回放的核心是“按码型数组精确控制载波的开和关”。我用定时器中断实现载波PWM一直在跑用一个GPIO引脚控制载波的输出使能。码型数组里每个元素包含“电平状态”和“持续时间”中断里根据当前元素设置使能引脚再装载下一个定时值。时序精度直接决定回放成功率。我实测下来持续时间误差超过5%就可能失败超过10%基本没反应。所以定时器中断的优先级要设高中断服务程序要尽量短只做“改引脚状态、重装定时值”两件事其他逻辑放到主循环里。如果单片机主频低中断响应有延迟可以在每个持续时间里减去一个固定的补偿值这个值通过实测校准一般几微秒到十几微秒。还有一个坑是中断嵌套。如果回放中断被其他中断打断时序就会乱。我一般把回放中断设成最高优先级其他中断在回放期间暂时关闭或者至少保证回放中断能抢占。用RTOS的话回放任务要设成最高优先级并且关掉任务调度器的抢占用临界区保护。4.2 不同品牌空调的响应差异与适配同样一份码型发给不同空调响应可能完全不同。我总结了几种典型情况。第一种是“完全匹配”码型发过去空调立刻响应温度和模式都正确。这种最省心说明采集和回放都没问题。第二种是“部分匹配”空调有响应但状态不对比如设26度实际变成25度。这通常是数据位的编码理解有偏差或者某个电平的持续时间在采集时被干扰了。解决办法是重新采集多采几遍取最稳定的那份或者手动修正可疑的电平值。第三种是“无响应”空调完全没动静。可能原因有三个载波频率不对、码型不完整、发射功率不够。我一般先换载波频率试再检查码型长度是否和原遥控器一致最后加大发射电流或换更高亮度的发射管。第四种是“误触发”空调响应了但执行的是别的指令。这通常是码型里混入了其他按键的片段或者重复次数不对。重新采集并核对码型内容一般能解决。4.3 回放成功率的量化评估方法光靠“有没有反应”判断太粗糙我设计了一个简单的量化评估方法。对同一个码型连续回放20次记录成功次数成功率低于90%就要排查。排查时把20次分成4组每组5次看失败是否集中在某组如果是可能是环境干扰随时间变化如果随机分布可能是时序精度不够或硬件不稳定。我还用逻辑分析仪抓回放时的红外发射管驱动波形和原遥控器的波形对比。重点看三个指标引导码宽度误差、数据位宽度误差、帧间隔误差。三个误差都在3%以内基本就能稳定回放。逻辑分析仪不贵几百块的入门款就够用比反复试错效率高得多。5. 常见问题排查与避坑经验实录5.1 采集端典型问题速查现象可能原因排查方法解决办法完全收不到码接收头接线错误或损坏测输出引脚空闲电平检查接线更换接收头码型长度异常短中断丢失或定时器溢出用逻辑分析仪看原始波形提高中断优先级增大定时器位宽码型长度异常长环境红外干扰关灯后重新采集排除干扰源加软件滤波同一按键多次采集码型不一致遥控器电池不足测电池电压更换电池或稳压供电码型中间出现超短电平接收头输出抖动统计电平分布加去抖滤波忽略小于100us的电平这张表是我踩坑踩出来的每一条都对应至少一次失败经历。特别是最后一条接收头在信号边沿偶尔会输出一个几十微秒的毛刺如果不滤掉回放时就会多出一个无效脉冲导致空调解析失败。我的做法是在预处理阶段把小于100微秒的电平合并到相邻电平里效果很好。5.2 回放端典型问题速查现象可能原因排查方法解决办法空调无任何反应载波频率偏差大换37.5k/38k/38.5k/40k试找到最灵敏的频率记入码型响应但状态错误码型数据位错误对比原遥控器波形重新采集或手动修正偶尔响应偶尔不响应发射功率不足测发射管电流减小限流电阻或增加发射管响应后空调死机码型不完整或校验失败检查码型文件CRC重新采集回放前验CRC多个空调互相干扰码型相似或重复次数过多隔离测试每台空调分房间测试调整重复次数回放端最隐蔽的问题是“码型不完整”。有些空调码型末尾有一个很长的低电平如果采集时提前停止回放时缺少这个收尾电平空调可能解析到一半就卡住。我的经验是采集时多等一会儿确保收到至少500毫秒的空闲高电平再停止这样码型一定是完整的。5.3 跨品牌兼容的独家避坑技巧跨品牌兼容最大的坑是“想当然”。我一开始以为所有空调都用NEC协议结果采了才发现空调码型比NEC复杂得多每家都有自己的变种。有的用脉冲位置调制有的用脉冲宽度调制有的两者混用。所以千万不要拿电视遥控器的解码库去套空调会死得很惨。第二个坑是“忽略载波占空比”。接收头解调时对占空比不敏感但空调接收端可能敏感。我遇到过一台空调38kHz方波占空比50%没反应改成33%就正常了。所以回放时占空比也可以作为一个可调参数一般33%到50%之间试。第三个坑是“重复发送间隔”。有些空调要求两次发送之间至少间隔100毫秒否则会认为是干扰。我最早连续发三遍间隔只有20毫秒空调直接无视。后来改成间隔120毫秒成功率立刻上去了。这个间隔值因品牌而异我一般从100毫秒起步不行就加到200毫秒。第四个坑是“电源噪声”。发射瞬间电流突增如果电源滤波不好单片机可能复位。我在电源端并了一个470uF的电解电容问题就解决了。电池供电的话尽量用碱性电池不要用充电电池因为充电电池电压低发射时压降更明显。6. 从空调码型到通用红外控制场景的扩展6.1 红外遥控电机控制的码型适配红外遥控电机控制和空调码型在底层是同一套逻辑区别在于电机控制通常只需要“正转、反转、停止”几个简单指令码型短、重复次数少。我把空调采集回放的框架直接搬过来只改了码型存储格式把“温度、模式、风速”字段换成“方向、速度、使能”半天就跑通了。电机控制对实时性要求比空调高因为电机启停有惯性指令延迟太大会导致位置偏差。所以回放时我把重复次数降到1次帧间隔缩到50毫秒牺牲一点抗干扰能力换响应速度。实测下来只要发射管对准电机接收头响应延迟可以控制在100毫秒以内满足大多数场景。6.2 红外遥控报警器的码型设计思路红外遥控报警器和空调相反它是“接收端”角色需要识别特定码型并触发报警。我用同一套接收头采集环境中的红外信号但码型比对逻辑不一样空调是“精确匹配”报警器是“特征匹配”。只要收到的码型里包含预设的特征序列就触发报警不需要完全一致。这样做的好处是抗干扰能力强环境里偶尔飘过的红外噪声不会误报只有符合特征模式的信号才触发。特征序列我一般取码型的引导码加前几个数据位长度约10到20个电平既保证特异性又留出容错空间。实测下来误报率可以压到每天一次以下比简单的电平触发靠谱得多。6.3 码型库的长期维护与版本管理码型库用久了会越来越乱我吃过亏之后定了一套简单的版本管理规则。每个码型文件头部记录“采集设备、采集人、采集日期、载波频率、校验和”文件名用“品牌_型号_功能_频率_日期”格式。每次修改码型不覆盖原文件而是新建一个带版本号的文件比如_v2、_v3原文件保留备查。定期做一次全库校验把所有码型的CRC重算一遍损坏的标记出来重新采集。我一般每季度做一次花不了多少时间但能避免关键时刻码型失效。另外码型库最好用Git管理每次采集和修改都提交一次这样任何一次改动都能回溯比手动备份靠谱得多。提示码型库不要只存一份我习惯在电脑、移动硬盘、云端各放一份。红外码型虽然不大但采集一次不容易丢了重新采很费时间。尤其是那些已经停产的老空调遥控器坏了就再也采不到了码型就是绝版资源。7. 实操心得与后续扩展方向整套方案跑下来我最深的体会是“时序精度决定一切”。采集时定时器分辨率不够、中断优先级不高回放时载波频率不准、帧间隔不对任何一个环节差一点最终结果就是空调不响应。所以如果你打算动手做先把定时器和中断调好用逻辑分析仪把波形看明白再往下走能省掉大量试错时间。另一个心得是“码型要采多遍”。同一按键至少采三遍取最一致的那份或者取三份的交集。单次采集受环境影响太大多采几遍能过滤掉大部分随机误差。我现在的流程是采五遍用软件自动比对选出最稳定的那份存入库。后续扩展方向我列了几个正在做的。一是把码型库做成手机App可调用的格式通过蓝牙或WiFi模块发送这样不用带开发板也能控制空调。二是加入学习模式让设备自动识别新遥控器的码型并入库省去手动采集的麻烦。三是把红外遥控电机控制和报警器的码型也整合进同一个库做成一个通用的红外控制平台。这些方向都不难核心还是今天讲的采集和回放两条链路把这两条链路吃透后面都是水到渠成的事。