鳕鱼天空

This is Mr Wang's Tech Blog.

人肉分析空调红外遥控器 with Arduino & C#(01)——温度篇

最近迷上了Arduino,简直痴迷,感叹小时候咋就没有那么好玩的东西。

那么,今天的主题是用Arduino控制红外发射器控制带红外的电器(没有红外的以后可以考虑另加,比如通过Nano板子:),今天的小白鼠是家里一个老的AUX壁挂空调,据说海尔的加密云云,改天再研究。

拿出UNO的板子,红外发送和接收的模块,装好库(https://github.com/z3t0/Arduino-IRremote ),翻翻示例,先是找到了IRrecvDumpV2,数据针脚插11,按下遥控器按钮后提示(IR code too long. Edit IRremoteInt.h and increase RAWBUF),问了万能的度娘,说是很多空调编码过长,100个缓存不够用,然调到255并无效果,此法弃疗。

接着问度娘,找到了一片神作,《“高帅富”空调的红外解码和遥控方法”》 http://www.arduino.cn/thread-5775-1-1.html,光看这个名字就厉害的不得了,我就转个代码,具体文章请去原地址拜读

/*
Author: AnalysIR
Revision: 1.0
 
This code is provided to overcome an issue with Arduino IR libraries
It allows you to capture raw timings for signals longer than 255 marks & spaces.
Typical use case is for long Air conditioner signals.
 
You can use the output to plug back into IRremote, to resend the signal.
 
This Software was written by AnalysIR.
 
Usage: Free to use, subject to conditions posted on blog below.
Please credit AnalysIR and provide a link to our website/blog, where possible.
 
Copyright AnalysIR 2014
 
Please refer to the blog posting for conditions associated with use.
[url]http://www.analysir.com/blog/2014/03/19/air-conditioners-problems-recording-long-infrared-remote-control-signals-arduino/[/url]
 
Connections:
IR Receiver      Arduino
V+          ->  +5v
GND          ->  GND
Signal Out   ->  Digital Pin 2
(If using a 3V Arduino, you may connect V+ to +3V)
*/
 
#define LEDPIN 13
//you may increase this value on Arduinos with greater than 2k SRAM
#define maxLen 600
 
volatile  unsigned int irBuffer[maxLen]; //stores timings - volatile because changed by ISR
volatile unsigned int x = 0; //Pointer thru irBuffer - volatile because changed by ISR
 
void setup() {
  Serial.begin(9600); //change BAUD rate as required
  attachInterrupt(0, rxIR_Interrupt_Handler, CHANGE);//set up ISR for receiving IR signal
}
 
void loop() {
  // put your main code here, to run repeatedly:
 
  //Serial.println(F("Press the button on the remote now - once only"));
  delay(5000); // pause 5 secs
  if (x) { //if a signal is captured
    digitalWrite(LEDPIN, HIGH);//visual indicator that signal received
    Serial.println();
    Serial.print(F("Raw: (")); //dump raw header format - for library
    Serial.print((x - 1));
    Serial.print(F(") "));
    detachInterrupt(0);//stop interrupts & capture until finshed here
    for (int i = 1; i < x; i++) { //now dump the times
      //if (!(i & 0x1)) Serial.print(F("-"));
      Serial.print(irBuffer[i] - irBuffer[i - 1]);
      Serial.print(F(","));
    }
    x = 0;
    Serial.println();
    Serial.println();
    digitalWrite(LEDPIN, LOW);//end of visual indicator, for this time
    attachInterrupt(0, rxIR_Interrupt_Handler, CHANGE);//re-enable ISR for receiving IR signal
  }
 
}
 
void rxIR_Interrupt_Handler() {
  if (x > maxLen) return; //ignore if irBuffer is already full
  irBuffer[x++] = micros(); //just continually record the time-stamp of signal transitions
 
}

仔细通篇看完,用此君的代码,读到了211和423,这里遇到了一个坑,其实此君代码会把连按的2次操作合到一起,最后经过多次测试,这只AUX遥控的按键RAW统统是211长度。经过对IRremote库的源代码的涩读(ir_NEC.cpp),发现了这个基本符合NEC代码的开头,先来段读出来的RAW:

9016,4520,540,1684,544,1684,544,560,544,556,544,556,544,560,544,1684,544,1684,544,1684,548,1680,548,1684,544,556,544,556,544,560,544,1684,544,1684,544,560,544,556,544,556,544,560,544,556,544,556,544,560,544,556,544,556,544,560,544,556,544,556,544,560,544,556,544,556,544,556,548,556,544,556,544,560,544,556,544,556,544,1688,544,556,544,1684,544,556,544,560,544,556,544,556,544,560,544,556,544,556,548,556,544,556,544,556,548,556,564,536,544,556,548,556,544,1684,568,532,568,532,568,536,564,540,540,560,560,540,564,540,564,536,564,536,544,556,568,532,548,556,568,532,568,532,568,536,568,532,564,540,564,536,568,532,568,532,568,536,568,532,568,532,568,536,568,532,564,540,568,532,568,532,568,532,572,532,568,532,568,536,568,532,568,1660,568,532,568,1664,564,536,568,532,568,536,564,536,568,532,568,1664,568,1660,568,1660,568,1660,568,536,568,1660,568,1660,568,532,596

看花了吧,然后用IRsendRawDemo竟然可以成功实现功能,但arduino那么小的内存如何装得下所有的代码,就算装下了,这不分析下具体原理和代码生成方式晚上如何睡得着。

于是,摘下眼镜揉一揉接着戴上,要上了!

第一个9000左右和第二个4500左右的值代表了NEC的特征,后面209个的最后一个600左右的是结尾,那么中间剩下208个就好分析了(什么,分析无力,那么多数字看花了,问我什么意思我也不知道,于是乎又去找度娘姐姐研究了下红外的原理:【扫盲贴】浅谈38K红外发射接受编码(非常好) http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=21227800&id=5747884 一遍看不懂多看几遍,还是看不懂就往下看,那个数字代表高电平低电平的时长,但是用38KHz波来实现的,有这个波低电平,没这个波高电平,一低一高的组合可以变成0或1),于是乎又从库的源代码中找到了转换的方法(ir_NEC.cpp)就2个方法,其中一个就是解码:

  // Build the data
  for (int i = 0;  i < NEC_BITS;  i++) {
    // Check data "mark"
    if (!MATCH_MARK(results->rawbuf[offset], NEC_BIT_MARK))  return false ;
    offset++;
    // Suppend this bit
    if  (MATCH_SPACE(results->rawbuf[offset], NEC_ONE_SPACE ))  data = (data << 1) | 1 ;
    else if (MATCH_SPACE(results->rawbuf[offset], NEC_ZERO_SPACE))  data = (data << 1) | 0 ;
    else                return false ;
    offset++;
  }

先来560左右的NEC_BIT_MARK,然后判断是NEC_ONE_SPACE就是1,NEC_ZERO_SPACE就是0,转换如下:

11000011111000110000000000000000000001010000000000000010000000000000000000000000000000001010000011110110

共104bit,换算成16进制就是C3E3000005000200000000A0F6(此时按的32度,除湿,微风,关机)

此时你心中也许会有千万匹神兽飞奔而过,那么多数字眼睛也看花了,老兄,你看看标题好不好,C#写的转换代码啦,你还真以为全人肉解码啊!

同理下面是开机代码:

11000011111000110000000000000000000001010000000000000010000000000000000000000100000000001010000011110001

共104bit C3E3000005000200000400A0F1(32度,除湿,微风,开机)

28度 除湿 风速无,开

11000011111001010000000000000000000001010000000000000010000000000000000000000100000000001010000011110110 
104bit C3E5000005000200000400A0F6

28度 除湿 风速无,关

11000011111001010000000000000000000001010000000000000010000000000000000000000000000000001010000011110010 
104bit C3E5000005000200000000A0F2

27度 除湿 风速无,开

11000011111110010000000000000000000001010000000000000010000000000000000000000100000000001010000011100110 
104bit C3F9000005000200000400A0E6

27度 除湿 风速无,关

11000011111110010000000000000000000001010000000000000010000000000000000000000000000000001010000011100010 
104bit C3F9000005000200000000A0E2

好,下面就找到了变化的部分,C3之后和结尾,结尾估计是校验码,以后再说,C3之后1个字节估计就和温度有关了,经过人肉演算,发现了如下规律:

E3 11100011 32

……

E5 11100101 28

F9 11111001 27

E9 11101001 26

F1 11110001 25

E1 11100001 24

FE 11111110 23

……

E2 11100010 16

什么,你没有找到规律!从第8位倒着往前看5位,还是不明白?我又抄了一遍。。。。。。

11000 32(度)

……

10100 28

10011 27

10010 26

10001 25

10000 24

01111 23

……

01000 16度(8)

基本上就是这样了,温度应该就是这几位了,顺便补充一下,大多数空调遥控器会把所有的状态一起发过去,所以每次一样长,而且带有所有信息,今天就分析到这,下次继续。

下面放一些也许值得参考的文章(次序不分先后):

万用遥控之红外解码分析仪(上位机源码、下位机源码、详细的制作讲解)

【扫盲贴】浅谈38K红外发射接受编码(非常好)

C#+Arduino使用红外遥控器

“高帅富”空调的红外解码和遥控方法【精华】 

Arduino教程(提高篇)——红外遥控(接收篇)

C#实现读取红外线遥控器

Arduino-IRremote库

海尔彩电遥控器型号对照表