Tutorial Microcontroladores
Microcontroladores
Jugando a la Computadora
Jugando a la computadora es una técnica de adiestramiento en la que pretenderemos ser una computadora interpretando y ejecutando las instrucciones de un programa. Los programadores a menudo verifican mentalmente un programa jugando a este juego del mismo modo que leen una subrutina. Mientras lo jugamos no es necesario dividir las instrucciones en ciclos individuales del procesador. En cambio, una instrucción es tratada como una única operación completa más que como diversas etapas definidas.
Los siguientes párrafos demuestran el proceso del juego partiendo del ejercicio del llamado a subrutina de la figura 4-3. Una aproximación para analizar esa secuencia es mucho menos detallada que el análisis ciclo por ciclo realizado, pero debemos cumplir el mismo objetivo básico (por ejemplo presentar qué pasa cuando la CPU ejecuta la secuencia). Luego de estudiar el capítulo de programación, podremos intentar lo propio con largos programas.
Debemos iniciar el proceso preparando una planilla de trabajo similar a la presentada en la figura 4-4. Esta planilla incluye los mnemónicos del programa y el código de máquina en que es ensamblado. (Podremos alternativamente optar por el uso de un listado adjunto a la planilla). La planilla además incluye a los nombres de los registros de la CPU a lo largo de su parte superior. Hay un amplio espacio disponible para escribir los nuevos valores con que los registros cambian en el curso del programa.
En esta planilla, hay un área para seguir la evolución de la pila. Una vez habituados al trabajo de la pila, probablemente prescindamos de esta área, aunque la dejaremos por ahora ya que nos sea instructiva.
Cuando un valor es ingresado en la pila, debemos tachar cualquier valor anterior y escribir el nuevo valor exactamente abajo en una fila vertical. Podemos ahora actualizar (decrementar) el valor del SP. Tachamos cualquier valor previo y escribimos el nuevo valor debajo de la columna correspondiente al SP. Cuando un valor es retirado de la pila, debemos actualizar (incrementar) el valor del SP, tachar el viejo valor y escribir el nuevo valor debajo. Podemos entonces leer el valor desde la posición de memoria apuntada por el SP y ponerlo en el lugar de la CPU correspondiente. (Por ejemplo en la mitad de más peso o en la de menos peso de la PC).
Fig. 4-4 – Hoja de trabajo para “Jugando a la Computadora”.
La figura 4-5 presenta cómo luce la planilla luego de actuar sobre la secuencia completa del JSR. Se explica el proceso siguiendo los números entre corchetes [número]. Durante el proceso, se escriben muchos valores y luego se tachan; para marcar una referencia se dibuja una línea desde el número entre corchetes hasta el valor o la tachadura correspondiente.
Fig. 4-5 – Hoja de trabajo Completa.
Iniciamos la secuencia con la PC apuntando a $0300 [1] y el SP apuntando a $00FF [2] (tal como lo asumimos previamente). La CPU lee y ejecuta la instrucción LDA $02 (carga del acumulador con el valor inmediato $02) por ello, escribimos en la columna del acumulador $02 [3] y reemplazamos el valor de la PC por $0302 [4], que es la dirección de la próxima instrucción. La instrucción carga del acumulador afecta los bits N y Z del CCR. Ya que el valor cargado es $02, los bits N y Z se ponen ambos en cero [5]. Esta información podemos encontrarla en el apéndice A. Como hay otros bits del CCR que no son afectados por la instrucción LDA y además no tenemos forma de saber su estado previo los marcaremos con un signo de interrogación [5].
A continuación la CPU lee la instrucción JSR SUBBY. Retiene temporariamente el valor $0305, que es la dirección a la que la CPU deberá regresar luego de ejecutar el llamado a sub-rutina. La CPU ingresa la mitad de menos peso de la dirección de retorno en la pila; por lo que , escribimos $05 [6] en la posición de memoria apuntada por el SP ($00FF) y decrementamos el SP [7] a $00FE. Luego la CPU ingresa la mitad de más peso de la dirección de retorno en la pila; así, escribimos $03 [8] en $00FE y luego decrementamos el SP [9] (ahora a $00FD). Para finalizar la instrucción JSR, cargamos el PC con $0400 [10], que es la dirección de la sub-rutina invocada.
La CPU busca la próxima instrucción. Como el PC contiene $0400, la CPU ejecuta la instrucción DECA, que es la primera instrucción de la sub-rutina. Tachamos el $02 de la columna del acumulador y escribimos su nuevo valor $01 [11]. Además podemos cambiar el contenido del PC a $0401 [12]. Puesto que la instrucción DECA altera el contenido del acumulador de $02 a $01 (que no es ni cero ni negativo) los bits Z y N siguen en cero. Mientras N yA se mantengan en cero [5] podemos dejarlos tal cual en la planilla.
La CPU ahora ejecuta la instrucción BNE SUBBY. Mientras el bit Z permanezca en cero, se cumple la condición de bifurcación y la CPU la realiza. Tachamos $0401 en la columna del PC y escribimos $0400 [13].
La CPU ejecuta la instrucción DECA otra vez. El acumulador ahora cambia de $01 a $00 [14] (que es cero y no negativo); por ello, el bit de Z va a uno y el bit N sigue en cero.. el PC avanza hasta la próxima instrucción [16].
La CPU ahora ejecuta la instrucción BNE SUBBY, pero esta vez es falsa la condición de bifurcación (Z está en uno), en consecuencia no se realiza la bifurcación. La CPU sigue simplemente con la próxima instrucción (RTS en $0403). Actualizamos el PC con $0403 [17].
La instrucción RTS obliga a la CPU a retirar el PC previamente ingresado a la pila. Retiramos la mitad de más peso del PC de la pila incrementando el SP a $00FE [18] y leyendo $03 de la posición de memoria $00FE. A continuación, retiramos la mitad de menos peso de la dirección de la pila incrementando el SP a $00FF y leyendo $05 de $00FF. La dirección recuperada de la pila reemplaza al valor en el PC [20].
La CPU ahora lee la instrucción STA $EO de la posición de memoria $0305. el flujo del programa ha retornado a la secuencia principal de programa desde la que se ha llamado a la subrutina. La instrucción STA (en modo de direccionamiento directo) escribe el valor del acumulador en la dirección directa $00EO, de la RAM del MC68HC705J1A. Podemos ver en la planilla que el valor del acumulador es $00, en consecuencia todos los bits de esa posición de memoria en RAM irán a cero. Si bien en la planilla original no hay un lugar establecido para colocar el valor en RAM, podemos hacerlo y escribir $00 allí [21].
Para un extenso programa, la planilla tendrá muchos más valores tachados, tantos como sean necesarios. Jugando a la computadora sobre la planilla luce como una buena técnica de adiestramiento, pero a medida que el programador gana experiencia, va simplificando el proceso. En el capítulo de programación veremos una herramienta de desarrollo llamada simulador que automatiza el proceso del juego. El simulador es un programa de computadora que corre sobre una PC. El contenido actualizado de los registros y de las posiciones de memoria son presentados en la pantalla de la PC.
Una de las primeras simplificaciones que podemos hacer es eliminar el seguimiento del PC pues comprenderemos cómo lo maneja la CPU y lo tendremos en cuenta. Otra más es eliminar el seguimiento del CCR. Al encontrar una instrucción de bifurcación dependiente de algún bit del CCR elaboraremos mentalmente el estado de los mismos para decidir si realizamos o no la bifurcación.
Luego, podemos obviar el almacenamiento de valores en la pila, además del seguimiento del SP. Un principio fundamental de la operación de la pila es que luego de un período de tiempo, el mismo número de items han sido retirados e ingresados a la pila. Así como en una fórmula matemática ambos miembros de una igualación deben coincidir, los JSRs y BSRs uno a uno deben coincidir con los subsecuentes RTSs en un programa. Los errores de quebrantar esta regla aparecerán como valores erróneos del SP mientras jugamos a la computadora.
A veces un programador experimentado aplica el juego para resolver un problema de cierta dificultad. El procedimiento que un programador experimentado usa es mucho menos formal que el aquí explicado, pero él se coloca en el lugar de la CPU y predice qué sucede al ejecutar el programa.
Resets
El reset es usado para forzar al sistema de MCU a ir a un punto de partida conocido (dirección). Los sistemas periféricos y muchos bits de control y estado son también forzados a un estado conocido como resultado del reset.
Las siguientes acciones internas ocurren como resultado de cualquier reset del MCU:
- 1)Todos los Registros de Dirección de Datos se colocan en cero (como entradas).
- 2)El puntero a la pila (SP) es forzado a $00FF.
- 3)El bit I del CCR se pone en uno inhibiendo a las interrupciones enmascarables.
- 4)El latch de interrupciones externas es borrado.
- 5)El latch de STOP es borrado.
- 6)El latch de WAIT es borrado.
Las siguientes condiciones pueden causar el reset del MC68HC705J1A:
- 1) Externamente, una señal de entrada activa baja en el pin / RESET.
- 2) Internamente, al encender la fuente de alimentación (power on reset POR).
- 3) Internamente, expiración de tiempo del cronómetro de vigilancia del comportamiento apropiado de la computadora (computer operating properly COP watchdog timed out).
- 4) Un intento de ejecutar una instrucción desde una dirección ilegal.
Una llave o un circuito externo puede conectarse a este pin para permitir el reset manual del sistema.
Reset al encender la Fuente de Alimentación (Power-On Reset)
El reset al encender la fuente de alimentación ocurre al detectarse una transición positiva sobre VDD. Su uso es estrictamente para la condición de encendido y no podrá utilizarse para detectar caídas de la tensión de la fuente de alimentación. Podrá usarse un circuito inhibidor de baja tensión (LVI) para detectar caídas de la fuente.
El circuito de power-on provee una demora de 4064 ciclos desde el momento en que el oscilador se ha activado. Si el pin de /RESET exterior permanece en bajo al expirar el tiempo de los 4064 ciclos de demora, el procesador permanecerá en la condición de reset hasta que /RESET se coloque en alto.
Reset por Watchdog Timer
El sistema de cronómetro de vigilancia del comportamiento apropiado de la computadora (computing operating properly COP watchdog timer system) se propone detectar errores de programas. Cuando se activa el COP es responsabilidad del programa evitar que un cronómetro de vigilancia que corre libremente llegue al final de su cuenta. Si llega a completar su cuenta, sería una indicación de que el programa no ha sido ejecutado por un largo período de tiempo en la secuencia deseada; entonces se inicia el reset del sistema.
Un bit de control del registro (no volátil) máscara de opciones (MOR) puede usarse para habilitar o deshabilitar el reset del COP. Si el COP es habilitado, la adecuada operación del programa debe periódicamente escribir un cero en el bit COPC del registro de control COPR. Ir a la hoja de datos del MC69HC705J1A por información sobre el ritmo del tiempo de expiración. Algunos miembros de la familia de microcontroladores MC68HC05 tienen distintos sistemas de cronómetro de vigilancia del comportamiento apropiado de la computadora.
Reset por Acceso a Dirección Ilegal
Si el programa es escrito incorrectamente, es posible que la CPU intente saltar o bifurcar a una dirección en la que no haya memoria. Si esto sucede, la CPU podría continuar leyendo datos (resultando ser valores impredecibles) e intentaría actuar en consecuencia si se tratase de programa. Estas instrucciones sin sentido pueden provocar que la CPU escriba datos inesperados en memoria o registros direccionados inesperados. Esta situación se llama desbocamiento.
En el MC68HC705J1A hay un circuito detector de direcciones ilegales para protegernos de la condición de desbocamiento. Si la CPU trata de buscar una instrucción de una dirección que no pertenece a la EPROM ($0300 - $07CF, $07F0 - $07FF), ni a la ROM de prueba interna ($07EE - $07EF), se genera un reset que obliga al programa a comenzar nuevamente.
Interrupciones
Son a veces usadas para interrumpir el procesamiento normal para responder a algún evento inusual. El MC68HC705J1A puede ser interrumpido por las siguientes fuentes de interrupción:
- 1) Un cero lógico aplicado al pin de interrupción externa (/IRQ).
- 2) Un cero lógico aplicado a cualesquiera de los pines PA3 - PA0 (si la función de port de interrupción es habilitada).
- 3) Un pedido de desborde (overflow TOF) o interrupción de tiempo real (RTIF) desde el sistema de temporización por programa (SWI).
- 4) La instrucción de interrupción por programa (SWI).
Las interrupciones pueden ser inhibidas en conjunto poniendo un uno en el bit I del CCR o bien individualmente, poniendo ceros en los bits de control de habilitación de cada fuente de interrupción. El reset fuerza el bit I a uno y a cero a todos los bits de habilitación de interrupciones locales a fin de prevenir interrupciones durante el proceso de inicialización. Cuando el bit I está en uno, ninguna interrupción (excepto SWI) es reconocida. Aunque pueda registrarse a la fuente de interrupción su pedido no será atendido hasta que el bit I se ponga en cero.
La figura 4-6 presenta cómo las interrupciones afectan el normal flujo de las instrucciones de la CPU. Las interrupciones provocan que los registros del procesador sean salvados en la pila y la máscara de interrupciones (el bit I) se ponga en uno, para prevenir interrupciones adicionales hasta la finalización de la presente interrupción. El vector de interrupción apropiado entonces apuntará a la dirección de inicio de la rutina de atención de interrupción (tabla 4-1). Completada la rutina de atención de interrupción, una instrucción RTI (que normalmente es la última instrucción de una rutina de atención de interrupción) provoca que el contenido de los registros sea recuperado de la pila. De esta forma el contador de programa es cargado con el valor previamente salvado en la pila, continuando con el procesamiento desde donde nos sacó la interrupción. En la figura 4-7 se presenta qué registros son recuperados de la pila en orden inverso al que fueron salvados.