Arduino infrared problems

Hello,

I just got an Arduino board a few days ago and it is really awesome. I just recently started working on hooking up an infrared reciever, an old parallax one http://www.parallax.com/detail.asp?product_id=350-00014. The sensor is responding and Arduino can read it, but I get the same measurement pattern for every button I push on a remote! I'm using the pulseIn command to measure 12 pulses, but I have also tried measuring only 8 with no change. Does anyone have any ideas?

int pwr_high = 4;  //Sensor pin 1
int pwr_low = 3;    //Sensor pin 2
int ir_pin = 2;    //Sensor pin 3, the data pin
int data[12];
  
void setup() {
  pinMode(pwr_high, OUTPUT);    
  pinMode(pwr_low, OUTPUT);
  pinMode(ir_pin, INPUT);
  digitalWrite(pwr_high, HIGH);    //Sensor pin 1 always high
  digitalWrite(pwr_low, LOW);      //Sensor pin 2 always low
  Serial.begin(9600);
}

void loop() {
  data[0] = pulseIn(ir_pin, LOW);    //Start measuring bits --the sensor defaults high, goes low on infrared 
  data[1] = pulseIn(ir_pin, LOW);
  data[2] = pulseIn(ir_pin, LOW);
  data[3] = pulseIn(ir_pin, LOW);
  data[4] = pulseIn(ir_pin, LOW);
  data[5] = pulseIn(ir_pin, LOW);
  data[6] = pulseIn(ir_pin, LOW);
  data[7] = pulseIn(ir_pin, LOW);
  data[8] = pulseIn(ir_pin, LOW);
  data[9] = pulseIn(ir_pin, LOW);
  data[10] = pulseIn(ir_pin, LOW);
  data[11] = pulseIn(ir_pin, LOW);
  
  Serial.println("-----");    //Send them all
  Serial.println(data[0]);
  Serial.println(data[1]);
  Serial.println(data[2]);
  Serial.println(data[3]);
  Serial.println(data[4]);
  Serial.println(data[5]);
  Serial.println(data[6]);
  Serial.println(data[7]);
  Serial.println(data[8]);
  Serial.println(data[9]);
  Serial.println(data[10]);
  Serial.println(data[11]);
}

For example, I only get:

-----
9842
787
9824
796
791
790
786
786
785
784
762
762

This is from a Tivo remote, every button reports the same with ~10-20 variance each time.

hi

try this: the gnd and power pins of the sensor should be driven from the GND and +5 pins of the Arduino respectively, rather than from the I/O pins as the code suggests.

D

Thanks for the tip. I thought about doing that myself at first, but I figured Arduino would provide plenty of power for a little sensor. Anyways, I tried hooking it up properly to the +5 and GND connections, but I still got the same results as before, different buttons returning very similar codes with a small variance in timings. I have a basic stamp laying around, and I got a basic idea for the project from this guide (pdf) http://www.parallax.com/dl/docs/prod/sic/WebIR-%20v1.1.pdf.

Oops, I just read through the guide a little more and found that I needed a resistor between the IR receiver and the microcontroller. That's a little weird though, because the resistor didn't change anything...

Ah, finally I got everything to work properly. I decided to dump the Tivo remote for a universal remote, setting it up for a Sony TV like the parallax guide recommended. After switching to the Sony protocol everything fell into place and it works beautifully. I don't know what unholy things the Tivo remote has to do to get its signal across.

Pins:
-2 and 3 of the IR receiver are in GND and +5 respectively
-1 of the IR receiver is connected through a 220-ohm resistor to pin 2 of the Arduino
-A green led is placed across pin 13 and GND on the Arduino to show when it is waiting for data

A quick summary of the Sony TV protocol:
-The whole set is 13 pulses long
-The pulses are only measured while low (I'm sure there's a cool word for that but I don't know it)
-The first pulse, the start pulse, lasts about 2.4 ms (2400 microseconds)
-The following pulses are 1.2 ms (1200 microseconds) for a 1, 0.6 ms (600 microseconds) for a 0
-Each data pulse is about 0.3 ms (300 microseconds) apart
-Every set of 13 pulses is about 20-30 ms apart from each other, repeating when a button is held down

The code below will watch for a 13 pulse set and returns the set's integer equivalent, different for every button on the remote. If you want to try your own TV code you can always set the debug flag to 1 and see all of the pretty microsecond measurements.

int ir_pin = 2;                        //Sensor pin 1 wired through a 220 ohm resistor
int led_pin = 13;                      //"Ready to Recieve" flag, not needed but nice
int debug = 0;                         //Serial connection must be started to debug
int start_bit = 2000;                  //Start bit threshold (Microseconds)
int bin_1 = 1000;                      //Binary 1 threshold (Microseconds)
int bin_0 = 400;                       //Binary 0 threshold (Microseconds)

  
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);
}

void loop() {
  int key = getIRKey();                //Fetch the key
  Serial.print("Key Recieved: ");      
  Serial.println(key);                
}


int getIRKey() {
  int data[12];
  digitalWrite(led_pin, HIGH);         //Ok, i'm ready to recieve
  while(pulseIn(ir_pin, LOW) < 2200) { //Wait for a start bit
  }
  data[0] = pulseIn(ir_pin, LOW);      //Start measuring bits, I only want low pulses
  data[1] = pulseIn(ir_pin, LOW);
  data[2] = pulseIn(ir_pin, LOW);
  data[3] = pulseIn(ir_pin, LOW);
  data[4] = pulseIn(ir_pin, LOW);
  data[5] = pulseIn(ir_pin, LOW);
  data[6] = pulseIn(ir_pin, LOW);
  data[7] = pulseIn(ir_pin, LOW);
  data[8] = pulseIn(ir_pin, LOW);
  data[9] = pulseIn(ir_pin, LOW);
  data[10] = pulseIn(ir_pin, LOW);
  data[11] = pulseIn(ir_pin, LOW);
  digitalWrite(led_pin, LOW);
  
  if(debug == 1) {
    Serial.println("-----");
  }
  for(int i=0;i<11;i++) {              //Parse them
    if (debug == 1) {
        Serial.println(data[i]);
    }             
    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(int i=0;i<11;i++) {              //Pre-check data for errors
    if(data[i] > 1) {                 
      return -1;                       //Return -1 on invalid data
    }
  }
  
  int result = 0;  
  int seed = 1;                                      
  for(int i=0;i<11;i++) {              //Convert bits to integer
    if(data[i] == 1) {
      result += seed;
    }
    seed = seed * 2;
  }
  return result;                       //Return key number
}

Now all I have to do is figure out what to do with it....

Hej,

this is my code for sender and receiver, note that the receiver is having a nasty hack to get the data out, but it sends and receives numbers from 1 to 8 with no problem :slight_smile:

RECEIVER
-----------------

int ir_pin = 7;                         //Sensor pin 1 wired through a 220 ohm resistor
int led_pin = 13;                           //"Ready to Receive" flag, not needed but nice
int debug = 0;                           //Serial connection must be started to debug
int start_bit = 2000;                   //Start bit threshold (Microseconds)
int bin_1 = 1000;                           //Binary 1 threshold (Microseconds)
int bin_0 = 400;                             //Binary 0 threshold (Microseconds)


void setup() {
 pinMode(led_pin, OUTPUT);             //This shows when we're ready to receive
 pinMode(ir_pin, INPUT);
 digitalWrite(led_pin, LOW);       //not ready yet
 Serial.begin(9600);
}

void loop() {
 int key = getIRKey();             //Fetch the key
 if (key != -1) {
   Serial.print("Key Recieved: ");
   Serial.println(key);
 }
}


int getIRKey() {
 int data[12];
 digitalWrite(led_pin, HIGH);     //Ok, i'm ready to recieve
 while(pulseIn(ir_pin, LOW) < 2200) { //Wait for a start bit
 }
 data[0] = pulseIn(ir_pin, LOW);       //Start measuring bits, I only want low pulses
 data[1] = pulseIn(ir_pin, LOW);
 data[2] = pulseIn(ir_pin, LOW);
 data[3] = pulseIn(ir_pin, LOW);
 data[4] = pulseIn(ir_pin, LOW);
 data[5] = pulseIn(ir_pin, LOW);
 data[6] = pulseIn(ir_pin, LOW);
 data[7] = pulseIn(ir_pin, LOW);
 data[8] = pulseIn(ir_pin, LOW);
 data[9] = pulseIn(ir_pin, LOW);
 data[10] = pulseIn(ir_pin, LOW);
 data[11] = pulseIn(ir_pin, LOW);
 digitalWrite(led_pin, LOW);

 if(debug == 1) {
   Serial.println("-----");
 }
 for(int i=0;i<11;i++) {                 //Parse them
   if (debug == 1) {
         Serial.println(data[i]);
   }
   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(int i=0;i<11;i++) {                 //Pre-check data for errors
   if(data[i] > 1) {
       return -1;                           //Return -1 on invalid data
   }
 }

 int result = 0;
 int seed = 1;
 for(int i=11;i>=0;i--) {                //Convert bits to integer
   if(data[i] == 1) {
       result |= seed;
   }
   seed = seed * 2;
 }

 //patch for the weird data result
 //I wish I knew wtf is wrong
 for (int j = 0; j <= 11; j++) {
 int aux = result;
   aux -= pow(2, j);
   if (aux < 0) {
     result = j;
     break;
   }
 }
 if (result > 8) result = -1;
 return result;                             //Return key number
}

SENDER
--------------

int ir_pin = 6;                         //Sensor pin 1 wired through a 220 ohm resistor
int led_pin = 13;                           //"Ready to Receive" flag, not needed but nice
int debug = 1;                           //Serial connection must be started to debug
int start_bit = 2400;                   //Start bit threshold (Microseconds)
int bin_1 = 1200;                           //Binary 1 threshold (Microseconds)
int bin_0 = 600;                             //Binary 0 threshold (Microseconds)
int dataOut = 0;
int guardTime = 300;


void setup() {
 pinMode(led_pin, OUTPUT);             //This shows when we're ready to recieve
 pinMode(ir_pin, OUTPUT);
 digitalWrite(led_pin, LOW);       //not ready yet
 digitalWrite(ir_pin, LOW);        //not ready yet
 Serial.begin(9600);
}

void loop() {
 if (Serial.available()) {
   int val = Serial.read();
   switch (val) {
   case '0':
     dataOut = val - 48;
     break;
   case '1':
     dataOut = val - 48;
     break;
   case '2':
     dataOut = val - 48;
     break;
   case '3':
     dataOut = val - 48;
     break;
   case '4':
     dataOut = val - 48;
     break;
   case '5':
     dataOut = val - 48;
     break;
   case '6':
     dataOut = val - 48;
     break;
   case '7':
     dataOut = val - 48;
     break;
   case '8':
     dataOut = val - 48;
     break;
   default:
     dataOut = 255;
     break;
   }
 }
 int key = sendIRKey(dataOut);             //Fetch the key
 Serial.print("Key Sent: ");
 Serial.println(key);
}


int sendIRKey(int dataOut) {
 int data[12];
 digitalWrite(led_pin, HIGH);     //Ok, i'm ready to send
 for (int i=0; i<12; i++)
   data[i] = dataOut>i & B1;   //encode data as '1' or '0'

 // send startbit
 oscillationWrite(ir_pin, start_bit);
 // send separation bit
 digitalWrite(ir_pin, HIGH);
 delayMicroseconds(guardTime);
 // send the whole string of data
 for (int i=11; i>=0; i--) {
   //digitalWrite(ir_pin, LOW);
   //if (data[i] == 0) delayMicroseconds(bin_0);
   //else delayMicroseconds(bin_1);
   if (data[i] == 0) oscillationWrite(ir_pin, bin_0);
   else oscillationWrite(ir_pin, bin_1);
   // send separation bit
   digitalWrite(ir_pin, HIGH);
   delayMicroseconds(guardTime);
 }
 delay(20);
 return dataOut;                            //Return key number
}

// this will write an oscillation at 38KHz for a certain time in useconds
void oscillationWrite(int pin, int time) {
 for(int i = 0; i <= time/26; i++) {
   digitalWrite(pin, HIGH);
   delayMicroseconds(13);
   digitalWrite(pin, LOW);
   delayMicroseconds(13);
 }
}

/d

Pure genious! :smiley:

I've been thinking of a way to control my tv and dvd-player from a computer for years now, and finally.. here it is in all it's glory! All hail pmalmsten!

I just need to adapt this code to work with my Phillips dvd-player (tricky bastard, using Manchester coding, and kidney shots too probably! -_-' ) Then, write some backend-stuff with VB and a php frontend, and voilá! I can control my tv and dvd-player, as well as lights and such, from my comuter and cellphone!

If I get this working, you, sire, will have my everlasting gratitude!

Oh, and by the way... why on earth hasn't this thread been made sticky?

Oh,

I fixed my code ... it was having plenty of bugs in it:

SENDER
----------
int ir_pin = 10;                         //Sensor pin 1 wired through a 220 ohm resistor
int led_pin = 13;                           //"Ready to Receive" flag, not needed but nice
int debug = 1;                           //Serial connection must be started to debug
int start_bit = 2400;                   //Start bit threshold (Microseconds)
int bin_1 = 1200;                           //Binary 1 threshold (Microseconds)
int bin_0 = 600;                             //Binary 0 threshold (Microseconds)
int dataOut = 0;
int guardTime = 300;


void setup() {
  pinMode(led_pin, OUTPUT);             //This shows when we're ready to recieve
  pinMode(ir_pin, OUTPUT);
  digitalWrite(led_pin, LOW);       //not ready yet
  digitalWrite(ir_pin, LOW);        //not ready yet
  Serial.begin(9600);
}

void loop() {
  if (Serial.available()) {
    int val = Serial.read();
    dataOut = val;
    int key = 0;
    for (int j = 0; j<10; j++) {
      key = sendIRKey(dataOut);             //Fetch the key
    }
      Serial.print("Key Sent: ");
      Serial.println(key);
  }
}


int sendIRKey(int dataOut) {
  int data[12];
  digitalWrite(led_pin, HIGH);     //Ok, i'm ready to send
  for (int i=0; i<12; i++) {
    data[i] = dataOut>>i & B1;   //encode data as '1' or '0'
    }
  // send startbit
  oscillationWrite(ir_pin, start_bit);
  // send separation bit
  digitalWrite(ir_pin, HIGH);
  delayMicroseconds(guardTime);
  // send the whole string of data
  for (int i=11; i>=0; i--) {
    if (data[i] == 0) oscillationWrite(ir_pin, bin_0);
    else oscillationWrite(ir_pin, bin_1);
    // send separation bit
    digitalWrite(ir_pin, HIGH);
    delayMicroseconds(guardTime);
  }
  delay(20);
  return dataOut;                            //Return key number
}

// this will write an oscillation at 38KHz for a certain time in useconds
void oscillationWrite(int pin, int time) {
  for(int i = 0; i <= time/26; i++) {
    digitalWrite(pin, HIGH);
    delayMicroseconds(13);
    digitalWrite(pin, LOW);
    delayMicroseconds(13);
  }
}
RECEIVER
------------
int ir_pin = 7;                         //Sensor pin 1 wired through a 220 ohm resistor
int led_pin = 13;                           //"Ready to Receive" flag, not needed but nice
int debug = 1;                           //Serial connection must be started to debug
int start_bit = 2000;                   //Start bit threshold (Microseconds)
int bin_1 = 1000;                           //Binary 1 threshold (Microseconds)
int bin_0 = 400;                             //Binary 0 threshold (Microseconds)


void setup() {
 pinMode(led_pin, OUTPUT);             //This shows when we're ready to receive
 pinMode(ir_pin, INPUT);
 digitalWrite(led_pin, LOW);       //not ready yet
 Serial.begin(9600);
}

void loop() {
 int key = getIRKey();             //Fetch the key
 if (key != -1) {
   Serial.print("Key Recieved: ");
   Serial.println(key);
 }
}


int getIRKey() {
 int data[12];
 digitalWrite(led_pin, HIGH);     //Ok, i'm ready to recieve
 while(pulseIn(ir_pin, LOW) < 2200) { //Wait for a start bit
 }
 data[0] = pulseIn(ir_pin, LOW);       //Start measuring bits, I only want low pulses
 data[1] = pulseIn(ir_pin, LOW);
 data[2] = pulseIn(ir_pin, LOW);
 data[3] = pulseIn(ir_pin, LOW);
 data[4] = pulseIn(ir_pin, LOW);
 data[5] = pulseIn(ir_pin, LOW);
 data[6] = pulseIn(ir_pin, LOW);
 data[7] = pulseIn(ir_pin, LOW);
 data[8] = pulseIn(ir_pin, LOW);
 data[9] = pulseIn(ir_pin, LOW);
 data[10] = pulseIn(ir_pin, LOW);
 data[11] = pulseIn(ir_pin, LOW);
 digitalWrite(led_pin, LOW);

 if(debug == 1) {
   Serial.println("-----");
 }
 for(int i=0;i<=11;i++) {                 //Parse them
   if (debug == 1) {
         Serial.println(data[i]);
   }
   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(int i=0;i<=11;i++) {                 //Pre-check data for errors
   if(data[i] > 1) {
       return -1;                           //Return -1 on invalid data
   }
 }

 int result = 0;
 int seed = 1;
 for(int i=11;i>=0;i--) {                //Convert bits to integer
   if(data[i] == 1) {
       result += seed;
   }
   seed = seed * 2;
 }

 return result;                             //Return key number
}

/d

...snip...
I get the same measurement pattern for every button I push on a remote!

..snip..

For what its worth, I'd say what was happening was your circuit was pulling low by default, and measuring the peaks (not the troughs) of the transmission..

this picture would help to illistrate the point:

except for the header, the peaks will always be the same, its the troughs that will vary (signifying 1's and 0's)

David,

I just found your code, I think I am going to use it (maybe it needs some modification) for sending an RC5 signal to a Philips TV. I found a good description of RC5 here: infrared

My TV needs to have it's brightness and contrast adjusted sometimes. I don't have the original remote anymore and so far haven't been able to find a remote that has the button (off button) to leave the main menu. So, I hope to be able to do this by sending code 83 (menu off) from my Arduino with IR tx led and 220ohm resistor to the TV set.

If you think there something I should be aware of before starting with this, please let me know! Thanks in advance!

I will post here if I have results...

Edit: It seems that your code doesn't take care of sending the AGV, CHK and ADDRESS bits as shown in this picture (Philips way of working):

Hello,

i am searching for a RC5 control with the arduino.. but diddn´t find anything yet. Did you manage it ?

thanks jules

Thanks for the code! This was almost exactly what I was looking for to use my old sony VCR guts for my little project. Now I can switch between LED patterns wireless-ly.

I did have to change a wee bit though, so I thought I'd post back here with my tweak. I wanted the getIRKey() function to be run from an interrupt, but it seemed to be hanging the rest of the processing, and never quite getting to the loop(). It looked to me like the while loop at the beginning waited forever for input > 2200. I ended up changing that to "if ... < 2200, return -1", then testing for key values greater than 0 in a wrapper. The wrapper is called via the interrupt. So, here's a bit of the modified code;

int ir_pin = 2;              //Sensor pin wired through a 220 ohm resistor
int start_bit = 2000;   //Start bit threshold (Microseconds)
int bin_1 = 1000;       //Binary 1 threshold (Microseconds)
int bin_0 = 400;        //Binary 0 threshold (Microseconds)

volatile int key = 137;    // key 137 is "0", default to off

void setup() {
  pinMode(ir_pin, INPUT);
  attachInterrupt(0, setOpts, LOW);    // interrupt 0, run setOpts(), interrupt when ir_pin goes LOW
}

void loop() {
  //do pretty flashy lights here
}

void setOpts() {
  int tempKey = getIRKey();
  if(tempKey > 1){
    key = tempKey;
  }
}

int getIRKey() {
  int data[12];
  if(pulseIn(ir_pin, LOW) < 2200) { //Wait for a start bit
    return -1;
  }
  data[0] = pulseIn(ir_pin, LOW);      //Start measuring bits, I only want low pulses
  data[1] = pulseIn(ir_pin, LOW);
  data[2] = pulseIn(ir_pin, LOW);
  data[3] = pulseIn(ir_pin, LOW);
  data[4] = pulseIn(ir_pin, LOW);
  data[5] = pulseIn(ir_pin, LOW);
  data[6] = pulseIn(ir_pin, LOW);
  data[7] = pulseIn(ir_pin, LOW);
  data[8] = pulseIn(ir_pin, LOW);
  data[9] = pulseIn(ir_pin, LOW);
  data[10] = pulseIn(ir_pin, LOW);
  data[11] = pulseIn(ir_pin, LOW);

  for(int i=0;i<11;i++) {              //Parse them             
    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(int i=0;i<11;i++) {              //Pre-check data for errors
    if(data[i] > 1) {                  
      return -1;                       //Return -1 on invalid data
    }
  }
  
  int result = 0;  
  int seed = 1;                                      
  for(int i=0;i<11;i++) {              //Convert bits to integer
    if(data[i] == 1) {
      result += seed;
    }
    seed = seed * 2;
  }
  return result;                       //Return key number
}

Seems to work for me, I can punch a button any time on the remote and it will reset the value of 'key', even in the middle of a delay(). I still have some work to go on it though, fiddling with my timings and such.

Thanks again.

David,
I just found your code, I think I am going to use it (maybe it needs some modification) for sending an RC5 signal to a Philips TV. I found a good description of RC5 here: infrared

Check my post on implementing an RC5 transmitter (seems like it should do what you want):

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1209565937

i tore the ir from a vcr ihad laying around and managed to get a reading from my rca remote, but im havin some trouble, the data isnt the same each time i hit a button on he remote, and i get 16 lines instead of the 11? any thoughts?

pmalmsten:
That is a fantastic piece of code to begin an IR Remote project with... I also started with the BOE Stamp kit and a few of those Panasonic sensors, then got bogged down with SX chips but today is my second day with the Arduino and your sketch (from your second code posting) just works perfectly.

I wonder... Has anyone has thought of creating a library based on it?

My project (for the last couple of years) has been to build a remote controlled attenuator so I can run the direct audio out of my TV/Media Center through an attenuator into the power amps. The attenuator uses a microcontroller (Arduino) to receive the remote control signal and set the volume up down + mute. I have the TI Burr Brown chips that attenuate and with this receiver code I now have a great foundation.

Thanks!

Is anyone still following this thread with interest in developing it further?

I've made some refinements to the code to make it a tiny bit more efficient and added code to the main loop for my needs but there are some other things I'm not so sure about like:

  • Should the code run as an interrupt instead of in the main loop
  • We've declared a start_bit variable of 2000 microseconds but it's never used
  • In the getIRKey() function we have a while(pulseIn(ir_pin, LOW) < 2200) loop that never does anything. It looks like it was set up for the start bit of the remote control's transmission and would have been used with the start_bit variable mentioned above.

Other than that, I wonder if we could extend the code to recognize other remotes and have a setup mode that would allow us to choose Sony, Hitachi, Panasonic, etc...

My version of the code only recognizes power, mute, volume up and volume down but could be extended to recognize other keys. At the moment it sends the state of the volume, mute and on/off to the serial monitor and saves those values to the EEPROM. My next step is to use shiftOut() to send values to a Texas Instruments PGA2311 stereo volume control chip as well as sending the values to a digital display of some sort.

Here's what I have so far:
(I moved all of the fixed variables into constants to reduce the footprint and use a loop to create the data[] array.)

/**
 * 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      1000                //Binary 1 threshold (Microseconds)
#define bin_0      400                //Binary 0 threshold (Microseconds)
#define ir_pin     2                //Sensor pin 1 wired through a 220 ohm resistor
#define led_pin    13                //"Ready to Recieve" flag, not needed but nice
#define debug      0                 //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 



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() {
  int data[12];
  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<11;i++){
    data[i] = pulseIn(ir_pin, LOW);   //Start measuring bits, I only want low pulses
  }
  
  digitalWrite(led_pin, LOW);

  if(debug == 1) {
    Serial.println("-----");
  }
  
  for(int i=0;i<11;i++) {          //Parse them
    
    if (debug == 1) {
      Serial.println(data[i]);
    }
    
    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<11;i++) {              //Pre-check data for errors
    if(data[i] > 1) {
      return -1;                //Return -1 on invalid data
    }
  }

  int result = 0;
  int seed = 1;
  for(int i=0;i<11;i++) {      //Convert bits to integer
    if(data[i] == 1) {
      result += seed;
    }
    seed = seed * 2;
  }
  return result;             //Return key number
}

THanks for sharing your code guys, I am working on a robot at the moment and am working on using my tv remote to control it (when its not controlling itself that is!)

David,

Thank you for the excellent piece of code. It worked well for me. If I might make a suggestion. When I connected O-scope to the send portion of the code I noticed that i was getting some intermittent gaps between the carrier frequency. It turns out they were some kind of interrupts perhaps from the UART. For a time sensitive code, I placed "noInterrupts()" before it sends out the whole string of data and placed an "interrupts()" after that portion of the code. After placing those functions I was able to recieve the data flawlessly. Thanks again for the great code :slight_smile:

My thanks for the code too!. It worked as-is: copied, compiled uploaded and done!. Works with sony remote, but Samsung remote returned 1 and -1... In fact it is too fast. I get 3 codes per button press. With a delay(50), I get one code per press.

Excellent piece of software, compact and clean.

Update: duh! It says "for sony remote" :slight_smile:

Hi,

I want to use the code inside a while loop. Because I have other code I would like the remote code to remain in a loop while there is still activity in the remote control (sort of to make it more efficient and maybe more responsive)

So my question is: what event would I use in the while loop? I thought of having an interrupt update a flag, but since there are many pulses, there would be many interrupts, and I only need one interrupt per sequence of pulses. Thought about reading HIGH on the input pin, but these are pulses and sometimes will be LOW. What else can I use?

Thanks.

glt: You want to run two different processes at the same time, is that is? One reading the remote, another doing whatever else needs to be done?

Sorry to say, as far as I know multithreading (multiple simultaneous processes) is not possible on the Atmega microcontrollers. It should still be doable though, having the arduino do two things fast enough for it to seem like they are happening at the same time.

What is the other process, other than monitoring the IR-signal, that you need the arduino to do?