Ich finde die Namensüberlappung von Vektoren und Pins verwirrend
Es ist!
Der Grund, warum es 8 verschiedene externe Pins für einen Interrupt-Vektor gibt, besteht darin, das Layout der Leiterplatte zu vereinfachen oder einen anderen Pin zu verwenden, wenn ein Konflikt mit einer anderen Pin-Funktion besteht.
Bin ich richtig im Denken ... Die einzige Möglichkeit, festzustellen, welche Pins den Interrupt verursacht haben, besteht darin, ihren Status nach jedem Interrupt aufzuzeichnen und die vorherigen und aktuellen Werte aller in PCMSKn aktivierten Pins zu vergleichen.
Nehmen wir an, Sie interessieren sich nur für PB0 (PCINT0) und PB1 (PCINT1). Die Pinwechsel-Aktivierungsmaske PCMSK0 würde also auf 0x03 gesetzt.
// 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
...
}
Wenn pins
also 0x01 ist, wissen Sie, dass es PB0 war ... Und wenn Sie wissen müssen, was sich geändert hat, müssen Sie es vergleichen previousPins
, ziemlich genau das, was Sie dachten.
Beachten Sie in einigen Fällen, dass dies pins
möglicherweise nicht genau ist, wenn der Status des Pins seit dem Interrupt geändert wurde, jedoch vorher pins = (PINB & 0x03)
.
Eine andere Möglichkeit wäre, separate Interrupt-Vektoren mit einem Pin von jedem Vektor zu verwenden, damit Sie wissen, welcher geändert wird. Auch dies hat auch einige Probleme, wie Interrupt - Priorität und wenn die CPU die ISR eintritt, der globale Interrupt - Freigabebit I-bit
in SREG
wird so gelöscht werden , dass alle anderen Interrupts deaktiviert sind, obwohl Sie es innerhalb der Interrupt einstellen können , wenn Sie wollen, das wäre ein verschachtelter Interrupt sein.
Weitere Informationen finden Sie in Atmels App-Hinweis Verwenden externer Interrupts für MegaAVR-Geräte.
Aktualisieren
Hier ist ein vollständiges Codebeispiel, das ich gerade hier gefunden habe .
#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 */
}
}