Go Down

Topic: Arduino infrared problems (Read 47354 times) previous topic - next topic

pmalmsten

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?

Code: [Select]
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:
Code: [Select]
-----
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.
-Paul Malmsten

Daniel

#1
Apr 09, 2007, 09:36 am Last Edit: Apr 09, 2007, 09:59 am by Daniel Reason: 1
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

pmalmsten

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...
-Paul Malmsten

pmalmsten

#3
Apr 10, 2007, 01:22 am Last Edit: Apr 10, 2007, 01:24 am by pmalmsten Reason: 1
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.

Code: [Select]
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....
-Paul Malmsten

David Cuartielles

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 :-)

Code: [Select]

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

PlastBox

Pure genious! :D

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?
Dreaming of extra senses through sensory substitution/agumentation since.. well, for ever.. =P
Going to automate my home, just gotta find the perfect DIY solution first!

David Cuartielles

Oh,

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

Code: [Select]

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


Code: [Select]

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

death

Quote

...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)

CrashingDutchman

#8
Feb 07, 2008, 11:35 am Last Edit: Feb 07, 2008, 11:39 am by jds Reason: 1
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: http://www.ustr.net/infrared/infrared1.shtml

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):

jules

Hello,

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


thanks jules

Rudolph

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;

Code: [Select]

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.

jmknapp

Quote
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: http://www.ustr.net/infrared/infrared1.shtml


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

Kronoticas

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?

awasson

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!  

awasson

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.)
Code: [Select]
/**
* 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
}

Go Up