Myślę, że nakładanie się nazw wektorów i szpilek jest mylące
To jest!
Powodem, dla którego istnieje 8 różnych styków zewnętrznych dla wektora przerwań, jest ułatwienie ułożenia płytki drukowanej lub użycie innego styku w przypadku konfliktu z inną funkcją styku.
Czy mam rację, myśląc ... jedynym sposobem ustalenia, które piny spowodowały przerwanie, jest zapisanie ich stanu po każdym przerwaniu i porównanie poprzednich i bieżących wartości wszystkich pinów, które są włączone w PCMSKn?
Powiedzmy, że dbasz tylko o PB0 (PCINT0) i PB1 (PCINT1). Zatem maska włączania zmiany pinów PCMSK0 byłaby ustawiona na 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
...
}
Więc jeśli pins
jest 0x01, wiesz, że to był PB0 ... A jeśli chcesz wiedzieć, co się zmieniło, musisz to porównać previousPins
, prawie dokładnie to, co myślałeś.
Pamiętaj, że w niektórych przypadkach pins
może być niedokładny, jeśli pin ma stan zmian od momentu przerwania, ale wcześniej pins = (PINB & 0x03)
.
Inną opcją byłoby użycie oddzielnych wektorów przerwań z jednym pinem z każdego wektora, abyś wiedział, który jest zmieniany. Ponownie, to ma również pewne problemy, takie jak przerwania priorytetu i raz CPU wchodzi do ISR, globalny przerwania umożliwić bit I-bit
w SREG
zostaną usunięte tak, że wszystkie inne przerwania są wyłączone, chociaż można ją ustawić wewnątrz przerwania jeśli chcesz, to byłoby być zagnieżdżonym przerwaniem.
Aby uzyskać więcej informacji, zapoznaj się z notatką aplikacji firmy Atmel Korzystanie z zewnętrznych przerwań dla urządzeń megaAVR.
Aktualizacja
Oto kompletny przykład kodu, który właśnie tu znalazłem .
#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 */
}
}