Penso che la sovrapposizione dei nomi di vettori e pin sia confusa
È!
La ragione per cui vi sono 8 pin esterni diversi per un vettore di interruzione è per semplificare il layout del PCB o l'uso di un pin diverso in caso di conflitto con un'altra funzione pin.
Sono corretto nel pensare ... l'unico modo per determinare quali pin hanno causato l'interrupt è quello di registrare il loro stato dopo ogni interrupt e confrontare i valori precedenti e attuali di tutti i pin abilitati in PCMSKn?
Praticamente, diciamo che ti interessa solo PB0 (PCINT0) e PB1 (PCINT1). Quindi la maschera di abilitazione cambio pin PCMSK0 sarebbe impostata su 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
...
}
Quindi se pins
è 0x01 sai che era PB0 ... E se hai bisogno di sapere a cosa è cambiato devi confrontarlo previousPins
, praticamente esattamente quello che pensavi.
Tieni presente che in alcuni casi, pins
potrebbe non essere preciso se il pin ha cambiato stato dall'interruzione ma primapins = (PINB & 0x03)
.
Un'altra opzione sarebbe quella di utilizzare vettori di interruzione separati con un pin da ciascun vettore in modo da sapere quale è cambiato. Ancora una volta, questo ha anche alcuni problemi, come la priorità di interruzione e una volta che la CPU entra nel ISR, il globale interrupt bit di abilitazione I-bit
in SREG
saranno cancellati in modo che tutti gli altri interrupt sono disattivati, anche se è possibile impostare all'interno del interrupt, se si vuole, che avrebbe essere un interrupt nidificato.
Per ulteriori informazioni, dai un'occhiata alla nota dell'app di Atmel Utilizzo di interrupt esterni per dispositivi megaAVR.
Aggiornare
Ecco un esempio di codice completo che ho appena trovato qui .
#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 */
}
}