9 votos

¿Determinar qué pin ha provocado una interrupción PCINTn?

¿Estoy en lo cierto al pensar que si tienes dos pines que causan la misma interrupción PCINT del AVR, (por ejemplo, PCINT0 vector causada por los pines PCINT0 o PCINT1 -- creo que la superposición de nombres de vectores y pines es confusa) la única manera de determinar qué pin(s) causó la interrupción es registrar su estado después de cada interrupción y comparar los valores anteriores y actuales de todos los pines que están habilitados en PCMSKn?

1 votos

Hace tiempo que no uso un AVR, pero estoy seguro de que tiene que haber una bandera que se active para el pin correcto. Esta bandera debería despejarse después de que se produzca la interrupción, de modo que no es necesario almacenar el estado. El hecho de que la bandera se establece debe ser suficiente

0 votos

@gl3829 las banderas son por grupo de pines si estoy entendiendo bien

12voto

user9730 Puntos 11

Creo que la superposición de nombres de vectores y pines es confusa

Lo es.

La razón por la que hay 8 pines externos diferentes para un vector de interrupción es para facilitar el diseño de la PCB o para utilizar un pin diferente si hay un conflicto con la función de otro pin.

¿Estoy en lo cierto al pensar... que la única manera de determinar qué pin(s) causó la interrupción es registrar su estado después de cada interrupción y comparar los valores anteriores y actuales de todos los pines que están habilitados en PCMSKn?

Más o menos, digamos que sólo te importa PB0 (PCINT0) y PB1 (PCINT1). Entonces la máscara de habilitación de cambio de pin PCMSK0 se establecería en 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
    ...
}

Así que si pins es 0x01 sabes que era PB0... Y si necesitas saber qué ha cambiado tienes que compararlo con previousPins más o menos lo que tú pensabas.

Tenga en cuenta en algunos casos, pins puede no ser exacta si el pin ha cambiado de estado desde la interrupción pero antes pins = (PINB & 0x03) .

Otra opción sería usar vectores de interrupción separados con un pin de cada vector para saber cuál se cambia. De nuevo, esto también tiene algunos problemas, como la prioridad de la interrupción y una vez que la CPU entra en la ISR, el bit de habilitación de la interrupción global I-bit en SREG se borrará para que todas las demás interrupciones queden deshabilitadas, aunque puedes establecerla dentro de la interrupción si quieres, eso sería una interrupción anidada.

Para más información, consulta la nota de la aplicación de Atmel Uso de interrupciones externas para dispositivos megaAVR.

Actualización

Aquí hay un ejemplo de código completo que acabo de encontrar aquí .

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

0 votos

El mega tiene tres interrupciones por cambio de pin, con vectores PCINT[0-2], pero cada una de ellas es disparada por un conjunto de pines. Mi pregunta es sobre cómo distinguir cuál de los pines de ese conjunto causó la interrupción.

0 votos

@TomDavies estás en lo cierto, gracias, he cambiado mi respuesta sin embargo es exactamente lo que pensabas. Y he leído a través de la hoja de datos, no hay ninguna bandera para indicar lo que cambió pin.

0 votos

@ Garret: ¿Reconociste que en tu ejemplo original se puede determinar fácilmente si fue el flanco descendente o el ascendente el que disparó la interrupción? (bueno, a menos que ambos pines cambiaran en el mismo momento exacto... pero en este caso sólo ayuda la magia negra) (pines_anteriores > pines): flanco descendente (pines_anteriores < pines): flanco ascendente Quizás valga la pena mencionar esto arriba.

1voto

zmechanic Puntos 131

En la nueva serie ATTINY INTFLAGS le dirá qué bit del puerto ha causado la interrupción.

Este es un extracto de la hoja de datos:

Bits 7:0 - INT[7:0]: Bandera de pin de interrupción El indicador INT se activa cuando un cambio/estado del pin coincide con la configuración del sentido de entrada del pin. Si se escribe un "1" en la ubicación de un bit de la bandera borrará la bandera.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X