5
\$\begingroup\$

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
\$\endgroup\$
  • 1
    \$\begingroup\$ EEVblog #506 - IR Remote Control Arduino Protocol Tutorial \$\endgroup\$ – RedGrittyBrick Aug 14 '13 at 17:53
  • \$\begingroup\$ @RedGrittyBrick I actually seen Dave's video this morning and that's why I started to work on this project. :) Could you figure out why I get inconsistent data out of the TSOP module? \$\endgroup\$ – Subin Sebastian Aug 14 '13 at 17:58
  • 1
    \$\begingroup\$ Are you sure your remote uses a 38 KHz carrier? The 1738 is locked to 38 KHz, which is not the only carrier frequency in use. It appears from the data received, that your remote could be 36 KHz or 40 KHz, both close enough to be detected by the 1738, but with invalid data frames. An easy check: Connect a photodiode (or in a pinch, a water-clear red LED) to oscilloscope probes, then see what carrier frequency shows up when a button is pressed on the remote while pointing it towards the photodiode or LED. \$\endgroup\$ – Anindo Ghosh Aug 14 '13 at 18:03
  • 1
    \$\begingroup\$ Your bin1 threshhold is too high, you're reading 2127 1952 2099 as 101 when it's clearly 111. The rest look like timing issues - problems identifying start of data. I'd follow Anindo's advice then check whether slow serial.print could be affecting anything (I'm not familiar with the functions used in your code). The other possibility is that long-press starts a secondary button function. \$\endgroup\$ – RedGrittyBrick Aug 14 '13 at 18:14
  • 1
    \$\begingroup\$ @Napster You can also find out carrier frequency by probing the legs of the LED(s) inside the remote, while pressing a button. You would probably not have any trouble attaching scope probes to the LED as remotes often use through-hole LEDs with legs kept long to reach the aperture in the plastic case. Source: I just opened up a few remotes to check this :-) \$\endgroup\$ – Anindo Ghosh Aug 15 '13 at 9:46
2
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ +1 for explaining different aspects of the process. Infact, I did what exactly you have explained in your answer. I did a rigorous parsing for exact key code values and anything that violates a timing range, gets ruled out as per my new code here. The problem we have with this approach is that, I have to press the same button multiple times to get it properly registered! That is, most of the key presses gets filtered out as invalid codes! :) \$\endgroup\$ – Subin Sebastian Aug 15 '13 at 15:50
  • 1
    \$\begingroup\$ I just noticed that the pattern looks like the NEC IR protocol remotecentral.com/features/irdisp4.htm ... the 32 bits consists of 4 x 8-bit bytes: [A, ~A, C, ~C] where A = address, C = command, and ~x means ones complement of x (i.e. inverted). So an additional safety check you could do is to make sure that (A xor ~A) == 0 and (C xor ~C) == 0. From your samples, it seems that there are two commands 0x80 and 0xE0 that represent the same button. A hint is that they are clustered together in time so it could be a "button rapid press" indicator mechanism. \$\endgroup\$ – aja Aug 16 '13 at 8:57
  • \$\begingroup\$ Yep, it is A,~A,C,~C ofcourse. But still the problem I mentioned in the above comment persists. I have added a screenshot of the signal from the oscilloscope in the blog post here. \$\endgroup\$ – Subin Sebastian Aug 16 '13 at 15:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.