Pin Change Interrupt - Which Pin, Registers = Mindblown

Hi all, as it says in the title i am struggling to detect which pin has triggered my pin change interrupt and to work out how to read the register correctly. My project is going to eventually use 5 infrared sensors to receive a signal and decode so that it can perform various functions dependent upon what triggered it (imagine a infrared target board) the issue i am having is that although i can measure the pulse lengths and decode the infrared i am unable to get this to work with more than a single sensor or work reliably.

The code uses an interrupt to detect a change on any of the pins 2-7 then checks micros, the PIND register and sets a flag so that we can process the pulse into an array before the 600 microseconds gap ends between pulses to only get the pulses i have an if statement to ignore anything that doesn’t match with the register B11011 (I think that is pin 3 low) however this seems to be slightly buggy it did work fine and then on attaching another sensor even if its not used and covered up it can cause it all to go to hell.

The goal is to have the header pulse detected and then turn off all other interrupts until i have decoded that code from that sensor but to get that far i need to detect what pin i need to turn the interrupt off, i have attached my code below and a serial printout of what i get when it works correctly using 1 sensor the reason i am using an interrupt is because i will also be using other modules such as RF an LCD screen and i need to ensure that its highest priority is receiving the infrared signal.

/* Infrared Reciever using pin change interrupts for multiple sensors.
 * C. Shand
 * Created 2018
 */

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) //Clear bit in byte at sfr address.
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) //Set bit in byte at sfr address.

volatile long unsigned PrevMicros; //sStore time of last pulse.
volatile long unsigned eventTime; //Store current time.
volatile long unsigned timeSinceLastEvent; //Length of Pulses.
int Pulse = 0; //Keep track of how many pulse lengths we record.
unsigned long bits[15]; //Store lengths here.
byte bin[15]; //store register.
volatile byte portDstatus; //For the regist status to be stored.
volatile byte eventFlag; //Set an even flag.

void setup() {
  Serial.begin(57600); //Begin serial communication.
  pinMode(3, INPUT); //Setup pin 3 as input.
  digitalWrite(3, HIGH); //Pullup pin 3 to high (IR reciever goes low on recieving a signal.)
  pinMode(4, INPUT); //Setup pin 4 as input.
  digitalWrite(4, HIGH); //Pullup pin 4 to high (IR reciever goes low on recieving a signal.)
  Serial.println("Reciever Started..."); //Let us know its ready.

  sbi (PCICR, PCIE2); //enable interrupt on PCI2
  sbi (PCMSK2, PCINT23); //pins 7.
  sbi (PCMSK2, PCINT22); //Pin 6
  sbi (PCMSK2, PCINT21); //Pin 5.
  sbi (PCMSK2, PCINT20); //Pin 4.
  sbi (PCMSK2, PCINT19); //Pin 3.
}

void loop() {
  
    Get_IR(); //Process any IR.
  
  if(Pulse >= 7 && eventFlag == 0){ //If there are no events and we have collected all our data.
    for(int i; i < 7; i++){ //Loop through the stored data and display it to the user.
      Serial.print("Pulse length: ");
      Serial.print(bits[i]);
      Serial.print(" - Register: ");
      Serial.println(bin[i], BIN);
    }
    Pulse = 0; //Reset the pulse count.
  }
}

int Get_IR(){
  if(eventFlag == 1 && (eventTime - PrevMicros > 300)){ //Only process pulses longer than 300 (Would be classed as error or noise) and only run if event flag is 1.
  timeSinceLastEvent = eventTime - PrevMicros; //Calculate time ISR has been running.
  PrevMicros = eventTime; //Remember the time now.
  if(portDstatus == B11011){ //Only add pulses that are from the pin going low.
  bits[Pulse] = timeSinceLastEvent; //Store the pulse lengths in array.
  bin[Pulse] = portDstatus; //Store the register status in array.
  Pulse++; //Increment to next part of array.
  }
  eventFlag = 0; //Reset the event flag.
  }
}

ISR (PCINT2_vect){
  portDstatus = PIND; //Record the register status.
  eventTime = micros(); //Note time of ISR.
  eventFlag = 1; //Set the event flag.
}

Any help would be much appreciated their doesn’t seem to be much information “that i can find” about using pin change interrupts without a library to detect the pin with the exception of a few videos saying “now if you want to detect pins you just compare the register status” yes easier said then done apparently.

Any help here?

evanmars i cant make sense of the first link you have there and the second link only tells me its possible which i know i would like some guidance that i can understand or an example of how it is accomplished. Thanks for the links anyhow.

Check out this library: GitHub - GreyGnome/EnableInterrupt: New Arduino interrupt library, designed for Arduino Uno/Mega 2560/Leon
You don't have to use it, but maybe you'll get some ideas by looking at the source code.

their doesn't seem to be much information "that i can find" about using pin change interrupts

The datasheet for the processor has everything you need to know about pin change interrupts.

YT video on Arduino interrupts.

Shandy:
evanmars i cant make sense of the first link you have there and the second link only tells me its possible which i know i would like some guidance that i can understand or an example of how it is accomplished. Thanks for the links anyhow.

Firstly, I will say that I've not done anything with the Pin Change Interrupts apart from the External Interrupts. That said, here's my understanding. The UNO (Atmega328P) has 2 pins that are considered external interrupt pins, each with a dedicated vector to trigger an interrupt. The remaining PCINT pins share 3 vectors together, as you've already discovered. They also share a bit in a register, PCICR, which toggles them on or off as a group. That is to say that PCINT0-7 can be set to trigger or ignore a pin change independent of PCINT 8-14 etc. Additionally, they share a register, PCMSK0, PCMSK1, PCMSK2 respectively which enables that pin in that group. So, you have to set bit 7 of SREG to enable interrupts (enabled by default), And you have to set the bit in PCICR to 1 to enable that group, and the bit in PCMSKn to enable that pin, and then the corresponding bit in PCIFR will be set to 1 when that pin changes state. The bottom line is, you only have 5 interrupt vectors, but that's all you need! For your 5 sensors, tie two to Arduino pins 2 and 3 and the other 3 sensors must be separated, one on one of the pins 8-12, one on one of the pins 14-19 (A0-A5) and the third on one of the pins 4-7. Then in software, set the bits accordingly.

Accomplished! Gougp i had not seen that video before and it helped wonders worth the hour watching, all 5 sensors are rigged up on pins 3-7 and i detect when something is being received and which sensor by, i will post my code but unfortunately i have another issue regarding some odd values that have crept into my code results i had not noticed until now unfortunately i feel posting for help on this here would exceed the scope of this thread so i will open another thread and post completed code here when its solved.