IR receiving and transmitting issues

Hi All,

I'm a relative newbie to Arduino but really enjoying the experimenting I've been doing so far. I've been playing around with IR code capture and transmission however have hit a snag with the code. I've hacked together the very useful tutorials at ladyada.net to receive a signal from a Sony digital photo frame IR remote, then transmit a signal to turn on the TV via IR.

Each aspect of the code works fine individually - I can turn the TV on and off using the procedures triggered by a delayed loop, and I can also capture the IR remote signal and turn on an LED. However, when this code is combined, I only get a partial success - the visible LED will turn on however the IR signal doesn't seem to be sent. I'm guessing it might be a speed issue with the Arduino given IR is very time sensitive however I'm not sure.

If anyone has any ideas, I'd be most grateful. Code is below:

#define IRpin_PIN PIND
#define IRpin 2

// the maximum pulse we'll listen for - 65 milliseconds is a long time
#define MAXPULSE 65000
#define NUMPULSES 50

// what our timing resolution should be, larger is better
// as its more 'precise' - but too large and you wont get
// accurate timing
#define RESOLUTION 20

// What percent we will allow in variation to match the same code
#define FUZZINESS 20

// we will store up to 100 pulse pairs (this is -a lot-)
uint16_t pulses[NUMPULSES][2]; // pair is high and low pulse
uint8_t currentpulse = 0; // index for pulses we're storing

#define IRArrayLen 72

int OnOffLEDPin = 5;
boolean LEDOnOff = false;

int IRledPin =  13;    // LED connected to digital pin 13

int SonyOnOff[] = {
// ON, OFF (in 10's of microseconds)
	240, 54,
	126, 52,
	64, 54,
	122, 56,
	64, 52,
	126, 54,
	64, 52,
	66, 52,
	64, 56,
	122, 54,
	64, 52,
	126, 54,
	124, 54,
	64, 52,
	66, 52,
	126, 52,
	126, 54,
	124, 54,
	122, 56,
	122, 56,
	126, 1082,
	238, 54,
	126, 54,
	62, 54,
	122, 56,
	64, 54,
	124, 54,
	64, 54,
	62, 54,
	64, 56,
	122, 54,
	64, 54,
	124, 54,
	124, 54,
	64, 54,
	64, 52,
	126, 54,
	124, 54,
	126, 52,
	122, 56,
	122, 56,
	126, 1082,
	240, 54,
	124, 54,
	64, 54,
	122, 56,
	64, 52,
	126, 54,
	64, 52,
	64, 54,
	64, 54,
	124, 54,
	62, 54,
	126, 52,
	126, 54,
	62, 54,
	64, 54,
	124, 54,
	126, 52,
	126, 52,
	124, 54,
	124, 56,
	124, 0};

int TVOnOff[IRArrayLen] = {// ON, OFF (in 10's of microseconds)
	876, 434,
	58, 56,
	54, 58,
	56, 56,
	56, 56,
	56, 56,
	56, 56,
	56, 58,
	56, 160,
	58, 162,
	58, 162,
	58, 162,
	58, 160,
	58, 162,
	58, 162,
	58, 162,
	58, 56,
	56, 56,
	56, 162,
	58, 56,
	56, 56,
	56, 58,
	54, 58,
	54, 58,
	54, 162,
	60, 160,
	58, 56,
	58, 160,
	58, 162,
	58, 162,
	58, 160,
	60, 160,
	58, 58,
	56, 3798,
	876, 218,
	58, 0};

void setup(void) {
  Serial.begin(9600);
  Serial.println("Ready to decode IR!");
  pinMode(OnOffLEDPin, OUTPUT);
}

void loop(void) {
  int numberpulses;
  numberpulses = listenForIR();
  
  Serial.print("Heard ");
  Serial.print(numberpulses);
  Serial.println("-pulse long IR signal");
  if (IRcompare(numberpulses, SonyOnOff,sizeof(SonyOnOff)/4)) {
    Serial.println("On/Off");
    transmitIRArray(TVOnOff);
    LEDOnOff = !LEDOnOff;
  }
  
  digitalWrite(OnOffLEDPin, LEDOnOff);
  delay(300);
}

//KGO: added size of compare sample. Only compare the minimum of the two
boolean IRcompare(int numpulses, int Signal[], int refsize) {
  int count = min(numpulses,refsize);
  Serial.print("count set to: ");
  Serial.println(count);
  for (int i=0; i< count-1; i++) {
    int oncode = pulses[i][1] * RESOLUTION / 10;
    int offcode = pulses[i+1][0] * RESOLUTION / 10;
       
    // check to make sure the error is less than FUZZINESS percent
    if ( abs(oncode - Signal[i*2 + 0]) <= (Signal[i*2 + 0] * FUZZINESS / 100)) {
    } else {
      // we didn't match perfectly, return a false match
      return false;
    }
    
    if ( abs(offcode - Signal[i*2 + 1]) <= (Signal[i*2 + 1] * FUZZINESS / 100)) {
    } else {
      // we didn't match perfectly, return a false match
      return false;
    }
    
  }
  // Everything matched!
  return true;
}

int listenForIR(void) {
  currentpulse = 0;
  
  while (1) {
    uint16_t highpulse, lowpulse; // temporary storage timing
    highpulse = lowpulse = 0; // start out with no pulse length
  
// while (digitalRead(IRpin)) { // this is too slow!
    while (IRpin_PIN & (1 << IRpin)) {
       // pin is still HIGH

       // count off another few microseconds
       highpulse++;
       delayMicroseconds(RESOLUTION);

       // If the pulse is too long, we 'timed out' - either nothing
       // was received or the code is finished, so print what
       // we've grabbed so far, and then reset
       
       // KGO: Added check for end of receive buffer
       if (((highpulse >= MAXPULSE) && (currentpulse != 0))|| currentpulse == NUMPULSES) {
         return currentpulse;
       }
    }
    // we didn't time out so lets stash the reading
    pulses[currentpulse][0] = highpulse;
  
    // same as above
    while (! (IRpin_PIN & _BV(IRpin))) {
       // pin is still LOW
       lowpulse++;
       delayMicroseconds(RESOLUTION);
        // KGO: Added check for end of receive buffer
        if (((lowpulse >= MAXPULSE) && (currentpulse != 0))|| currentpulse == NUMPULSES) {
         return currentpulse;
       }
    }
    pulses[currentpulse][1] = lowpulse;

    // we read one high-low pulse successfully, continue!
    currentpulse++;
  }
}
void printpulses(void) {
  Serial.println("\n\r\n\rReceived: \n\rOFF \tON");
  for (uint8_t i = 0; i < currentpulse; i++) {
    Serial.print(pulses[i][0] * RESOLUTION, DEC);
    Serial.print(" usec, ");
    Serial.print(pulses[i][1] * RESOLUTION, DEC);
    Serial.println(" usec");
  }
  
  // print it in a 'array' format
  Serial.println("int IRsignal[] = {");
  Serial.println("// ON, OFF (in 10's of microseconds)");
  for (uint8_t i = 0; i < currentpulse-1; i++) {
    Serial.print("\t"); // tab
    Serial.print(pulses[i][1] * RESOLUTION / 10, DEC);
    Serial.print(", ");
    Serial.print(pulses[i+1][0] * RESOLUTION / 10, DEC);
    Serial.println(",");
  }
  Serial.print("\t"); // tab
  Serial.print(pulses[currentpulse-1][1] * RESOLUTION / 10, DEC);
  Serial.print(", 0};");
}

void pulseIR(long microsecs) {
  // we'll count down from the number of microseconds we are told to wait
 
  cli();  // this turns off any background interrupts
 
  while (microsecs > 0) {
    // 38 kHz is about 13 microseconds high and 13 microseconds low
   digitalWrite(IRledPin, HIGH);  // this takes about 3 microseconds to happen
   delayMicroseconds(10);         // hang out for 10 microseconds
   digitalWrite(IRledPin, LOW);   // this also takes about 3 microseconds
   delayMicroseconds(10);         // hang out for 10 microseconds
 
   // so 26 microseconds altogether
   microsecs -= 26;
  }
 
  sei();  // this turns them back on
}

void transmitIRArray(int *IRArray){
  for (int i=1; i<= IRArrayLen; i=i+2){
    pulseIR(IRArray[i-1]*10);
    delayMicroseconds(IRArray[i]*10);
  }
  for (int i=1; i<= IRArrayLen; i=i+2){
    Serial.println(TVOnOff[i-1]*10);
    Serial.println(TVOnOff[i]*10);
  }
  
}

ArduLearning:
...the visible LED will turn on however the IR signal doesn't seem to be sent. I'm guessing it might be a speed issue with the Arduino given IR is very time sensitive however I'm not sure.

Is the visible LED in series with the IRED ("IRLED")?

No, the visible LED is on a different pin. The procedure changes the variable after (supposedly) sending the IR signal to the TV however this part isn't functioning. The strange thing is that if I create a sketch that basically includes the transmitIRArray(TVOnOff) procedure without also trying to detect IR signals from the receiver, the procedure works.

Try removing all your Serial.print()s. Putting out the strings to the serial interface uses interrupts. Although you have deactivated interrupts while sending out one pulse of IR, you haven't done so while waiting before sending the next. The interrupt may insert a delay that's a little bit longer than one without the interrupt, letting the recipient of the signal fail to decode it.

Have you tried using the IRremote library? It does this stuff with hardware timers and is therefore much more precise and almost immune to problems described above.

Putting out the strings to the serial interface uses interrupts. Although you have deactivated interrupts while sending out one pulse of IR, you haven't done so while waiting before sending the next.

If you're using an up-to-date IDE, you could put a "Serial.flush ()" after every print sequence to ensure the entire output has been sent, before doing anything else.