如何几块钱红外遥控格力空调?| 附代码

21ic电子网 2025-07-01 16:13

来源:公众号【鱼鹰谈单片机】

作者:鱼鹰Osprey

ID   :emOsprey

夏天来了,空调成了必备,如何让空调定时器启动/关闭,或者人回来了自动开启空调?

首先要了解的是红外编、解码。

需要购买两个小模块,一个用于接收,一个用于发送,几块钱搞定。

另外需要一个示波器,或者逻辑分析仪,能看到高低电平即可,不需要很高的带宽。如果都没有,那么自己通过单片机也可自行处理解析高低电平数据。

5 V 供电,3.3 V 也能工作,可能距离短一点。

首先我们要了解自己的遥控器编码,简单一点,直接遥控器(型号 YAP0F3)对准接收器,可以看到接收模块灯亮了,同时逻辑分析仪可以清楚知道电平状态:

第一个数据:

第二个数据:
按下一次按键后全部发送数据展示:

使用 nec 解码器

可以看到,按下按键时,发送了两次数据,每次数据 8 字节。有可能不是标准 nes,因此可以看到后面的 4 字节无法解析。

可以看到,有几个元素:

起始位:

低电平持续时间 : 9000us (即 IO 翻转频率 38KHz,驱动红外发射管,此时接收管表现为低电平状态)

高电平持续时间: 4500us  (不驱动红外发射管,设置 0 或 1 都可)

数据位定义(字节内,低位先发送,低字节先发):

bit:0

低电平持续时间 : 650 us 

高电平持续时间: 650 us 

bit:1

低电平持续时间: 650 us 

高电平持续时间 : 1650 us 

共 4*8 + 3 bit,后面的 3bit 为固定时间 0b010

然后是

连接码 1 bit:

低电平持续时间 : 650 us 

高电平持续时间 : 20000us 

之后跟随 32 bit 数据。

最后一个停止码:

低电平持续时间 : 650 us 

高电平持续时间 : 40000us 

一次数据传输结束。

然后又是一个起始码,重复上一次输出,但是数据有所不同,鱼鹰还没搞清楚为什么要发两次不同的码,有了解的道友可以留言讨论一下。

学习红外,都会看到 38Khz 载波,其实对于工程师来说,你只要知道,使用 PWM 38KHz 驱动红外发射管,接收管会显示低电平即可,剩下的就是如何组织数据和时序了。

下面附关键代码:

typedef enum {    GREE_MODE_AUTO = 0,             // 自动    GREE_MODE_COOL = 1,             // 制冷    GREE_MODE_HUMIDIFICATION = 2,   // 加湿    GREE_MODE_FAN = 3,              // 送风    GREE_MODE_HEAT = 4,             // 加热}GREE_MODE;typedef enum {    GREE_FAN_SPEED_AUTO = 0,    GREE_FAN_SPEED_1 = 1,    GREE_FAN_SPEED_2 = 2,    GREE_FAN_SPEED_3 = 3,}GREE_FAN_SPEED;typedef struct {    union {        uint32_t data;         struct {            GREE_MODE  mode_flag:3// 模式            uint32_t  on_off:1;     // 开关            uint32_t  fan_speed:2;  // 风速            uint32_t  swing_flap:1// 扫风            uint32_t  sleep:1;      // 睡眠            uint32_t  temprature:4// 16°C = 0  30°C = 0111,   =26°C-16°C            uint32_t  timer:8;      // 定时            uint32_t  humidification:1// 加湿            uint32_t  lamplight:1;  // 灯光            uint32_t  anion:1;  // 负离子            uint32_t  save_electricity:1;   // 节电            uint32_t  aeration:1;   // 换气            uint32_t  fix_data:7;   // 固定值? 0001010b ?   40,56 ?        }bits;    }first; // 后面有 3 bit 固定数据和连接码    union {        uint32_t data;         struct {            uint32_t  fan_up_down:1;    // 上下扫风            uint32_t  reserver_1:3;     // 000b            uint32_t  fan_left_right:1// 左右扫风            uint32_t  reserver_2:3;     // 000b            uint32_t  display_temperature:2// 温度显示            uint32_t  reserver_3:16;            uint32_t  energy_conservation:1;   // 节能            uint32_t  reserver_4:1;            //             uint8_t   sum2  :4;  // checksum of the previous bytes (8-14)        }bits;    }second;}nec_gree_data_def;
void nec_carrier(uint32_t bit, uint32_t time_us){    if(bit) {        GPIOC->BSRR = GPIO_PIN_14;        hw_delay_us(time_us);    }    else {        for(int i = 0; i < time_us/13; i++) { // 38 Khz,             if(i &1)  {                GPIOC->BSRR = GPIO_PIN_14;            }            else {                GPIOC->BRR = GPIO_PIN_14;            }            hw_delay_us(13);        }    }}
void send_bit(uint32_t bit) {    nec_carrier(0650);  // 687us    nec_carrier(1, bit? 1620650); // 1619us}
void nec_send(uint32_t data, uint32_t sec_data){    nec_carrier(08800);  // 9.021ms    nec_carrier(14500);  // 5.143ms    for(int i = 0;i < 32; i++)    {        send_bit(data&1);  // low bit fist        data >>= 1;    }    // 后面跟随三位 固定值    send_bit(0);    send_bit(1);    send_bit(0);    // 连接码    nec_carrier(0560);    nec_carrier(120000);
    for(int i = 0; i < 32; i++)    {        send_bit(sec_data&1);        sec_data >>= 1;    }    nec_carrier(0560);}
关机代码(可以自己写优雅一点,方便阅读):
uint8_t tx_data[4] = {0x790x0a000x50};   // 开机,只需这个好像就可以。uint8_t tx_data_2[4] = {0x00x000x000xD0};nec_gree_data_def gree_data;gree_data.first.data = *(uint32_t*)tx_data;gree_data.second.data = *(uint32_t*)tx_data_2;nec_send(gree_data.first.data, gree_data.second.data);// 后面这个不知道有啥用uint8_t tx_data3[4] = {0x790x0a000x70};   // 开机uint8_t tx_data4[4] = {0x00x000x300x00};nec_gree_data_def gree_data2;gree_data2.first.data = *(uint32_t*)tx_data3;gree_data2.second.data = *(uint32_t*)tx_data4;nec_send(gree_data2.first.data, gree_data2.second.data);
开机代码(可以自己写优雅一点):
uint8_t data[4] = {0x71, 0x0a, 000x50}; // 关机uint8_t data_2[4] = {0x0, 0x00, 0x00, 0x50};nec_gree_data_def gree_data3;gree_data3.first.data = *(uint32_t*)data;gree_data3.second.data = *(uint32_t*)data_2;nec_send(*(uint32_t*)data, *(uint32_t*)data_2);hw_delay_us(40000);uint8_t data3[4] = {0x71, 0x0a, 000x70}; // 关机uint8_t data4[4] = {0x0, 0x00, 0x30, 0x80};nec_send(*(uint32_t*)data3, *(uint32_t*)data4);
网上找的校验码,发现和我手上的遥控器不一致,仅供参考:
uint8_t sum2 = ((uint8_t)gree_data.first.bits.mode_flag - 1) + gree_data.first.bits.temprature + 5 +        gree_data.second.bits.fan_left_right + gree_data.first.bits.aeration +         gree_data.second.bits.energy_conservation - gree_data.first.bits.on_off;

上面的数据解析可能有所不同,但大体不差,大家可以根据自己的情况修改。

由于校验值没法得出,因此算是一个小遗憾,不过能控制开关机就不错了。后面有时间可以参考:

https://github.com/crankyoldgit/IRremoteESP8266

另外为简单起见,没有使用 PWM,后续可以优化一下,同时没有学习功能,如果有的话,就可以轻松自动学习了,不用额外的逻辑分析仪了。


END




最后提一句,21ic论坛(bbs.21ic.com)正在招募原创作者,单篇文章奖励最高500元,欢迎广大网友踊跃投稿! 点击了解活动详情

往期精选:

扫描二维码,关注视频号

请点下【♡】给小编加鸡腿



声明:内容取材于网络,仅代表作者观点,如有内容违规问题,请联系处理。 
空调
Copyright © 2025 成都科技区角科技有限公司
蜀ICP备2025143415号-1
  
川公网安备51015602001305号