Ustalanie, który pin wywołał przerwanie PCINTn?

9

Czy mam rację, myśląc, że jeśli masz dwa piny powodujące to samo przerwanie AVR PCINT, (np. Wektor PCINT0 spowodowany przez piny PCINT0 lub PCINT1 - myślę, że nakładanie się nazw wektorów i pinów jest mylące), jedynym sposobem ustalenia, który pin (s) spowodował, że przerwanie ma rejestrować swój stan po każdym przerwaniu i porównywać poprzednie i bieżące wartości wszystkich pinów, które są włączone w PCMSKn?

Tom Davies
źródło
1
Minęło trochę czasu, odkąd użyłem AVR, ale jestem pewien, że musi być flaga, która zostanie wyzwolona dla właściwej szpilki. Ta flaga powinna zostać wyczyszczona po wystąpieniu przerwania, aby nie trzeba było zapisywać stanu. Wystarczy ustawić flagę
Gustavo Litovsky
@ gl3829 flagi są na grupę pinów, jeśli dobrze rozumiem
Tom Davies

Odpowiedzi:

11

Myślę, że nakładanie się nazw wektorów i szpilek jest mylące

To jest!

Powodem, dla którego istnieje 8 różnych styków zewnętrznych dla wektora przerwań, jest ułatwienie ułożenia płytki drukowanej lub użycie innego styku w przypadku konfliktu z inną funkcją styku.

Czy mam rację, myśląc ... jedynym sposobem ustalenia, które piny spowodowały przerwanie, jest zapisanie ich stanu po każdym przerwaniu i porównanie poprzednich i bieżących wartości wszystkich pinów, które są włączone w PCMSKn?

Powiedzmy, że dbasz tylko o PB0 (PCINT0) i PB1 (PCINT1). Zatem maska ​​włączania zmiany pinów PCMSK0 byłaby ustawiona na 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
    ...
}

Więc jeśli pinsjest 0x01, wiesz, że to był PB0 ... A jeśli chcesz wiedzieć, co się zmieniło, musisz to porównać previousPins, prawie dokładnie to, co myślałeś.

Pamiętaj, że w niektórych przypadkach pinsmoże być niedokładny, jeśli pin ma stan zmian od momentu przerwania, ale wcześniej pins = (PINB & 0x03).

Inną opcją byłoby użycie oddzielnych wektorów przerwań z jednym pinem z każdego wektora, abyś wiedział, który jest zmieniany. Ponownie, to ma również pewne problemy, takie jak przerwania priorytetu i raz CPU wchodzi do ISR, globalny przerwania umożliwić bit I-bitw SREGzostaną usunięte tak, że wszystkie inne przerwania są wyłączone, chociaż można ją ustawić wewnątrz przerwania jeśli chcesz, to byłoby być zagnieżdżonym przerwaniem.

Aby uzyskać więcej informacji, zapoznaj się z notatką aplikacji firmy Atmel Korzystanie z zewnętrznych przerwań dla urządzeń megaAVR.

Aktualizacja

Oto kompletny przykład kodu, który właśnie tu znalazłem .

#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 */
    }
}
Garrett Fogerlie
źródło
Mega ma trzy przerwania zmiany pinów z wektorami PCINT [0-2], ale każde z nich jest wyzwalane przez zestaw pinów. Moje pytanie dotyczy tego, jak odróżnić, które z pinów w tym zestawie spowodowały przerwanie.
Tom Davies,
@TomDavies masz rację, dziękuję, zmieniłem odpowiedź, jednak dokładnie tak myślałeś. I czytam arkusz danych, nie ma flagi wskazującej, który pin się zmienił.
Garrett Fogerlie,
@ Garret: Czy zdałeś sobie sprawę, że w swoim oryginalnym przykładzie można łatwo ustalić, czy to opadająca, czy rosnąca krawędź wywołała przerwanie? (cóż, chyba że oba piny zmieniły się dokładnie w tym samym momencie ... ale w tym przypadku pomaga tylko czarna magia) (previous_pins> pins): opadająca krawędź (poprzednie szpilki <szpilki): rosnąca krawędź Może warto o tym wspomnieć powyżej.
@TomDavies PINB obejmuje PCINT0-7, PINC obejmuje PCINT8-15 itp.
EkriirkE
0

W nowszej serii ATTINY INTFLAGS rejestr powie ci, który bit portu spowodował przerwanie.

Oto fragment arkusza danych:

Bity 7: 0 - INT [7: 0]: Przerwanie flagi pinu Flaga INT jest ustawiana, gdy zmiana / stan pinu odpowiada konfiguracji wykrywania wejścia pinu. Zapisanie „1” w miejscu bitowym flagi spowoduje jej usunięcie.

zmechanic
źródło