IR Decoding Issues with ATMega328p

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm using an ATMega328p to try and decode the NEC protocol from a remote I have.  The signal is being picked up by a TSOP38238 ir receiver and sent to the input capture pin (ICP1/PINB0 on my mega).  I have the input capture interrupt set up, and am using two LEDs to verify that everything is working as I expect.  Specifically, here's what I expect to happen:

 

  • On Input Capture Interrupt, if listening for the rising edge
    • turn LISTENING_FALLING_LED on, LISTENING_RISING_LED off.  Start listening for falling edge
  • On Input Capture Interrupt, else if listening for the falling edge
    • turn LISTENING_RISING_LED on, LISTENING_FALLING_LED off.  Start listening for the rising edge

 

Since our last interrupt should be triggered by a falling edge (NEC protocol below for reference), the LISTENING_RISING_LED should be on and stay on.

 

 

Instead, the opposite happens:

  • I press a button the IR remote
  • LISTENING_FALLING_LED turns on and stays on.  LISTENING_RISING_LED turns on immediately and turns off immediately

 

What am I doing wrong?

 

#define F_CPU 16000000L
#define LISTENING_FALLING_LED PINC0
#define LISTENING_RISING_LED PINC3

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>

bool icp_listening_for_rising();
bool icp_listening_for_falling();
void icp_listen_for_rising();
void icp_listen_for_falling();

int main(void) {

    DDRC = (1 << LISTENING_FALLING_LED) | (1 << LISTENING_RISING_LED);

    /*
        ICNC1 high to turn on input capture noise canceling
	ICES1 high to initially trigger input capture on rising edge
    */
    TCCR1B = (1 << ICNC1) | (1 << ICES1);

    /* ICIE1 high to enable the input capture interrupt */
    TIMSK1 = (1 << ICIE1);
    sei();

    /* Start Timer1 with a prescaler of 8 */
    TCCR1B |= (1 << CS11);
    while (1) { }
}

ISR(TIMER1_CAPT_vect) {
    if(icp_listening_for_rising()) {

        icp_listen_for_falling();
        PORTC = (1 << LISTENING_FALLING_LED);

    } else if(icp_listening_for_falling()) {

        icp_listen_for_rising();
        PORTC = (1 << LISTENING_RISING_LED);

    }
}

bool icp_listening_for_rising() {
    if(TCCR1B & (1 << ICES1)) {
        return true;
    }
    return false;
}

bool icp_listening_for_falling() {
    return !icp_listening_for_rising();
}

void icp_listen_for_rising() {
    TCCR1B |= (1 << ICES1);
}

void icp_listen_for_falling() {
    TCCR1B ^= (1 << ICES1);
}

 

 

 

Last Edited: Fri. Aug 11, 2017 - 06:39 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you aware of the fact that TSOP38238 has an active-low output? It essentially inverts the optical signal (like many other similar modules).

TSOP38238 input vs output signal

 

If that is already taken care of somehow but problem remains, then I suggest you try hooking up a simple mechanical switch to toggle the signal manually and see the LED activity (but note that you probably need to debounce!).

/Jakob Selbing

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sounds like your signal is active low when you are expecting active high.   A logic analyzer is a useful tool in this case.

 

Jim

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't understand what you're trying to do by checking ICSE1 bit. It should be set according to your needs.

If you want to get rising pulse so set the ICSE1 bit to rising pulse and vice versa.

And since when the ICSE1 bit is in TIMSK and not in TCCR1B?

 

 

MG

I don't know why I'm still doing this hobby

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I want to do something different if the interrupt was triggered by a rising edge (start pulse timer) vs. triggered by a falling edge (end pulse timer).  I need to measure the length of each mark and space to decode the signal, because a logical 0 is on for 562us and off for 562us, where a logical 1 has different timings.  In order to determine if the interrupt was triggered by a rising edge or falling edge, I check the current settings of the ICES1 bit, and then flip it to listen for the other edge.  Does that make sense?

 

I just looked through my code again and I don't think I'm using ICES1 in TIMSK in any spot.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tylerlee12 wrote:
I want to do something different if the interrupt was triggered by a rising edge (start pulse timer) vs. triggered by a falling edge (end pulse timer)

Well I don't have anything to say then.

 

Tylerlee12 wrote:
I just looked through my code again and I don't think I'm using ICES1 in TIMSK in any spot.

Yes you are right. I misread that. I'm sorry for that.

 

 

 

 

MG

I don't know why I'm still doing this hobby

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think your code makes sense. I didn't check it in detail though.

 

Did you read my comment (post #2) regarding the signal being active-low? The LED behavior you are seeing is expected, since the last edge is in fact a rising edge.

/Jakob Selbing

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just checked - yes, that was the problem, and no, I didn't know the signal was inverted from the TSOP382 crying.  Lesson learned - read the datasheet, for everything!!!

 

Follow up questions:

 

  1. Why was the TSOP382 designed to invert the output signal?
  2. Can I use a transistor to flip the output from the TSOP382 back to active high before it hits my microcontroller?  
  3. Would this even be a good idea?  Or would it be better practice to just code for this inverted, active low, signal?

Last Edited: Sat. Aug 12, 2017 - 09:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can you invert the signal with a transistor, (e.g. NFet, of other)?  Yes.

 

Do you need to?  No.

 

If you are writing your own front end driver for the system, then write it for the inverted signal that you are presented with.

 

No point in adding the extra complexity of additional, unnecessary hardware, when that additional hardware does not gain you any new capability.

 

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tylerlee12 wrote:

  1. Why was the TSOP382 designed to invert the output signal?
  2. Can I use a transistor to flip the output from the TSOP382 back to active high before it hits my microcontroller?  
  3. Would this even be a good idea?  Or would it be better practice to just code for this inverted, active low, signal?

1. Most IR receiver modules are designed that way for some reason.

2. Yes.

3. Just change the code.

/Jakob Selbing

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jaksel wrote:

Tylerlee12 wrote:

  1. Why was the TSOP382 designed to invert the output signal?

1. Most IR receiver modules are designed that way for some reason.

 

Along with most of the rest of the 'embedded' world, it's just one of those things you get used to. When using uCs 'active' is usually a logic-low signal.

pragmatic - dealing with things sensibly and realistically in a way that is based on practical rather than theoretical consideration.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There are good electrical reasons for active-low. You can cope with different logic voltages e.g. switching a 12V lamp or 2V led.
Or running on different battery voltages.
Or testing a push-button.
.
The 8051 can only switch active-low. The AVR can switch active-low and active-high.
.
Before the Arduino most LEDs were wired as active-low. However the Arduino user can not be expected to understand this level of complexity. So most Arduino projects prefer active-high.
.
David.