Catching air conditioner IR codes

I’m trying to catch IR codes of popular air conditioner remote controls, like LG Art Cool or Mitsubishi Electric.
I don’t know which frequency modulation they use, and I suppose they are long codes, not like television set codes.
I used a 33kHz or 36kHz Vishay IR receiver connected with a 220ohm resistor and a 100nF polyester ceramic capacitor (don’t know if it’s ok) and a IR photodiode (790 to 1050nm) with a 10k ohm resistor.
Data input connected to PIN 7.
I took a code I found on the forum for detecting Sony IR codes, and modified it to display the pulseIn readings (both high and low), catch 128 bits and convert them to 8-bit integers.
This is the code (I know it’s dirty)

/**
 * Receives signal from IR remote control on pin 2 and displays the function to the serial monitor.
 * Writes state of control to EEPROM for recall when power is turned off.
 * Reads state of control from EEPROM when power is turned on.
 */

#include <EEPROM.h>

//CONSTANTS
#define btnPower   149
#define btnMute    148
#define btnDown    147
#define btnUp      146
#define rate       4
#define start_bit  2000                //Start bit threshold (Microseconds)
#define bin_1      1100                //Binary 1 threshold (Microseconds)
#define bin_0      300                //Binary 0 threshold (Microseconds)
#define ir_pin     7                //Sensor pin 1 wired through a 220 ohm resistor
#define led_pin    13                //"Ready to Recieve" flag, not needed but nice
#define debug      1                 //Serial connection must be started to debug

//VARIABLES
int power  = EEPROM.read(0);  
int mute   = EEPROM.read(1);  
int volume = EEPROM.read(2);
int i      = 0;                    //general purpose counter
int j      = 0;
int data[128];

void setup() {
  pinMode(led_pin, OUTPUT);          //This shows when we're ready to recieve
  pinMode(ir_pin, INPUT);
  digitalWrite(led_pin, LOW);          //not ready yet
  Serial.begin(9600);
  if(volume == 255) volume = 0;    //Don't start up at full volume
}

void loop() {
  //Fetch the key  
  int key = getIRKey();
  
  //Switch to print insructions to Serial Monitor
   switch (key) {    
    case btnPower:
      if(power == 0){
        power = 1;
        Serial.println("Turn On");
      } else {
        power = 0;
        Serial.println("Turn Off");
      }
      EEPROM.write(0, power);
      delay (500); //Debounce switch
      break;
      
    case btnMute:    
      if(mute == 0){
        mute = 1;
        Serial.println("Mute On");
      } else {
        mute = 0;
        Serial.println("Mute Off");
      }
      EEPROM.write(1, mute);
      delay (500); //Debounce switch
      break;
      
    case btnDown:
      if(volume > 0 && volume - rate > 0) {
        volume -= rate;
      } else {
        volume = 0;
      }
      Serial.print("Volume: ");
      Serial.println(volume);
      EEPROM.write(2, volume);
      break;  
      
    case btnUp:
      if(volume < 255 && volume + rate <= 255) {
        volume += rate;
      } else {
        volume = 255;
      }
      Serial.print("Volume: ");
      Serial.println(volume);
      EEPROM.write(2, volume);
      break;
  }

}


int getIRKey() {
  
  digitalWrite(led_pin, HIGH);         //Ok, i'm ready to recieve  
  
  while(pulseIn(ir_pin, LOW) < 2200) {
    //Wait for a start bit
  }
  
  for(i=0;i<127;i+= 2){
    data[i] = pulseIn(ir_pin, LOW);   //Start measuring bits, I only want low pulses
    data[i+1]= pulseIn(ir_pin, HIGH);
  }
  
  digitalWrite(led_pin, LOW);

  if(debug == 1) {
    Serial.println("-----");
  }
  
  for(int i=0;i<127;i++) {          //Parse them
    
    if (debug == 1) {
      Serial.print(data[i]);
      Serial.print(" ");
    }
    
    if(data[i] > bin_1) {          //is it a 1?
      data[i] = 1;
    } else {
      if(data[i] > bin_0) {        //is it a 0?
        data[i] = 0;
      } else {
        data[i] = 2;              //Flag the data as invalid; I don't know what it is!
      }
    }
    
  }
  
  //for(i=0;i<127;i++) {
  //  Serial.print(data[i]);
  //}  
  for(i=0;i<127;i++) {              //Pre-check data for errors
      if(data[i] > 1) {
      return -1;                //Return -1 on invalid data
    }
  }
  int dataint[15];
  Serial.print("--> ");
  for(int j=0;j<127;j+=8) {
    dataint[j]=BtoI(j,8);
    Serial.print(dataint[j]);
    Serial.print(" ");
  }  
    
} 

unsigned int BtoI(int start, int numofbits){    //binary array to integer conversion
  unsigned int integer=0;
  unsigned int mask=1;
  for (i = numofbits+start-1; i >= start; i--) {
    if (data[i]) integer |= mask;
    mask = mask << 1;
  }
  return integer;
}

It seems I’m able to capture reliably Mitsubishi codes, but not LG codes. It catches command only sometimes (which i think it has a shorter start bit), and when it catches, it displays strange PulseIn readings with unusually big or negative numbers like these:

1st reading (36kHz IR detector)
634 1541 585 476 585 475 585 476 585 1552 585 476 585 475 585 467 594 467 593 467 593 467 594 467 593 1545 585 1553 585 475 586 476 585 476 585 1553 585 1544 594 1544 593 467 594 1541 594 467 584 476 586 476 585 1552 586 1552 585 1553 585 -5840 8452 4109 612 1551 585 476 584 476 585 476 585 1544 594 467 593 444 617 467 594 467 593 467 585 476 585 476 585 1553 585 1553 585 92 199 88 656 475 586 1544 593 467 593 467 593 467 593 467 593 1545 584 476 582 475 585 1553 585 476 585 476 585 476 585 -15554 8447 4109 621 1540 593 92 191

3rd reading (33kHz IR detector)
568 1579 547 512 547 512 552 507 552 1587 552 508 552 504 556 504 556 504 555 504 556 504 560 504 556 504 555 1579 552 507 552 512 547 1587 552 512 547 1579 561 499 560 504 556 1579 560 499 561 504 555 504 544 512 547 1592 547 512 547 -16263 8423 4173 547 1587 552 504 556 504 555 504 555 1584 556 504 555 504 556 504 552 1587 549 1587 547 512 552 507 552 512 547 505 555 504 555 504 561 504 555 504 555 504 555 504 552 507 552 1587 552 508 551 1587 552 507 552 513 547 504 555 1584 555 -4502 8423 4168 552 1587 547 512 552 507 552

From what I saw through a digital camera, the Mitsubishi burst is much longer than LG. I would say 0.5" against 0.2".
If I use the photodiode, I can see the modulation is 2 microseconds low and 12 microseconds high.

QUESTIONS:

  • How can I filter the modulation from the photodiode reading?
  • Why the IR codes I found use an analog pin like 2, and it doesn’t work to me?
  • Does the pulseIn function works only on digital pins?
  • I tried to increase the reading to 256 bits but it locks up… does it eat up all the RAM? How can I capture longer readings?

These are Mitsubishi codes fully converted:
80 16 81 5 20 16 64 0 0 0 0 16 0 16 84 1 (ON, 23 degrees)
80 16 81 5 20 16 64 0 0 0 0 16 0 16 20 1 (ON, 24 degrees)
80 16 81 5 20 16 64 0 0 0 0 0 0 16 1 1 (OFF)
It doesn’t miss a code with Mitsubishi, but it seems it’s longer than 16 bytes because the codes changes only with on/off, temperature and mode. Other parameters probably are out of the first 16 bytes.

Hi, I haven't had time to look closely at your code but:-

polyester ceramic capacitor

It's either polyester or ceramic you can't have both, but as it is only decoupling it shouldn't matter although ceramic is the better one.

I can see the modulation is 2 microseconds low and 12 microseconds high.

That is a modulation frequency of about 71.5KHz if this is true then it is probably too high for that receiver.

Does the pulseIn function works only on digital pins

Yes The negative numbers from pulse in are probably due to it recording a very large count and it overflowing the integer variable. The function of pulsIn() has changed in Arduino 13 to fix a "problem" of only starting to time at the beginning of a new pulse not part way through. What version of the environment are you using?

Why the IR codes I found use an analog pin like 2, and it doesn't work to me

Not sure I understand this, is "IR codes" refering to programms you have found?

How can I filter the modulation from the photodiode reading

You can remove the modulation with a simple RC filter with a time constant of half the size of the pulses you want to see through. So suppose you want to see 1mS pulses the the value of R multiplied by C should be equal to 0.5mS. (Yes when you multiply the units of capacitance by the units of resistance you get the units of time!)

Hey Mike, thank you for the reply.

It’s either polyester or ceramic

Yeah I must learn more on capacitors, there are so many types!

That is a modulation frequency of about 71.5KHz if this is true then it is probably too high for that receiver.

Hmm that’s bad… I’ll try to find a 71kHz part or try making the RC filter you said.

What version of the environment are you using?

I’m using 0012, didn’t notice there’s the new 0013 version… I’m updating right now.

is “IR codes” refering to programms you have found?

Yes sorry my sentence wasn’t understandable… An example of this is on the Playground http://www.arduino.cc/playground/Code/InfraredReceivers
It uses pin 2, I tried and it doesn’t work. However if I change it to one of the digital pins, it works as expected. Why use an analog pin if there are only digitalRead calls in the code?

You can remove the modulation with a simple RC filter…

I had a look on wikipedia but it’s full of formulas hehe… Should I filter the low pulse (2uS), high pulse (12uS) or their sum? Is there a particular capacitor type suited for this use?

Should I filter the low pulse (2uS), high pulse (12uS) or their sum?

It’s the reciprocal of the sum, that gives you the frequency and that is what you want to remove. The frequency to set the break point of the filter would be half way between this and the maximum frequency you want to see when the modulation is removed. The type of capacitor don’t matter much but polyester are probably best.

Why use an analog pin if there are only digitalRead calls in the code?

Sorry I can’t see any technical reason for this.

I looked for a RC filter used on a IR repeater, and they used a 22nF capacitor and 3.3kOhm resistor for wideband support (30 to 120 kHz) In this case the middle of the frequency is 3.3x22= 72.6 uS I need half of 1/14=71.5 --> 35,75. I round it to 36 so I need a 20nF capacitor and a 1.8kOhm resistor. Does it make sense or I'm completely wrong with the math? Isn't it strange that 35.75? many IR remotes are 36kHz, is this one really twice the frequency or is there another explaination? :D