Определение того, какой вывод вызвал прерывание PCINTn?


9

Правильно ли я считаю, что если у вас есть два контакта, вызывающих одно и то же прерывание AVR PCINT (например, вектор PCINT0, вызванный выводами PCINT0 или PCINT1 - я думаю, что совпадение имен векторов и выводов сбивает с толку), то единственный способ определить, какой вывод (s) вызвало прерывание, чтобы записать их состояние после каждого прерывания и сравнить предыдущие и текущие значения всех контактов, которые включены в PCMSKn?


1
Прошло много времени с тех пор, как я использовал AVR, но я уверен, что должен быть флаг, который срабатывает для правильного вывода. Этот флаг должен сбрасываться после прерывания, поэтому вам не нужно сохранять состояние. То, что флаг установлен, должно быть достаточно
Густаво Литовский

@ gl3829 флаги на группу пинов, если я правильно понимаю
Том Дэвис

Ответы:


11

Я думаю, что совпадение имен векторов и выводов сбивает с толку

Это!

Причина, по которой существует 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
    ...
}

Так что, если pins0x01, вы знаете, что это 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 */
    }
}

Мега имеет три прерывания смены контактов, с векторами PCINT [0-2], но каждое из них запускается набором контактов. Мой вопрос о том, как определить, какие из контактов в этом наборе вызвали прерывание.
Том Дэвис

@ TomDavies вы правы, спасибо, я изменил свой ответ, но это именно то, что вы подумали. И я прочитал таблицу данных, там нет флага, чтобы указать, какой контакт изменился.
Гаррет Фогерли

@ Гаррет: Вы узнали, что в вашем первоначальном примере легко определить, было ли это прерывание или спад или нарастающий фронт? (хорошо, если только оба контакта не изменились в один и тот же момент ... но в этом случае помогает только черная магия) (предыдущие_пины> выводы): спадающий фронт (предыдущие пины <контакты): нарастающий фронт Возможно, это стоит упомянуть выше.

@TomDavies PINB покрывает PCINT0-7, PINC покрывает PCINT8-15 и т. Д.
EkriirkE

0

В более новом регистре серии ATTINY INTFLAGSбудет указано , какой бит порта вызвал прерывание.

Вот выдержка из таблицы:

Биты 7: 0 - INT [7: 0]: флаг контакта прерывания Флаг INT устанавливается, когда изменение / состояние контакта соответствует конфигурации чувствительности входа контакта. Запись '1' в битовое местоположение флага очистит флаг.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.