Monday, 15 July 2013

Interfacing a TV Remote with the on-board TSOP Remote Control Receiver

TSOP Remote Control Receiver

The TSOP SM0038 is an IR receiver on the InduinoX. The TSOP will help you to interface your TV remote with the InduinoX and in the Process learn the basics of Wireless Communication.  On the Induino R3, the TSOP is connected to  digital pin 15(A0).

The TSOP outputs a constant HIGH signal when idle and as it receives data, it tends to invert the data. i.e when an IR LED is transmitting data onto the TSOP, everytime the IR led goes high, the TSOP will go LOW and vice versa. Remote control signals are often bytes of data that is encoded and transmitted by pulsing(switching ON & OFF the IR LED at a specific frequency) Most TV remote controls work at 32-40 Khz frequency and most receivers can receive this range.

Heres a link to a nice write up on different remote control protocols. lets first take a look how the Sony Remote Control Protocol Works. We stick to Sony as it is the easiest one to get started with. Read this before proceeding 

Here's a basic outline of how the data is sent. Every time you press a button on a Sony remote control, it sends out a 13Bit data. The first bit is a start bit indicating there are 12 bits of data following it. The next 7 bits are the command bit which will vary depending upon the keys being pressed. The last 5 bits are the address bits which will the same for all buttons but vary for remote controls of different devices.

The black bars in the following image correspond to high signals (called marks) and the white spaces in between correspond to low signals (called spaces). The duration of the 'marks' varies according to the bit being transmitted. It is 2.4ms for the start bit, 1.2ms for HIGH bit and 0.6ms for LOW bit. The duration of the 'spaces' is a constant 0.6ms. Every mark is followed by a space. Any data can be converted to binary format and transmitted in this manner. In fact this is the basic form of all types of serial communication.

Technique to decode this signal train, would be to constantly monitor the TSOP pin[Digital 15] for its normal state and the moment it produces a low signal, measure the duration of the low signal. If the measured duration of the low signal is around 2ms then measure and store the duration for the next 12 bits of the incoming data. After storing the data, evaluate the duration and based on the duration convert the data to decimal / hexadecimal and use it in your application.

The duration of a signal on an input pin of the arduino can be measured using the pulseIn() function.

Now Here's how we are going to go ahead with decoding

  1. Keep checking the TSOP pin (Pin 15) for a LOW pulse of duration in excess of 2ms, the moment you get such a signal proceed on to step 2
  2. Run a 'for' loop for 12 counts, during each iteration of the loop, get the current pulse duration using the pulseIn function. Check if the duration is greater than 1000ms (means its a '1') else its a '0'
  3. As soon as you detect a '1' or '0' add it to an appropriate binary to decimal conversion logic.
  4. We will process the whole signal as a 12-bit data rather than process the address / command data separately.  We will consider the first data received as the LSB. These 2 aspects might change depending upon your application. Here our objective is to use a TV remote to control our board.
Here's a program to calculate and the print the decimal value for each button, You can plug in the remote function into any of your programs, just remember to declare pin 15 as INPUT.


/* Induino R3 User Guide - Program 7.0 - TSOP Remote Receiver Program for Sony Remote*/

void setup()  
{  
  pinMode(15,INPUT); // TSOP is connected on the 15ht pin  
  Serial.begin(9600);  
}  

void loop()  
{  
  int remote_val = remote();  // Call the remote function to get the value of the key pressed
  if(remote_val>0)  // check if the value is greater than 0. A 0 means that no signal was received by the TSOP
  {  
    Serial.println(remote_val);  
    delay(150); // A remote press will normally generate 3 signal trains. This is to avoid reading duplicates  
  }  
}  


// A Dedicated function that will calculate and return a decimal value for each of the buttons on a remote.
int remote()  
{  
  int value = 0;  // a Variable to store our final calculated value
  int time = pulseIn(15,LOW);  // we need to look for the duration of the LOW pulse as TSOP will invert the incoming HIGH pulse
  if(time>2000) // Checking if the Start Bit has been received. Start Bit Duration is 2.4ms  
  {  
    for(int counter1=0;counter1<12;counter1++) // A loop to receive the next 12 bits The loop is in the inverse order as we will be receiving the MSB   
    {  
      if(pulseIn(15,LOW)>1000) // checking the duration of each pulse, if it is a '1' then we use it in our binary to decimal conversion, '0's can be ignored.  
      {  
        value = value + (1<< counter1);// binary to decimail conversion. 1<< i is nothing but 2 raised to the power of i  
      }  
    }  
  }  
  return value;  
}  

Powers of 2
In the above program, we used a left shift (<<) operator to find the powers of 2.  The Left shift operator, shifts the bits in the given number by the given number of places and fills in zeroes in the right most given number of places.

(given number) << (given number of places)

Lets try a few examples,
lets shift 10 by 2 places =>  10 << 2  =>  00001010 << 2  => 00101000 =>  40 => 10 x (2 power 2)

lets shift 10 by 4 places => 10 << 4 => 00001010 << 4 => 10100000 => 160 => 10 x (2 Power 4)

So as we can see left shift produces multiplication of the given number by powers of 2. If the given number was 1, then we will end up with the powers of 2.

Now Let's add a remote control interface to our Binary Counter using the remote() function from the above program


/*  Induino R3 User Guide - Program 7.1 -  Remote Controlled Binary Counter
 
 This sketch increases a 3 bit number every time the channel up key on a remote is pressed
 and decreases a 3 bit number every time the channel down key on a remote is pressed
 and shows the output on 3 LEDs   
 */

int i = 0; // the countervalue for the binary counter
void setup()  
{  
  pinMode(11,OUTPUT);   // declare LED pins as output pins  
  pinMode(12,OUTPUT);  
  pinMode(13,OUTPUT);  
  pinMode(15,INPUT); // declare the tsop pin as Input
}  
void loop()  
{  
  int remote_val = remote();  // Call the remote function to get the value of the key pressed
  if(remote_val>0)  // check if the value is greater than 0. A 0 means that no signal was received by the TSOP
  {
    if(remote_val == 144) // 144 is the Channel UP Button Value on the Sony Remote provided as part of the Induino R3 Learners Kit
    {
      if(i<7)        // if counter value is less than 7 or 3 bits  
        i++;        // increment counter value  
      else           
        i=0;        // reset counter to 0 
    }
    if(remote_val == 144) // 145 is the Channel UP Button Value on the Sony Remote provided as part of the Induino R3 Learners Kit
    {
      if(i>0)        // if counter value is greater than 0 or 3 bits  
        i--;        // decrement counter value  
      else           
        i=7;        // reset counter to 7
    }


    int a=i%2;      // calculate LSB   
    int b=i/2 %2;     // calculate middle bit  
    int c=i/4 %2;     // calculate MSB   
    digitalWrite(11,a);  // write MSB  
    digitalWrite(12,b);  // write middle bit  
    digitalWrite(13,c);  // write LSB  
    delay(150);     // A remote press will normally generate 3 signal trains. This is to avoid reading duplicates
  }  
}  

// A Dedicated function that will calculate and return a decimal value for each of the buttons on a remote.
int remote()  
{  
  int value = 0;  // a Variable to store our final calculated value
  int time = pulseIn(15,LOW);  // we need to look for the duration of the LOW pulse as TSOP will invert the incoming HIGH pulse
  if(time>2000) // Checking if the Start Bit has been received. Start Bit Duration is 2.4ms  
  {  
    for(int counter1=0;counter1<12;counter1++) // A loop to receive the next 12 bits  
    {  
      if(pulseIn(15,LOW)>1000) // checking the duration of each pulse, if it is a '1' then we use it in our binary to decimal conversion, '0's can be ignored.  
      {  
        value = value + (1<< counter1);// binary to decimail conversion. 1<< i is nothing but 2 raised to the power of i  
      }  
    }  
  }  
  return value;  
}  


Incase you do not have a Sony Remote, you can still use any of your TV remotes with the Induino R3 Board. However you would require to use a library for the same.

There is an interesting IR remote library that can help you read different remotes without any difficulty. It can also generate different remote signals. However currently it can generate these signals only on the 3rd pin of the Arduino / Induino R3 (PWM pin). Incase you want to use this library to generate remote control signals, we advise that you put the RGB LED OFF and connect a wire between the 3rd pin and the Analog 0 of the Induino R3. The IR LED on the Induino R3 is connected to Analog 0 (a.k.a digital 14)

You can download the IR remote library and other libraries, sample codes for the Induino R3 here -> Click Here to Download Induino R3 Sample Codes & Required Libraries[Right Click & use Save As]

Wondering how to install this library? check this -> http://arduino.cc/en/Guide/Libraries

Once you install the IRremote, You can try the example program, IRrecvDemo. This program will give you a serial output of the HEX code for each value corresponding to each button on a remote.
Make a note of the values, we will see how we can substitute them in our program.

Here's the modified Remote Controlled Binary Counter Program using the Library. Remember to change the pin number to 15 => int RECV_PIN = 15;


/*  Induino R3 User Guide - Program 7.2 -  Remote Controlled Binary Counter using the IR remote library
 
 This sketch increases a 3 bit number every time the channel up key on a remote is pressed
 and decreases a 3 bit number every time the channel down key on a remote is pressed
 and shows the output on 3 LEDs   
 */
#include <IRremote.h>

int RECV_PIN = 15;

IRrecv irrecv(RECV_PIN);

decode_results results;

int i = 0; // the countervalue for the binary counter
void setup()  
{  
  pinMode(11,OUTPUT);   // declare LED pins as output pins  
  pinMode(12,OUTPUT);  
  pinMode(13,OUTPUT);  

  irrecv.enableIRIn(); // Start the receiver
}  
void loop()  
{  
  if (irrecv.decode(&results))   // check whether a signal was received and decoded
  {
    if(results.value == 0x90) // 0x90 is the Channel UP Button Value on the Sony Remote provided as part of the Induino R3 Learners Kit
    {
      if(i<7)        // if counter value is less than 7 or 3 bits  
        i++;        // increment counter value  
      else           
        i=0;        // reset counter to 0 
    }
    if(results.value == 0x890) // 0x890 is the Channel UP Button Value on the Sony Remote provided as part of the Induino R3 Learners Kit
    {
      if(i>0)        // if counter value is greater than 0 or 3 bits  
        i--;        // decrement counter value  
      else           
        i=7;        // reset counter to 7
    }

    int a=i%2;      // calculate LSB   
    int b=i/2 %2;     // calculate middle bit  
    int c=i/4 %2;     // calculate MSB   
    digitalWrite(11,a);  // write MSB  
    digitalWrite(12,b);  // write middle bit  
    digitalWrite(13,c);  // write LSB  
    delay(150);     // A remote press will normally generate 3 signal trains. This is to avoid reading duplicates
    irrecv.resume();
  }  
}  


Thats It For This Part! Enjoy... and feel free to drop us an email with questions you might have -> info@simplelabs.co.in

Visit www.simplelabs.co.in for more interesting products

Back to List of Contents

3 comments:

  1. It’s very good post! Congratulations! I really enjoyed to reading your blog. Thanks for share all this information. I’m looking forward your next post

    IR Extender

    ReplyDelete