Determinare quale pin ha attivato un interrupt PCINTn?


9

Ho ragione nel pensare che se si hanno due pin che causano lo stesso AVR PCINT interrupt (ad es. Vettore PCINT0 causato da pin PCINT0 o PCINT1 - penso che la sovrapposizione di nomi di vettori e pin sia confusa) l'unico modo per determinare quale pin (s) causato l'interrupt è quello di registrare il loro stato dopo ogni interrupt e confrontare i valori precedenti e attuali di tutti i pin che sono abilitati in PCMSKn?


1
È passato un po 'di tempo da quando ho usato un AVR, ma sono sicuro che ci deve essere un flag che viene attivato per il pin giusto. Questo flag dovrebbe cancellarsi dopo che si è verificato l'interrupt, quindi non è necessario memorizzare lo stato. Il fatto che la bandiera sia posizionata dovrebbe essere sufficiente
Gustavo Litovsky il

@ gl3829 le bandiere sono per gruppo di pin se ho capito bene
Tom Davies il

Risposte:


11

Penso che la sovrapposizione dei nomi di vettori e pin sia confusa

È!

La ragione per cui vi sono 8 pin esterni diversi per un vettore di interruzione è per semplificare il layout del PCB o l'uso di un pin diverso in caso di conflitto con un'altra funzione pin.

Sono corretto nel pensare ... l'unico modo per determinare quali pin hanno causato l'interrupt è quello di registrare il loro stato dopo ogni interrupt e confrontare i valori precedenti e attuali di tutti i pin abilitati in PCMSKn?

Praticamente, diciamo che ti interessa solo PB0 (PCINT0) e PB1 (PCINT1). Quindi la maschera di abilitazione cambio pin PCMSK0 sarebbe impostata su 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
    ...
}

Quindi se pinsè 0x01 sai che era PB0 ... E se hai bisogno di sapere a cosa è cambiato devi confrontarlo previousPins, praticamente esattamente quello che pensavi.

Tieni presente che in alcuni casi, pinspotrebbe non essere preciso se il pin ha cambiato stato dall'interruzione ma primapins = (PINB & 0x03) .

Un'altra opzione sarebbe quella di utilizzare vettori di interruzione separati con un pin da ciascun vettore in modo da sapere quale è cambiato. Ancora una volta, questo ha anche alcuni problemi, come la priorità di interruzione e una volta che la CPU entra nel ISR, il globale interrupt bit di abilitazione I-bitin SREGsaranno cancellati in modo che tutti gli altri interrupt sono disattivati, anche se è possibile impostare all'interno del interrupt, se si vuole, che avrebbe essere un interrupt nidificato.

Per ulteriori informazioni, dai un'occhiata alla nota dell'app di Atmel Utilizzo di interrupt esterni per dispositivi megaAVR.

Aggiornare

Ecco un esempio di codice completo che ho appena trovato qui .

#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 */
    }
}

Il mega ha tre interruzioni di cambio pin, con i vettori PCINT [0-2], ma ognuno di questi è attivato da una serie di pin. La mia domanda è su come distinguere quale dei pin in quel set ha causato l'interruzione.
Tom Davies il

@TomDavies hai ragione, grazie, ho cambiato la mia risposta ma è esattamente quello che pensavi. E ho letto il foglio dati, non c'è bandiera per indicare quale pin è cambiato.
Garrett Fogerlie,

@ Garret: hai riconosciuto che nel tuo esempio originale si può facilmente determinare se è stata la caduta o il fronte di salita a innescare l'interruzione? (beh, a meno che entrambi i pin non siano cambiati nello stesso preciso istante ... ma in questo caso solo la magia nera aiuta) (puntini precedenti> piedini): fronte di discesa (piedini precedenti <perni): fronte di salita Forse vale la pena essere menzionato sopra.

@TomDavies PINB copre PCINT0-7, PINC copre PCINT8-15 ecc.
EkriirkE

0

Nel INTFLAGSregistro di serie ATTINY più recente viene indicato quale bit di porta ha causato l'interruzione.

Ecco un estratto dal foglio dati:

Bit 7: 0 - INT [7: 0]: Interrompi Pin Flag Il flag INT viene impostato quando un cambio / stato di un pin corrisponde alla configurazione del rilevamento dell'ingresso del pin. Scrivere un '1' nella posizione di bit di una bandiera cancellerà la bandiera.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.