Я думаю, что совпадение имен векторов и выводов сбивает с толку
Это!
Причина, по которой существует 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 */
}
}