Eu acho que a sobreposição de nomes de vetores e pinos é confusa
Isto é!
A razão pela qual existem 8 pinos externos diferentes para um vetor de interrupção é facilitar o layout da PCB ou usar um pino diferente se houver um conflito com outra função de pino.
Estou correto ao pensar ... a única maneira de determinar quais pinos causaram a interrupção é registrar seu estado após cada interrupção e comparar os valores anteriores e atuais de todos os pinos ativados no PCMSKn?
Basicamente, digamos que você só se preocupa com PB0 (PCINT0) e PB1 (PCINT1). Portanto, a máscara de habilitação de alteração de pino PCMSK0 seria definida como 0x03.
// External Interrupt Setup
...
volatile u_int8 previousPins = 0;
volatile u_int8 pins = 0;
ISR(SIG_PIN_CHANGE0)
{
previousPins = pins; // Save the previous state so you can tell what changed
pins = (PINB & 0x03); // set pins to the value of PB0 and PB1
...
}
Então, se pins
0x01, você sabe que foi PB0 ... E se você precisa saber o que mudou, precisa compará-lo com previousPins
, exatamente o que você pensou.
Lembre-se de que, em alguns casos, pins
pode não ser preciso se o pino mudar de estado desde a interrupção, mas antes pins = (PINB & 0x03)
.
Outra opção seria usar vetores de interrupção separados com um pino de cada vetor, para que você saiba qual deles foi alterado. Mais uma vez, isso também tem alguns problemas, como prioridade de interrupção e uma vez que a CPU entra no ISR, o mundial de interrupção bit de habilitação I-bit
em SREG
serão apagados de forma que todas as outras interrupções estão desativadas, mas você pode configurá-lo dentro da interrupção, se quiser, que ser uma interrupção aninhada.
Para obter mais informações, consulte a nota do aplicativo da Atmel, Usando interrupções externas para dispositivos megaAVR.
Atualizar
Aqui está um exemplo de código completo que acabei de encontrar aqui .
#include <avr/io.h>
#include <stdint.h> // has to be added to use uint8_t
#include <avr/interrupt.h> // Needed to use interrupts
volatile uint8_t portbhistory = 0xFF; // default is high because the pull-up
int main(void)
{
DDRB &= ~((1 << DDB0) | (1 << DDB1) | (1 << DDB2)); // Clear the PB0, PB1, PB2 pin
// PB0,PB1,PB2 (PCINT0, PCINT1, PCINT2 pin) are now inputs
PORTB |= ((1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2)); // turn On the Pull-up
// PB0, PB1 and PB2 are now inputs with pull-up enabled
PCICR |= (1 << PCIE0); // set PCIE0 to enable PCMSK0 scan
PCMSK0 |= (1 << PCINT0); // set PCINT0 to trigger an interrupt on state change
sei(); // turn on interrupts
while(1)
{
/*main program loop here */
}
}
ISR (PCINT0_vect)
{
uint8_t changedbits;
changedbits = PINB ^ portbhistory;
portbhistory = PINB;
if(changedbits & (1 << PB0))
{
/* PCINT0 changed */
}
if(changedbits & (1 << PB1))
{
/* PCINT1 changed */
}
if(changedbits & (1 << PB2))
{
/* PCINT2 changed */
}
}