Problem adding more IR codes to Ladyada's IR Commander sketch

Post here about your Arduino projects, get help - for Adafruit customers!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
Johannes_SE
 
Posts: 3
Joined: Sun Oct 23, 2011 12:15 pm

Problem adding more IR codes to Ladyada's IR Commander sketch

Post by Johannes_SE »

Hi!
I'm building a media center, and plan to use my B&O Beo4 ir remote to control it.
I use a TSOP7000 455kHz IR receiver and an Arduino Duemilanove.
I started out with a couple IR commands, and it all played well.
The problem starts when I try to add more than 4 codes to the sketch. All of a sudden, all the Arduino prints is an "Å".
No "Ready to decode IR!" or any response when I push remote buttons.

Can anyone help out?

I hope it's OK to paste the whole sketch & header file here, I really don't know where the problem lies.
I commented out the attempted fifth code (TV4).

Code: Select all

/* Raw IR commander
 
 This sketch/program uses the Arduno and a PNA4602 to 
 decode IR received.  It then attempts to match it to a previously
 recorded IR signal
 
 Code is public domain, check out www.ladyada.net and adafruit.com
 for more tutorials! 
 */

// We need to use the 'raw' pin reading methods
// because timing is very important here and the digitalRead()
// procedure is slower!
//uint8_t IRpin = 2;
// Digital pin #2 is the same as Pin D2 see
// http://arduino.cc/en/Hacking/PinMapping168 for the 'raw' pin mapping
#define IRpin_PIN      PIND
#define IRpin          2

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

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

// 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[100][2];  // pair is high and low pulse 
uint8_t currentpulse = 0; // index for pulses we're storing

#include "ircodes.h"

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

void loop(void) {
  int numberpulses;
  
  numberpulses = listenForIR();
  
  //Serial.print("Heard ");
  //Serial.print(numberpulses);
  //Serial.println("-pulse long IR signal");
  if (IRcompare(numberpulses, TV0)) {
    Serial.println("TV0");
  }
    if (IRcompare(numberpulses, TV1)) {
    Serial.println("TV1");
  }
    if (IRcompare(numberpulses, TV2)) {
    Serial.println("TV2");
  }
    if (IRcompare(numberpulses, TV3)) {
    Serial.println("TV3");
    }
    /*if (IRcompare(numberpulses, TV4)) {
    Serial.println("TV4");
  }  */
}

boolean IRcompare(int numpulses, int Signal[]) {
  
  for (int i=0; i< numpulses-1; i++) {
    int oncode = pulses[i][1] * RESOLUTION / 10;
    int offcode = pulses[i+1][0] * RESOLUTION / 10;
    
    /*
    Serial.print(oncode); // the ON signal we heard
    Serial.print(" - ");
    Serial.print(Signal[i*2 + 0]); // the ON signal we want 
    */
    
    // check to make sure the error is less than FUZZINESS percent
    if ( abs(oncode - Signal[i*2 + 0]) <= (Signal[i*2 + 0] * FUZZINESS / 100)) {
      //Serial.print(" (ok)");
    } else {
      //Serial.print(" (x)");
      // we didn't match perfectly, return a false match
      return false;
    }
    
    /*
    Serial.print("  \t"); // tab
    Serial.print(offcode); // the OFF signal we heard
    Serial.print(" - ");
    Serial.print(Signal[i*2 + 1]); // the OFF signal we want 
    */
    
    if ( abs(offcode - Signal[i*2 + 1]) <= (Signal[i*2 + 1] * FUZZINESS / 100)) {
      //Serial.print(" (ok)");
    } else {
      //Serial.print(" (x)");
      // we didn't match perfectly, return a false match
      return false;
    }
    
    //Serial.println();
  }
  // 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
       if ((highpulse >= MAXPULSE) && (currentpulse != 0)) {
         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);
       if ((lowpulse >= MAXPULSE)  && (currentpulse != 0)) {
         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};");
}
ircodes.h:

Code: Select all

/******************* our codes ************/

int TV0[] = {
// ON, OFF (in 10's of microseconds)
	22, 284,
	20, 286,
	22, 1510,
	22, 284,
	20, 592,
	22, 590,
	22, 590,
	22, 592,
	20, 592,
	22, 590,
	20, 592,
	22, 590,
	22, 592,
	22, 590,
	20, 592,
	22, 590,
	22, 590,
	24, 590,
	20, 592,
	22, 590,
	20, 1204,
	22, 0};

int TV1[] = {
// ON, OFF (in 10's of microseconds)
	22, 284,
	20, 286,
	22, 1510,
	20, 286,
	20, 592,
	22, 590,
	20, 592,
	22, 590,
	22, 590,
	24, 590,
	20, 592,
	22, 590,
	22, 590,
	22, 590,
	22, 592,
	22, 590,
	20, 592,
	22, 590,
	22, 590,
	24, 896,
	20, 1204,
	22, 0};

int TV2[] = {
// ON, OFF (in 10's of microseconds)
	22, 284,
	22, 284,
	22, 1510,
	22, 284,
	20, 592,
	22, 590,
	22, 592,
	22, 590,
	20, 592,
	22, 590,
	20, 592,
	22, 590,
	22, 592,
	22, 590,
	20, 592,
	22, 590,
	22, 592,
	22, 590,
	20, 898,
	22, 284,
	22, 1204,
	20, 0};

int TV3[] = {
// ON, OFF (in 10's of microseconds)
	22, 284,
	22, 284,
	20, 1512,
	20, 286,
	22, 590,
	20, 592,
	22, 590,
	22, 590,
	22, 592,
	20, 592,
	22, 590,
	20, 592,
	22, 590,
	22, 590,
	22, 592,
	20, 592,
	22, 590,
	22, 590,
	24, 896,
	20, 592,
	22, 1204,
	20, 0};

/*
int TV4[] = {
// ON, OFF (in 10's of microseconds)
	20, 286,
	22, 284,
	20, 1510,
	22, 284,
	24, 590,
	20, 592,
	22, 590,
	20, 592,
	22, 590,
	22, 592,
	20, 592,
	20, 592,
	22, 590,
	20, 592,
	22, 590,
	22, 592,
	22, 590,
	20, 898,
	22, 284,
	22, 590,
	22, 1204,
	22, 0};
*/
Last edited by Johannes_SE on Sun Oct 23, 2011 5:48 pm, edited 1 time in total.

Johannes_SE
 
Posts: 3
Joined: Sun Oct 23, 2011 12:15 pm

Re: Problem adding more IR codes to Ladyada's IR Commander sketch

Post by Johannes_SE »

Just found the answer on arduino.cc forums (http://arduino.cc/forum/index.php?topic=72645.0). Simply a memory problem.
I tried changing

Code: Select all

uint16_t pulses[100][2];
to

Code: Select all

uint16_t pulses[22][2];
, since all codes are 22 pulse pairs, and that allowed me to add three more buttons. :cry:

Then I realized I had an Atmega 328 with Arduino bootloader laying around, so now I have at least the 0-9 buttons on the remote working. I'm about to test how many more there's room for.

Johannes_SE
 
Posts: 3
Joined: Sun Oct 23, 2011 12:15 pm

Re: Problem adding more IR codes to Ladyada's IR Commander sketch

Post by Johannes_SE »

Managed to squeeze in 18 commands. Not really enough, but I guess it kind of does the job. 0-9, Vol +/-, up, down, left, right, go, menu.

Is there a duemilanove compatible atmega with more SRAM, like 4/8KB? Or could it be done with changes in the code?
I am not very experienced with this stuff...

If anyone with a unidirectional B&O remote like the Beo4 wants the modified code, you can find it here:
ircommander.pde http://BANNED.com/hwkDCyj1
ircodes.h http://BANNED.com/zchCQfGz

musslan
 
Posts: 3
Joined: Sun Jul 22, 2012 10:56 am

Re: Problem adding more IR codes to Ladyada's IR Commander sketch

Post by musslan »

Hi Johannes,
Neat - I'm starting a similar project myself with an Arduino. Was tapping into the MCL bus before and converted it to RS232, but is now keen on getting this to work with IR instead. Did you get it to work on the Duemilanove? I was thinking of doing this on a Uno, but am now considering to get the Mega to get some more SRAM. Maybe there would be a way to compress the ircodes.h though as many of the codes would be quite similar?

Also, where did you manage to source the TSOP7000? Seems like they're discontinued from Vishay. Was considering slaughtering an old MX myself to steal the IR receiver :-)

Johannes & SE låter svenskt förresten!

User avatar
tessellated_dreams
 
Posts: 17
Joined: Sat Oct 22, 2011 9:04 pm

Re: Problem adding more IR codes to Ladyada's IR Commander sketch

Post by tessellated_dreams »

If you need more room, you can move your arrays of IR codes into PROGMEM, the same flash memory that's used for the bootloader. Otherwise you're stuck with the 2k of ram. There's no reason to get a larger arduino for the ram when you can just move the codes into the flash memory.

Here's a modified IR commander sketch that I recently worked on that puts the codes into the flash memory:

https://github.com/acolourfullife/IR-Commander
http://arduino.cc/en/Reference/PROGMEM
http://itp.nyu.edu/~gpv206/2008/04/maki ... o_mem.html

The syntax for placing data into progmem is fairly simple. You just use a modified variable declaration and include PROGMEM in the declaration of an array:

Code: Select all

prog_uint16_t VolDownSignal[] PROGMEM = {

872, 434....
....};
To pull the codes out of progmem you need to specify the address for them. The onState and offState variables hold the information that's pulled from progmem:

Code: Select all

int onState = pgm_read_word_near(&(Signal[i*2 + 0]));
    int offState = pgm_read_word_near(&(Signal[i*2 + 1]));

Full code for the IRcompare function:

Code: Select all

boolean IRcompare(int numpulses, uint16_t Signal[], int refsize) {
  int count = min(numpulses,refsize);
  for (int i=0; i< count-1; i++) {
    int oncode = pulses[i][1] * RESOLUTION / 10;
    int offcode = pulses[i+1][0] * RESOLUTION / 10;
    int onState = pgm_read_word_near(&(Signal[i*2 + 0]));
    int offState = pgm_read_word_near(&(Signal[i*2 + 1]));

#ifdef DEBUG
    Serial.print(oncode); // the ON signal we heard
    Serial.print(" - ");
    Serial.print(onState); // the ON signal we want
#endif
    
    // check to make sure the error is less than FUZZINESS percent
     if ( abs(oncode - onState) <= (onState * FUZZINESS / 100)) {
#ifdef DEBUG
      Serial.print(" (ok)");
#endif
    } else {
#ifdef DEBUG
      Serial.print(" (x)");
#endif
      // we didn't match perfectly, return a false match
      return false;
    }
    
    
#ifdef DEBUG
    Serial.print(" \t"); // tab
    Serial.print(offcode); // the OFF signal we heard
    Serial.print(" - ");
    Serial.print(offState); // the OFF signal we want
#endif
    
   if ( abs(offcode - offState) <= (offState * FUZZINESS / 100)) {
#ifdef DEBUG
      Serial.print(" (ok)");
#endif
    } else {
#ifdef DEBUG
      Serial.print(" (x)");
#endif
      // we didn't match perfectly, return a false match
      return false;
    }
    
#ifdef DEBUG
    Serial.println();
#endif
  }
  // Everything matched!
  return true;
}

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino”