Help with reading Ir code

I’ve been trying to make a custom IR Code reader just for learning. I know that I can do this the Arduino library but I want to know how to make the library my self and learn more Ir signals while doing it.

I made a simple function that works sometimes. It records IR signals each time but will I think there is a problem somewhere.Maybe a timing problem. When I send the recorded signal, sometimes it works, sometimes it doesn’t. I looked through it and realized that the problem is my recording function which is posted below. There is something wrong with it. Can anyone here figure out what the problem is? The transmit Ir code function is fine. Just the recording function…

For example when I record the IR value, it will only work 1 out of 10 tries. It will generate a valid value once out of about 10 tries. Sometimes it will generate 3 valid values out of 10 times. When I say valid values, I mean pair of values that works if sent through IR led.

void recordIRPattern() {
#define IRpin_PIN      PIND
  int IrReceiverPin = 2;
  bool keepReading = true;
  long RESPONSE_TIMEOUT = 5000; //Seconds second wait
  long tempTimeOut = RESPONSE_TIMEOUT + millis();
  bool pinFirstTimeHigh = true;

  unsigned long pinHighTime = 0;
  unsigned long pinLowTime = 0;

  int pulseAmount = 0;
  unsigned long pauseWaitTime[5000];

  Serial.println("Started recoring ");

  bool oldPinStatus = false;

  while ((keepReading) && (millis() < tempTimeOut)) {
    //Check if pin is high
    if (IRpin_PIN & (1 << IrReceiverPin) && !(oldPinStatus)) {
      //Check if this is the first name pin is going high
      if (pinFirstTimeHigh) {
        //get time pin went high, increement pulseAmount then make pinFirstTimeHigh false
        pinHighTime = micros();
        pulseAmount++; //Because of this first increementation, we use pulseAmount-1 each time we want to update the value in the index
        oldPinStatus = true;
        pinFirstTimeHigh = false;
      } else {

        //Not first time High(get time pin went high)
        //get time pin went high, calcualte & and save how long pin was low then increement pulseAmount
        pinHighTime = micros();
        pauseWaitTime[pulseAmount - 1] = pinHighTime - pinLowTime;
        pulseAmount++;
        oldPinStatus = true;
      }

    } else if (! (IRpin_PIN & _BV(IrReceiverPin)) && (oldPinStatus)) {
      //Ignore low reading if pinFirstTimeHigh is true
      if (pinFirstTimeHigh) {
      } else {

        //get time pin went low, calcualte & and save how long pin was high then increement pulseAmount
        pinLowTime = micros();
        pauseWaitTime[pulseAmount - 1] = pinLowTime - pinHighTime;
        pulseAmount++;
        oldPinStatus = false;
      }
    }
  }
  //The amount of pulse is pulseAmount-1;
  pulseAmount--;

  //Make sure we dont have a nagative number
  if (pulseAmount < 0) {
    pulseAmount = 0;
  }

  Serial.print("We got: ");
  Serial.print(pulseAmount);
  Serial.println(" bytes");

  Serial.print("They are: ");
  for (int i = 0; i < pulseAmount; i++) {
    Serial.print(pauseWaitTime[i]);
    Serial.print(" ");
  }
}

Which Arduino are you using? Allocating a 20kB array on the stack is going to blow up UNO and MEGA.

  unsigned long pauseWaitTime[5000];

Pete

Uno. I am not sure that is the problem because I changed it to 400 and the problem is still there. Also with 5000, the values recorded in the array are still being printed and no weird things occurred. The rest of my code runs smoothly.

The transmit Ir code function is fine

You know that how ?

If you have seen this post at the top of the page Read this before posting a programming question you will understand the need to post all of your program to help with understanding the problem.

unsigned long pauseWaitTime[5000];takes how many bytes ?

Futhermore, what is
#define IRpin_PIN      PINDdoing in the middle of a function ?

I know that the transmit code is working 100% of the time because I've tested it for hours with a static IR code and it works. For example, when I reset the arduino and press the POWER button on my tv power remote, it stores the value and then calls the send from the receive function. Lets just say that it worked this time and the Arduino was able to send the signal to the tv and my tv turned on or off, I assume that it worked. I then copied the values I received and hardcoded it into the send function.

Below is an example of valid power code I received:

unsigned long sampleone[] = {228, 872, 932, 816, 360, 792, 384,
                      768, 1036, 740, 440, 732, 448, 704,
                      476, 696, 476, 25868, 2416, 556, 1244,
                      560, 620, 556, 1244, 552, 624, 552,
                      1252, 552, 620, 552, 624, 552, 1252,
                      548, 632, 540, 636, 540, 632, 544,
                      636
                     };

When I pass the sampleone array variable with the number of bytes to my send function, it works. It has never failed to work. It works 100% of the time.

To make it short, If I hardcode any value that worked with record function, it works. If I hardcode any value I received that didn't work, it won't work. This is the experiment I did to decide that the record function is the problem. I hope this clears things out.
The function I am using is modified version of Ir transmit from Adafruits. Basically what I am doing in the send function is looping over the arrays and going HIGH, LOW and delaying based on the value i n the array. Below is the link of what the send function looks like:

I put #define IRpin_PIN PIND in the receive function to so that anyone in this forum can easily compile the function and test it themselves. The function is actually on top of my program not in my function but that's not a problem too. I use this to read pins quickly so that I won't have to use digitalRead() which may not be fast enough for what I am doing.

unsigned long pauseWaitTime[5000];
*takes how many bytes ? *

It doesn't take a fixed value of number of bytes. I am making this to support any remote and the number of bytes depends on the number of bytes the remote sends. If the remotes sends more than 5000 bytes, then there will be a buffer overflow which I don't think is the problem now. The highest bytes I got from my remote is about 300 so I am safe.

It doesn't take a fixed value of number of bytes. I am making this to support any remote and the number of bytes depends on the number of bytes the remote sends.

NO IT DOES NOT. You have allocated an array of fixed size - 20,000 bytes. Very few Arduinos have that much memory AND those that do have dedicated sub-forums.

PaulS:
NO IT DOES NOT. You have allocated an array of fixed size - 20,000 bytes. Very few Arduinos have that much memory AND those that do have dedicated sub-forums.

What's your point? Since I changed it to 400, the problem is the array size which is 400?

400 could still be to big,

you are using a long that means 400*4 bytes = 1600 bytes.
that leaves about 400 bytes over for all other code.

i believe including Serial should make the arduino crash already.
try it with 10 or something, if the problem still exists then you can be sure it's not i that part

you can use this function to check your mem usage:

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

when i use it and it returns about 130 i ran out of memory. ( so it's not 100% accurate )

An UNO has 2048 bytes of ram. Your array uses 1600 of those bytes. That leaves very little room for anything else and, since you have only posted the code for the one function, we have no way of knowing what else is using up that space.

The largest value in your sampleone array was 25868. If you can be sure that the values that you read do not exceed 65535, you could declare the array as "unsigned int" which would cut the space requirement in half.

Pete

Below is an example of valid power code I received:…

The signal you posted is a ‘partial’ SONY power signal (0xA90)…see attached image.

SONY format IR signals are sent 3 times for each button press on the remote.

However, as you may see from the attached image - the signal you have captured is only part of the complete signal. For a good signal you need to repeat the good part 3 times. So a valid signal would be something like:

unsigned long sampleone[] = {2416, 556, 1244,560, 620, 556, 1244, 552, 624, 552,1252, 552, 620, 552, 624, 552, 1252,548,25868,2416, 556, 1244,560, 620, 556, 1244, 552, 624, 552,1252, 552, 620, 552, 624, 552, 1252,548,25868,2416, 556, 1244,560, 620, 556, 1244, 552, 624, 552,1252, 552, 620, 552, 624, 552, 1252,548};

(note the 26ms or 25,868 uSecs spacing between the repeated signals

To improve the performance of the signal you could correct the timings by replacing the numbers above to the nearest of 2400,1200,600,26000

AnalysIR, I owe you a bottle of beer :slight_smile: :slight_smile: . I knew the problem was NOT memory issue.
The is the pseudo code that fixed it:

if irsig >= 0 && irsig <= 800 
        irsig  = 600;
      else if irsig  > 800 && irsig  <= 1700
        irsig  = 1200;
      else if irsig  > 1700 && irsig  <= 3500
        irsig  = 2400;
      else if irsig  >= 20000 && irsig  <= 28000 
        irsig  = 26000;

I looped over the received Ir value and updated it with the code above before sending it to my Tv. I also tested it 200 times and it worked 200 times with no single fail. Just like I said before, I know I can do this with available Arduino library but I just want to learn how Ir transmission works by making my own simple library.

The Tv I am using is Westinghouse Tv NOT Sony. I am sure the signal is similar with Sony Tv and it may work with Sony Tv.

I have 3 more questions about this.

  1. The four numbers you mentioned 2400,1200,600,26000, are they only for Sony Tvs or is it standard number found on every IR powered devices? If not, what other numbers do other tv manufacturers use?

  2. Will this work with other Tv made by Toshiba, Samsung and others?

  3. Since your solution solved the problem, this is a sign that the values Arduino calculated is way off from the value it is suppose to be receiving from the remote. For example, when I receive 400 from the remote, that 400 is means 600 and has to be changed to 600. Sometimes I get 552 instead of 600. If the value is between 580 and 600, it would be ok.

Where is my calculation wrong? I did NOT use digitalRead() because of problems like this… Is the micros() function NOT precise? Any ideas?

Once again, thanks for your solution :smiley: .

Many manufactures just rebrand TVs and other devices from each other. So no surprise it is a Sony dressed up as a US TV. You can never tell until you need spares/repair. Maybe Sony just manufacture it to order.

The timings provided are for the Sony IR protocol only, others use different timings.

Other devices most likely will have different IR protocols & timings...there are many hundreds for common TVs, not to mention other media devices & aircons etc etc (maybe 10s of thousands overall).

IR receivers distort the timings by +/-100 uSecs or more. This is normal & decoders account for this. There is a good post on our blog about this, with more details. Sometimes the timings can be even worse just because of interference or reflections.

Micros() should be accurate to +/- 4 uSecs on Arduino.

If you purchased a 'cheapo' IR receiver that could explain your issues. Vishay are pretty good manufacturer of quality IR receivers.

To understand IR protocols search for "sbprojects ir" which is a great resource & lots of IR related posts on our own blog.

That makes sense. I am using normal Ir photo-transistor(two terminals) instead of the one with with 3 terminals are that made to receive fixed IR frequency and filter out the others. It works so I am fine with it.

I went to your website and I like it. Is there a link to it that shows other numbers for other manufactures like the Sony 2400,1200,600,26000?

see the search suggetion in my previous post!

also available in both the IRremote & IRLib libraries & via online search.

Otherwise - no simple/easy answer to that.