Arduino红外遥控格力空调的问题
本帖最后由 mep 于 2013-5-14 00:14 编辑Arduino红外遥控空调失败。
我主要参考了这里:
http://blog.sina.com.cn/s/blog_942d7fa20100uyfm.html
的红外编码格式,空调遥控的型号正是YBOF2。
主要代码如下,利用了IRremote库
void GreeAC::sendpresumable()
{
irsend.mark(9000);
irsend.space(4500);
}
void GreeAC::send0()
{
irsend.mark(560);
irsend.space(565);
}
void GreeAC::send1()
{
irsend.mark(560);
irsend.space(1690);
}
//
void GreeAC::sendGree(byte ircode, byte len)
{
byte mask = 0x01;
for(int i = 0;i < len;i++)
{
if (ircode & mask)
{
send1();
}
else
{
send0();
}
mask <<= 1;
}
}
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);
}
放了一晚上了。。。。没人搞过这个吗? 我今年的毕业设计是做一个语音遥控器,主要是控制空调的。要想用红外控制不同品牌的控制,这个工作量是非常大的。因为要知道不同厂家的遥控器代码。最容易实现也是最笨的方法就是破解官方遥控器的代码。见笑了,我也是这样做的。下面我说一下格力品牌空调的红外代码结构:引导码+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”。 楼主的编码果然跟我破解的是一样的,新的格力编码方式
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);
} pgf017979 发表于 2013-5-14 08:58 static/image/common/back.gif
楼主的编码果然跟我破解的是一样的,新的格力编码方式
void GreeAC::test()
{
谢谢你的回复,不过我的代码在测试中并不能起作用,请问你能看出问题来吗? 把你的整个工程文件上存,有空帮你看看,你只是上存部分程序呀,好像没有问题
pgf017979 发表于 2013-5-14 15:45 static/image/common/back.gif
把你的整个工程文件上存,有空帮你看看,你只是上存部分程序呀,好像没有问题
好的,不过程序的其他部分看起来无关紧要。
我的代码共有三个文件,TestIR.ino,Gree.cpp,Gree.h。
板子是Arduino Uno,上面连接了DFRobot IR发射管,数字口3,一个按钮,数字口2
TestIR.ino
#include "IRremote.h"
#include "Gree.h"
IRsend irsend;
GreeAC gree;
volatile boolean flag;
void trig()
{
flag = true;
}
void setup()
{
Serial.begin(9600);
flag = false;
attachInterrupt(0, trig, FALLING);
}
void loop()
{
if (flag == true)
{
gree.test();
flag = false;
}
}
Gree.h文件:
#ifndef __Gree_h__
#define __Gree_h__
#include <arduino.h>
#include "IRremote.h"
//#define DEBUG 1
class GreeAC
{
private:
void sendpresumable();
void send0();
void send1();
void sendGree(byte ircode, byte len);
public:
void setstate(byte mode, byte fan, byte temp, byte power);
void test();
};
extern IRsend irsend;
#endif
还有一个文件Gree.cpp,就是我在第一个帖子里的代码。
红外管发射的时候我用手机摄像模式观察过,有红外光发射。
我用Arduino IDE 1.0.3 编译不了你的工程文件 用示波器观察才发现是定时器溢出了。延时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);
} 楼主的程序我编译不了,于是自己把它改到#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;
}
}
一个工程里面 pgf017979 发表于 2013-5-15 11:15 static/image/common/back.gif
用示波器观察才发现是定时器溢出了。延时20毫秒要分开延时2次10毫秒就解决问题。
{
irsend.enableIROut ...
过程有理有据,nice work!
我回去试试看,晚上反馈结果。 @pgf017979:很遗憾仍然没有成功,我把20毫秒延时改成了两个10毫秒,
也试过irsend.space(0);delay(20000);
都无效。你用格力空调测试过我的代码吗? 本帖最后由 mep 于 2013-5-16 07:30 编辑
问题解决了。除了@pgf017979指出的溢出问题以外,我的红外编码也是有问题的,
看来网上来的东西还需要自己验证。。。
我自己写了一个程序来获取遥控器的编码。
下面的编码在格力YBOF2遥控器上测试成功。
我测试得到的制冷/开机/26度/全速风的编码如下:sendpresumable();
sendGree(0x39, 8);
sendGree(0x0A, 8);
sendGree(0x20, 8);
sendGree(0x50, 8);
sendGree(0x02, 3);
irsend.mark(560);
irsend.space(10000);
irsend.space(10000);
sendGree(0x00, 8);
sendGree(0x21, 8);
sendGree(0x00, 8);
sendGree(0xF0, 8);
irsend.mark(560);
irsend.space(0);这是获取红外编码的程序,,注意这种方式必须把红外接收头连接到数字口8,
测量精度0.5微秒
如下:const int inputCapturePin = 8;
const int prescale = 8;
const byte prescaleBits = B010;
const long precision = (1000000 * prescale/(F_CPU/1000));
//const unsigned int precision = 500;
const int numberOfEntries = 256;
volatile byte index = 0;
volatile unsigned long results;
volatile int overflows = 0;
volatile byte stopFlag = false;
void stop()
{
stopFlag = true;
}
ISR(TIMER1_CAPT_vect)
{
TCNT1 = 0;
if( index != 0 || bitRead(TCCR1B, ICES1) == false)
{
results = ICR1;
index++;
}
TCCR1B ^= _BV(ICES1);
}
ISR(TIMER1_OVF_vect)
{
overflows++;
}
void setup()
{
Serial.begin(9600);
pinMode(inputCapturePin, INPUT);
TCCR1A = 0;
TCCR1B = prescaleBits;
TCCR1B |= _BV(ICES1);
TIMSK1 = _BV(ICIE1);
TIMSK1 |= _BV(TOIE1);
TIMSK1 |= _BV(ICIE1);
//bitSet(TIMSK1, ICIE1);
attachInterrupt(0, stop, RISING);
Serial.println(precision);
}
void loop()
{
if(stopFlag == true)
{
stopFlag = false;
Serial.print("Total pulses: ");
Serial.println(index);
if (index >= numberOfEntries)
{
Serial.println("pulses count overflowed");
}
else
{
long duration;
Serial.print(results * precision / 1000);
Serial.print(" ");
Serial.println(results * precision / 1000);
for(int i = 3;i < index;i++)
{
duration = results * precision;
Serial.print(duration / 1000);
Serial.print(" ");
if( ((i-2)%16) == 0)
{
Serial.println("");
}
}
Serial.println("done");
}
delay(10000);
}
}注意上面代码中的溢出逻辑实际上没有起作用,请自行注意计数器溢出的问题。
获得的结果截取如下:648 1667 649 590 612 591 612 1654 654 1658 650 1652 657 590 613 591
613 591 614 1656 651 591 613 1651 657 590 613 591 613 591 613 591
613 590 559 671 588 590 614 590 613 591 552 1715 653 592 613 591
558 647 613 590 614 590 613 559 641 1661 650 591 614 1649 658 590
614 590 614 1651 656 590
614 20109
614 592 613 590 614 589 611 593 614 590 613 590 613 591 610 594
613 1651 657 590 612 592 612 592 614 590 614 1654 653 591 614 590
614 590 613 591 612 591 614 590 614 590 613 591 613 590 612 592
614 590 612 592 613 590 614 590 613 1648 659 1650 656 1653 654 1645
662翻译得到的二进制如下:1001 1100
0101 0000
0000 0100
0000 1010
010
0000 0000
1000 0100
0000 0000
0000 1111供需要的人参考,谢谢 mep 发表于 2013-5-15 23:34 static/image/common/back.gif
问题解决了。除了@pgf017979指出的溢出问题以外,我的红外编码也是有问题的,
看来网上来的东西还需要自己 ...
@mep 按照你的方法做了,我家的格力没响应。确定发射管没问题
这个方法使用YB0F吗?
能共享一下最终的代码吗?想 用你的试试看 :lol:lol:lol顶顶顶顶顶
页:
[1]
2