去年折腾一个红外网关项目一开始想得很美电视、机顶盒、风扇、投影仪全都一个红外转发器搞定。结果到了空调这一关直接被打脸同一套模块、同一套代码电视随便按两下就换台空调却纹丝不动。一开始我还以为是红外学习模块坏了后来用逻辑分析仪把原装遥控器和学习模块回发的波形同时抓下来对比才发现问题根本不在硬件而在于空调的红外编码机制跟电视完全不是一回事而且不同品牌空调之间编码差异比想象中大得多。这篇文章就把我在这个项目里踩过的坑、总结的编码差异观察以及红外学习模块的调试方法一次性说清楚。适合正在做智能家居红外转发器、空调联动网关或者自己DIY万能遥控器的朋友参考尤其适合那种“万能遥控器学不了空调”“学习模块学完没反应”的情况。1. 从“电视能控、空调失灵”说起空调红外为什么比电视难搞1.1 电视遥控发的是“短命令”空调遥控发的是“状态快照”电视遥控的按键逻辑很简单你按一下音量它发一个单帧命令接收端执行完就完事。典型NEC协议一帧也就4个字节左右总共几十毫秒。这种短报文对红外学习模块非常友好缓冲区小一点也能完整装下。空调遥控器就完全是另一回事了。你按一下“26度制冷”它发出去的不是“温度调低”这种简单指令而是一份“当前全部设定状态”的快照——包含开机/关机状态、模式制冷/制热/除湿/送风、设定温度、风速、上下扫风、左右扫风、定时剩余时间甚至还有健康、节能这类辅助功能字段。这些字段合在一起编码成的脉冲序列往往在100ms以上有些机型还会在按键期间持续重复发送好几秒。所以判断一台红外模块会不会在空调上翻车第一件事就是看它的学习缓冲区能存多久波形。有的模块标称“支持100ms学习”这种学电视很稳学空调大概率学到一半就截断了。我自己用过一款学习模块学格力老定频空调时按一次学习回放出来才发现尾部被砍掉了一截——遥控器上“温度”这种靠辅助字节实现的命令往往正好落在帧尾部于是出现“开关机能控制温度加减没反应”的怪现象。这里顺带纠正一个误区很多人以为“万能遥控器”是把每个按键对应的一小段码存下来其实空调遥控器每次按键发送的都是完整的整表状态所以它更像“把一个表格拍照存起来再原样放回去”。理解成状态快照之后你就能明白为什么自学习模块对于空调类设备如此重要——它不需要理解每个品牌的状态字段怎么编排只需要保证把波形“原样”抄走。1.2 空调接收端的状态机逻辑让“学得一样”也未必有效还有一个让新手崩溃的点即使你学习到的波形和原装遥控器已经高度一致空调也可能不响应。原因在于空调室内机的红外接收逻辑本身带状态机和去抖机制。电视的红外接收逻辑是收到码、校验OK、执行动作。空调的红外接收则复杂一些很多机型要求连续收到2-3帧相同数据才开始处理或者要求帧与帧之间的间隔在一定范围内。这是为了避免用户或者外界红外干扰导致误动作。你如果学习模块只记录了单帧回放时也只发单帧即使单帧内容完全正确空调端也可能认为这是一个无效或者偶发信号直接丢弃。另一个容易被忽略的是断电复位。空调内部有记忆上次状态的存储区如果你调试时空调一直处于某种非目标状态或者之前收到了半截错误码导致状态机挂起后面再怎么发都不理你。我遇到过好几次最后把空调电源断了重开再手动开机设好运行模式遥控码才恢复正常响应。这个在调试章节我还会再提但先说结论空调不响应时不要只盯着波形也要给空调本身一个复位的机会。2. 多品牌编码差异实测美的、格力、海尔的特征拆解2.1 实测样本里的差异对照表我手头能测到的空调不多但代表性的几个品牌基本都碰过。下表的结论只代表我实测的机型样本不同年份、不同系列之间差异非常大仅供参考不要当成“官方协议”。品牌/机型实测载波频率编码风格单帧长度解调后按键期间重复行为美的2018年款某挂机38KHz脉冲宽度调制命令字段多约150ms-250ms持续重复帧间隔约80ms-100ms格力老款定频38KHz自定义时序引导码较长约200ms以上重复发送间隔不固定海尔某变频挂机38KHz近似NEC-like多字节结构约120ms-200ms连续重复三菱电机某型号38KHz自定义长帧约200ms-300ms按住时一直循环这里最直观的感受是载波频率基本都在38KHz附近说明至少在物理层大家还能对得上。但一旦往下看数据层的时序就是各家各派了。很多人以为红外编码就是NEC、SONY、飞利浦RC5那几套标准协议其实空调领域几乎全部是厂商自定义协议。哪怕模块支持5种标准协议解码面对空调一样没用。这也是为什么做空调项目红外学习模块比纯协议库更靠谱的原因。有个很典型的观察细节格力某老款定频的引导码明显比一般NEC引导码长我用逻辑分析仪抓出来引导高电平大约9ms低电平大约10ms以上后面数据位的宽度也和NEC对不上。如果用“NEC解码器”去解解出来的字节是乱的但不影响它实际工作因为空调接收端认的是这套自定义时序。所以在调试时不要先入为主地按某个已知协议去套先原样记录波形再慢慢分析字段语义。2.2 载波频率相同不等于协议相同同是38KHz载波为什么美的的码放到格力上完全无效这就要把“红外编码”拆成两个层次来看。第一层是物理层遥控器把38KHz的载波信号按一定时间片段调制发射或者关闭形成一串“有载波段”和“无载波段”。接收端的一体化红外接收头比如TSOP38238它的作用是把载波包络解调出来输出一串高低电平方波。这一层只关心有没有载波、以及载波频率是否在接收头通带内不关心数据内容。第二层是数据层解调出来的方波高电平和低电平各持续多长时间以及这些持续时间如何映射成二进制位。不同厂商在这儿的约定完全不一样。比如NEC风格逻辑1用560us高加1690us低逻辑0用560us高加560us低部分自家协议用高电平持续1个时间单位还是3个时间单位来区分0和1还有更小众的用脉位调制0和1的位置差异体现在脉冲的偏移位置而不是宽度。所以即使两台空调都用38KHz载波它们在数据层的脉冲宽度和边界定义依然可能完全不同自然无法互通。这就好比两个国家都说同一种电话线路标准物理层一致但一个说中文一个说英文数据层不同互相听不懂。2.3 关于美的空调红外编码规则我观察到的几点网上搜“美的空调红外编码”能找到很多爱好者抓出来的码表我自己主要是拿逻辑分析仪直接抓波形来分析。以我手头那台2018年款美的挂机为例解调后的波形大体上有这么几个特征。一是帧头明显。开头是一段较长的引导脉冲然后跟着若干字节数据每个字节由8个位组成。这和NEC的帧头类似但命令长度远超4个字节。二是数据内容里能明显看到状态字段的变化。比如按温度其他数据基本不变只有某个字节或者某几个位发生固定变化按风速也会出现对应字段变化。把多个按键的波形放到一起逐位对比就能看出哪段是温度、哪段是风速、哪段是模式。三是存在地址或者批次字段。我对比过同品牌不同系列的遥控器波形命令字段之后的某些字节默认值不一样这个大概率是地址识别码。同型号新老批次之间也可能存在地址不一致的情况。所以“美的是否通用”取决于地址段是否匹配不是所有美的空调都能用同一套码。四是校验不是简单的和校验。具体算法我没有完整逆向出来但观察到位翻转比较散不是NEC那种“地址取反”的简单规则。做产品的话不建议用纯码表方式硬编码每个温度值而是应该自学习或者按具体机型抓完整时序存储。说实话我见过的项目里凡是“我直接从网上抄了一份美的码库烧进去发现只有某几台能用”基本都是栽在地址段和校验位上。如果你只是想自用最稳妥的做法是拿着原装遥控器按一次键就完整学习一次不要贪图“一个码库管所有”。3. 红外学习模块的工作机制学到了什么又漏掉了什么3.1 学习链路与存储原理把红外学习模块拆开看其实就是一个“信号波形录音机”。学习过程大致是这样红外遥控器发射信号一体化接收头完成接收和解调输出一个高低电平序列主控MCU通过定时器输入捕获或者轮询采样把每一次电平跳变的时间点记录下来相邻两个时间点之差就是每个电平的持续时长把这些时长按顺序存成一个数组完成学习。发射过程反过来MCU从数组里逐个取出时长值控制一个IO口翻转电平同时与一个载波信号叠加经过三极管或者驱动管放大点亮红外发射管把波形重新发出去。用一个生活化的类比学习模块学到的不是“声音的音色”而是“一段音乐的节奏节拍”。载波频率就是“音色”的一部分很多低端学习模块记录时只记了“什么时候有声音、什么时候停、持续多长”没记录“这个声音是什么调”。学完再播放节奏一模一样但音色变成了模块默认的38KHz。如果原遥控器恰好也是38KHz没问题如果原遥控器是33K或者40K那接收端就认不出来了。存储格式通常是数组比如一组边沿对[{low, 3500us}, {high, 1700us}, ...]或者直接用时间数组[3500, 1700, 450, ...]再配一个标志位表示首电平是低还是高。这个数组的容量直接决定了能学多长的帧。3.2 最容易“走样”的三个环节根据我调试多个模块的经验学习再回放过程中“走样”基本集中在这三个环节。第一个是采样粒度。MCU定时器输入捕获的精度一般能做到微秒级但有些低成本模块用的是普通IO口轮询采样周期可能到100us甚至更粗。空调遥控器数据位动辄几百微秒100us的误差可能让原本560us的脉冲被记成500或者600us累积起来回放时整帧时序已经面目全非。第二个是缓冲区上限。这是所有空调项目的头号杀手。有的模块学习数组上限是64或者128个边沿学一个电视遥控绰绰有余学空调这种几百毫秒、边沿数量动辄几百甚至上千的帧直接装不下。装不下的结果不是报错而是静默截断——模块自认为学完了回放时只发前面半段。这类问题用逻辑分析仪一抓就现形尾部明显少了一截。第三个是载波频率的记录缺失。学习模块如果只存了电平时长没有探测和记录原遥控器的载波频率回放时用默认38KHz去复合。空调接收头对载波频率有一定容忍带宽但偏离超过2-3KHz就可能完全不响应。所以调这种问题不要一开始就怀疑代码逻辑先测一下回放波形的载波频率再说。4. 调试红外学习模块的完整链路与实战手段4.1 工具准备与接线调试红外学习模块用不着一堆高级仪器。我常备的最低配置就三样一个逻辑分析仪、一个一体化红外接收头、一台电脑上的逻辑分析仪软件。有示波器自然更好但没有也完全不耽误事。接线很简单。把一体化接收头的OUT接到逻辑分析仪的某个通道GND共地再把学习模块发射管的控制端或者发射管两端引一根线到另一个通道。这里注意两点一是红外接收头的工作电压常见3.3V或者5V看模块规格别接错二是发射端如果你直接测发射管两端看到的是叠加了38KHz载波的信号测出来波形是一簇一簇的如果只想看数据时序最好先用接收头解调一次或者测MCU控制端的原始方波那样看的是干净的高低电平序列。逻辑分析仪的采样率建议最低4MHz起步。38KHz载波的周期大概是26.3us如果采样率只有几百K载波细节直接糊掉。看解调后的数据波形可以降低采样率但既然要对比还是一路高采样率抓到底比较省事。4.2 第一步抓原装遥控器波形建基准模板我调这类东西的固定习惯是别急着写代码先拿原装遥控器在逻辑分析仪上抓一段波形把它当成“标准答案”。具体操作把红外接收头放在原装遥控器前方按下按键抓取完整信号再松开按键换一个功能键再抓一段。每个关键按键都留一份保存下来。这样后面无论模块怎么改都有一个可靠的参照物。抓完之后在逻辑分析仪软件里量这几个关键参数引导码或者帧头的高电平时长和低电平时长数据段里最短脉冲和最长脉冲分别多少us这决定了采样精度需要多高完整一帧从开始到结束总共多少ms这直接告诉你学习缓冲区至少要多长按键期间连续发送了几帧、帧间隔多少ms这决定了回放时是发一次还是发多次。把这些参数记到一张表格里就是你这个机型的“基准模板”。有了它后续排查任何问题都有一条清晰的裁判线。4.3 第二步抓学习模块回放波形做差分对比学习模块完成学习后让它对着红外接收头发射同样用逻辑分析仪抓下来。然后把这份“回放波形”和刚才的“基准模板”做对比。对比重点就三个地方帧头对不对、每个脉冲宽度差多少、尾部有没有被截断或者多出东西。我拿一个实际案例说明。某次调试模块回放出来的波形和原装遥控器看起来差不多但空调就是不响应。把两段波形拖进分析仪软件里逐段量发现原装遥控器的引导码高电平是3500us低电平是1700us模块回放出来的是3400us和1600us——误差虽然只有100us左右但到了数据段因为模块固件的定时器配置有偏差原本560us的脉冲被稳定地拉成了520us一帧下来累积偏差导致接收端的位判定出错。这种问题靠肉眼根本看不出来必须用工具量。用一张表来对比会非常直观对比项原装遥控器学习模块回放判定引导码高电平3500us3400us偏差-100us引导码低电平1700us1600us偏差-100us数据位最短脉冲560us520us偏差-40us超10%整帧时长220ms205ms尾部疑似截断帧重复次数连续5帧只有1帧空调端可能判无效排查方向立刻就有定时器分频算错了、缓冲区不够、或者发射前没有加帧重复逻辑。4.4 第三步用串口打印时序数组辅助定位逻辑分析仪能看到现象但要定位到代码里哪一行的问题还得靠学习模块自己把存储的时序数组打印出来。很多学习模块固件里已经有这个功能如果没有动手加一个也很快。下面是一个示意性的打印函数void dump_timing(uint16_t *edges, int count, int first_level) { printf(start level: %s\n, first_level ? HIGH : LOW); for (int i 0; i count; i) { printf(%d %s %dus\n, i, (i % 2 0) ? LOW : HIGH, edges[i]); } }打印出来的日志长这样start level: HIGH 0 HIGH 3500us 1 LOW 1700us 2 HIGH 560us 3 LOW 560us 4 HIGH 560us 5 LOW 1690us ...这里有一条实用经验打印的时候不要只打印“相对跳变”一定要把每个电平的绝对时长和极性一起打出来。我曾经接过一份只打时长的日志没法判断极性也没法和逻辑分析仪波形对上号白白折腾了半天。拿到日志后把它和基准模板的时间数组逐项比。如果发现整体时间都比基准值小多半是定时器时钟算错了如果只是尾部少了一串那就是缓冲区溢出或者停止条件提前触发如果某些电平时长忽大忽小那要考虑是不是学习时环境光引入了杂波。提示串口打印的时序数组是调试的中间产物不要删。拿到新机型时先保存一份基准后面做对比会省很多事。4.5 第四步测载波频率排除物理层不匹配如果时序数组和基准模板完全一致但空调还是不响应就轮到载波频率登场了。测量方法很简单在逻辑分析仪抓到的一段载波脉冲里量几个连续脉冲的周期取平均值。比如周期是26.3us那载波频率就是1/26.3us约等于38KHz如果是30.3us那就是约33KHz如果是25us那就是40KHz。不同空调原装遥控器的载波频率确实存在差异。我实测过的样本里大多数是38KHz但也遇到过个别机型原装遥控器不是标准38K尤其是日系老空调和一些代工遥控器。如果原装遥控器用的是40KHz而学习模块回放时固定用38KHz即使时序完全正确接收头也可能因为频率偏离通带中心太远而收不到。解决办法是在固件里做载波频率检测学习阶段采样原装遥控器的载波周期把频率值也存进码库发射阶段用这个频率去配置PWM。如果模块不允许动态设置频率那就至少准备几个常见频率版本33K、36K、38K、40K逐个试。5. 五个高频坑与对应排查路线5.1 学习头距离和光照导致的杂波误码典型现象是学完后回放空调偶尔有反应偶尔又完全不理。你查代码和波形都可能正常但就是不稳定。这个问题的根子往往在学习过程。一体化接收头有自动增益控制如果学习时离遥控器太近信号过强导致接收头饱和输出波形边沿会出现抖动如果离得太远信号太弱中间又容易丢段。另外强光里含红外分量会直接干扰接收头输出。排查路线先用逻辑分析仪抓一段学习时接收头的实际输出看波形上有没有不规则的毛刺。有毛刺的话一是调整学习距离到3-5cm二是给接收头做遮光处理用黑热缩管或者黑色胶带遮住除正面以外的部分三是换一个没有强光直射的环境再学习。这一步很多人忽略但十个不稳定案例里至少有四个是这个原因。5.2 发射驱动电流不足距离一远就失控现象很典型模块贴着空调能控制拉开一米不到就失灵。这种基本不是编码问题而是发射功率不够。红外发射管要在几十毫安到几百毫安的脉冲电流下才能保持足够的辐射强度。很多DIY模块图省事直接用MCU的IO口串联一个限流电阻去驱动发射管IO口输出能力有限实测电流可能只有10-20mA照射距离自然不行。排查链路第一步用万用表串进发射管回路测峰值电流目标至少100mA脉冲状态平均电流不大不用怕管子发烫第二步看供电电压红外发射管正向压降约1.2-1.5V限流电阻的压降也要留余量第三步如果电流不够加NPN三极管或者MOS管做开关驱动或者直接用专用红外发射驱动电路第四步还可以两个发射管并联提升发光强度同时配合聚光透镜。注意加了驱动管之后波形相位会反转一次所以要确认最终发射端的包络和原始数据电平一致别又给调反了。5.3 解调波形极性理解反了一体化接收头输出的是反相逻辑。常规理解是“收到载波时为低电平没有载波时为高电平”因为接收头内部输出级通常是一个反相器。如果用示波器或者逻辑分析仪看引导码的“有载波段”在接收头输出端是低电平而不是高电平。很多学习模块的固件在记录或者在发射时会把极性处理错导致回放波形和理论波形正好高低对调。如果只是把极性反了发射出去的信号在接收端是完全认不出来的——因为对于红外接收头来说载波包络的位置才是信息极性反了等于把“有信号”和“没信号”互换。排查方法很直接把学习模块记录数组的第一个元素打印出来看它记录的引导段是HIGH还是LOW再对比逻辑分析仪抓到的接收头解调输出。如果模块把有载波段记录成了HIGH而实际解调输出是LOW那就要在代码里做一次取反。这类问题代码层面一改就行难的是意识到问题在这。5.4 空调不响应不一定是编码问题先说我犯过的错花了两天在波形和代码里找问题最后发现空调要么没通电要么通电后处于某种内部状态机卡死的情况。空调接收逻辑带有状态记忆如果之前收到过半截码或者异常码可能一直不理会后续信号。排查链路建议按这个顺序先把空调断电重开让它复位再用原装遥控器确认空调能正常响应确保空调本身没问题然后手动把空调设置到一个确定可识别的状态比如制冷模式、26度最后再用学习模块回放测试。判断模块有没有真正发出红外信号除了逻辑分析仪还有一个土办法用手机摄像头对着发射管按下发射键摄像头画面里应该能看到一团紫白色的光闪烁。这个方法用来快速确认“发没发”非常方便但不能判断“发得对不对”。5.5 学习缓冲区容量不够长帧被截断空调遥控器的帧长和边沿数量远比电视遥控器大。我之前统计过手头几台空调单帧边沿数量普遍在400个以上有些复杂机型的多功能帧甚至上千个。如果学习模块的边沿数组只有256或者更小学空调必然截断。截断后的表现很迷惑一部分功能正常一部分功能不行。因为数据字段是按顺序排列的截断的位置决定了丢了哪部分功能。比如温度字段靠后就会出现“开关机能控、温度死活调不了”的现象。排查路线回放波形对比基准模板的尾部如果尾部消失就是缓冲区不足或者看固件日志里的边沿计数和基准模板的边沿数对比。解决办法有三个一是换支持更大缓冲区的模块二是把数组从256扩到1024甚至2048注意MCU内存够不够三是对超长帧做分段存储再拼接回放但拼接技术对时序要求高实际项目里我不推荐直接用大缓冲区更省心。做多品牌空调红外项目这么久我个人的习惯总结起来就一句话先抓波形再写代码。别管网上的码库多全、协议文档多详细到了自己手头这一台机器只有逻辑分析仪抓出来的波形才是唯一可信的基准。调试红外学习模块时也建议先把“能不能完整学习、原样回放”这条基本功练扎实再谈协议解析和码库优化。缓冲区按1K组边沿对设计载波频率检测做成可选功能采样精度至少保证单脉冲误差在5%以内做到这三点市面上绝大多数空调长帧都能稳稳拿下。希望这篇对正在和空调红外编码较劲的朋友有帮助尤其是那些“学了但没反应”的案子别急着怀疑模块先按上面的排查链路走一遍。