Page 112
Curso Introductorio sobre Microcontroladores familias HC705 y HC908 de Freescale
Como no se puede igualar (hacer un equate) con el mismo nombre para dos valores
binarios diferentes, el segundo equate (EQU) usará un punto “.” después del nombre del
bit. Para obtener un nombre de bit correspondiente al número de bit (7 – 0) se debe usar
el nombre simplemente, para obtener una máscara de indicación de la posición del bit,
se debe usar el mismo nombre seguido de un punto. Esta convención se usa en el
entorno de trabajo (framework) del lazo cíclico o programa calesita, pero no
necesariamente es un estándar recomendado por Freescale o por las companías de
ensambladores.
En el set de instrucciones del MC68HC05, las instrucciones de manipulación de bits son
de la siguiente forma....
xxxx 14 08 ------- BSET bit#,dd ; Set bit in location dd
__rendered_path__53
Bit# es un número entre 7 y 0 que identifica el bit dentro del registro en la localización
dd a ser cambiado o testeado.
En otros casos, si uno quisiera construir una máscara con varios bits en “1” (seteados) y
luego escribir este valor compuesto en la localización de un registro, por ejemplo
supongamos querer setear los bits RTIFR, RTIE y RT1 en el Registro TCSR, podríamos
usar las siguientes instrucciones.
Xxxx A6 16 LDA #{RTIFR.+RTIE.+RT1.}
;Form Mask
Xxxx B7 08 STA TCSR ;Write mask to TCSR Register
__rendered_path__57
El símbolo # significa modo de direccionamiento inmediato. La expresión
(RTIFR.+RTIE.+RT1.) es la operación OR booleana de tres bits de la máscara de
posición.
El ensamblador evalúa la expresión booleana durante la compilación (ensamblado) del
programa y sustituye la respuesta ( un solo valor binario de 8 bits) dentro del programa
ensamblado. La siguiente sentencia de programa produciría exactamente el mismo
resultado, pero no sería tan fácil de leer como la anterior.
xxxx A6 16
LDA #%00010110 ;Form mask
xxxx B7 08 STA TSCR
;Write mask to Register
__rendered_path__13__rendered_path__57
112
Autor : Ing. Daniel Di Lella – Dedicated Field Application Engineer
__rendered_path__9__rendered_path__11
www.edudevices.com.ar - dilella@arnet.com.ar

Page 113
Curso Introductorio sobre Microcontroladores familias HC705 y HC908 de Freescale
Equates del sistema de aplicación.
Será común encontrar directivas Equates específicas en un programa que definen las
señales conectadas a los pines de I/O. Estas directivas EQU deberían ubicarse después
de las directivas equates estándar del MCU y antes del comienzo del programa
propiamente dicho. El entorno de trabajo del tipo lazo cíclico fue desarrollado teniendo
en mente una pequeña placa de desarrollo. Este sistema tiene un interruptor (switch)
conectado al bit 0 del puerto A (PA0) y un LED conectado al bit 7 del puerto A (PA7)
de forma tal que dichas conexiones fueron definidas con directivas EQU.
El interruptor no se usó en el programa de lazo cíclico o calesita del listado 7-1 , pero no
sería malo incluir la directiva EQU relativa al mismo. Las directivas EQU no generan
código objeto alguno que ocupe lugar de memoria en el sistema microcontrolado final.
Seteo de Vectores.
Todos los programas deben tener SETEADOS (definidos) los vectores de RESET y
de interrupciones!!!!. Los vectores especifican la dirección donde el CPU comenzará
el procesamiento de la instrucciones cuando un RESET o una INTERRUPCION
ocurran.
El RESET y cada fuente de interrupción esperan encontrar sus vectores asociados en un
específico par de locaciones de memoria. Por ejemplo, el vector de reset está en las dos
más altas posiciones de memoria ($07FE y $07FF en el MC68HC705J1A). Si no se
pusieran valores en esas posiciones, el CPU tomaría cualquiera de los valores binarios
encontrados en dicha posición y los interpretaría como si fueran la dirección de
comienzo del programa o de la rutina correspondiente a dicha interrupción, sin poder
distinguir el error cometido.
El Reset Vector (vector de Reset) debe SIEMPRE especificarse y es una buena
práctica también especificar los vectores de interrupciones aún si no se usaran los
mismos. Un error muy común en los programadores noveles (recién iniciados) es
omitir los vectores de Reset e interrupciones, originando de esta forma que el
ensamblador no incluya los mismos en la memoria de programa del MCU. Este
error genera que el MCU al ser alimentado y salir de la etapa de Power On Reset
(inicialización interna) busque el vector de Reset con un contenido frecuente de
$0000 (memoria de programa virgen del MCU tipo OTP ROM ) o $FFFF
(memoria de programa virgen del MCU tipo HC908 FLASH) que NO SON
POSICIONES DE MEMORIA DE PROGRAMA VALIDAS y dan como resultado
que el MCU quede en un loop errático sin posibilidad de salir de el.
RESET VECTOR (VECTOR DE RESET).
La forma usual para definir un vector es con la directiva FDB.
07FE 03 00 RESETV FDB START ;Beginning of program on reset
__rendered_path__13__rendered_path__82
113
Autor : Ing. Daniel Di Lella – Dedicated Field Application Engineer
__rendered_path__9__rendered_path__11
www.edudevices.com.ar - dilella@arnet.com.ar

Page 114
Curso Introductorio sobre Microcontroladores familias HC705 y HC908 de Freescale
Durante el ensamblado, el ensamblador evalúa la etiqueta START en una dirección de
dos bytes y almacena esa dirección en los próximos dos lugares disponibles de la
memoria del programa. Las columnas a la izquierda de la línea de listado muestran que
la dirección $0300 fue almacenada en $07FF. ($03 en $07FE y $00 en $07FF).
RESETV es una etiqueta opcional en esa línea de programa. Vemos también que no es
usada como referencia por otra sentencia en este programa en particular. Solo fue
incluida para identificar esa línea de directiva FDB como la sentencia que define el
vector de reset.
El vector de reset fue seteado para apuntar a la etiqueta START. Los variados sistemas
simuladores en circuito y emuladores que Motorola y otros fabricantes de terceras partes
ofrecen como herramientas de muy bajo costo, usan esta información para setear la
pantalla de simulación. Cuando un programa se carga en el simulador, el simulador
busca la dirección en el vector de reset del programa cargado. Si se encuentra, el
simulador selecciona la instrucción de programa y muestra ello en la ventana del código
fuente del simulador. Si no hubiera un vector de reset, el simulador mostraría un
mensaje de atención indicando que el vector de reset no fue inicializado. Aun así se
podría seguir con la depuración del programa, pero el mismo no funcionaría si se
quisiera programar este en la memoria de un MCU EPROM , porque el programa no
comenzaría cuando se produjera el reset.
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.
__rendered_path__13
114
Autor : Ing. Daniel Di Lella – Dedicated Field Application Engineer
__rendered_path__9__rendered_path__11
www.edudevices.com.ar - dilella@arnet.com.ar

Page 115
Curso Introductorio sobre Microcontroladores familias HC705 y HC908 de Freescale
Image_448_0
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
__rendered_path__61
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.
__rendered_path__13
115
Autor : Ing. Daniel Di Lella – Dedicated Field Application Engineer
__rendered_path__9__rendered_path__11
www.edudevices.com.ar - dilella@arnet.com.ar

Page 116
Curso Introductorio sobre Microcontroladores familias HC705 y HC908 de Freescale
“ “ “
0351
BADINT
BRA
BADINT
;Infinite loop to here
“ “ “
07FA
VECTOR
FDB
BADINT
;Hang on unexpected int
__rendered_path__79
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.
__rendered_path__13
116
Autor : Ing. Daniel Di Lella – Dedicated Field Application Engineer
__rendered_path__9__rendered_path__11
www.edudevices.com.ar - dilella@arnet.com.ar

Page 117
Curso Introductorio sobre Microcontroladores familias HC705 y HC908 de Freescale
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.
Image_455_0
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.
__rendered_path__13
117
Autor : Ing. Daniel Di Lella – Dedicated Field Application Engineer
__rendered_path__9__rendered_path__11
www.edudevices.com.ar - dilella@arnet.com.ar

Page 118
Curso Introductorio sobre Microcontroladores familias HC705 y HC908 de Freescale
Image_459_0
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.
__rendered_path__13
118
Autor : Ing. Daniel Di Lella – Dedicated Field Application Engineer
__rendered_path__9__rendered_path__11
www.edudevices.com.ar - dilella@arnet.com.ar

Page 119
Curso Introductorio sobre Microcontroladores familias HC705 y HC908 de Freescale
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.
__rendered_path__13
119
Autor : Ing. Daniel Di Lella – Dedicated Field Application Engineer
__rendered_path__9__rendered_path__11
www.edudevices.com.ar - dilella@arnet.com.ar