Electronic – arduino – How to get consistent codes from IR receiver module TSOP1738

arduinoinfraredwireless

I'm doing some experiments with a TSOP1738 receiver module. I picked up a small 'remote control' (aka an IR transmitter) from my car audio system and I'm trying to send some command over to a robot. I have no idea what encoding this particular remote control is using. I hooked up the TSOP module to an oscilloscope and figured out the signals coming out of it. I decoded it like the following.

  • Initial burst is for around 4000+uS.
  • Logical 1 is for around 2000+uS
  • Logical 0 is for around 600+uS

From this information I decoded the commands sent by the remote control and it looked pretty reasonable. I wired up the TSOP module to an Arduino and used some bit-by-bit work on the data coming up from the IR receiver module. I lately found that all the first 16-bit coming from it was exactly the same for all buttons I press on the remote control. So I stripped it off and used the last 16 bits for making an unsigned int key value for each buttons on the remote control. I found it working as expected. But the problem I face right now is that, I'm getting different key values for the same button press! That is, if I press the power button on the remote control twice, both the presses gives me different data. How can I make this consistent? Is this some kind of noise that causes the problem?

Here is the arduino sketch I use.

int irPin = 2;          //Sensor pin 1 wired to Arduino's pin 2
int statLED = 13;       //Toggle the status LED every time Power is pressed
int start_bit = 2200;   //Start bit threshold (Microseconds)
int bin_1 = 2000;       //Binary 1 threshold (Microseconds)
int bin_0 = 600;        //Binary 0 threshold (Microseconds)

void setup() {
    pinMode(statLED, OUTPUT);
    digitalWrite(statLED, LOW);
    pinMode(irPin, INPUT);
    Serial.begin(9600);
    Serial.println("Waiting: ");
}

void loop() {
    unsigned int key = getIRKey();
    Serial.print(" > ");
    Serial.println(key);
}

int getIRKey() {
    int data[32];
    int i;

    while(pulseIn(irPin, LOW) < start_bit);//Wait for a start bit

    for(i = 0 ; i < 32 ; i++)
        data[i] = pulseIn(irPin, HIGH);    //Start measuring bits, only high    pulses needed.

    int key_data[16];                      //First 16 bits arw the same for all keys.
    for(i = 16 ; i < 32 ; i++)  {          //Parse them
        Serial.print(data[i]);
        Serial.print(" ");
        if(data[i] > bin_1)                //is it a 1?
            key_data[i-16] = 1;
        else if(data[i] > bin_0)           //is it a 0?
            key_data[i-16] = 0;
        else
            return -1;                     //Flag the data as invalid;
    }

    Serial.print(" = ");
    unsigned int result = 0;
    for(i = 0 ; i < 16 ; i++)  {           //Convert key_data bits to integer
        Serial.print(key_data[i]);
        if(key_data[i] == 1)
            result |= (1 << i);
    }
    return result;
}

And this is the output of the above sketch, when I press the same button on the remote control a couple of times.

2162 725 682 695 694 694 658 730 652 2094 2165 2167 2171 2164 2167 2128  = 1000000001111111 > 65025
2095 721 658 692 696 627 659 650 650 2090 2053 2173 2139 2093 2098 2129  = 1000000001111111 > 65025
2124 2128 2127 654 619 691 620 654 649 648 610 2131 2132 2131 2127 2091  = 1110000000011111 > 63495
2133 2103 2089 613 610 682 619 654 655 654 617 2127 2124 2124 2137 2132  = 1110000000011111 > 63495
2125 2127 2133 654 619 649 612 645 649 648 619 2136 2133 2123 2094 2124  = 1110000000011111 > 63495
2093 2089 2098 657 655 610 649 612 646 648 654 2098 2098 2093 2089 2090  = 1110000000011111 > 63495
2099 2123 2091 684 655 654 657 621 620 683 612 2124 2128 2136 2133 2091  = 1110000000011111 > 63495
2104 2095 2128 657 649 611 688 627 657 665 658 2056 2094 2060 2169 2132  = 1110000000011111 > 63495
2127 1952 2099 692 620 620 657 648 610 682 611 2098 2132 2136 2127 2125  = 1010000000011111 > 63493
2091 649 648 611 683 621 655 655 621 2090 2090 2094 2102 2099 2102 2090  = 1000000001111111 > 65025
2127 649 620 654 655 657 620 683 612 2125 2090 2135 2135 2123 2091 2125  = 1000000001111111 > 65025
2093 649 655 619 691 620 654 684 646 2091 2090 2102 2098 2125 2094 2091  = 1000000001111111 > 65025
2098 655 648 612 682 611 646 658 655 2099 2090 2094 2089 2098 2101 2099  = 1000000001111111 > 65025
2161 694 658 691 697 646 612 686 615 2127 2133 2136 2124 2125 2131 2135  = 1000000001111111 > 65025
2101 2167 2090 683 646 623 655 621 694 691 648 2166 2094 2064 2173 2161  = 1110000000011111 > 63495
2090 2097 2128 658 695 655 658 688 684 615 649 2095 2099 2101 2095 2090  = 1110000000011111 > 63495
2162 729 661 623 697 617 649 722 650 2095 2173 2066 2164 2059 2131 2170  = 1000000001111111 > 65025

Best Answer

In my experience when decoding IR signals it is almost always better to be very pedantic about the signal timings. For example, just accumulating the HIGH times in an array will work most of the time, but will not cope with the occasional noise burst. You need to validate each HIGH and each LOW period.

As another example of the need to be careful with timings, for the "start" signal, you only detect that the initial LOW period (i.e. 38 kHz IR burst) is longer than the minimum (2200)...but what if it is way longer due to a noise burst? And what if the quite time immediately after that is too long or too short? You'll trigger falsely, and then continue to try to make sense of the possibly still noisy signal that follows and get an unreliable result.

What I would suggest is that you use your scope and timing figures to get a feel for the correct timings (which you have largely done), and write your code to detect whether each individual bit is valid (that is, both LOW and HIGH times are within tolerance) and, if an invalid bit is encountered, ignore all further transitions for say 100 ms before listening again for a "start" sequence. The aim is to never attempt to process a command unless it is known to be parsed completely.

Also (probably less important) the 16 bits that seem to be always the same may not always be that way. You may just not have seen the cases where they are significant. Maybe they are for a device address and/or flags (such has "key pressed and held"). In some protocols, the signal sequence changes significantly when a remote key is pressed and held, and others toggle a bit in the "command" field as each command is issued.

I think a good way to rigorously parse an IR signal is by using a finite state machine (FSM). For an example you can see my open source project at http://sourceforge.net/projects/irk-usb/ ...it's not for arduino, but it should be helpful nonetheless.