Bueno, si quieres hacerlo como lo hace TimerOne, tienes que declarar una variable global (o static) de la siguiente manera:
void (*isrAUsar)();
Un poco difícil de explicar, pero básicamente es una variable que almacena un puntero de una subrutina (función) que no retorna nada ni necesita parámetros.
Un puntero de estos debe apuntar (valga la redundancia) al primer byte que representa la primera instrucción (máquina) de dicha función. El programa siempre está en memoria flash; por lo tanto, el valor de esa variable se interpretará como una dirección de dicha memoria.
¿Cuál valor exactamente debería tener? De eso no te preocupes, que el compilador de eso se encargará.
Para asignarle una subrutina, sería de la siguiente manera:
void attachSomeInterrupt(void (*funcion)()) {
isrAUsar = funcion;
// Otras configuraciones
}
Sin embargo aún así no te libras de la forma en que el compilador realmente define una rutina de interrupción:
ISR(NOMBRE_DEL_VECTOR_vect) {
isrAUsar(); // Así de simple se usa la función que le asignes
}
PD: cuidado al crear funciones tipo detachInterrupt, usualmente estos lo único que hacen es deshabilitar la interrupción, pero nunca resignan un valor a la variable (como ponerle cero). Redefinir el valor del puntero mientras la interrupción siga habilitada puede llevar a alguna de las siguientes situaciones:
- Ejecutar la rutina main (implícita en los códigos de Arduino, pero obligatoria en lenguajes C), lo que básicamente llevaría a un "soft-reset" pero sin pasar por el bootloader y sin limpiar la pila de ejecución. Si esto se repitiera indefinidamente, eventualmente el programa se cuelga por desbordamiento de pila ("stack overflow" en inglés); en efecto eso sería como recursividad infinita.
- Ejecutar de nuevo la misma ISR, como un ciclo infinito pero con el eventual desbordamiento de pila (recursividad infinita).
- Ejecutar erróneamente y total o parcialmente, funciones ya existentes (sin contar el antes mencionado main). El resultado puede variar desde la modificación inesperada de variables globales, recursividad infinita, o si la función difiere de tipo de retorno y número de parámetros, corrupción de la pila de ejecución. En otras palabras, un desastre total.
- La más probable: ejecutar "basura", datos grabados con PROGMEM o incluso código de programas antiguos (la memoria flash nunca se sobrescribe en su totalidad). En el peor (o mejor) de los casos ocurre un cuelgue inmediato por intentar ejecutar una "instrucción ilegal"; y en el mejor (o peor) de los casos, la rutina sale normalmente, pero con la memoria RAM lo suficientemente corrompida para que, sin mucha demora, ocurra otro cuelgue.
Por cosas como estas es que los videojuegos de los 80s y 90s tienen de esos fallos de programación que resultan en desastres o ventajas (trampas).