Geht das jetzt nur um Tastenabfragen an den Inputs?
Dann würde ich NICHT den PortChange-Interrupt verwenden, sondern einen Timer im ms-Bereich. Der alleine bewerkstelligt schon die Entprellung.
Der Code gestaltet sich vielleicht mithilfe einer Loop etwas schöner, wobei ich auch gleich das Allgemeingültige vom Anwendungsspezifischen trennen würde:
Code:
uint8_t prevPINA;

void InitKeys()
{
    prevPINA = PINA;
}

ISR (TIM0_OVF_vect)
{
  uint8_t actPINA = PINA; //buffer actual state
  uint8_t chPINA = prevPINA ^ actPINA;   //get changes with XOR
  uint8_t setPINA = chPINA & actPINA;    // get new set pins
  uint8_t clPINA = chPINA & ~actPINA;    // get new cleared pins

  prevPINA = actPINA; //save actual PINA in prevPINA for next ISR call 
    
  for (uint8_t i = 0; i<8; i++)
  {
    if ((setPINA >>i) & 0x01)
      KeyDown(i);
 
    if ((clPINA >>i) & 0x01)
      KeyUp(i);
  }
}
InitKeys wird einmalig nach dem Controllerreset aufgerufen, die ISR wäre hier z.B. der TimerOverflow.

Das Applikationsspezifische:
Code:
#define KEY_ENTER 0
#define KEY_ESC 1
#define KEY_UP 6
#define KEY_DOWN 7

void KeyDown(uint8_t key)
{
  switch (key)
  {
    case KEY_ENTER:
        //TODO
        break;

    case KEY_ESC:
        //TODO
        break;


  }


}


void KeyUp(uint8_t key)
{
    //Das gleiche in grün
}
Ob man nun alle Pins mit Tasten belegt hat oder nur einige, ist dem allgemeinen Teil egal. Das wird erst durch die cases in den Switches entschieden.

(nicht kompiliert, daher ohne Gewähr! Aber mal so als Idee)