Hay dos tipos de interrupciones de tipo "cambio de pin". Las interrupciones externas, de las cuales hay dos en el Uno. Se llaman 0 y 1, sin embargo, se refieren a los pines digitales 2 y 3 en el tablero. Estos se pueden configurar para detectar ascensos, caídas, cambios (subiendo o bajando) o BAJOS.
Además de eso, hay interrupciones de "cambio de pin", que detectan un cambio en el estado del pin en cualquiera de los 20 pines (A0 a A5 y D0 a D13). Estas interrupciones de cambio de pin también están basadas en hardware , por lo que, en sí mismas, serán tan rápidas como las interrupciones externas.
Ambos tipos son un poco complicados de usar en el nivel de registro, pero el IDE estándar incluye attachInterrupt (n) y detachInterrupt (n) que simplifica la interfaz para las interrupciones externas. También puede usar la biblioteca de cambio de pin para simplificar las interrupciones de cambio de pin.
Sin embargo, alejándonos de la biblioteca por un minuto, podemos establecer que las interrupciones de cambio de pin pueden ser tan rápidas o más rápidas que las interrupciones externas. Por un lado, aunque las interrupciones de cambio de pin funcionan en lotes de pin, no tiene que habilitar todo el lote. Por ejemplo, si desea detectar cambios en el pin D4, esto será suficiente:
Bosquejo de ejemplo:
ISR (PCINT2_vect)
{
// handle pin change interrupt for D0 to D7 here
if (PIND & bit (4)) // if it was high
PORTD |= bit (5); // turn on D5
else
PORTD &= ~bit (5); // turn off D5
} // end of PCINT2_vect
void setup ()
{
// pin change interrupt (example for D4)
PCMSK2 |= bit (PCINT20); // want pin 4
PCIFR |= bit (PCIF2); // clear any outstanding interrupts
PCICR |= bit (PCIE2); // enable pin change interrupts for D0 to D7
pinMode (4, INPUT_PULLUP);
pinMode (5, OUTPUT);
} // end of setup
void loop ()
{
}
Mi prueba indica que el pin de "prueba" (pin 5) tardó 1.6 µs en reaccionar ante un cambio en el pin de interrupción (pin 4).
Ahora, si adopta el enfoque simple (¿perezoso?) Y utiliza attachInterrupt (), encontrará que los resultados son más lentos, no más rápidos.
Código de ejemplo:
void myInterrupt ()
{
if (PIND & bit (2)) // if it was high
PORTD |= bit (5); // turn on D5
else
PORTD &= ~bit (5); // turn off D5
} // end of myInterrupt
void setup ()
{
attachInterrupt (0, myInterrupt, CHANGE);
pinMode (2, INPUT_PULLUP);
pinMode (5, OUTPUT);
} // end of setup
void loop ()
{
}
Esto toma 3.7 µs para cambiar el pin de prueba, mucho más que los 1.6 µs anteriores. ¿Por qué? Debido a que el código que el compilador tiene que generar para el manejador de interrupciones "genérico" tiene que guardar todos los registros imaginables (empujarlos) en la entrada al ISR y luego restaurarlos (abrirlos) antes de regresar. Además, está la sobrecarga de otra llamada de función.
Ahora podemos evitarlo evitando attachInterrupt () y haciéndolo nosotros mismos:
ISR (INT0_vect)
{
if (PIND & bit (2)) // if it was high
PORTD |= bit (5); // turn on D5
else
PORTD &= ~bit (5); // turn off D5
} // end of INT0_vect
void setup ()
{
// activate external interrupt 0
EICRA &= ~(bit(ISC00) | bit (ISC01)); // clear existing flags
EICRA |= bit (ISC00); // set wanted flags (any change interrupt)
EIFR = bit (INTF0); // clear flag for interrupt 0
EIMSK |= bit (INT0); // enable it
pinMode (2, INPUT_PULLUP);
pinMode (5, OUTPUT);
} // end of setup
void loop ()
{
}
Esa es la más rápida de todas con 1,52 µs: parece que se guardó un ciclo de reloj en alguna parte.
Sin embargo, hay una advertencia para las interrupciones de cambio de pin. Están agrupados, por lo que si desea tener interrupciones en muchos pines, debe probar dentro de la interrupción cuál cambió. Puede hacerlo guardando el estado del pin anterior y comparándolo con el nuevo estado del pin. Esto no es necesariamente particularmente lento, pero cuantos más pines necesite verificar, más lento será.
Los lotes son:
Si solo desea un par de pines de interrupción más, puede evitar cualquier prueba simplemente eligiendo usar pines de diferentes lotes (por ejemplo, D4 y D8).
Más detalles en http://www.gammon.com.au/interrupts