当前位置: 首页 > news >正文

从波形到指令:深度拆解格力空调红外协议

1. 从一串“嘀嘀”声开始:红外协议逆向工程到底在玩什么?

大家好,我是老张,一个在智能硬件和嵌入式领域摸爬滚打了十多年的老玩家。今天我们不聊那些高大上的AI模型,来点接地气的“硬核”手艺——拆解你家格力空调遥控器发出的那串红外信号。你可能觉得这玩意儿有啥好研究的,按一下遥控器,空调“嘀”一声就工作了。但如果你是一个物联网开发者,或者是一个喜欢折腾智能家居的硬件爱好者,这串看不见的红外光,就是你让旧空调变“智能”的钥匙。

想象一下这个场景:你手头有一台逻辑分析仪,或者一个简单的红外接收头加单片机,你抓取到了遥控器按下“制冷25度”时发出的原始波形。屏幕上显示的是一连串高低起伏的方波,就像心电图一样。你的任务,就是像破译密码一样,弄明白这串“嘀嘀嗒嗒”背后到底说了什么。最终目标,是写出一份协议文档,让一块ESP32开发板或者一个单片机,也能模仿遥控器,精准地控制空调。这个过程,我们称之为“红外协议逆向工程”。今天,我就以格力空调为例,带大家走一遍从原始波形到可编程指令的完整拆解之路,内容会比网上常见的解析更深入、更实操,我会把踩过的坑和验证过的方法都分享出来。

2. 红外通信的“摩斯电码”:基础原理扫盲

在动手拆解格力协议之前,我们得先统一语言,理解红外通信最基本的工作原理。这就像学外语先学字母一样。

2.1 载波:信号的“搬运工”

红外通信不是直接用高低电平来表示0和1的。如果直接发射,环境中的普通红外光源(比如太阳、白炽灯)就会产生巨大干扰。所以,工程师们想了个办法:调制。他们选用了一个频率固定(通常是38kHz)的方波作为载波。这个载波本身不携带信息,它的作用就像一辆卡车。

真正的数据(0和1),是通过控制这辆“卡车”是否发出红外光来传递的。具体来说,发射管会以38kHz的频率疯狂闪烁(即发出载波),但我们会控制它闪烁的“时间段”。在需要发送信号的时间段内,载波开启,红外接收头收到这个特定频率的闪烁,就会输出低电平;在不需要发送信号的时间段内,载波关闭,接收头收不到38kHz的信号,就输出高电平。所以,我们最终在逻辑分析仪上看到的波形,其实是接收头输出的、已经解调掉38kHz载波之后的数据电平信号。记住,我们后续分析的所有高低电平时序,都是指这个数据电平。

2.2 编码:0和1的“长相”

去掉了38kHz的载波“背景音”,数据本身的0和1如何区分呢?这就靠脉冲宽度编码。最常见的编码方式是NEC协议用的那种,但格力空调用的是一种自定义的格式。不过万变不离其宗,核心思想就是:用“低电平+高电平”的组合来代表一个比特位,而0和1的区别,在于高电平部分的持续时间不同

举个例子,格力空调的协议里(这是我实测多款格力遥控器总结的):

  • 比特‘0’:可能是646微秒的低电平,紧接着516微秒的高电平。
  • 比特‘1’:同样是646微秒的低电平,但后面跟着的是1643微秒的高电平。

你看,低电平时间是一样的,起跑线相同,但高电平“坚持”的时间长短不一,这就区分了0和1。这个时间参数非常关键,不同品牌、甚至同品牌不同型号都可能不同,所以必须用自己的逻辑分析仪抓取确认,网上查到的只能作为参考。

3. 捕获与测量:用逻辑分析仪看清波形真面目

理论说再多,不如动手抓一包数据看看。这里假设你已经有了逻辑分析仪(Saleae Logic系列、DSView配廉价山寨探头都行),并且接到了红外接收头的信号输出脚。

3.1 连接与抓取步骤

首先,把红外接收头的VCC和GND接好,信号线(OUT)接到逻辑分析仪的一个通道上。打开遥控器,对准接收头,按下某个键(比如“开关”)。在逻辑分析仪软件里,设置一个合适的采样率(比如1MHz就足够),然后触发抓取。你会在屏幕上看到一串密集的脉冲。这里有个关键技巧:一次按键发射的,往往不止一帧数据。格力遥控器通常会连续发送相同的两到三帧数据,以确保接收的可靠性。所以,我们要在波形里找到那一段重复的、完整的信号段作为分析对象。

3.2 关键时序的测量与确认

抓取到稳定波形后,我们需要用测量工具,精确读出几个关键时间参数。这是我反复实测后,为某款主流格力空调总结的典型值,强烈建议你以自己的测量为准

信号单元低电平时间 (us)高电平时间 (us)说明
起始码90004500一帧数据的开始,非常长的低电平,很好识别
连接码64620000分隔两段数据的桥梁,高电平超长
结束码646(很长)帧结束,高电平持续到下次发送
数据 ‘0’646516高电平较短
数据 ‘1’6461643高电平较长,约是‘0’的3倍

怎么测量呢?在软件里,框选从一个下降沿开始到下一个下降沿之前的那个高电平脉冲。测量其高电平的持续时间。多测量几个‘0’和‘1’,看看是否稳定。这里容易踩坑:环境光干扰、接收头质量、探头接触都可能让波形边沿有点“毛刺”,导致测量值有几十微秒的波动。只要波动在合理范围(比如±50us)内,取个平均值或众数即可,不必追求绝对精确。

4. 拆解数据帧结构:格力协议的“语法规则”

现在我们知道了字母(0和1)怎么写,接下来要看它们怎么组成单词和句子,也就是帧结构。格力空调的一帧完整红外数据,结构很有特点,它分为两段:

[起始码] + [第一段数据(35位)] + [连接码] + [第二段数据(32位)] + [结束码]

是的,你没看错,第一段是35位,不是常见的8的倍数。这增加了点解析难度。整个帧看起来会很长,因为起始码和连接码的时长非常夸张,在波形上显得格外突出,这反而成了我们定位的“路标”。

4.1 起始、连接与结束:帧的标点符号

  • 起始码:一个长达9000us的低电平加上4500us的高电平。这个组合在数据流中独一无二,是帧开始的绝对标志。在解析程序里,我们首先就要在连续的电平信号中搜索这个特殊的模式,来找到一帧的头部。
  • 连接码:位于两段数据之间,646us低电平后跟一个长达20ms的高电平。这个20ms的空白,在波形上是一段漫长的“平坦”区域,清晰地将前后数据分开。
  • 结束码:第二段数据后的646us低电平,之后高电平会一直持续。实际上,在程序处理时,我们更关注数据位的结束,这个结束码更多是一个自然的停止。

理解这些“标点”后,我们就可以用程序逻辑来分割数据了:找到起始码 -> 读取后续的35个比特 -> 跳过连接码 -> 再读取32个比特 -> 一帧结束。

4.2 数据0与1的解析算法

在代码里,我们如何将连续的波形翻译成0和1的二进制串呢?下面是一个简单的算法思路,你可以用C、Python或Arduino IDE来实现:

  1. 持续监测输入引脚的电平。
  2. 检测到一个下降沿(从高到低)时,开始计时低电平持续时间。如果这个低电平时间在646us左右(例如600-700us范围内),则认定它是一个有效比特的开始。
  3. 低电平结束后,进入高电平,计时高电平持续时间。
  4. 根据高电平的时长判断比特值:
    • 如果高电平时间在400-600us左右,判定为比特‘0’
    • 如果高电平时间在1500-1800us左右,判定为比特‘1’
    • 如果时间不符合,则可能是误码或帧头/连接码,需要特殊处理。
  5. 将这个比特存入缓冲区,继续等待下一个下降沿。

注意:实际编写时,要考虑定时器的精度和中断处理。对于发送端,逻辑相反:要严格按照时序,控制红外发射管输出对应的低高电平组合。

5. 数据位深度解析:每个比特管什么?

这是逆向工程最核心、也最有趣的部分——给每个比特位赋予意义。我们以“制冷25℃,低风速,开机”这个常用状态为例,把抓取到的二进制数据摊开来,对照遥控器功能一个个试。

5.1 第一段数据(35位)功能映射

经过大量测试和交叉验证,我梳理出第一段数据中关键比特位的功能。请注意,不同型号可能存在差异,以下映射常见于许多格力型号,但务必以你实测为准。

  • Bit 3 (第4位):电源开关

    • 0: 关闭空调
    • 1: 打开空调
    • 这个位非常稳定,是必改的位。
  • Bit 4 & Bit 5:风速控制

    • 00: 自动风(Auto)
    • 10: 一级风(低风)
    • 01: 二级风(中风)
    • 11: 三级风(高风)
    • 注意这里的二进制顺序,有时需要反转一下才能直观理解,实际测试时发送10看看是不是低风。
  • Bit 6:扫风开关(水平扫风)

    • 0: 扫风关闭
    • 1: 扫风开启
    • 这个位需要和第二段数据的Bit 0联动,两者通常保持一致。
  • Bit 8, 9, 10, 11:温度设置

    • 这4个比特以某种编码表示设定温度。常见的映射关系如下(以16-28度为例):
      • 0000: 16℃
      • 1000: 17℃
      • 0100: 18℃
      • 1100: 19℃
      • 0010: 20℃
      • 1010: 21℃
      • 0110: 22℃
      • 1110: 23℃
      • 0001: 24℃
      • 1001: 25℃ (我们的例子)
      • 0101: 26℃
      • 1101: 27℃
      • 0011: 28℃
    • 看起来有点乱,但其实有一定规律,可以理解为“温度值-16”的某种二进制变形。直接查表是最稳妥的。
  • Bit 15:定时开关

    • 0: 定时功能关闭
    • 1: 定时功能开启
    • 这个位开启后,后面的定时时间位才有效。
  • Bit 16-19:定时小时数

    • 当定时开启时,这几位表示定时的小时部分。例如1000可能代表1小时,0100代表2小时,等等。需要结合定时分钟数一起解析。

5.2 第二段数据(32位)与校验码

第二段数据的前面部分可能包含模式(制冷、制热、除湿等)等信息,但不同型号差异极大。有一个位是相对统一的:

  • Bit 0:扫风开关(再次出现)
    • 通常与第一段的Bit 6值相同。修改扫风状态时,需要同时改变这两个位。

最最重要的是第二段数据的最后4位(Bit 28-31),这是校验码。校验码是协议为了防止传输错误或验证数据合法性而设置的。网上流传很多格力校验码公式,比如“和校验”或“取反”,但我实测发现并不通用。

我通过大量数据反推,找到一个在我测试的几款格力空调上有效的经验公式:校验码 = (设定温度 - 18) + 定时小时数 + (开关状态 × 8)其中,开关状态:开机为1,关机为0。

以“开机、25℃、不定时”为例:校验码 = (25-18) + 0 + (1*8) = 7 + 8 = 15。15的十六进制是0xF,二进制是1111。你去看抓到的数据帧最后4位,很可能就是1111

重要提醒:这个公式是我自己试出来的,可能不适用于所有格力机型。最可靠的方法是,你固定其他所有参数,只改变温度,观察校验码的变化规律,自己归纳出公式。校验码是协议逆向的最后一道关卡,必须攻克。

6. 从协议到代码:构建你的红外指令库

当我们完整掌握了波形时序、帧结构和数据位映射后,就可以动手创建一份可编程的协议字典了。这份字典本质上就是一个函数,输入是“开关、温度、风速”等参数,输出是一个符合格力红外协议的、代表高低电平时序的数组。

6.1 构建数据帧函数

以Arduino平台为例,我们可以这样设计一个发送函数:

// 定义时序常量(单位:微秒) #define START_LOW 9000 #define START_HIGH 4500 #define CONNECT_LOW 646 #define CONNECT_HIGH 20000 #define BIT_ZERO_LOW 646 #define BIT_ZERO_HIGH 516 #define BIT_ONE_LOW 646 #define BIT_ONE_HIGH 1643 void sendGreeIR(bool power, int temp, int fanSpeed, bool swing) { // 1. 创建缓冲区,存放最终的脉冲时序(低、高、低、高...) unsigned int rawData[67 * 2]; // 估算大小,实际需计算 int index = 0; // 2. 添加起始码 rawData[index++] = START_LOW; rawData[index++] = START_HIGH; // 3. 根据参数,计算第一段35位数据 unsigned long segment1 = 0; // 设置Bit3: 电源 if(power) segment1 |= (1UL << 3); // 设置Bit4-5: 风速,假设fanSpeed: 0=Auto,1=Low,2=Mid,3=High segment1 |= ((fanSpeed & 0x03) << 4); // 设置Bit6: 扫风 if(swing) segment1 |= (1UL << 6); // 设置Bit8-11: 温度 (需要查表或计算) unsigned char tempCode = getTempCode(temp); // 自定义函数,根据温度返回4位编码 segment1 |= ((tempCode & 0x0F) << 8); // ... 设置其他位(模式、定时等,假设为默认值) // 4. 将segment1的35位,按位转换为时序,填入rawData for(int i=34; i>=0; i--) { // 从高位开始发送 rawData[index++] = BIT_ZERO_LOW; // 低电平时间固定 if((segment1 >> i) & 0x01) { rawData[index++] = BIT_ONE_HIGH; } else { rawData[index++] = BIT_ZERO_HIGH; } } // 5. 添加连接码 rawData[index++] = CONNECT_LOW; rawData[index++] = CONNECT_HIGH; // 6. 计算第二段32位数据,包含校验码 unsigned long segment2 = 0; // 设置Bit0: 扫风(与第一段一致) if(swing) segment2 |= (1UL << 0); // ... 设置其他位 // 计算校验码 unsigned char checksum = (temp - 18) + 0 + (power ? 8 : 0); // 简化公式 segment2 |= ((checksum & 0x0F) << 28); // 7. 将segment2的32位,按位转换为时序,填入rawData for(int i=31; i>=0; i--) { rawData[index++] = BIT_ZERO_LOW; if((segment2 >> i) & 0x01) { rawData[index++] = BIT_ONE_HIGH; } else { rawData[index++] = BIT_ZERO_HIGH; } } // 8. 添加结束码(低电平部分) rawData[index++] = BIT_ZERO_LOW; // 结束码低电平 // 高电平部分在发送函数中处理为一段延时 // 9. 调用底层红外发射函数,发送rawData数组 irSender.sendRaw(rawData, index, 38); // 38代表38kHz载波频率 }

6.2 调试与验证:让空调听你的话

代码写好了,怎么验证?最好的方法就是搭建一个简单的发射电路。用一个NPN三极管(如8050)驱动一个红外发射二极管,单片机引脚通过一个100欧姆左右的电阻连接到三极管基极,发射管串联一个限流电阻(比如100欧姆)接在VCC和集电极之间。

上传代码后,用手机摄像头(大部分手机摄像头能看到红外光)对着发射管,按下测试按钮。你应该能看到发射管发出微弱的紫光(这是红外光被摄像头转换后看到的)。然后,拿着这个自制发射器对准空调,尝试发送开机、调温指令。

调试过程中常见的坑:

  1. 空调没反应:首先检查硬件连接和电源。然后用逻辑分析仪抓一下你发射的波形,和原装遥控器的波形对比,看时序对不对。最常见的问题是时序单位弄错(微秒当成毫秒),或者载波频率不对。
  2. 空调反应错乱:比如开机变成关机。这大概率是数据位映射错了。回去仔细核对是哪个功能位出了问题,可以尝试只修改一个位(比如只改温度),发送后观察空调反应,进行“二分法”排查。
  3. 校验码错误:空调可能完全不理睬,或者执行一次后不再响应。这说明你的校验码计算错误。老老实实多抓几组不同状态下的原装信号,用排除法推导校验算法。

这个过程需要耐心,但当你亲手让ESP32成功控制空调的那一刻,成就感是非常足的。这份你自己逆向出来的协议文档和代码,就是最宝贵的资产。以后无论遇到什么型号的格力空调,你都有了快速上手分析的能力。红外协议逆向就像一门手艺,掌握基本方法后,剩下的就是经验和细心。希望这篇超详细的拆解能帮你打开这扇门。

http://www.jsqmd.com/news/452624/

相关文章:

  • 西门子S7-200SMART模拟量模块接线全攻略:从选型到实战避坑
  • 决策树算法实战:用Python从零开始构建鸢尾花分类器(附完整代码)
  • Frida安卓调试踩坑实录:解决‘invalid address‘报错的3种实战方案
  • 5个付费内容解锁功能:高效实用的价值定位指南
  • HTC VIVE新手必看:从开箱到畅玩VR的完整设置指南(附常见问题解决)
  • Ultimate SD Upscale实战指南:AI图像高清放大效率提升全攻略
  • 如何解决幻兽帕鲁存档迁移难题:palworld-host-save-fix工具跨平台解决方案指南
  • SAR型ADC入门指南:从原理到实际应用(附常见问题解答)
  • 大规模数据下的xyflow流畅渲染:性能优化实战指南
  • 3步实现专业级音频降噪:Audacity AI智能处理全指南
  • SRWE:突破分辨率枷锁的终极窗口定制方案
  • MQTT协议在QT中的实现:阿里云物联网平台数据上传避坑指南
  • 5步构建高效学术工作流:Zotero Connectors插件深度应用指南
  • 解密OpenDroneMap:从航拍影像到三维模型的技术解析与实战之路
  • 三维重建开源工具:OpenDroneMap的技术突破与行业实践
  • 兆威机电下周上市:发行价71.28港元 募资净额18亿港元 高瓴是基石
  • 禅道 vs JIRA vs Tapd:三大项目管理工具在bug管理中的深度对比(含禅道7.0专属技巧)
  • 2024年最值得关注的AI业务流程增强技术趋势
  • 5个步骤掌握Windows APK安装工具:从零基础到高效部署
  • 空间转录组技术:从单细胞到组织微环境的基因表达解析
  • 5个星露谷物语增强工具让农场主实现经营效率跃升
  • 如何用Zotero Format Metadata解决文献格式混乱:给学术研究者的效率提升指南
  • 突破游戏本性能枷锁:OmenSuperHub开源工具如何实现散热效率85%提升?
  • DCT-Net模型监控:性能指标与日志分析
  • 电荷泵(Charge Pump)工作原理详解:5种常见升压电路对比与选型指南
  • 电子课本高效获取:突破平台限制的tchMaterial-parser技术解析
  • 从零手撸C#泛型集合:比List<T>更轻量的实现方案
  • Youtu-Parsing作品集:法律合同中‘甲方/乙方’条款抽取+手写签名区域高亮标注
  • ChatGPT Atlas浏览器实战:构建高效智能浏览器的技术解析与避坑指南
  • 突破分辨率枷锁:SRWE如何让窗口自定义不再受限