Я думаю, що перекриття назв векторів і штифтів є заплутаним
Це є!
Причина, що існує 8 різних зовнішніх штифтів для переривчастого вектора, - це спростити компонування друкованої плати або використовувати інший штифт, якщо є конфлікт з іншою функцією контакту.
Чи правильно я думаю, що єдиний спосіб визначити, який контактний контакт (и) спричинив переривання - це записати їх стан після кожного переривання та порівняти попередні та поточні значення всіх штифтів, які включені в PCMSKn?
До речі, скажемо, що ви дбаєте лише про PB0 (PCINT0) та PB1 (PCINT1). Отже маска включення зміни контакту PCMSK0 буде встановлена на 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
...
}
Отже, якщо pins
це 0x01, ви знаєте, що це був PB0 ... І якщо вам потрібно знати, що змінилося, вам потрібно порівняти його previousPins
, майже з тим, що ви думали.
Майте на увазі, що в деяких випадках pins
може не бути точним, якщо штифт змінив стан після перерви, але раніше pins = (PINB & 0x03)
.
Іншим варіантом буде використання окремих векторів переривання з одним штифтом від кожного вектора, щоб ви знали, який з них змінюється. Знову ж , це також має деякі проблеми, такі як переривання пріоритету і після того , як центральний процесор входить в ISR, вирішення глобальних переривань біт I-bit
в SREG
буде очищений так , що всі інші переривання відключені, але ви можете встановити його всередині переривання , якщо ви хочете, що б бути вкладеним перериванням.
Для отримання додаткової інформації дивіться примітку програми Atmel з використанням зовнішніх переривань для пристроїв megaAVR.
Оновлення
Ось повний приклад коду, який я щойно знайшов тут .
#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 */
}
}