Problem Interrupt based IR decoder

Hi folks,

I'm trying to develop (and understand) my own interrupt based IR decoder (please excuse my worse english :roll_eyes:).

What I've done so far:

  • connected a TSOP4838 to digital pin 11 on my arduino UNO.
  • enabled pin change interrupt for PCINT7..0
  • set pin change interrupt mask to enable for digital pin 11 (PCINT3)

What is working:

  • when I press a key on my RC I get the recorded counter values

I don't know how to write code to measure the exact low an high value durations in the ISR :~

So here is my code:

volatile uint8_t irPin = 11;
volatile uint8_t irqFlag = 0;
volatile unsigned long lowDuration;
volatile unsigned long highDuration;
volatile unsigned long totalDuration;

void setup() {
  pinMode(irPin, INPUT);      // Set Arduino pin 11 (PCINT3/PORTB3) as input
  digitalWrite(irPin, HIGH);  // Set pull-up resistor
  
  PCICR  |= _BV(PCIE0);     // Enable Pin Chane Interrupt 0 for PCINT7..0
  PCMSK0 |= _BV(PCINT3);    // Enable Pin Change Interrupt for digital pin 11 (PCINT3)
  
  Serial.begin(115200);
  Serial.println ("Waiting for interrupts..");
  interrupts();
}

void loop() {
  if (irqFlag == 1) {
    Serial.println("Interrupt detected!");
    //Serial.println(PINB & _BV(PINB3), BIN);
    Serial.print(highDuration); Serial.print("-"); Serial.println(lowDuration);
    Serial.println(totalDuration);
    irqFlag = 0;
  }
}

ISR(PCINT0_vect) {
  noInterrupts();    // Disable all interrupts
  uint16_t lowCounter;
  uint16_t highCounter;
  
  while ((PINB & _BV(PINB3)) == 0) {
    lowCounter++;
  }
  
  while ((PINB & _BV(PINB3)) == 1) {
    highCounter++;
  }
  
  while ((PINB & _BV(PINB3)) == 0) {
    lowCounter++;
  }
  
  lowDuration=lowCounter;
  highDuration=highCounter;
  totalDuration=lowCounter + highCounter;
  
  irqFlag = 1;       // Set interrupt flag to notify loop()
  interrupts();      // Enable all interrupts
}

I don't know how to write code to measure the exact low an high value durations in the ISR

Why not look at how Ken Shirriff did it? Testing the Arduino IR remote library

uint16_t lowCounter;
  uint16_t highCounter;
  
  while ((PINB & _BV(PINB3)) == 0) {
    lowCounter++;

Haven't you forgotten to initialise these counters?

ISR(PCINT0_vect) {
  noInterrupts();    // Disable all interrupts
  
  irqFlag = 1;       // Set interrupt flag to notify loop()
  interrupts();      // Enable all interrupts
}

Interrupts are already disabled during an ISR. No need to do it again. No need to do it again.

Interrupts are already enabled when an ISR ends. No need to do it again. No need to do it again.

OK, now I've initialized the counters with 0.
The resulting output ist below:

Interrupt detected!
0-0
0
Interrupt detected!
0-0
0

So still not what I've expected :disappointed_relieved:

@PaulS: Thanks for this information. I wasn't aware of that, I've fixed that. Ken Shirriff used a timer instead of using interrupt - I'm not sure if I can combine both.

I don't know how to write code to measure the exact low an high value durations in the ISR

Having an ISR loop like that is not a good idea.

Much better would be to remember the time the pin goes low (use millis() or micros() ) and then leave the interrupt. Then when the pin changes again make a note of the new time. The duration is one minus the other.