极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 57058|回复: 19

Arduino红外遥控格力空调的问题

[复制链接]
发表于 2013-5-13 21:29:49 | 显示全部楼层 |阅读模式
本帖最后由 mep 于 2013-5-14 00:14 编辑

Arduino红外遥控空调失败。

我主要参考了这里:
http://blog.sina.com.cn/s/blog_942d7fa20100uyfm.html
的红外编码格式,空调遥控的型号正是YBOF2。

主要代码如下,利用了IRremote库

  1. void GreeAC::sendpresumable()
  2. {
  3.   irsend.mark(9000);
  4.   irsend.space(4500);
  5. }

  6. void GreeAC::send0()
  7. {
  8.   irsend.mark(560);
  9.   irsend.space(565);
  10. }

  11. void GreeAC::send1()
  12. {
  13.   irsend.mark(560);
  14.   irsend.space(1690);
  15. }

  16. //
  17. void GreeAC::sendGree(byte ircode, byte len)
  18. {
  19.   byte mask = 0x01;
  20.   for(int i = 0;i < len;i++)
  21.   {
  22.     if (ircode & mask)
  23.     {
  24.       send1();
  25.     }
  26.     else
  27.     {
  28.       send0();
  29.     }
  30.     mask <<= 1;
  31.   }
  32. }

  33. void GreeAC::test()
  34. {
  35.   irsend.enableIROut(38);
  36.   sendpresumable();
  37.   sendGree(0x49, 8);
  38.   sendGree(0x0A, 8);
  39.   sendGree(0x60, 8);
  40.   sendGree(0x50, 8);
  41.   sendGree(0x02, 3);
  42.   irsend.mark(560);
  43.   irsend.space(20000);
  44.   sendGree(0x01, 8);
  45.   sendGree(0x20, 8);
  46.   sendGree(0x00, 8);
  47.   sendGree(0xF4, 8);
  48.   irsend.mark(560);
  49.   irsend.space(0);
  50. }
复制代码
回复

使用道具 举报

 楼主| 发表于 2013-5-14 00:15:18 | 显示全部楼层
放了一晚上了。。。。没人搞过这个吗?
回复 支持 反对

使用道具 举报

发表于 2013-5-14 08:55:08 | 显示全部楼层
我今年的毕业设计是做一个语音遥控器,主要是控制空调的。要想用红外控制不同品牌的控制,这个工作量是非常大的。因为要知道不同厂家的遥控器代码。最容易实现也是最笨的方法就是破解官方遥控器的代码。见笑了,我也是这样做的。下面我说一下格力品牌空调的红外代码结构:引导码+35位信息码(旧);引导码+35位信息码+延时20ms+32位信息码(新);这个我也是费了很大劲才搞懂新的格力遥控器的编码。注意:新的遥控器为了兼容旧款的遥控器,前面的编码是一样的。只是后面的32位新增加的。格力的编码符合NEC格式的码元时间。
红外一开始发送一段13.5ms的引导码,引导码由9ms的高电平和4.5ms的低电平组成,采用脉宽调制的串行码,以脉宽为0.565ms、间隔0.56ms、周期为1.125ms的组合表示二进制的“0”;以脉宽为0.565ms、间隔1.685ms、周期为2.25ms的组合表示二进制的“1”。
回复 支持 反对

使用道具 举报

发表于 2013-5-14 08:58:13 | 显示全部楼层
楼主的编码果然跟我破解的是一样的,新的格力编码方式
void GreeAC::test()
{
  irsend.enableIROut(38);
  sendpresumable();
  sendGree(0x49, 8);
  sendGree(0x0A, 8);
  sendGree(0x60, 8);
  sendGree(0x50, 8);
  sendGree(0x02, 3);
  irsend.mark(560);
  irsend.space(20000);
  sendGree(0x01, 8);
  sendGree(0x20, 8);
  sendGree(0x00, 8);
  sendGree(0xF4, 8);
  irsend.mark(560);
  irsend.space(0);
}
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-5-14 13:13:16 | 显示全部楼层
pgf017979 发表于 2013-5-14 08:58
楼主的编码果然跟我破解的是一样的,新的格力编码方式
void GreeAC::test()
{

谢谢你的回复,不过我的代码在测试中并不能起作用,请问你能看出问题来吗?
回复 支持 反对

使用道具 举报

发表于 2013-5-14 15:45:30 | 显示全部楼层
把你的整个工程文件上存,有空帮你看看,你只是上存部分程序呀,好像没有问题
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-5-14 20:30:09 | 显示全部楼层
pgf017979 发表于 2013-5-14 15:45
把你的整个工程文件上存,有空帮你看看,你只是上存部分程序呀,好像没有问题

好的,不过程序的其他部分看起来无关紧要。

我的代码共有三个文件,TestIR.ino,Gree.cpp,Gree.h。
板子是Arduino Uno,上面连接了DFRobot IR发射管,数字口3,一个按钮,数字口2

TestIR.ino


  1. #include "IRremote.h"
  2. #include "Gree.h"

  3. IRsend irsend;
  4. GreeAC gree;
  5. volatile boolean flag;

  6. void trig()
  7. {
  8.   flag = true;
  9. }

  10. void setup()
  11. {
  12.   Serial.begin(9600);
  13.   flag = false;
  14.   attachInterrupt(0, trig, FALLING);
  15. }

  16. void loop()
  17. {
  18.   if (flag == true)
  19.   {
  20.     gree.test();
  21.     flag = false;
  22.   }
  23. }
复制代码
Gree.h文件:

  1. #ifndef __Gree_h__
  2. #define __Gree_h__

  3. #include <arduino.h>
  4. #include "IRremote.h"

  5. //#define DEBUG 1

  6. class GreeAC
  7. {
  8.   private:
  9.     void sendpresumable();
  10.     void send0();
  11.     void send1();
  12.     void sendGree(byte ircode, byte len);
  13.   public:
  14.     void setstate(byte mode, byte fan, byte temp, byte power);
  15.     void test();
  16. };

  17. extern IRsend irsend;

  18. #endif
复制代码
还有一个文件Gree.cpp,就是我在第一个帖子里的代码。

红外管发射的时候我用手机摄像模式观察过,有红外光发射。
回复 支持 反对

使用道具 举报

发表于 2013-5-15 09:45:07 | 显示全部楼层
我用Arduino IDE 1.0.3 编译不了你的工程文件
回复 支持 反对

使用道具 举报

发表于 2013-5-15 11:15:43 | 显示全部楼层
用示波器观察才发现是定时器溢出了。延时20毫秒要分开延时2次10毫秒就解决问题。
{
  irsend.enableIROut(38);
  sendpresumable();
  sendGree(0x49, 8);
  sendGree(0x0A, 8);
  sendGree(0x60, 8);
  sendGree(0x50, 8);
  sendGree(0x02, 3);
  irsend.mark(560);
  irsend.space(10000);//定时器溢出,要分开两次延时20ms
  irsend.space(10000);//
  sendGree(0x01, 8);
  sendGree(0x20, 8);
  sendGree(0x00, 8);
  sendGree(0xF4, 8);
  irsend.mark(560);
  irsend.space(0);
}

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

发表于 2013-5-15 11:19:21 | 显示全部楼层
楼主的程序我编译不了,于是自己把它改到[pre lang="arduino" line="1" ]#include "Arduino.h"
#include <IRremote.h>
#include <IRremoteInt.h>
//#include <Gree.h>


IRsend irsend;
volatile boolean flag;

extern IRsend irsend;
//#define DEBUG 1


//    void setstate(byte mode, byte fan, byte temp, byte power);
    void test();
    void sendpresumable();
    void send0();
    void send1();
    void sendGree(byte ircode, byte len);
void sendpresumable()
{
  irsend.mark(9000);
  irsend.space(4500);
}   
void send0()
{
  irsend.mark(560);
  irsend.space(565);
}

void send1()
{
  irsend.mark(560);
  irsend.space(1690);
}

//
void sendGree(byte ircode, byte len)
{
  byte mask = 0x01;
  for(int i = 0;i < len;i++)
  {
    if (ircode & mask)
    {
      send1();
    }
    else
    {
      send0();
    }
    mask <<= 1;
  }
}

void test()
{
  irsend.enableIROut(38);
  sendpresumable();
  sendGree(0x49, 8);
  sendGree(0x0A, 8);
  sendGree(0x60, 8);
  sendGree(0x50, 8);
  sendGree(0x02, 3);
  irsend.mark(560);
  irsend.space(10000);
  irsend.space(10000);
  sendGree(0x01, 8);
  sendGree(0x20, 8);
  sendGree(0x00, 8);
  sendGree(0xF4, 8);
  irsend.mark(560);
  irsend.space(0);
}
void trig()
{
  flag = true;
}

void setup()
{
  Serial.begin(9600);
  flag = false;
  pinMode(2,INPUT_PULLUP);
//  attachInterrupt(0, trig, FALLING);
}

void loop()
{
   int val = digitalRead(2);
  if (val == 0)
  {
    test();
    delay(2000);
//    flag = false;
  }
}
[/code]一个工程里面
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-5-15 11:40:50 | 显示全部楼层
pgf017979 发表于 2013-5-15 11:15
用示波器观察才发现是定时器溢出了。延时20毫秒要分开延时2次10毫秒就解决问题。
{
  irsend.enableIROut ...

过程有理有据,nice work!
我回去试试看,晚上反馈结果。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-5-15 22:04:02 | 显示全部楼层
@pgf017979:很遗憾仍然没有成功,我把20毫秒延时改成了两个10毫秒,
也试过irsend.space(0);delay(20000);
都无效。你用格力空调测试过我的代码吗?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-5-15 23:34:25 | 显示全部楼层
本帖最后由 mep 于 2013-5-16 07:30 编辑

问题解决了。除了@pgf017979指出的溢出问题以外,我的红外编码也是有问题的,
看来网上来的东西还需要自己验证。。。
我自己写了一个程序来获取遥控器的编码。
下面的编码在格力YBOF2遥控器上测试成功。

我测试得到的制冷/开机/26度/全速风的编码如下:
  1.   sendpresumable();
  2.   sendGree(0x39, 8);
  3.   sendGree(0x0A, 8);
  4.   sendGree(0x20, 8);
  5.   sendGree(0x50, 8);
  6.   sendGree(0x02, 3);
  7.   irsend.mark(560);
  8.   irsend.space(10000);
  9.   irsend.space(10000);
  10.   sendGree(0x00, 8);
  11.   sendGree(0x21, 8);
  12.   sendGree(0x00, 8);
  13.   sendGree(0xF0, 8);
  14.   irsend.mark(560);
  15.   irsend.space(0);
复制代码
这是获取红外编码的程序,,注意这种方式必须把红外接收头连接到数字口8,
测量精度0.5微秒
如下:
  1. const int inputCapturePin = 8;
  2. const int prescale = 8;
  3. const byte prescaleBits = B010;
  4. const long precision = (1000000 * prescale/(F_CPU/1000));
  5. //const unsigned int precision = 500;
  6. const int numberOfEntries = 256;

  7. volatile byte index = 0;
  8. volatile unsigned long results[numberOfEntries];
  9. volatile int overflows = 0;
  10. volatile byte stopFlag = false;

  11. void stop()
  12. {
  13.   stopFlag = true;
  14. }

  15. ISR(TIMER1_CAPT_vect)
  16. {
  17.   TCNT1 = 0;
  18.   if( index != 0 || bitRead(TCCR1B, ICES1) == false)
  19.   {
  20.     results[index] = ICR1;
  21.     index++;
  22.   }
  23.   TCCR1B ^= _BV(ICES1);
  24. }

  25. ISR(TIMER1_OVF_vect)
  26. {
  27.   overflows++;
  28. }

  29. void setup()
  30. {
  31.   Serial.begin(9600);
  32.   pinMode(inputCapturePin, INPUT);
  33.   
  34.   TCCR1A = 0;
  35.   TCCR1B = prescaleBits;
  36.   TCCR1B |= _BV(ICES1);
  37.   
  38.   TIMSK1 = _BV(ICIE1);
  39.   TIMSK1 |= _BV(TOIE1);
  40.   TIMSK1 |= _BV(ICIE1);
  41.   //bitSet(TIMSK1, ICIE1);
  42.   attachInterrupt(0, stop, RISING);
  43.   Serial.println(precision);
  44. }

  45. void loop()
  46. {
  47.   if(stopFlag == true)
  48.   {
  49.     stopFlag = false;
  50.     Serial.print("Total pulses: ");
  51.     Serial.println(index);
  52.    
  53.     if (index >= numberOfEntries)
  54.     {
  55.       Serial.println("pulses count overflowed");
  56.     }
  57.     else
  58.     {
  59.       long duration;
  60.       Serial.print(results[0] * precision / 1000);
  61.       Serial.print(" ");
  62.       Serial.println(results[1] * precision / 1000);
  63.       for(int i = 3;i < index;i++)
  64.       {
  65.         duration = results[i] * precision;
  66.         Serial.print(duration / 1000);
  67.         Serial.print(" ");
  68.         if( ((i-2)%16) == 0)
  69.         {
  70.           Serial.println("");
  71.         }
  72.       }
  73.       Serial.println("done");
  74.     }
  75.     delay(10000);
  76.   }
  77. }
复制代码
注意上面代码中的溢出逻辑实际上没有起作用,请自行注意计数器溢出的问题。

获得的结果截取如下:
  1. 648 1667 649 590 612 591 612 1654 654 1658 650 1652 657 590 613 591
  2. 613 591 614 1656 651 591 613 1651 657 590 613 591 613 591 613 591
  3. 613 590 559 671 588 590 614 590 613 591 552 1715 653 592 613 591
  4. 558 647 613 590 614 590 613 559 641 1661 650 591 614 1649 658 590
  5. 614 590 614 1651 656 590
  6. 614 20109
  7. 614 592 613 590 614 589 611 593 614 590 613 590 613 591 610 594
  8. 613 1651 657 590 612 592 612 592 614 590 614 1654 653 591 614 590
  9. 614 590 613 591 612 591 614 590 614 590 613 591 613 590 612 592
  10. 614 590 612 592 613 590 614 590 613 1648 659 1650 656 1653 654 1645
  11. 662
复制代码
翻译得到的二进制如下:
  1. 1001 1100
  2. 0101 0000
  3. 0000 0100
  4. 0000 1010
  5. 010
  6. 0000 0000
  7. 1000 0100
  8. 0000 0000
  9. 0000 1111
复制代码
供需要的人参考,谢谢
回复 支持 反对

使用道具 举报

发表于 2013-7-16 22:37:54 | 显示全部楼层
mep 发表于 2013-5-15 23:34
问题解决了。除了@pgf017979指出的溢出问题以外,我的红外编码也是有问题的,
看来网上来的东西还需要自己 ...

@mep 按照你的方法做了,我家的格力没响应。确定发射管没问题
这个方法使用YB0F吗?

能共享一下最终的代码吗?想 用你的试试看
回复 支持 反对

使用道具 举报

发表于 2013-7-18 00:15:27 | 显示全部楼层
顶顶顶顶顶
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-5-4 06:23 , Processed in 0.046595 second(s), 22 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表