This is a bit of a blurb I wrote a while back that tries to walk someone through the use of pin change interrupts.
Before we start, understand that we are talking about the atmega328p microcontroller which is used in the Uno, Nano, Micro and a host of other boards. As long as you're using AVR-GCC as the compiler and include avr/io.h with the defined processor being AVR_ATmega328P the translations will work. If you're usimg the Arduino IDE or ATStudio you do not really need to know this as it is done 'under the hood' for you. As this is kind of a tutorial though, I'll mention it for completeness.
Next, to make sure we're on the same page, see that you have the datasheet handy. I'll use what I believe to be the latest version dated 11/2016. If you need it, the following link will deliver it to you.
328P datasheet
INT0 and INT1 are the external interrupts attached to Arduino pins 2 and 3 respectively. We will not be discussing them here.
The sections of the datasheet that mean the most for this discussion begin on page 92, section 17.2.4, the Pin Change Interrupt Control Register.
Before that however, I think it useful to have a table that shows the mapping of the pins. Referring to the diagram on page 14,
PCINT Port Pin Arduino Uno
PCINT0 PB0 8
PCINT1 PB1 9
PCINT2 PB2 10
PCINT3 PB3 11
PCINT4 PB4 12
PCINT5 PB5 13
(PB6 and 7 are used for the crystal)
PCINT8 PC0 14/A0
PCINT9 PC1 15/A1
PCINT10 PC2 16/A2
PCINT11 PC3 17/A3
PCINT12 PC4 18/A4
PCINT13 PC5 19/A5
(PC6 and 7 are not avaiable on the Uno)
PCINT14 reset
PCINT15 doesn't exist
PCINT16 PD0 0
PCINT17 PD1 1
PCINT18 PD2 2
PCINT19 PD3 3
PCINT20 PD4 4
PCINT21 PD5 5
PCINT22 PD6 6
PCINT23 PD7 7
Ok so far? Go back to page 92 and read from the bottom up.
PCIE0: Pin Change Interrupt Enable 0
Handles PCINT[7:0], that's Atmel nomenclature for PCINT7, PCINT6, ... , PCINT0 which correspond the the pins on PORTB.
Similarly, PCIE1 handles PCINT[14:8] aka PORTC leaving PCIE2 for PORTD and PCINT[23:16].
Now look at the top of the page where you see the Pin Change Interrupt Control Register and the lower three bits reflect the PCIE we just talked about. Writing a 1 to any of these bit positions enables the interrupts for that port. In our case we want A0 - PCINT8 which is part of the group under PCIE1.
So you can:
PCICR |= 1 << PCIE1; or
bitSet(PCICR,PCIE1); or
bitSet(PCICR,1); or
PCICR |= 0B00000010; or
bitWrite(PCICR,1,1); or
bitWrite(PCICR,PCIE,HIGH); or
on and on ...
What you have just done is enable interrupts for the entire group (port) but as yet no interrupts are active. To activate interrupts on a specific pin in that group, you need to address the mask for that particular grouping. The masks are detailed on pages 94-96 with the mask port PCIE1 on page 95. Again skip to the bottom and read first confirming that PCMSK1 indeed enables PCINT8 thru PCINT14 and we see now from the register diagram that PCINT8 maps to bit position 0. As before we can:
PCMSK |= 1 << PCINT8; or any one of the other methods that meets your fancy.
Having done that now any level change on pin C0/A0/14/PCINT8 will fire the interrupt that deals with that group. Not here that there is one interrupt for each of the groups, not the individual pins. Any pin activated by writing a 1 to the corresponding bit position in its respective PCIE will trigger the interrupt. It is up to your interrupt service routine to determine which is the culprit. This is often done by reading the entire port and then comparing that reading with a previous value and noting the change(s?). As in this particular case we are only dealing with a single pin we know that any interrupt is a result of it changing. Turning to page 82 we see that the interrupt is at address 0x0008 which we know will jmp us to the routine named ISR(PCINT1_vect) so in your code,
ISR(PCINT1_vect)
{
// your interrupt service routine goes here
}
That just about does it. All of this presupposes that global interrupts are turned on. sei() will take care of that as will SREG |= 0B10000000;.
A couple of little extras, perhaps for convenience, switching the interrupt off/on, which you may choose to do while servicing it so as not to be sidelined;
#define enableA0 PCMSK1 |= 0B00000001
#define disableA0 PCMSK1 &= 0B11111110
Of course you can rename enableA0 and disableA0 to anything you like.
Good luck. Let me know if you're still confused. I've keyed this in as slowly as I could.
dkw