Je pense que le chevauchement des noms des vecteurs et des broches est déroutant
C'est!
La raison pour laquelle il existe 8 broches externes différentes pour un vecteur d'interruption est de faciliter la disposition du PCB ou d'utiliser une broche différente en cas de conflit avec une autre fonction de broche.
Ai-je raison de penser ... la seule façon de déterminer quelle (s) broche (s) a causé l'interruption est d'enregistrer leur état après chaque interruption et de comparer les valeurs précédentes et actuelles de toutes les broches qui sont activées dans PCMSKn?
À peu près, disons que vous ne vous souciez que de PB0 (PCINT0) et PB1 (PCINT1). Ainsi, le masque d'activation de changement de broche PCMSK0 serait défini sur 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
...
}
Donc, si pins
c'est 0x01, vous savez que c'était PB0 ... Et si vous avez besoin de savoir ce qui a changé, vous devez le comparer previousPins
, à peu près exactement ce que vous pensiez.
Gardez à l'esprit dans certains cas, pins
peut ne pas être précis si la broche a changé d'état depuis l'interruption mais avant pins = (PINB & 0x03)
.
Une autre option serait d'utiliser des vecteurs d'interruption séparés avec une broche de chaque vecteur pour que vous sachiez lequel est changé. Encore une fois, cela a aussi des problèmes, comme priorité d' interruption et une fois que l'unité centrale de traitement entre ISR, le bit global d' interruption permettent I-bit
en SREG
sera effacé afin que toutes les autres interruptions sont désactivées, mais vous pouvez le mettre à l' intérieur de l'interruption si vous voulez, ce serait être une interruption imbriquée.
Pour plus d'informations, consultez la note d'application d'Atmel Utilisation des interruptions externes pour les appareils megaAVR.
Mise à jour
Voici un exemple de code complet que je viens de trouver ici .
#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 */
}
}