Home MundoTec Software Código fuente Tutorial / pdf Minijuegos
Cerrar

Tutorial Microcontroladores

Tutorial Microcontroladores.







Microcontroladores

Interrupciones No Utilizadas.

Para toda interrupción que sea usada, los vectores de las mismas pueden ser definidos tal cuál como fue definido el vector de reset (con una directiva FDB). En el programa de ejemplo, la interrupción del Timer se usa para lograr interrupciones en tiempo real. La interrupción externa y la interrupción SWI no son usadas.

Es una buena idea setear los vectores de interrupción NO UTILIZADOS para el caso que una de esas interrupciones sea inesperadamente requerida. Bien podríamos imaginarnos lo que sucedería en un sistema funcionando si alguna interrupción no utilizada fuera atendida.

Este tipo de errores es muy común en programadores noveles, que podrían ocasionar la habilitación y el disparo de interrupciones no contempladas en el programa original. Las siguientes líneas del listado muestran como las interrupciones y el vector de reset fueron seteados en el programa de ejemplo.

Microcontroladores

Las primeras líneas en este listado parcial muestran las primeras y las últimas líneas de la rutina de servicio de la interrupción del Timer. La línea.....

0351 80 AnRTI RTI ;Return from RTIF interrupt

Muestra una instrucción de Retorno desde Interrupción (RTI , Return To Interrupt) con la etiqueta “AnRTI”. La próxima línea iguala la etiqueta “UNUSED” a la dirección de la instrucción RTI en AnRTI. Más abajo en el listado, los vectores de interrupciones no utilizados y la interrupción SWI se setean para apuntar a esa instrucción RTI ($0351).

Si una interrupción SWI fuera encontrada inesperadamente, el CPU salvaría los registros de internos de este en el stack (pila, RAM temporaria) y cargaría el contador de programa con la dirección $0351 el vector de SWI. El CPU cargaría luego la instrucción RTI desde la dirección $0351. La instrucción RTI le diría al CPU que recobre los registros salvados del CPU (incluyendo el contador de programa) desde el stack (pila). El valor del contador de programa recobrado determinaría que haría el CPU como próximo paso.

Una manera alternativa de responder a una interrupción no esperada sería resetear el stack pointer (puntero de pila , SP) (con una instrucción RSP) y luego saltar a la misma dirección como si un reset hubiera ocurrido. Esta aproximación parte de asunción pesimista que si una interrupción no esperada ocurre, puede haber otros problemas serios. Por acción de resetear el stack pointer (SP) y empezar todo nuevamente, podríamos pensar que estaríamos en mejores condiciones para corregir la o las causas que pudieron haber provocado la interrupción no esperada.

Mientras se depura un programa en un simulador, hay otra forma posible de manejar interrupciones no esperadas.

“ “ “ " " " "
0351 BADINT BRA BADINT ;Infinite loop to here

“ “ “ " " " "
07FA VECTOR FDB BADINT ;Hang on unexpected int

En este esquema, una interrupción no esperada causará que el vector asociada a esta, apunte a BADINT. La instrucción a BADINT es un lazo infinito a la propia instrucción BADINT, de esta forma el sistema queda corriendo dentro de este lazo indefinidamente. Se puede detener el simulador y chequear los valores de los registros del CPU en el STACK (PILA) para poder ver que estaba haciendo el programa cuando este recibe una interrupción no esperada.

Variables en RAM.

Las variables de un programa cambian de valor durante la ejecución del programa en curso. Estos valores no pueden especificarse antes de que el programa sea escrito y grabado en el MCU. El CPU debe usar instrucciones para inicializar y modificar estos valores. Cuando el programa se escribe, se reserva espacio para las variables en la RAM del MCU, usando directivas de reserva de bytes de memoria (RMB).

Primero, se colocará una directiva originate (ORG) para setear el contador del ensamblador a la dirección de comienzo de la RAM en el MCU ($00C0 en el MC68HC705J1A).

Cada variable o grupo de variables serán seteadas con una directiva RMB. La línea RMB se identifica por el nombre de la variable. El ensamblador le asigna el nombre (etiqueta) al próximo espacio de memoria disponible. Después de que cada variable o grupo de variables es asignada, el contador de localización se avanza a la próxima posición libre de memoria.

Como se podrá ver en variados casos, algunos programadores, sostienen que es buena práctica limpiar todas las posiciones de memoria RAM utilizadas, como un de los primeros pasos de inicialización luego de salir de la condición de reset. Esto puede ser útil, cuando en nuestro proceso de depuración de código de programa, queremos comprobar la escritura o no de una posición de memoria RAM por procesos propios del programa, ya que los nuevos valores serán seguramente distintos de cero y por eso es sencillo observar que posiciones de memoria han variado.

Lazo de Paso (Paced Loop).

El “lazo de paso” es una estructura de software de uso general que es utilizable para una gran variedad de aplicaciones con MCUs. La idea principal, es dividir la aplicación en una serie de tareas como por ejemplo, mantener un seguimiento del tiempo, leer entradas al sistema, y actualización de las salidas del mismo. Cada tarea se escribirá como una subrutina. Un lazo principal se construye fuera de las instrucciones a los saltos a subrutina (JSR) para cada tarea. En lo alto del lazo habrá un “derivador” (pacemaker) de software.

Cuando el derivador se dispara, la lista de subrutinas de tareas se ejecuta de a una por vez y una instrucción de derivación nos ubicará en lo alto del lazo a la espera del próximo disparo del derivador.

La figura 7-1 nos muestra un diagrama de flujo para el lazo de paso principal. El bloque superior es un lazo que espera por el disparo del derivador (cada 100 milisegundos). Los siguientes bloques tienen que efectuar el mantenimiento del contador de TIC. La versión de este programa mostrada en el listado 7-1 tiene dos simples tareas principales, TIME (tiempo) y BLINK (destello). El lector puede remover una o ambas tareas de este lazo de paso y sustituirlas por las propias. La única limitación en el número de tareas principales es que todas deben terminar rápidamente de modo que el derivador no pierda de “disparar” a alguna de ellas. El último bloque en el diagrama de flujo es justamente un salto a la parte superior del lazo donde se esperará un nuevo disparo del derivador.

Microcontroladores

Fig. 7-1. Diagrama de Flujo del Lazo de Paso principal.

Disparador del Lazo.

En el programa de lazo de paso del listado 7-1, el derivador se basa en una interrupción de tiempo real (RTI). Esta RTI está ajustada para generar una interrupción al CPU cada 32,8 milisegundos. El diagrama de flujo de la figura 7-2, muestra que sucede en cada interrupción RTI. Esta actividad de la interrupción puede pensarse como si esta sucediera en forma asincrónica con respecto al programa principal. El bit significativo de la variable se usa como bandera (flag) para decirle al programa principal cuando es tiempo de incrementar la variable TIC y ejecutar una vuelta a través del programa de lazo de paso.

Microcontroladores

Fig. 7-2. Diagrama de Flujo de la Rutina de Servicio de la Interrupción RTI.

La variable en RAM RTIFs se usa para contar 3 interrupciones de tiempo real antes de setear el bit más significativo (MSB) de la variable TIC. El programa principal estará vigilando la variable TIC para ver cuando el MSB se pone en “1”.

Cada 32,8 milisegundos el flag (bandera) de RTIF se pondrá en “1”, disparando de esta forma un pedido de interrupción. Uno de los usos de una rutina de servicio de interrupción, es limpiar el flag que causa la interrupción antes de que se retorne desde la interrupción.

Si RTIF no es limpiado antes de retornar, un nuevo pedido de interrupción se genera inmediatamente en lugar de esperar los 32,8 milisegundos para el nuevo disparo.

Reloj del sistema de lazo (System Clock).

La variable “TIC” es el reloj más básico para el derivador. TIC cuenta de 0 a 10. Como TIC se incrementa de 9 a 10, el programa reconoce ello y resetea TIC a 0. Excepto dentro del derivador en si mismo, TIC aparece contando desde 0 a 9. TIC es 0 cada décimo pulso de disparo del derivador.

La primera subrutina de tareas en el lazo principal se llama “TIME” . Esta rutina hace el mantenimiento de un reloj más lento llamado “TOC” . TOC se incrementa cada vez que el lazo de paso se ejecuta y TIC es 0. TOC es seteado como un contador de software que cuenta desde 0 a 59. Las restantes rutinas de tareas después de TIME pueden usar los valores corrientes de TIC y TOC para decidir que se necesita hacer en cada pasada del lazo de paso.

Vuestro Programa.

Hay muy pocas restricciones en la implementación de subrutinas de tareas. Cada subrutina de tarea deberá realizar todas las cosas que necesite hacer, tan rápidamente como sea posible, y luego ejecutar un Retorno desde Subrutina (RTS). El tiempo total requerido para ejecutar una pasada a través de todas las subrutinas de tareas deberá ser menor que dos disparos del derivador. El punto importante es que la subrutina de tarea no espere por la ocurrencia o no de algún evento externo tal como un interruptor o pulsador que deba ser oprimido. Esto conspiraría con el mantenimiento de los tiempos dentro del lazo de paso.

El lazo de paso puede proporcionar el sensado “anti-rebote” del pulsador. Es importante implementar rutinas de “filtrado” de los estados de un pulsador para evitar el “rebote” (múltiples pasos abierto-cerrado) típico de estos. Para un microcontrolador es sencillo implementar rutinas de supervisión de estados, ya que puede realizar esta tarea rutinaria dentro de otra rutina principal. Existen soluciones de hardware (circuitos anti-rebote) que podrían implementarse, pero requerirían de circuitería adicional y mayor costo en el producto final.

Consideraciones de Tiempo.

Idealmente se deberían terminar todas las rutinas dentro del lazo de paso, antes que el próximo disparo del derivador arribe. Si en una sola pasada por el lazo de paso, alguna rutina toma más tiempo que el conveniente haciendo que el disparo del derivador sea superado, el flag (bandera) que indica que es tiempo para comenzar una nueva pasada por el lazo principal estará continuamente prendido (seteado) cuando se regrese a la cima del lazo. Nada malo pasará si se regresa antes que un nuevo disparo del derivador tenga efecto, ya que se podrá reconocer el pedido anterior siempre y cuando no se supere los dos pedidos de disparo consecutivos dentro del lazo.

Consideraciones de la Pila (Stack).

Pequeños controladores como el MC68HC705J1A tienen poca RAM para la pila (stack) y las variables de programa. Las interrupciones toman 5 Bytes del stack en RAM y cada subrutina toma otros 2 bytes en el stack. Si una subrutina llama a otra subrutina, y una interrupción es requerida antes que la segunda subrutina fuera finalizada, el stack usaría 2+2+5=9 Bytes de RAM de los 64 disponibles en este pequeño controlador. Si el stack se torna más profundo (más variables de distintas subrutinas e interrupciones son guardadas en el) se corre el riesgo de corromper (sobre-escribir) los datos de otras variables del sistema almacenadas en RAM.

Para evitar este problema, se deberá calcular el peor caso de “profundidad” del stack y la suma de ello más todas las variables utilizadas en el sistema deben ser inferior a la cantidad total de RAM disponible.

A continuación, se presentará un programa de trabajo que puede utilizarse como plataforma para todos nuestros futuros trabajos de práctica.
En el podremos encontrar:
  • - Sentencias Equate para todos los registros y nombres de bits del MC68HC705J1A.
  • - Sentencias Equate específicamente para la aplicación.
  • - Sección de Variables de Programa.
  • - Sección de Inicialización (START).
  • - Derivador para el programa principal basado en interrupciones del tipo RTI.
  • - Llamados a Subrutinas de tareas.
  • - Dos ejemplos muy sencillos de subrutinas de tareas (TIME y BLINK).
  • - Una rutina de Servicio de Interrupción (para interrupciones RTIF).
  • - Sección de definición de vectores.
Microcontroladores

Microcontroladores

Microcontroladores

Microcontroladores

Microcontroladores

Microcontroladores