Визначення, який штифт викликав переривання 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
    ...
}

Отже, якщо 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 */
    }
}

Мега має три штиркові переривання зміни, вектори PCINT [0-2], але кожен з них спрацьовує набором штифтів. Моє запитання про те, як розрізнити, який із штифтів у цьому наборі спричинив перерву.
Том Девіс

@TomDavies ви праві, дякую, я змінив свою відповідь, але це саме те, що ви думали. І я перечитав аркуш, немає прапора, який би вказував, який штифт змінився.
Гаррет Фогерлі

@ Garret: Чи ти визнав, що у твоєму первісному прикладі можна легко визначити, чи викликав переривання саме падаючий чи піднімаючий край? (ну, якщо тільки обидва штифти не змінилися в той самий момент ... але в цьому випадку допомагає лише чорна магія) (попередні_піни> шпильки): падаюча грань (попередні шпильки <шпильки): піднімається край Можливо, це варто згадати вище.

@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.