¿Es una buena idea actualizar una pantalla (matriz LED de 8x8 en este caso) dentro de un controlador de interrupciones?

Digamos que tengo un Arduino conectado a un 8x8 LED matrix.

En mi caso, la matriz de LED se controla mediante dos 74HC595registros de desplazamiento (uno para las filas y otro para las columnas).

Dado que solo puede configurar el estado de 8 LED a la vez (una fila), la idea es actualizar las filas lo suficientemente rápido para que el ojo humano no note el parpadeo.

Esto generalmente se hace en el loop()método:

int led_status[8]; //contains LED status (which is on/off) for each row

void loop() {
   process_otherstuff(); //eg: key inputs,...
   display(); //shift led_status[] to shift register and latch result.   
}

Aquí hay un problema potencial: ¿qué pasa si la CPU tiene que hacer algún proceso que consume mucho tiempo en el método de bucle (por ejemplo, matemáticas pesadas)? Se llamará al método display() con un cierto retraso que podría notarse (el LED comenzará a parpadear o, lo que es peor: deja de actualizarse, parece estar atascado en una fila).

Una posible solución que se me ocurre es actualizar la matriz de LED en un controlador de interrupciones:

void setup()
{
  analogWrite(3, 100);
  attachInterrupt(1, refreshdisplay, RISING);
}

int row = 0;
void refreshdisplay()
{
   //refresh one single row
   refreshrow(row++);
   if(row > 7) row = 0;
}

Es esta una buena idea ? De esa manera, no importa cuánto tiempo se dedique al método loop(), la pantalla se actualizará tan rápido como sea necesario. El problema potencial que puedo ver es que ahora se gasta mucho tiempo en la interrupción, lo que generalmente es algo malo (el controlador de interrupciones debe ser lo más corto posible).

Otra solución es usar un controlador de controlador LED separado (por ejemplo, conectado a Arduino usando el bus I2C), pero esto requiere cambiar la lista de componentes.

No sea demasiado tímido al escribir ISR complejos. Es otra de estas cosas como "¡¡no uses estructuras globales!!" que no son tan universales como la gente piensa. Si su bucle principal no es crítico en cuanto al tiempo, no hay nada de malo en "interrumpirlo". Esperar en ISR no es tan buena idea. Es mejor usar un temporizador para disparar el ISR nuevamente después del retraso que desea.
Si su interrupción se actualiza una fila a la vez y tiene ocho filas, desea que toda la matriz se actualice en al menos 1/30 segundos para mantener la persistencia de la visión. Entonces, desea que un temporizador en chip active al menos 240 interrupciones por segundo. A esto se suma el tiempo necesario para que el controlador de interrupciones guarde y restaure el estado actual del procesador. Esto parece factible y un enfoque sensato. No olvide restablecer su puntero de matriz, así como su contador de filas.

Respuestas (2)

Sí, ese es el enfoque correcto: actualice la pantalla en un ISR.

Incluso los cambios de sincronización leves pueden dar lugar a artefactos visuales, por lo que es necesario mantener la sincronización bastante ajustada si desea una apariencia de alta calidad en la pantalla.

Si es posible, use hardware (por ejemplo, el periférico SPI) para escribir en los registros de desplazamiento y, por supuesto, use una velocidad de reloj relativamente alta. Si lo hace, el tiempo total empleado en la ISR debería ser solo un pequeño porcentaje del ancho de banda del procesador, y dado que se toma en "fragmentos" pequeños, el procesamiento en segundo plano procederá casi como si tuviera un procesador funcionando a, digamos, 12 MHz. en lugar de 16MHz.

Los procesos simples y (relativamente) críticos en el tiempo, como actualizar una pantalla, son exactamente para lo que sirven los ISR. También es un buen momento (mientras se encuentra en una ISR periódica) para escanear los interruptores de entrada en busca de antirrebote, por ejemplo.

Exactamente la respuesta correcta. Experiencia personal: una vez trabajé con esas pantallas alfanuméricas de 4 caracteres de HP (esencialmente una matriz de 5x28), con una MCU basada en 8051. Descubrí que incluso la fluctuación de tiempo asociada con el ingreso al ISR producía cierto parpadeo visual. Tuve que implementar una técnica de "tiempo preciso" (leer y modificar el valor del temporizador de hardware, en lugar de simplemente borrarlo a ciegas) para obtener algo aceptable.

Normalmente, los controladores de interrupción se usan para acciones cortas. La razón es que el programa principal se bloquea.

Sin embargo, si el controlador principal no realiza ninguna acción crítica en el tiempo, es un problema menor.

Asegúrese de que el controlador de interrupciones no tarde más que la siguiente llamada de interrupción. Entonces recibe una llamada de interrupción dentro de una llamada de interrupción, etc.

En su caso, su función de actualización probablemente siempre tome el mismo tiempo. Puede medirlo (haga una prueba con 1000 iteraciones y divida el tiempo entre 1000, o 1M es que no puede medirlo). Y conoces la frecuencia de actualización. Entonces sabe cuánto porcentaje (menos algunos gastos generales) queda para su programa principal.

Personalmente, creo que escribir 64 pines GPIO, incluso con registros de desplazamiento, debe hacerse muy rápido, pero probar es mejor que suponer.

Por lo general, deshabilitaría las interrupciones anidadas y/o están deshabilitadas de forma predeterminada de todos modos. A menos que, ya sabes, te guste el dolor.