Thursday 27 June 2013

A Simple IR Decoder For Arduino

One of the design goals for the project I'm working on is to have IR control, so I set about writing some simple code for the Arduino to do just that.
A quick search revealed that the Philips RC-5 IR protocol is by far the most common and so my decoder is based on this type of encoding: Manchester Coding.




Looking at the diagram we see that each 'bit' is signified by a transition, a rising or a falling edge, whereby a rising edge means a logical '1' and a falling edge a logical '0'. These transitions lie within a window of approximately 1778 uS (889 uS x2) and there are 14 'bits' or transitions in one transmission.

The first two bits are the 'start bits' and are always a logical 1. These give the decoder time to recognise that there is an incoming transmission. The next bit is the 'toggle bit' which changes every time a key is pressed, this tells the decoder whether a key is being constantly held down, or repeatedly pressed by the user.
The next five bits signify the device in question (ie. CD player, TV, etc.) and the last six signify the command (ie. volume up, volume down, mute, etc.)

We need to detect these transmissions, but ensure that we don't detect the wrong transitions, like the transitions in between bits for example. As a result we need to look very carefully at timing in our code.


Proof of concept sketch:

#define irPin 10

void setup()
{
  Serial.begin(9600);
  pinMode(irPin, INPUT);
}

void loop()
{
  // We need to keep checking for the first start bit
  // If the first start bit is detected...
  if(!digitalRead(irPin))
  {
    // ...decode the rest!
    int code = irDecode();
    
    Serial.print("Code: ");
    Serial.println(code);
  }
}

// This is the decoder function itself
int irDecode()
{
  int data = 0;
  for(int i=12; i>=0; i--) 
  {
    delayMicroseconds(1333); // We wait 1333 uS (1.5 x 889 uS)
    unsigned long microsOld = micros(); // For timeout
    boolean irOld = digitalRead(irPin); //Read current pin state    
    
    while(1) // This is our 'transition detector'
    {
      if(digitalRead(irPin) != irOld)   // Look for transition
      {
        bitWrite(data, i, irOld);       // Write the bit to 1 or 0
        break;                          // Done for this bit!
      }
   
      if((micros() - microsOld) > 889)  // Timeout
      {
        return -1;
      }
    }
  }
  
  delayMicroseconds(1333);  // Ignore "tail" of transmission
  return data;
}


A fully commented and explained version can be found on my GitHub here: https://github.com/frodofski/RC5_Decoder

I uploaded this to my Arduino Uno and hooked up an IR receiver to pin 10. I then opened the serial monitor, pressed some buttons on my Philips remote, and lo and behold, codes! It works! :D



Now unfortunately this code isn't very efficient, we need to continually check for the start bit in our code, and when its decoding, the Arduino can't do anything else in the meantime (ie. its blocking code) but it does show that this algorithm for decoding the RC-5 protocol does work.

I will revisit this decoder in the future with some more complicated, but much more efficient code.

No comments:

Post a Comment