Sie sind auf Seite 1von 77

PROGRAMACION DE

LA TARJETA CT6811 EN
LENGUAJE C

COMPILADOR CRUZADO DE C
IMAGECRAFT V0.47

MICROBÓTICA S.L.
Programación de la tarjeta CT6811 en lenguaje C

2
Programación de la tarjeta CT6811 en lenguaje C

INDICE
PROLOGO................................................................................................................................... 5
1.- INTRODUCCION.................................................................................................................... 7
1.1.- ¿Qué es un compilador cruzado?........................................................................................ 7
1.2.- Lenguajes de alto nivel VS lenguaje ensamblador............................................................... 7
1.3.- Objetivos............................................................................................................................ 7
1.4.- Cómo leer este libro............................................................................................................ 7

2.- EL COMPILADOR DE C DE IMAGECRAFT...................................................................... 9


2.1.- Características del compilador........................................................................................... 9
2.2.- Ficheros que componen el compilador................................................................................ 9
2.3.- Funcionamiento del compilador......................................................................................... 9
2.4.- Fichero de arranque y configuración CRT.S....................................................................... 10
2.5.- Implementación de los tipos de variables............................................................................ 11
2.5.1.- Variables estáticas y automáticas............................................................................. 11
2.5.2.- Los tipos de variables CHAR e INT......................................................................... 12
2.6.- Interfaz entre el C y el lenguaje ensamblador...................................................................... 12
2.6.1.- Llamadas a funciones en ensamblador..................................................................... 12
2.6.2.- Inclusión de instrucciones en ensamblador en el código en C................................... 12
2.7.- Rutinas de servicio de interrupción..................................................................................... 13
2.7.1.- Cambio del vector de interrupción........................................................................... 13
2.7.2.- Activación de las interrupciones.............................................................................. 13
2.7.3.- Rutina de servicio de la interrupción........................................................................ 13
2.8.- Un ejemplo......................................................................................................................... 14

3.- PROGRAMACION DE LA CT6811 EN MODO ENTRENADOR....................................... 17


3.1.- INTRODUCCION.............................................................................................................. 17
3.2.- CONFIGURACION DEL COMPILADOR......................................................................... 17
3.2.1- El fichero de arranque y configuración CTRAMINT.S............................................. 17
3.2.2.- Unificación de programas en ensamblador............................................................... 18
3.2.3.- Situación de las variables al comienzo del fichero en ensamblador........................... 18
3.2.4.- Generación de archivos ejecutables .S19.................................................................. 19
3.2.5.- Resumen de los pasos necesarios para obtener ficheros ejecutables para la RAM
interna.................................................................................................................. 19
3.2.6.- El archivo CINT.BAT para compilar programas en C para la RAM interna de la
CT6811.................................................................................................................. 22
3.2.7.- Un ejemplo.............................................................................................................. 22
3.3.- REGISTROS DE CONTROL Y VECTORES DE INTERRUPCION................................. 25
3.3.1.- Acceso a los registros de control del 68HC11.......................................................... 25
3.3.2.- Acceso a los vectores de interrupción...................................................................... 26
3.4.- PROGRAMACION DE LOS RECURSOS DEL 68HC11.................................................. 29
3.4.1.- Introducción.......................................................................................................... 29
3.4.2.- Los puertos de ENTRADA/SALIDA...................................................................... 29
3.4.2.1.- Programación del puerto A...................................................................... 29
3.4.2.2.- Programación del puerto B...................................................................... 31
3.4.2.3.- Programación del puerto C...................................................................... 32
3.4.2.4.- Programación del puerto D...................................................................... 32
3.4.2.5.- Programación del puerto E...................................................................... 33
3.4.3.- Programación del SCI........................................................................................... 35
3.4.4.- Programación del SPI........................................................................................... 41
3.4.5.- Programación del temporizador principal............................................................. 45
3.4.6.- Programación de las interrupciones en tiempo real............................................... 47
3.4.7.- Programación de los comparadores...................................................................... 49
3.4.8.- Programación de los capturadores......................................................................... 53
3.4.9.- Programación del acumulador de pulsos............................................................... 55

3
Programación de la tarjeta CT6811 en lenguaje C

3.4.10.- Programación de la interrupción IRQ.................................................................. 57


3.4.11.- Programación del conversor analógico-digital (A/D)........................................... 59
3.4.12.- Programación de la EEPROM............................................................................. 61

4.- PROGRAMACION DE LA CT6811 EN MODO AUTONOMO.......................................... 63


4.1.- INTRODUCCION............................................................................................................. 63
4.2.- CONFIGURACION DEL COMPILADOR........................................................................ 63
4.2.1.- El fichero de arranque y configuración CTEEPROM.S........................................... 63
4.2.2.- Situación de las variables al comienzo del fichero en ensamblador.......................... 63
4.2.3.- Generación de archivos ejecutables .S19................................................................. 64
4.2.4.- Resumen de los pasos necesarios para obtener ficheros ejecutables para la memoria
EEPROM............................................................................................................... 64
4.2.5.- El archivo CEEPROM.BAT para compilar programas para la EEPROM................ 64
4.3.- EJEMPLOS DE PROGRAMAS PARA LA EEPROM....................................................... 67
4.4.- CONSIDERACIONES A TENER EN CUENTA............................................................... 70

5.- LIBRERIAS EN ENSAMBLADOR........................................................................................ 73


5.1.- Librería SCIASM.H para manejo del SCI.......................................................................... 73
5.2.- Librería SPIASM.H para manejo del SPI........................................................................... 73
5.3.- Librería DELAYASM.H para realizar pausas.................................................................... 77

4
Programación de la tarjeta CT6811 en lenguaje C

PROLOGO

Desde que comenzamos con el microcontrolador 68HC11, allá por Marzo de


1995, hemos ido desarrollando aplicaciones cada vez más complejas. Cada poco tiempo
‘nacía’ una nueva tarjeta entrenadora que corregía los fallos de las anteriores y añadía
multitud de mejoras. El resultado final ha sido la tarjeta CT6811, que aunque parezca tan
pequeña y simple, ha sido pensada hasta el último mílimetro. No hay nada que se haya
introducido al azar, sino que todo ha sido fruto de una necesidad a nivel práctico.
Podemos decir que desde nuestro punto de vista hemos creado la tarjeta “perfecta” para
cubrir nuestras necesidades.

Cuando hablamos de la tarjeta CT6811 no sólo nos referimos al circuito


electrónico, sino a todo el entorno software/hardware. Con el entorno desarrollado
podemos crear sistemas autónomos en muy poco tiempo: robots autónomos, circuitos de
control de luces, relojes con despertador, adquisición de datos...

Con este libro queremos dar un paso más hacia adelante. Desde el punto de vista
HARDWARE hemos avanzado muchísimo. Así, tenemos la familia de tarjetas CT:
CT6811, CT3216, CT3020, CT293 y la familia de periféricos PCT: PCT-595, PCT-293,
PCT5916. Sin embargo desde el punto de vista SOFTWARE no hemos podido avanzar
mucho. Teníamos una serie de librerías predefinidas en ensamblador y nada más. Con
este libro pretendemos dar un salto a nivel software. Queremos que nuestros sistemas se
puedan programar con un lenguaje de ‘alto nivel’ y queremos desarrollar unas librerías
para poder controlar todos los recursos del 68HC11 así como los periféricos que se
pueden conectar a la tarjeta CT6811.

Este libro se ha escrito fundamentalmente como una herramienta para nosotros.


No obstante, pensamos que también le puede ser muy útil a otras personas y eso nos ha
llevado a difundirlo. Esperamos contribuir un poco más al acercamiento de los
universitarios hacia el mundo de los microcontroladores. En este mundo, un poco
desconocido para el universitario, hay muchas cosas por hacer y hay muy poca gente que
las sepa hacer.

Nosotros apostamos por los sistemas autónomos e inteligentes, que poco a poco
se van abriendo camino a todos los niveles.

GRUPO J&J. MAYO 19971

1
El Grupo J&J actualmente es parte integrante de la empresa MICROBÓTICA S.L.

5
Programación de la tarjeta CT6811 en lenguaje C

6
Programación de la tarjeta CT6811 en lenguaje C

1.- INTRODUCCION
1.1.- ¿Qué es un compilador cruzado de C?

Un compilador cruzado es un compilador que se ejecuta en un ordenador (Por ejemplo un PC)


pero que genera código ejecutable para una CPU distinta a la del propio ordenador. Para el caso del
compilador cruzado de C utilizado en este libro, el compilador se ejecuta en un PC pero genera código
para el microcontrolador 68HC11.

1.2.- Lenguajes de alto nivel VS lenguaje ensamblador

Normalmente los microcontroladores se programan en lenguaje ensamblador porque suelen ser


programas cortos y además es necesario conocer con un alto grado de detalle lo que ocupa el programa y
la velocidad a la que se va a ejecutar. Al emplear un lenguaje de alto nivel ganamos en comodidad,
abstracción, portabilidad, legibilidad y se necesita menor tiempo de codificación, pero por el contrario se
pierde un poco la noción de qué es lo que está pasando dentro del microcontrolador. Además, el
volumen de código generado es mucho mayor que el que se hubiese obtenido programando el mismo
programa directamente en ensamblador.

Para obtener el mejor rendimiento a nuestros programas, lo ideal es utilizar cada lenguaje para
un propósito diferente: El lenguaje ensamblador será necesario utilizarlo cuando queramos optimizar
rutinas en tiempo y espacio, situación que suele ser muy corriente en el mundo de los
microcontroladores. Los lenguajes de alto nivel es mejor emplearlos para la descripción de algoritmos
que se deban ejecutar en el micro, ya que su implementación directa en ensamblador puede resultar muy
tediosa de codificar y de depurar.

Finalmente, dentro de los lenguajes de alto nivel, el lenguaje C es el más adecuado para la
programación de microcontroladores puesto que es un lenguaje que permite estar muy en contacto con la
máquina que hay debajo, a la vez que es un lenguaje de alto nivel.

1.3.- Objetivos

Los principales objetivos de este libro son:

- Describir brevemente cómo funciona el compilador de imagecraft.


- Adaptar este compilador para trabajar con la tarjeta CT6811. (La configuración también será
válida para trabajar con tarjetas equivalentes, como la del MIT).
- Presentar ejemplos de programación de los recursos del 68HC11
- Presentar unas librerías optimizadas para la gestión de los recursos del 68HC11

1.4.- Cómo leer este libro

Este libro contiene dos partes diferenciadas. En una parte se muestra el funcionamiento del
compilador y cómo configurarlo para trabajar con la CT6811. En otra parte se muestran ejemplos de
programación en C para la tarjeta CT6811. Si el lector sólo está interesado en saber cómo se compila
y cómo hay que programar, puede saltar directamente a la sección 3.4.- PROGRAMACION DE
LOS RECURSOS DEL 68HC11. Si el lector está interesado en saber las caracterísitcas generales del
compilador y quiere aprender a configurarlo debe comenzar desde el principio.

7
Programación de la tarjeta CT6811 en lenguaje C

8
Programación de la tarjeta CT6811 en lenguaje C

2.- EL COMPILADOR DE C DE IMAGECRAFT


2.1.- Características del compilador

• Compilador exclusivo para el 68HC11: Otros compiladores de C están diseñados para


generar código para microcontroladores y microprocesadores muy diversos, lo que complica
enormemente su utilización.
• Fácil llamada a rutinas en ensamblador: Es posible programar rutinas directamente en
ensamblador y llamarlas desde los programas en C
• Inserción de intrucciones en ensamblador: Es posible insertar instrucciones en
ensamblador en el propio código en C, utilizando la instrucción ASM.
• Generación de ficheros en ensamblador: Este compilador no generar archivos ejecutables
directamente, sino que crea archivos en ensamblador que luego se convierten en ejecutables.
Estos archivos en ensamblador pueden ser modificados por el usuario lo que permite
optimizar el código.
• Fichero ejecutable en formato .S19: El fichero ejecutable generado se encuentra en el
formato .S19 que es el utilizado por los programas MCBOOT y DOWNMCU para envíar
programas a la CT6811.
• Fácil configuración de la situación del código, pila y datos
• El lenguaje soportado es ANSI C

2.2.- Ficheros que componen el compilador

• ICC11.EXE :Programa principal del compilador. Este programa se llama a todos los
demás.
• ICPP.EXE: Preprocesador de C
• ICCOM11.EXE: Compilador de C propiamente dicho. Transforma archivos .C en archivos
en ensamblador con extensión .S
• IASM11.EXE: Ensamblador utilizado para convertir los ficheros .S en fichero .S19
• CRT.S: Fichero de Arranque y configuración

2.3.- Funcionamiento del compilador

Fichero fuente COMPILADOR Ficheros en ensamblador ENSAMBLADOR Fichero ejecutable


.C .S .S19

Figura 1: Funcionamiento del compilador de C

El funcionamiento del compilador es como el indicado en la figura 1. Primero se toma un


archivo en C, se compila y se obtiene un archivo .S en ensamblador. Este archivo se vuelve a compilar
utilizando el ensamblador y se crea un ejecutable con extensión .S19. En la figura 2 se muestra un
ejemplo de cómo se compilaría un programa llamado prueba.c. Utilizando el ejecutable ICC11 con el
parámetro -S se compila el programa y se genera el fichero PRUEBA.S en ensamblador. Este programa
se ensambla utilizando el ensamblador IAS11.

El parámetro -S se utiliza para que el compilador sólo genere un fichero .s. En la figura 3 se
muestra otra forma de compilar. En este caso sólo es necesario llamar al programa ICC11, el cual se
encarga de llamar al resto de ejecutables (preprocesador, compilador y ensamblador). Se genera
directamente el archivo ejecutable PRUEBA.S19. Al utilizar esta segunda opción se incluye en el
ejecutable el archivo CRT.S que es un archivo en ensamblador que contiene el arranque y configuración
del sistema. Al llamar al programa ICC11 se utiliza el parámetro -o prueba para que se genere el

9
Programación de la tarjeta CT6811 en lenguaje C

archivo PRUEBA.S19. La primera forma de compilar, la empleada en la figura 2, es la


forma que más se utilizará.

C:\6811\ICC\PRUEBA>icc11 -S prueba.c

C:\6811\ICC\PRUEBA>ias11 prueba.s

C:\6811\ICC\PRUEBA>dir

Volumen en unidad C es GRUPO JJ


Número de serie de volumen es 395D-1CD5
Directorio de C:\6811\ICC\PRUEBA

. <DIR> 04-20-97 8:22a


.. <DIR> 04-20-97 8:22a
PRUEBA C 702 04-16-97 11:19a
PRUEBA S19 36 04-20-97 8:23a
PRUEBA S 59 04-20-97 8:23a
5 archivo(s) 797 bytes
739377152 bytes libres

C:\6811\ICC\PRUEBA>_

Figura 2: Ejemplo de compilación del programa PRUEBA.C

C:\6811\ICC\PRUEBA>icc11 prueba.c -o prueba

C:\6811\ICC\PRUEBA>dir

Volumen en unidad C es GRUPO JJ


Número de serie de volumen es 395D-1CD5
Directorio de C:\6811\ICC\PRUEBA

. <DIR> 04-20-97 8:22a


.. <DIR> 04-20-97 8:22a
PRUEBA C 702 04-16-97 11:19a
PRUEBA S19 492 04-20-97 8:32a
PRUEBA S 59 04-20-97 8:32a
CRT S 1480 07-06-96 6:41a
6 archivo(s) 2733 bytes
735969280 bytes libres

C:\6811\ICC\PRUEBA>_

Figura 3: Otra forma de compilar el programa PRUEBA.C

2.4.- EL FICHERO DE ARRANQUE Y CONFIGURACION CRT.S

Antes de ejecutar programas en una tarjeta entrenadora es necesario configurarlos para que
funcionen correctamente en dicha entrenadora. Mas concretamente, tendremos que indicar la dirección
de comienzo del código, de los datos y de la pila. En la figura 4 se muestra un fragmento del fichero
CRT.S que viene por defecto con el compilador. Este archivo está pensado para trabajar con la
entrenadora de motorola que incluye el programa BUFFALO grabado en la EEPROM.

Se pueden especificar dos tipos de segmentos: segmento de código y segmento de datos. El


segmento de código es la porción de memoria en la que se va a encontrar el código. Este segmento queda
identificado por la directiva sect 0. El segmento de datos es el que va a contener los datos. Queda
identificado por la directiva sect 1. En el ejemplo de la figura 4 los datos se encuentran situados a partir
de la dirección $8000 y el código a partir de la dirección $4000.

Siguiendo el ejemplo de la figura 4, el programa en sí comienza en la línea 11. Primero se


configura la pila y después se realiza un salto al comienzo del programa, que está definido por la
etiqueta _main. El resto del código que aparece son diferentes rutinas implementadas en ensamblador
para manejar la entrenadora de motorola.

10
Programación de la tarjeta CT6811 en lenguaje C

* define starting addresses


sect 0 * code
org $4000
sect 1 * data
org $8000
stackbase equ $7ffb
*
* start of code
*
sect 0
lds #stackbase
jsr _main
swi
__lsrd: cpy #0
beq __lsrd_done
lsrd
dey
bra __lsrd

Figura 4: Fragmento del fichero de arranque y configuración


CRT.S

Para utilizar el comilador de C con la tarjeta CT6811 habrá que utilizar diferentes archivos de
inicialización dependiendo de si estamos trabajando en modo entrenador, sólo con la memoria RAM
interna, o en modo autónomo, con la memoria RAM y EEPROM interna.

2.5.- IMPLEMENTACION DE LOS TIPOS DE VARIABLES

2.5.1.- Variables estáticas y automáticas

Desde un punto de vista de la situación de las variables en memoria, en C se definen dos tipos
de variables: variables estáticas y varibles automáticas. Las variables variables estáticas conservan su
valor durante toda la ejecución del programa. Las variables automáticas desaparecen cuando se sale del
ámbito en el que se está trabajando.

Las variables automáticas se almacenan en la pila, de tal manera que al salir de los
procedimientos la pila se vacía y se pierde el valor de las variables. Las variables estáticas se sitúan en
posiciones fijas de memoria. La situación de estas variables se configura en el fichero CRT.S.

Debido a estas implementaciones hay que tener en cuenta varias cosas. Al utilizar variables
estáticas se genera menor código y los programas son más cortos y rápidos. En contraposición se
utiliza más cantidad de memoria puesto que todas las funciones tienen que tener sus variables en
memoria, se estén o no ejecutando. Las variables automáticas se almacenan en la pila y por tanto habrá
que tener en cuenta el tamaño de la pila y el tamaño de las variables automáticas para que no se
produzcan desbordamientos de la pila.

Por defecto todas las variables locales son automáticas y todas las variables globales son
estáticas. Las variables globales no pueden ser automáticas pero las locales sí pueden ser estáticas, no
perdiendo su valor al finalizar la función.

Los parámetros de las funciones se pasan todos a través de la pila, con lo que también habrá que
tenerlos en cuenta para calcular el tamaño de la pila.

Como regla general hay que decir que cuantas más variables estáticas se utilicen y cuantos
menos parámetros se pasen a las funciones, más optimo será el código en velocidad pero los datos
ocuparán más memoria. Y cuantas más variables locales y parámetros en las funciones se utilicen,
menor sera la memoria empleada para variables pero el código será mayor y la ejecución más lenta.

11
Programación de la tarjeta CT6811 en lenguaje C

2.5.2.- Los tipos de variables CHAR e INT.

Las variables de tipo char ocupan 1 byte de memoria. Las variables de tipo int ocupan 2 bytes.
Es indiferente que se utilice el modificador short. Una variable del tipo short int también ocupará 2
bytes. Todos los punteros ocupan 2 bytes.

2.6.- INTERFAZ ENTRE EL C Y EL LENGUAJE ENSAMBLADOR

2.6.1.- Llamadas a funciones en ensamblador

Es posible llamar a funciones realizadas en ensamblador directamente desde nuestros


programas en C. La única condición que se debe cumplir es que las etiquetas que definen el comienzo de
una función en ensamblador deben comenzar con el carácter _.

En la figura 5 se muestra un programa en C que simplemente llama a la funcion ledon( ) para


encender un led. La función ledon se ha implementado en ensamblador y su código se puede ver en la
figura 6. Obsérvese que en el programa fuente en C no main()
ha hecho falta especificar que la función ledon() es {
externa. Al compilar el programa en C se generará un } ledon();
salto a la etiqueta _ledon. Por ello al implementar esta
función en ensamblador deberemos especificar la Figura 5: Programa en C que llama a una
etiqueta de entrada como _ledon, como se muestra en la función implementada en ensamblador
figura 6.

sect 0 Si se definiese una función con


_ledon ; Comienzo rutina ledon()
LDAA #$40
parámetros de entrada la cosa sería un poco más
STAA $1000 complicada.
RTS

Figura 6: Implementación en ensamblador de la


función ledon()

2.6.2.- Inclusión de instrucciones en ensamblador en el código en C

Algunas veces son necesarias ciertas instrucciones de control del 68HC11 que se encuentran en
ensamblador pero que no se definen en el compilador de C como por ejemplo RTI, WAIT, SWI... Para
poder incluir estas instrucciones en nuestro código en C el compilador dispone de la instrucción ASM
que permite introducir una instrucción directamente en ensamblador. La sintaxis de esta instrucción es
ASM(“ línea en ensamblador”). Esta instrucción lo que hace es pasar directamente al ensamblador la
cadena enviada. La cadena que se pasa como argumento a la instrucción ASM puede ser incorrecta. El
compilador de C no la analizará. Simplemente la copiará tal cual en el programa en ensamblador. Será
el ensamblador en la etapa de ensamblado el que determinará si es o no correcta.

Hay una serie de reglas importantes a la hora de utilizar la instrucción ASM:

1. Si se escribe una instrucción en ensamblador hay que colocar por lo menos un espacio al comienzo
de la cadena, para indicar al ensamblador que es una instrucción y no una etiqueta. Ejemplos:
• Correcto: asm (“ RTI”);
• Incorrecto: asm (“RTI”);
2. Las etiquetas se deben escribir justo a la izquierda de la cadena, sin espacios intermedios:
• Correcto: asm (“bucle LDAA #$40”);
• Incorrecto: asm (“ bucle LDAA #$40”);

12
Programación de la tarjeta CT6811 en lenguaje C

main()
{
Es posible hacer referencia a variables en c desde la static char c;
instrucción asm. Para ello utilizamos el carácter %. En la
figura 7 se muestra un ejemplo muy simple. Queremos cargar c=leer_car();
asm (“ LDAA %c”);
en el acumulador A el valor de la variable c. La instrucción .
asm(“ LDAA %c”) lo soluciona. El carácter % hace que se .
}
le pase al ensamblador la etiqueta asociada a la variable
situada a continuación del carácter %, en vez del identificador Figura 7: Ejemplo de carga de la
de la propia variable. variable c en el acumulador A

2.7.- RUTINAS DE SERVICIO DE INTERRUPCION

A la hora de hacer rutinas de servicio de interrupción hay que tener en cuenta los tres puntos
siguientes:

1. Cambio del vector de interrupción


2. Activación de las interrupciones
3. Codificación de la rutina de servicio de interrupción

En la figura 8 se /* Vector de interrupción */


muestra el modelo a seguir para #define vint (*(unsigned int *)0xFFD6)
la puesta en funcionamiento de
/* Rutina de servicio de interrupción */
las rutinas de servicio de void rsi()
interrupción. {
.
.
2.7.1.- Cambio del vector de .
interrupción asm (“ RTI”);
}

En el modelo de la main()
figura 8 se ha modificado el { /* Cambiar vector de interrupción */
vector de interrupción de la vint = (unsigned int)rsi;
dirección 0xFFD6 para que
/* Activar las interrupciones */
apunte a la rutina de servicio de asm (“ CLI”);
interrupción rsi(). Primero se .
define la situación del vector de .
.
interrupción por medio de una }
instrucción define. Lo que
estamos indicando al Figura 8: Programa modelo de una rutina de servicio de
compilador es que vint es una interrupción
constante que representa un
valor entero que debe estar situado en la dirección 0xFFD6. Para hacer que este valor apunte a la rutina
que nosotros queramos simplemente se realiza la asignación vint = (unsigned int)rsi; que introduce la
dirección de comienzo de la función rsi() en la dirección 0xFFD6.

2.7.2.- Activación de las interrupciones

Una vez que se ha cambiado el vector de interrupción es necesario activar las interrupciones.
No existe ninguna instrucción en el estándar ANSI C que permita hacer eso, por lo que se recurre a
escribir directamente la instrucción en ensamblador mediante la instrucción asm (“ CLI”). Si se quieren
inhibir las interrupciones bastará con escribir asm(“ SEI”);

2.7.3.- Rutina de servicio de la interrupción

Las rutinas de atención a las interrupciones deben terminar con la instrucción RTI, en lugar de
la instrucción RTS que es la utilizada para retornar de una subrutina. En el estándar ANSI C no se

13
Programación de la tarjeta CT6811 en lenguaje C

contempla ninguna palabra reservada para indicar al compilador que una función en C es
una rutina de servicio de interrupción y que por tanto debe finalizar con la instrucción RTI en lugar de
RTS. Por ello es necesario introducir directamente la instrucción RTI al final de la rutina de servicio de
interrupción por medio de la instrucción asm (“ RTI”). Pero esto tiene problemas. El compilar puede
haber generado un código que utilice la pila. Antes de salir de la rutina de interrupción habrá que vaciar
por completo la pila o de lo contrario llegará un momento que se desbordará.

Para solucionar esto se utiliza el truco de la subrutina de servicio de interrupción. Para cada
interrupción que tomemos se definen dos funciones. Una función será la rutina de servicio de
interrupción y la otra será la subrutina de servicio de interrupción. El nuevo vector de interrupción se
modificará para que apunte a la rutina de servicio de interrupción, la cual debe acabar con la instrucción
asm (“ RTI”). En la subrutina de servicio de interrupción se introduce el código necesario para atender
a la interrupción. A continuación se muestra un esquema de funcionamiento:

void ssi()
/* Subrutina de servicio de interrupción */
{
/* Codigo */
...
...
}

void rsi()
/* Rutina de servicio de interrupción */
{
ssi(); /* Llamar a la subrutina de servicio de interrupción */
asm (“ RTI”); /* Retorno de interrupción */
}

main()
{
/* Cambiar el vector de interrupción para que apunte a rsi() */
...
...
}

2.8.- UN EJEMPLO

A continuación se muestra un pequeño programa en C que sirve para hacer que un led situado
en el bit 6 del puerto A se ponga a parpadear. Este ejemplo no está adaptado a ninguna entrenadora,
simplemente se compila el archivo .C y se genera el archivo equivalente .S. Para que funcione con una
entrenadora concreta, como por ejemplo la CT6811, habrá que utilizar un archivo de configuración
especial y realizar algunas modificaciones en los ficheros .S. Esto se trata en el apartado 3:
Programación de la tarjeta CT6811 en modo entrenador.

En la figura 9 se muestra el codigo en C.

14
Programación de la tarjeta CT6811 en lenguaje C

/*
+------------------------------------------------------------------------+
¦ LEDP.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo para encender el led de la tarjeta CT6811. ¦
+------------------------------------------------------------------------+ */

#define PORTA (*(unsigned char *)0x1000)

unsigned int i;

main()
{
for (;;) {
PORTA^=0x40;
for (i=0; i<0x8000; i++);
}
}

Figura 9: Programa LEDP.C

En la figura 10 se puede ver el archivo en ensamblador (LEDP.S) generado. Para generarlo se ha


tecleado: ICC11 -S ledp.c sect 0
_main:
L2.ledp:
Obsérvese que existen dos secciones. ldab 4096
En la sección 0 se encuentra el código. En la clra
eorb #64
sección 1 se encuentra la única variable que stab 4096
hay en el programa. Esta variable es global. ldd #0
std _i
jmp L9.ledp
Ensamblando directamente el L6.ledp:
programa LEDP.S no conseguimos obtener el L7.ledp:
ejecutable LEDP.S19 deseado. Debemos ldd _i
addd #1
ensamblarlo junto con un fichero .S de std _i
configuración que indique la posicón en L9.ledp:
ldd _i
memoria de las dos secciones. cpd #-32768
blo L6.ledp
jmp L2.ledp
L1.ledp:
sect 1
_i:
RMB 2

Figura 10: Fichero LEDP.S

15
Programación de la tarjeta CT6811 en lenguaje C

16
Programación de la tarjeta CT6811 en lenguaje C

3.- PROGRAMACION DE LA CT6811 EN MODO


ENTRENADOR
3.1.- INTRODUCCION

El objetivo es configurar el compilador de C para que $0000


RAM INTERNA
funcione con los 256 bytes de RAM de la CT6811. Lo que se
quiere es crear programas en C para ser probados en la RAM
interna del 68HC11, es decir, en el modo entrenador de la $1000 RGISTROS
tarjeta CT6811. DE CONTROL

El mapa de memoria de la tarjeta CT6811 se muestra


en la figura 11. Al trabajar en modo entrenador lo que nos
interesa son los 256 bytes de RAM interna, situados desde la
dirección $00 hasta la $FF, y los registros de control. $B600 EEPROM

Para poder utilizar el compilador de C tendremos que


configurarlo para que se genere código para este mapa de BOOTSTRAP
memoria. El código debe empezar en la dirección $0000 y no ROM
puede sobrepasar la dirección $FF, o de lo contrario
desbordaremos la memoria interna del 68HC11. $E000

Tanto el código, como los datos y la pila se deben ROM


situar en la RAM interna. Por ello podemos hablar de un
único segmento de trabajo.

Figura 11: Mapa de memoria de la


CT6811

3.2.- CONFIGURACION DEL COMPILADOR

3.2.1.- El fichero de arranque y configuración CTRAMINT.S

El fichero de arranque y configuración empleado se muestra en la figura 12. Se ha llamado


CTRAMINT.S para indica que es para generar código y datos para la ram interna de la CT6811

* +------------------------------------------------------------------------+
* ¦ CTRAMINT.S (C) GRUPO J&J. ABRIL 1997 ¦
* ¦------------------------------------------------------------------------¦
* ¦ Fichero de arranque y configuración para trabajar con la tarjeta ¦
* ¦ CT6811 en modo entrenador. ¦
* +------------------------------------------------------------------------+ */

ORG $0000 ; Comienzo de la RAM interna

jsr _main ; Saltar al programa principal


inf bra inf ; ¡Bucle infinito!

Figura 12: Fichero de arranque y configuración para trabajar con la CT6811 en modo
entrenador

En este archivo se sitúa el comienzo de todos los programas a partir de la dirección $0000 que
es donde empieza la RAM interna. Este programa realiza un salto a la etiqueta _main que es el nombre
que recibe la etique de comienzo del programa principal. Si se retorna del programa principal, se entra
en un bucle infinito para que el 68HC11 no ejecute instrucciones al azar.

17
Programación de la tarjeta CT6811 en lenguaje C

Este archivo de configuración puede ser modificado. Por ejemplo, si el propio


programa principal en C nunca termina, lo que suele ser habitual, se puede eliminar la última línea del
archivo CTRAMINT.S con lo que se ahorran bytes de memoria. Teniendo únicamente 256 bytes de
memoria hay que aprovechas hasta el último byte.

Puesto que para que la CT6811 funcione en modo entrenador ,el 68HC11 debe arrancar en el
modo BOOTSTRAP, con lo que la pila ya se encuentra inicializada en la dirección $FF y no será
necesario inicializarla en el archivo de arranque y configuración.

Obsérvese que en el fichero de arranque y configuración no se han definido secciones. Esto es


debido a que el código, los datos y la pila se deben situar dentro de la misma sección. Un programa de
estas características es lo que denominaremos programa unificado.

3.2.2.- Unificación de programas en ensamblador

El código en ensamblador generado por el compilador de C no se encuentra unificado. Es


decir, que las variables se sitúan en la sección 1 y el código en la sección 0. Para solucionar esto se
utiliza el programa UNIFICA.EXE desarrollado por el Grupo J&J. Este programa simplemente toma un
fichero en ensamblador y genera otro fichero igual que el original pero en el que se han eliminado todas
las secciones. En la figura 13 se muestra un ejemplo de utilización. A partir del programa prueba.s no
unificado se genera el fichero pruebau.s ya unificado.

C:\6811\ICC\CT68INT>unifica prueba.s pruebau.s

UNIFICA V1.0 (C) GRUPO J&J. Abril 1997.


Generación de código unificado en ensamblador

Fichero a Filtrar: prueba.s


Fichero destino : pruebau.s

C:\6811\ICC\CT68INT>

Figura 13: Generación del fichero unificado pruebau.s a partir del fichero no
unificado prueba.s

Será con los programas unificados con los que se trabajará cuando queramos utilizar la CT6811
en modo entrenador.

3.2.3.- Situación de las variables al comienzo del fichero en ensamblador

No se pueden ensamblar los archivos unificados junto con el archivo de arranque y


configuración para generar un ejecutable con extensión .S19 que se pueda cargar en la RAM interna de
la CT6811. Es necesario realizar una transformación más al archivo en ensamblador. El compilador
sitúa todas las variables estáticas al final del fichero en ensamblador. Para poder ensamblar un programa
de estas caracteristicas que comience en la RAM interna, es necesario que las variables se sitúen al
comienzo del código. Los programas que comiencen en otras direcciones de memoria fuera de la RAM
interna no sufrirán esta restricción, sus variables podrán estar en cualquier sitio. Sin embargo, los
programas para la RAM interna deben sufrir estas restricciones por motivos que están fuera de los
objetivos de este libro.2

Para solucionar esto se utiliza el programa GETVARS.EXE, también desarrollado por el


Grupo J&J, que sirve para ‘extraer’ todas las variables de un fichero en ensamblador. En la figura 14 se
muestra cómo funciona este programa. Con el primer comando se genera el fichero prueba.s sin
variables a partir del fichero pruebau.s. El programa getvars imprime en pantalla la única variable que
ha encontrado. Con el siguiente comando se hace lo mismo pero se guarda la variable extraida en el

2
Cuando se trabaja en la RAM interna, el ensamblador genera un código más optimizado puesto que el
68HC11 permite utilizar direccionamiento directo.

18
Programación de la tarjeta CT6811 en lenguaje C

fichero vars. Finalmente, con el último comando se genera el archivo pruebaf.s que ya está
listo para ser ensamblado junto con el archivo de arranque y configuración ctramint.s

C:\6811\ICC\CT68INT>getvars pruebau.s prueba.s


_i:
RMB 2

C:\6811\ICC\CT68INT>getvars pruebau.s prueba.s > vars

C:\6811\ICC\CT68INT>copy vars+prueba.s pruebaf.s


VARS
PRUEBA.S
1 archivo(s) copiado(s)

C:\6811\ICC\CT68INT>_

Figura 14: Generación del fichero pruebaf.s con las variables al comienzo

3.2.4.- Generación de archivos ejecutables .S19

Una vez que se tienen todos los ficheros .S y se quiere obtener el fichero ejecutable con
extensión .S19, se utilizará el ensamblador IAS11.EXE según se muestra en la figura 15. En ese
ejemplo se genera el fichero PROGRAMA.S19 a partir de los ficheros en ensamblador PRUEBA1.S,
PRUEBA2.S y el fichero de arranque y configuración CTRAMINT.S. El parámetro -o seguido por
programa indica al ensamblador que se genera un archivo ejecutable con nombre programa.s19. Si no
se especifica este parámetro el ensamblador generará el fichero ejecutable con el nombre del primer
archivo .S que se haya pasado como argumento.

C:\6811\ICC\CT68INT>ias11 -o programa ctramint.s prueba1.s prueba2.s

C:\6811\ICC\CT68INT>dir programa.s19

Volumen en unidad C es GRUPO JJ


Número de serie de volumen es 395D-1CD5
Directorio de C:\6811\ICC\CT68INT

PROGRAMA S19 152 04-27-97 10:15a


1 archivo(s) 152 bytes
728432640 bytes libres

C:\6811\ICC\CT68INT>_

Figura 15: Generación del fichero ejecutable programa.s19 a partir de los ficheros
prueba1.s, prueba2.s y ctramint.s.

3.2.5.- Resumen de los pasos necesario para obtener ficheros ejecutables para la RAM interna

En la figura 16 se muestra un esquema con todos los pasos que hay que realizar aplicados al
programa ledp.C para generar el fichero ejecutable ledp.S19.

Los pasos que hay que realizar en general son:

• Compilar todos los archivos .C que integren el programa final. Para ello utilizar: ICC11 -S fichero.c
Con esto conseguimos tener una serie de archivos .S en ensamblador.
• Aplicar a cada archivo .S la unificación mediante el programa UNIFICA.EXE
• Situar todas las variables al comienzo del código con el progrma GETVARS.EXE
• Ensamblar todos los ficheros .S ya modificados junto con el archivo de arranque y configuración
CTRAMINT.S
• Ya se dispone de un archivo .S19 listo para ser enviado a la tarjeta CT6811.

19
Programación de la tarjeta CT6811 en lenguaje C

COMPILADOR MODIFICACION DE
UNIFICACION
Fichero ledp.c DE C VARIABLES
UNIFICA ledp.s ledpu.s
getvars ledpu.s ledpv.s > vars
ICC11 -S ledp.c
copy vars+ledpv ledpf

ENSAMBLADOR
Fichero ledp.S19
IAS11 -o ledp ctramint.s ledpf

Figura 16: Pasos a realizar para crear el fichero ledp.S19 a partir del fichero ledp.C

Por si el lector tiene curiosidad, se van a presentar los distintos ficheros intermedios generados
en el ejemplo de la figura 16. En la figura 17 se muestra el programa ledp.C y en la figura 18 el fichero
ledp.S ya compilado.
/*
+------------------------------------------------------------------------+
¦ LEDP.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo para encender el led de la tarjeta CT6811. ¦
+------------------------------------------------------------------------+ */

#define PORTA (*(unsigned char *)0x1000)

unsigned int i;

main()
{
for (;;) {
PORTA^=0x40;
for (i=0; i<0x8000; i++);
}
}

Figura 17: Programa LEDP.C

sect 0
_main:
L2.ledp:
ldab 4096
clra
eorb #64
stab 4096
ldd #0
std _i
jmp L9.ledp
L6.ledp:
L7.ledp:
ldd _i
addd #1
std _i
L9.ledp:
ldd _i
cpd #-32768
blo L6.ledp
jmp L2.ledp
L1.ledp:
sect 1
_i:
RMB 2

Figura 18: Fichero LEDP.S recién compilado

20
Programación de la tarjeta CT6811 en lenguaje C

En la figura 19 se muestra el programa ledpu.s que ya ha sido unificado. La única


diferencia es que se han suprimido las directivas sect 0 y sect 1.

_main:
L2.ledp:
ldab 4096
clra
eorb #64
stab 4096
ldd #0
std _i
jmp L9.ledp
L6.ledp:
L7.ledp:
ldd _i
addd #1
std _i
L9.ledp:
ldd _i
cpd #-32768
blo L6.ledp
jmp L2.ledp
L1.ledp:

_i:
RMB 2

Figura 19: Fichero LEDPU.S

En la figura 20 se muestra el archivo LEDPF.S. Es igual que el archivo unificado LEDPU.S


con la diferencia que la variable está definida al comienzo en vez de al final.

_i:
RMB 2

_main:
L2.ledp:
ldab 4096
clra
eorb #64
stab 4096
ldd #0
std _i
jmp L9.ledp
L6.ledp:
L7.ledp:
ldd _i
addd #1
std _i
L9.ledp:
ldd _i
cpd #-32768
blo L6.ledp
jmp L2.ledp
L1.ledp:

Figura 20: Fichero LEDPF.S listo para ser ensamblado

21
Programación de la tarjeta CT6811 en lenguaje C

3.2.6.- El archivo CINT.BAT para compilar programas en C para la RAM interna de la CT6811

En la figura 21 se muestra el archivo .BAT creado para realizar la compilación automática de


los programas en C.

@REM
@REM ------------- Compilar de .c a .s ------------------
@REM
@icc11 -S %1.c
@REM
@REM ------------ Generar fichero en ensamblador unificado -------
@REM
@unifica %1.s temp.s
@REM
@REM ------------ Eliminación de las variables RMB ---------------
@REM
@getvars temp.s temp2.s > %1.var
@REM
@REM ------------ Generación del fichero .s final -----------------
@REM
@copy %1.var+temp2.s %1.s > NUL
@REM
@REM ------------- Borrar ficheros temporales --------
@del temp.s > NUL
@del temp2.s > NUL
@REM
@REM ------------ Generar fichero .S19 ---------------------
@REM
@ias11 -o %1 ctramint.s %1.s

Figura 21: Fichero CINT.BAT para la compilación automática de los programas en C

Con este archivo, que puede ser modificado por el usuario para adaptarlo a sus necesidades, es
muy fácil generar archivos ejecutables .S19 directamente. En el apartado 3.2.7 se muestra cómo
compilar el archivo LEDP.C para generar el archivo LEDP.S19 que será enviado a la tarjeta CT6811.

3.2.7.- Un ejemplo

En la figura 22 se muestran los comandos necesarios para compilar el programa LEDP.C,


mostrado en la figura 17, generar el archivo LEDP.S19 y enviárselo a la CT6811 por medio del
programa DOWNMCU.EXE. En el ejemplo se supone que la CT6811 se encuentra conectada al
COM2.

A partir de ahora ya disponemos de las herramientas necesarias para empezar a generar


programa en C para el 68HC11.

22
Programación de la tarjeta CT6811 en lenguaje C

C:\6811\ICC\CT68INT>cint ledp

UNIFICA V1.0 (C) GRUPO J&J. Abril 1997.


Generación de código unificado en ensamblador

Fichero a Filtrar: ledp.s


Fichero destino : temp.s

C:\6811\ICC\CT68INT>
C:\6811\ICC\CT68INT>downmcu ledp -com2

DOWN-MCU. V1.0 (C) GRUPO J&J. Noviembre-1996.


Envío de programas a la entrenadora

Fichero a enviar: .\ledp.S19


Puerto serie: COM2

Pulse reset en la entrenadora...


Transmitiendo: >>>>>..>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.......................
................................................................................
................................................................................
...............................OK!
Envío correcto
Tamaño del programa: 40 bytes

C:\6811\ICC\CT68INT>

Figura 22: Ejemplo de compilación del programa LEDP.C y envío a la CT6811

23
Programación de la tarjeta CT6811 en lenguaje C

24
Programación de la tarjeta CT6811 en lenguaje C

3.3.- REGISTROS DE CONTROL Y VECTORES DE INTERRUPCION

3.3.1.- Acceso a los registros de control del 68HC11

Para controlar cualquier recurso interno del 68HC11 es necesario acceder a los registros de
control que se encuentran situados en el mapa de memoria entre las direcciones $1000 y $103F. La
forma más optimizada de acceder a estos registros es como se indica en la figura 23. En este ejemplo se
envía el valor $FF al puerto A y se vuelve a leer.

#define porta (*(unsigned char *)0x1000)

char i;

main()
{
porta=0xFF; /* Envio de datos al puerto A */
i=porta; /* Lectura de datos del puerto A */
}

Figura 23: Ejemplo de acceso a los registros de control . Se envía el valor $FF al puerto A

Para facilitar el acceso a todos los registros de control, se han incluido todas las definiciones en
el fichero REGS6811.H, que se muestra a continuación.

/*
+------------------------------------------------------------------------+
¦ REGS6811.H (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Fichero que contiene todos los registros internos del 68HC11. ¦
¦ ¦
+------------------------------------------------------------------------+ */

#define PORTA (*(unsigned char *)0x1000)


#define PIOC (*(unsigned char *)0x1002)
#define PORTC (*(unsigned char *)0x1003)
#define PORTB (*(unsigned char *)0x1004)
#define PORTCL (*(unsigned char *)0x1005)
#define DDRC (*(unsigned char *)0x1007)
#define PORTD (*(unsigned char *)0x1008)
#define DDRD (*(unsigned char *)0x1009)
#define PORTE (*(unsigned char *)0x100A)
#define CFORC (*(unsigned char *)0x100B)
#define OC1M (*(unsigned char *)0x100C)
#define OC1D (*(unsigned char *)0x100D)

#define TCNT (*(unsigned int *)0x100E)


#define TIC1 (*(unsigned int *)0x1010)
#define TIC2 (*(unsigned int *)0x1012)
#define TIC3 (*(unsigned int *)0x1014)
#define TOC1 (*(unsigned int *)0x1016)
#define TOC2 (*(unsigned int *)0x1018)
#define TOC3 (*(unsigned int *)0x101A)
#define TOC4 (*(unsigned int *)0x101C)
#define TOC5 (*(unsigned int *)0x101E)

#define TCTL1 (*(unsigned char *)0x1020)


#define TCTL2 (*(unsigned char *)0x1021)
#define TMSK1 (*(unsigned char *)0x1022)
#define TFLG1 (*(unsigned char *)0x1023)
#define TMSK2 (*(unsigned char *)0x1024)
#define TFLG2 (*(unsigned char *)0x1025)
#define PACTL (*(unsigned char *)0x1026)
#define PACNT (*(unsigned char *)0x1027)
#define SPCR (*(unsigned char *)0x1028)
#define SPSR (*(unsigned char *)0x1029)
#define SPDR (*(unsigned char *)0x102A)
#define BAUD (*(unsigned char *)0x102B)
#define SCCR1 (*(unsigned char *)0x102C)
#define SCCR2 (*(unsigned char *)0x102D)
#define SCSR (*(unsigned char *)0x102E)
#define SCDR (*(unsigned char *)0x102F)
#define ADCTL (*(unsigned char *)0x1030)
#define ADR1 (*(unsigned char *)0x1031)

25
Programación de la tarjeta CT6811 en lenguaje C

#define ADR2 (*(unsigned char *)0x1032)


#define ADR3 (*(unsigned char *)0x1033)
#define ADR4 (*(unsigned char *)0x1034)
#define OPTION (*(unsigned char *)0x1039)
#define COPRST (*(unsigned char *)0x103A)
#define PPROG (*(unsigned char *)0x103B)
#define HPRIO (*(unsigned char *)0x103C)
#define INIT (*(unsigned char *)0x103D)
#define TEST1 (*(unsigned char *)0x103E)
#define CONFIG (*(unsigned char *)0x103F)

Los nombres utilizados para los registros de control son los mismo que se encuentran en el
manual del 68HC11 original. Utilizando el archivo REGS6811.H el programa de la figura 23 queraría
como se muestra en la figura 24.

#include “REGS6811.H”

char i;

main()
{
PORTA=0xFF; /* Envio de datos al puerto A */
i=PORTA; /* Lectura de datos del puerto A */
}

Figura 24: Ejemplo de utilización del fichero de definición de registros internos REGS6811.H

3.3.2.- Acceso a los vectores de interrupción.

Cuando se trabaja con la CT6811 tanto en modo entrenador como autónomo, el 68HC11
arranca en modo bootstrap. En este modo los vectores de interrupción se encuentran en la memoria
ROM de arranque, y están apuntando a direcciones de la RAM interna. Las direcciones a las que
apuntan van desde la $00C4 hasta la $00FF. Cada ‘vector de interrupción’ en RAM está compuesto por
3 bytes libres. El primer byte se reserva para situar una instrucción JMP y los dos siguientes para situar
la dirección de la rutina de servicio de interrupción. Por ello, para cambiar un vector de interrupción, se
deben realizar dos pasos. En el primer paso se sitúa la instrucción JMP. En el segundo paso se sitúa la
dirección de la rutina de servicio.

Supongamos que queremos utilizar la interrupción del SCI, que se encuentra en la dirección
$00C4. Cada vez que se produzca un acontecimiento en el SCI, y si las interrupciones están habilitadas,
el 68HC11 realizará un salto a la dirección $00C4. En esta dirección se deberá situar la instrucción JMP.
En la dirección $00C5 el byte alto de la dirección de comienzo de la rutina de atención a la interrupción
y en la dirección $00C6 el byte bajo de la dirección de la rutina de atención a la interrupción. En la
figura 25 se muestra un ejemplo (no completo) de cómo es posible hacer esto.

#define visci1 (*(char *)0xC4) /* SCI */


#define visci2 (*(unsigned int *)0xC5)

void rsisci()
/* Rutina de atención a la interrupción del SCI */
{
......
......

asm (" RTI");


}

main()
{
visci1=0x7E; /* Colocar instrucción JMP */
visci2=(unsigned int)rsisci; /* Colocar dirección rutina servicio */
....
....
}

Figura 25: Ejemplo de cambio del vector de interrupción de la interrupción del SCI

26
Programación de la tarjeta CT6811 en lenguaje C

El programa de la figura 25 se comentará con un poco más de detalle. Obsérvese


que se han realizado dos “defines”. Se han definido el objeto visci1 y el objeto visci2. Los números 1 y 2
hacen referencia al byte del vector de interrupción. Para el caso del SCI, el primer byte (que debe
contener la instrucción JMP) se encuentra en la dirección $00C4. El segundo byte se encuentra en la
dirección $00C5. El nombre visci significa Vector Interrupción del SCI.

La rutina de atención a la interrupción se ha denominado rsisci (Rutina de Servicio de


Interrupción del SCI). El programa principal lo primero que hace es modificar el vector de interrupción
del SCI. Con la primera instrucción se sitúa el código 0x7E en la dirección $00C4. Este código se
corresponde con el código de la instrucción JMP. La siguiente instrucción sitúa la dirección de la rutina
de atención de interrupción, que es rsisci.

Para la implementación de la rutina de servicio de interrupción hay que utilizar el ‘truco’ de la


subrutina de servicio de interrupción, tal como se comentó en el punto 2.7.4.

En el fichero VECTINT.H se encuentran definidos todos los vectores de interrupción de todas


las interrupciones del 68HC11. Todas las constantes definidas comienzan por vi indicando vector de
interrupción. Todas acaban en un 1 ó en un 2 indicando si se trata del byte para la instrucción JMP o del
entero que contiene la dirección de la rutina de atención.

/*
+------------------------------------------------------------------------+
¦ VECTINT.H (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Vectores de interrupción del modo BOOTSTRAP. ¦
¦ Por cada vector se dan dos direcciones. La primera corresponde al ¦
¦ espacio reservado para colocar una instrucción JUMP. La segunda se ¦
¦ corresponde con la dirección del vector de interrupcion. La conjun- ¦
¦ ción de ambas provoca una intrucción de la forma JMP dir en el vector ¦
¦ especificado. ¦
+------------------------------------------------------------------------+ */

#define visci1 (*(char *)0xC4) /* SCI */


#define visci2 (*(unsigned int *)0xC5)

#define vispi1 (*(char *)0xC7) /* SPI */


#define vispi2 (*(unsigned int *)0xC8)

#define viap1 (*(char *)0xCA) /* Acumulador de Pulsos */


#define viap2 (*(unsigned int *)0xCB)

#define vioap1 (*(char *)0xCD) /* Overflow en acumulador de pulsos */


#define vioap2 (*(unsigned int *)0xCE)

#define viot1 (*(char *)0xD0) /* Overflow en temporizador */


#define viot3 (*(unsigned int *)0xD1)

#define vioc51 (*(char *)0xD3) /* Comparador 5 */


#define vioc52 (*(unsigned int *)0xD4)

#define vioc41 (*(char *)0xD6) /* Comparador 4 */


#define vioc42 (*(unsigned int *)0xD7)

#define vioc31 (*(char *)0xD9) /* Comparador 3 */


#define vioc32 (*(unsigned int *)0xDA)

#define vioc21 (*(char *)0xDC) /* Comparador 2 */


#define vioc22 (*(unsigned int *)0xDD)

#define vioc11 (*(char *)0xDF) /* Comparador 1 */


#define vioc12 (*(unsigned int *)0xE0)

#define viic31 (*(char *)0xE2) /* Capturador 3 */


#define viic32 (*(unsigned int *)0xE3)

#define viic21 (*(char *)0xE5) /* Capturador 2 */


#define viic22 (*(unsigned int *)0xE6)

#define viic11 (*(char *)0xE8) /* Capturador 1 */


#define viic12 (*(unsigned int *)0xE9)

#define virti1 (*(char *)0xEB) /* Tiempo real */


#define virti2 (*(unsigned int *)0xEC)

27
Programación de la tarjeta CT6811 en lenguaje C

#define viirq1 (*(char *)0xEE) /* IRQ */


#define viirq2 (*(unsigned int *)0xEF)

#define vixirq1 (*(char *)0xF1) /* XIRQ */


#define vixirq2 (*(unsigned int *)0xF2)

#define viswi1 (*(char *)0xF4) /* Interrupción Software */


#define viswi2 (*(unsigned int *)0xF5)

#define viiop1 (*(char *)0xF7) /* Instrucción ilegal */


#define viiop2 (*(unsigned int *)0xF6)

#define visf1 (*(char *)0xFA) /* Fallo del sistema */


#define visf2 (*(unsigned int *)0xFB)

#define vicopf1 (*(char *)0xFD) /* Fallo en el monitor del reloj */


#define vicopf2 (*(unsigned int *)0xFE)

En la figura 26 se muestra el mismo ejemplo que en la figura 25 pero utilizando el archivo


VECTINT.H

#include “VECTINT.H”

void rsisci()
/* Rutina de atención a la interrupción del SCI */
{
......
......

asm (" RTI");


}

main()
{
visci1=0x7E; /* Colocar instrucción JMP */
visci2=(unsigned int)rsisci; /* Colocar dirección rutina servicio */
....
....
}

Figura 26: Cambio del vector de interrupción del SCI utilizando el archivo VECTINT.H

28
Programación de la tarjeta CT6811 en lenguaje C

3.4.- PROGRAMACION DE LOS RECURSOS DEL 68HC11

3.4.1.- INTRODUCCION

En esta sección se va a comenzar a programar todos los recursos del 68HC11. Los programas
están pensados para ser ejecutados en la RAM interna del 68HC11, pero si se quieren adaptar para
funcionar en memoria externa o en la memoria EEPROM lo único que habrá que modificar será el
archivo de arranque y configuración.

A partir de aqui ya disponemos de las herramientas necesarias para empezar a programar. Para
compilar los programas simplemente habrá que utilizar el archivo CINT.BAT:

C:> CINT fichero_fuente (sin extensión)

A la hora de realizar los programas se utilizarán los archivos REGS6811.H y VECTINT.H


definidos en las secciones 3.3.1 y 3.3.2 respectivamente.

En los ejemplos que se muestran en toda la sección se van a ir construyendo librerías para
trabajar con los recursos internos del 68HC11. La primera versión de las librerías siempre estará en C.
Sin embargo, para optimizar memoria es mejor realizar algunas librerías directamente en
ensamblador. Como se verá más adelante, con ello conseguiremos un enorme ahorro de memoria. Las
librerías en ensamblador tienen el mismo interfaz de cara a nuestros programas en C pero se han
programado utilizando la directiva ASM del compilador de C.

3.4.2.- LOS PUERTOS DE ENTRADA/SALIDA

3.4.2.1.- PROGRAMACION DEL PUERTO A

EJEMPLO 1: Encender el led de la tarjeta CT6811

El primer ejemplo va a ser el más sencillo posible. Simplemente se va a encender el led de la


CT6811, que se encuentra en el bit 6 del puerto A (Bit PA6). Para recapitular ideas, este va a ser un
ejemplo completo. Se va a mostrar el código fuente en C y los comandos utilizados para compilar y
enviar el programa ejecutable a la CT6811, que se supondrá que se encuentra situada en el puerto
COM2.

/*
+------------------------------------------------------------------------+
¦ LEDON.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo para encender el led de la tarjeta CT6811. ¦
+------------------------------------------------------------------------+ */

#include “REGS6811.H”

main()
{
PORTA=0x40;
}

Lo primero que se hace es incluir el archivo REGS6811.H que contiene todas las definiciones
de los registros de control del 68HC11. Entre ellas está la definición del puerto A. El programa principal
simplemente envía el valor 0x40 al puerto A, con lo que se encenderá el led de la CT6811. En la figura
27 se muestran todos los pasos que hay que realizar para compilar y para enviar el programa a la
CT6811.

29
Programación de la tarjeta CT6811 en lenguaje C

C:\6811\ICC\CT68INT>cint ledon

UNIFICA V1.0 (C) GRUPO J&J. Abril 1997.


Generación de código unificado en ensamblador

Fichero a Filtrar: ledon.s


Fichero destino : temp.s

C:\6811\ICC\CT68INT>
C:\6811\ICC\CT68INT>downmcu ledon -com2

DOWN-MCU. V1.0 (C) GRUPO J&J. Noviembre-1996.


Envío de programas a la entrenadora

Fichero a enviar: .\ledon.S19


Puerto serie: COM2

Pulse reset en la entrenadora...


Transmitiendo: >>>>>>>>>>>......................................................
................................................................................
................................................................................
...............................OK!
Envío correcto
Tamaño del programa: 11 bytes

C:\6811\ICC\CT68INT>_

Figura 27: Compilando y cargando el programa LEDON.C

EJEMPLO 2: Hacer parpadear el LED de la tarjeta CT6811

Este ejemplo simplemente hace parpadear el LED de la tarjeta CT6811. La novedad que se
introduce en este programa es que se ha definido la variable global i.

/*
+------------------------------------------------------------------------+
¦ LEDP.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo para encender el led de la tarjeta CT6811. ¦
+------------------------------------------------------------------------+ */

#include "REGS6811.H"

unsigned int i;

main()
{
for (;;) {
PORTA^=0x40; /* Cambiar de estado PA6 */
for (i=0; i<0x8000; i++); /* Realizar una pausa */
}
}

EJEMPLO 3: Utilización del bit 7 del puerto A como salida

El bit 7 del puerto A por defecto está configurado como entrada. En este ejemplo se configura
como salida y se activa, de tal forma que si se conecta un led se enciende.

/*
+------------------------------------------------------------------------+
¦ PA7.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Se configura el bit 7 del puerto A para salida y se activa con ¦
¦ un '1'. ¦

30
Programación de la tarjeta CT6811 en lenguaje C

+------------------------------------------------------------------------+ */

#include "REGS6811.H"

main()
{
PACTL=0x80; /* Poner bit 7 del registro PACTL a '1' para configurar */
/* el bit 7 del puerto A como salida */
PORTA=0x80; /* Mandar un '1' por el bit 7 del puerto A */
}

EJEMPLO 4: Lectura y escritura en el puerto A.

En este ejemplo se refleja el estado del bit PA0 (bit de entrada) sobre el bit PA6 de salida. Si la entrada
PA0 se pone a ‘1’, el bit de salida PA6 se pondrá a ‘1’. Lo mismo con el estado ‘0’.

/*
+------------------------------------------------------------------------+
¦ PA0.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Programa ejemplo de la lectura del bit PA0. El estado de esta bit ¦
¦ se refleja sobre el bit de salida PA6. ¦
+------------------------------------------------------------------------+ */

#include "REGS6811.H"

char pa0;

main()
{
for (;;) {
pa0=PORTA & 0x01; /* Leer bit 0 del puerto A */
PORTA=(pa0 << 6); /* Enviar bit leido por el bit 6 del puerto A */
}
}

3.4.2.2.- PROGRAMACION DEL PUERTO B

El puerto B es un puerto de 8 bits de salida.

EJEMPLO 1: Activación rotativa de los 8 bits de l puerto B. En este ejemplo se activa primero el bit
0 del puerto B, después el 1,.... hasta el bit 8. Después se vuelve a comenzar.

/*
+------------------------------------------------------------------------+
¦ PUERTOB.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Activación rotativa de los bits del puerto B. ¦
+------------------------------------------------------------------------+ */

#include "REGS6811.H"

unsigned int i;
char b;

main()
{
b=0x01;
for (;;) {
PORTB=b; /* Actualizar puerto B */
for (i=0; i<0x8000; i++); /* Realizar una pausa */
b=b<<1;
if (b==0) b=1;
}
}

31
Programación de la tarjeta CT6811 en lenguaje C

3.4.2.3.- PROGRAMACION DEL PUERTO C

El puerto C es un puerto de 8 bits configurables como entrada o salida.

EJEMPLO 1: Lectura y escritura con el puerto C. En este ejemplo se sonfiguran los 4 bits de menor
peso del puerto C para entradas y los 4 bits de mayor peso para salidas. El estado de las entradas se
refleja sobre los bits de salida.

/*
+------------------------------------------------------------------------+
¦ PUERTOC.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Los 4 bits de menor peso del puerto C se configuran para entrada y ¦
¦ los 4 bits de mayor peso del puerto C se configuran para salida. El ¦
¦ estado de la entrada se refleja sobre los bits de salida. ¦
+------------------------------------------------------------------------+ */

#include "REGS6811.H"

char c;

main()
{
DDRC=0xF0; /* Configurar el puerto C: Bits 0,1,2,3 entrada */
/* Los bits 4,5,6 y 7 para entradas */
for (;;) {
c=PORTC & 0x0F; /* Leer puerto C */
PORTC=(c << 4); /* Escribir en puerto C */
}
}

3.4.2.4.- PROGRAMACION DEL PUERTO D

El puerto D es un puerto de 6 bits de E/S.

EJEMPLO 1: Lectura y escritura del puerto D. Lectura del estado del bit PD2 y escritura sobre el bit
PD3.

/*
+------------------------------------------------------------------------+
¦ PUERTOD.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Se configura el bit 2 del puerto D como entrada y el bit 3 como ¦
¦ salida. El estado del bit de entrada se refleja sobre el bit de ¦
¦ salida. ¦
+------------------------------------------------------------------------+ */

#include "REGS6811.H"

char d;

main()
{
DDRD=0x08; /* Configurar el puerto D: Bit 3 salida. Resto entradas */
for (;;) {
d=PORTD & 0x04; /* Leer puerto D */
PORTD=(d << 1); /* Escribir en puerto D */
}
}

32
Programación de la tarjeta CT6811 en lenguaje C

3.4.2.5.- PROGRAMACION DEL PUERTO E

EJEMPLO 1: Reflejo del estado del bit PE0 sobre el bit PA6.

/*
+------------------------------------------------------------------------+
¦ PUERTOE.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ El estado del bit 0 del puerto E se refleja sobre el led de la ¦
¦ tarjeta CT6811. ¦
+------------------------------------------------------------------------+ */

#include "REGS6811.H"

char e;

main()
{
for (;;) {
e=PORTE & 0x01; /* Leer puerto E */
PORTA=(e << 6); /* Escribir en puerto A */
}
}

33
Programación de la tarjeta CT6811 en lenguaje C

34
Programación de la tarjeta CT6811 en lenguaje C

3.4.3.- PROGRAMACION DEL SCI

Primero se van a presentar unos ejemplos de manejo del SCI. Después se van a extrar algunas
de las rutinas de los ejemplos para crear una libreria de comunicaciones serie llamada SCI.H. Con esta
libreria se van a realizar algunos ejemplos. Finalmente se van a presentar ejemplos de manejo del SCI
mediante interrupciones. Todos los ejemplos que utilicen la librería SCI.H también pueden utilizar la
librería SCIASM.H. Ambas tienen el mismo interfaz pero la segunda está implementada en
ensamblador por lo que es más rápida y ocupa menos memoria.

EJEMPLO 1: Lectura y escribura de datos por el puerto serie.

En este ejemplo se presentan las funciones leer_car y enviar_car que sirven para leer datos del
puerto serie y para enviar datos por él. Estas dos funciones van a formar parte de la librería SCI.H. El
ejemplo simplemente realiza un eco de los caracteres recibidos. Este mismo ejemplo se presenta más
adelante pero utilizando la librería SCI.H

/*
+------------------------------------------------------------------------+
¦ SCI1.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo manejo del SCI del 68HC11. Se hace 'eco' de todos los ¦
¦ caracteres recibidos por el SCI ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"

char leer_car()
/* +--------------------------------------------------------+
¦ Función que devuelve el carácter recibido por el SCI ¦
+--------------------------------------------------------+ */
{
while(!(SCSR & 0x10));
return SCDR;
}

void enviar_car(char c)
/* +------------------------------------------+
¦ Enviar un carácter por el puerto serie. ¦
+------------------------------------------+ */
{
while (!(SCSR & 0x40));
SCDR = c;
}

char c;

main()
{
for (;;) {
c=leer_car(); /* Esperar a que venga un carácter por el SCI */
PORTA^=0x40; /* Cambiar el led de estado */
enviar_car(c); /* Hacer eco del caracter recibido */
}
}

EJEMPLO 2: Librería SCI.H para comunicaciones serie mediante espera activa

A continuación se presenta la librería SCI.H que contiene las tres funciones siguientes:

• enviar_car : Función para enviar un carácter por el puerto Serie. Es la misma que la utilizada en el
ejemplo 1
• leer_car : Función para esperar a que se reciba un carácter por el puerto serie. Es la misma que la
utilizada en el ejemplo 2.
• enviar : Función para enviar una cadena por el puerto serie.

35
Programación de la tarjeta CT6811 en lenguaje C

/*
+------------------------------------------------------------------------+
¦ SCI.H (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Rutinas de manejo del SCI mediante espera activa. ¦
¦ ¦
¦ leer_car() -----> Leer el carácter que venga por el SCI. ¦
¦ enviar_car(c) --> Enviar un carácter por el SCI ¦
¦ enviar(cad) ----> Enviar una cadena de caracteres por el SCI ¦
¦ ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"

char leer_car()
/* +--------------------------------------------------------+
¦ Función que devuelve el carácter recibido por el SCI ¦
+--------------------------------------------------------+ */
{
while(!(SCSR & 0x10));
return SCDR;
}

void enviar_car(char c)
/* +------------------------------------------+
¦ Enviar un carácter por el puerto serie. ¦
+------------------------------------------+ */
{
while (!(SCSR & 0x40));
SCDR = c;
}

void enviar(char *cad)


/* +-------------------------------+
¦ Enviar una cadena por el SCI ¦
+-------------------------------+ */
{
static unsigned char i;

i=0;
while (cad[i]) {
enviar_car(cad[i]);
i++;
}
}

En los siguientes ejemplos se muestra cómo utilizar esta librería.

EJEMPLO 3: Eco por el puerto serie. Se trata del mismo ejemplo que el 1 pero se utiliza la librería
SCI.H

/*
+------------------------------------------------------------------------+
¦ ECO.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo manejo del SCI del 68HC11. Se hace 'eco' de todos los ¦
¦ caracteres recibidos por el SCI ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"
#include "sci.h"

char c;

main()
{
for (;;) {
c=leer_car(); /* Esperar a que venga un carácter por el SCI */
PORTA^=0x40; /* Cambiar el led de estado */
enviar_car(c); /* Hacer eco del caracter recibido */
}
}

36
Programación de la tarjeta CT6811 en lenguaje C

Este programa ocupa 149 bytes.

EJEMPLO 4: Envío de cadenas por el SCI. En este ejemplo se utiliza la función enviar de la librería
SCI.H para enviar la cadena ‘hola como estas’cada vez que se reciba un carácter por el puerto serie.

/*
+------------------------------------------------------------------------+
¦ SCICAD.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Envio de cadenas por el puerto serie. Cada vez que se recibe un ¦
¦ caracter por el SCI se responde enviando un mensaje ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"
#include "sci.h"

main()
{
for (;;) {
leer_car(); /* Esperar a que venga un carácter por el SCI */
PORTA^=0x40; /* Cambiar el led de estado */
enviar("Hola como estas"); /* Enviar una cadena */
}
}

Este programa ocupa 159 bytes.

EJEMPLO 5: Interacción con el usuario. Este ejemplo presenta un menu al usuario con dos opciones.
Una opción sirve para cambiar el estado del led de la CT6811. Cada vez que se pulsa la otra opción se
envía por los 4 bits del puerto C un número. (Si se tiene conectado un display de 7 segmentos en el
puerto C se podrá observar el número enviado).

/*
+------------------------------------------------------------------------+
¦ SCIMENU.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Se presenta un pequeño menu de opciones. Ejemplo de programa inte- ¦
¦ ractivo con el usuario. ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"
#include "sci.h"

char c;
char i;

main()
{
DDRC=0xF0; /* Configuración del puerto C para la tarjeta PCT-S47 */
i=0;
enviar("\n\r1-Led");
enviar("\n\r2-Display\n\r");
for (;;) {
c=leer_car();
switch(c) {
case '1': PORTA^=0x40; break;
case '2': PORTC=i;
i+=16;
}
}
}

Este programa ocupa 239 bytes.

EJEMPLO 6: Utilización de las librerías optimizadas SCIASM.H. En todos los ejemplos mostrados
anteriormente se utilizaba la librería SCI.H. Si en cualquiera de esos ejemplos se sustituye #include

37
Programación de la tarjeta CT6811 en lenguaje C

“SCI.H” por #include “SCIASM.H” los programas seguirán funcionando igual pero
ocuparán mucho menos. A continuación se presenta el programa eco.c que utiliza la librería SCIASM.H.
Este programa ocupa 99 bytes. Con la librería SCI.H ocupaba 149 bytes. ¡¡¡Utilizando la librería
SCIASM.H conseguimos un ahorro de 50 bytes!!!!

La única diferencia se encuentra al compilar los programas. Al utilizar la librería SCIASM.H


aparecerá un Warning. No hay que preocuparse. Simplemente hay que ignorarlo.

/*
+------------------------------------------------------------------------+
¦ ECOASM.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Este programa hace lo mismo que el programa ECO.C pero se utilizan ¦
¦ las rutinas de la librería SCIASM.H en vez de SCI.H ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"
#include "sciasm.h" /* SE HA SUSTITUIDO POR #include “SCI.H” */

char c;

main()
{
for (;;) {
c=leer_car(); /* Esperar a que venga un carácter por el SCI */
PORTA^=0x40; /* Cambiar el led de estado */
enviar_car(c); /* Hacer eco del caracter recibido */
}
}

Puesto que el interfaz que ‘ve’ nuestro programa principal es el mismo para las dos librerías,
pero con la librería SCIASM.H conseguimos un ahorro de 50 bytes, es mejor utilizar esta librería. Esta
librería se describe con más detalle más adelante.

EJEMPLO 7: Utilización de las interrupciones del SCI.

En este ejemplo cada vez que se recibe un carácter por el SCI se cambia el estado del LED de la
CT6811. Obsérverse que le programa principal entra en un bucle infinito y no hace nada. En este bucle
se podría estar ejecutando un trozo de código mientras que el led se sigue encendiendo y apagando cada
vez que se recibe un carácter por el SCI.

/*
+------------------------------------------------------------------------+
¦ SCILED.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de utilización del SCI mediante interrupciones. Cada vez ¦
¦ que se recibe un caracter se cambia el estado del led mediante ¦
¦ interrupciones ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"
#include "vectint.h"

void ssisci()
/*
+------------------------------------------------+
¦ Subrutina de servicio de interrupción del SCI ¦
+------------------------------------------------+ */
{
static char c;

c=SCSR; /* Quitar flag de interrupción */


c=SCDR;

PORTA^=0x40; /* Cambiar de estado el led */


}

38
Programación de la tarjeta CT6811 en lenguaje C

void rsisci()
/*
+------------------------------------------------+
¦ Subrutina de servicio de interrupción del SCI ¦
+------------------------------------------------+ */
{
ssisci(); /* Llamar a la subrutina de servicio de interrupción */
asm (" RTI");
}

main()
{
/* ----------- Cambiar vector de interrupción del SCI ------------------ */
visci1=0x7E; /* Colocar instrucción JMP */
visci2=(unsigned int)rsisci; /* Colocar dirección rutina servicio */

SCCR2 |= 0x20; /* Activar interrupción de DATO recibido del SCI */


asm (" CLI"); /* Permitir las interrupciones */

for (;;) ; /* Bucle infinito */


}

39
Programación de la tarjeta CT6811 en lenguaje C

40
Programación de la tarjeta CT6811 en lenguaje C

3.4.4.- PROGRAMACION DEL SPI

Se van a presentar una serie de ejemplos de manejo del SPI. Todos ejemplos se han pensado
para conectar dos tarjetas CT6811 a través del SPI. Un 68HC11 se configura como maestro y el otro
como esclavo. Cada uno ejecuta un programa diferente.

Las rutinas de manejo del SPI se encuentran en la librería SPI.H. La librería SPIASM.H
contiene exactamente las mismas funciones pero implementadas en ensamblador por lo que se ahorra
memoria. Todos los ejemplos se han realizado con la librería SPIASM.H. Para utilizar la otra
simplemente habrá que cambiar en los ejemplos la línea #include “SPIASM.H” por #include “SPI.H”

EJEMPLO 1: La librería SPI.H para comunicaciones por el SPI

/*
+------------------------------------------------------------------------+
¦ SPI.H (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Rutinas de manejo del SPI mediante espera activa. ¦
¦ ¦
¦ spi(c) --> Función que realizar un 'intercambio' por el SPI. Envía ¦
¦ El carácter c y devuelve lo que se reciba por el SPI. ¦
¦ spi_maestro() -> Macro para configurar el SPI en modo maestro. ¦
¦ spi_esclavo() -> Macro para configurar el SPI en modo esclavo ¦
¦ ¦
+------------------------------------------------------------------------+ */
#include "REGS6811.H"

/* +-------------------------------+
--------------------¦ Macros para configurar el SPI ¦-----------------
+-------------------------------+ */
#define spi_maestro() DDRD=0x38; SPCR=0x54; PORTD=0x00
#define spi_esclavo() DDRD=0x04; SPCR=0x44

char spi(char c)
/* +--------------------------------------------------------+
¦ Esta función realizar un 'intercambio' de información ¦
¦ por el SPI: Se envía el carácter indicado y se devuel- ¦
¦ ve lo que venga por el SPI. ¦
+--------------------------------------------------------+ */
{
SPDR=c; /* Enviar dato */
while (!(SPSR & 0x80)); /* Esperar a que el dato se envíe */
return SPDR; /* Devolver el dato recibido */
}

Lo que más llama la atención de estas rutinas es que no exiten las típicas funciones de enviar y
recibir datos. Sólo existe una única función que realiza el intercambio de información. En los siguientes
ejemplos se muestra cómo se emplea esta función para enviar y recibir datos.

EJEMPLO 2: Envío de datos del maestro al esclavo. En este ejemplo se envían datos desde el maestro
al esclavo. El esclavo cambia de estado el led cada vez que recibe un dato por el SPI. Además, si se tiene
conectado un display de 7 segmentos en los 4 bits más significativos del puerto C se podrán ver los datos
recibidos. El programa maestro toma los datos del puerto serie. De esta forma, para que el probar que el
programa funciona correctamente el usuario envía los datos desde el teclado del PC hasta el 68HC11
maestro por medio del SCI. De aquí son enviados al 68HC11 esclavo vía el SPI.

PROGRAMA MAESTRO

/*
+------------------------------------------------------------------------+
¦ SPILEDM.C (C) GRUPO J&J. Abril 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Programa ejemplo de manejo del SPI. El micro se configura como ¦
¦ MAESTRO. Todos caracteres que se reciben por el SCI se envían a ¦
¦ través del SPI. ¦
¦ ¦
+------------------------------------------------------------------------+

41
Programación de la tarjeta CT6811 en lenguaje C

*/

#include "REGS6811.H"
#include "SCIASM.H"
#include "SPIASM.H"

char c;

main()
{
spi_maestro(); /* Configurar micro como maestro */
for (;;) {
c=leer_car(); /* Esperar a que se reciba un dato por SCI */
spi(c); /* Enviar carácter por el SPI */
}
}

PROGRAMA ESCLAVO:

/*
+------------------------------------------------------------------------+
¦ SPILEDE.C (C) GRUPO J&J. Febrero 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ PROGRAMA ESCLAVO ¦
¦ ¦
¦ Cada vez que se recibe un carácter por el SPI se cambia el estado ¦
¦ del led. Los 4 bits más bajos de carácter recibido se envían por los ¦
¦ 4 bits más altos del puerto C de tal manera que si se ha conectado ¦
¦ un display de 7 segmentos se pueden ver los números recibidos. ¦
+------------------------------------------------------------------------+
*/

#include "REGS6811.H"
#include "SPIASM.H"

char c;

main()
{
DDRC=0xF0; /* Configurar puerto C: Bits 7,6,5 y 4 salidas. */
PORTC=0x80; /* Mandar un 8 al display para que se encienda */

spi_esclavo(); /* Configurar micro como esclavo */

for (;;) {
c=spi(0); /* Recibir dato del maestro */
PORTC=(c << 4); /* Mandar dato al display 7-seg */
PORTA^=0x40; /* Cambiar led de estado */
}
}

Obsérverse cómo funciona la función spi. En el caso del maestro lo que queremos es transmitir
un dato. Por ello simplemente se llama a la función pasando como parámetro el dato a enviar: spi(c). En
el caso del esclavo lo que se quiere es recibir. La función spi() transmite y recibe a la vez. Por ello para
recibir un carácter transmitirmos un carácter ‘basura’ cualquiera. En el ejemplo se ha transmitido el
carácter 0: c=spi(0). Pero se podría haber transmitido cualquiera puesto que el maestro los ignora.

EJEMPLO 3: Envío de datos al esclavo y obtención de la respuesta del esclavo.

Es muy común que después de enviar datos al esclavo, el maestro se quede esperando a recibir
una respuesta del esclavo. En este ejemplo la respuesta del esclavo es un eco modificado de lo recibido
por el SPI. La modificación consiste en sumar una unidad al carácter recibido. De esta forma, si el
maestro envía una ‘A’, recibirá como eco una ‘B’(‘B’= ‘A’+ 1).

PROGRAMA MAESTRO

/*
+------------------------------------------------------------------------+
¦ SPIECOM.C (C) GRUPO J&J. Abril 1997 ¦
¦------------------------------------------------------------------------¦

42
Programación de la tarjeta CT6811 en lenguaje C

¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦


¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Programa ejemplo de manejo del SPI. El micro se configura como ¦
¦ MAESTRO. Todos caracteres que se reciben por el SCI se envían a ¦
¦ través del SPI. La respuesta del esclavo se envía a través del SCI ¦
¦ ¦
+------------------------------------------------------------------------+
*/

#include "REGS6811.H"
#include "SCIASM.H"
#include "SPIASM.H"

char c;
unsigned int i;

main()
{
spi_maestro(); /* Configurar micro como maestro */
for (;;) {
c=leer_car(); /* Esperar carácter por el SCI */
spi(c); /* Enviar el carácter leido */

for (i=0; i<2; i++); /* Pequeña pausa para que al esclavo tenga tiempo */
/* de procesar el dato */
c=spi(0); /* Recibir dato del esclavo */
enviar_car(c); /* Enviar dato por el SCI */
}
}

PROGRAMA ESCLAVO

/*
+------------------------------------------------------------------------+
¦ SPIECOE.C (C) GRUPO J&J. Febrero 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ PROGRAMA ESCLAVO: ¦
¦ ¦
¦ Se lee lo que viene por el SPI y se hace un ECO. El caracter enviado ¦
¦ es el recibido incrementado en una unidad. Si se recibe el carácter ¦
¦ 'A' se envía el carácter 'B'. Los 4 bits de menor peso del carácter ¦
¦ recibido se envían por los 4 bits de mayor peso del puerto C. Se ¦
¦ modifica el estado del led por cada carácter recibido por el SPI ¦
¦ ¦
+------------------------------------------------------------------------+
*/

#include "REGS6811.H"
#include "SPIASM.H"

char c;

main()
{
DDRC=0xF0; /* Configurar puerto C: 4 bits mayor peso como salidas */
PORTC=0x80; /* Enviar un 8 al display de 7 segmentos */

spi_esclavo(); /* Configurar micro como esclavo */

for (;;) {
c=spi(0); /* Recibir dato del maestro */
PORTC=(c << 4); /* Mandar dato al display 7-seg */
PORTA^=0x40;
c++; /* Incrementar carácter recibido */
spi(c); /* Enviar nuevo carácter al maestro */
}
}

43
Programación de la tarjeta CT6811 en lenguaje C

44
Programación de la tarjeta CT6811 en lenguaje C

3.4.5.- PROGRAMACION DEL TEMPORIZADOR PRINCIPAL

EJEMPLO 1: Lectura del temporizador. En este ejemplo se muestra cómo leer el temporizador
principal. Cada vez que se recibe un carácter por el SCI, el 68HC11 devuelve el valor del byte bajo del
temporizador principal.

/*
+------------------------------------------------------------------------+
¦ TIMER.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de lectura del temporizador principal. Cuando se recibe ¦
¦ un carácter por el SCI se devuelve el valor del byte bajo del ¦
¦ temporizador principal. ¦
+------------------------------------------------------------------------+ */

#include "REGS6811.H"
#include "SCIASM.H"

unsigned int tempo;


char c;

main()
{
for (;;) {
leer_car();
tempo=TCNT; /* Leer valor del temporizador */
c=(char) (tempo & 0x00FF); /* Quedarse con el byte bajo del temporizador */
enviar_car(c);
}
}

EJEMPLO 2: Modificación de la frecuencia del temporizador. En este ejemplo se modifica el


temporizador para que se incremente a la velocidad de E/16. Para la tarjeta CT6811 esta velocidad es de
125KHZ. El estado del bit más significativo del temporizador se presenta en el led de la CT6811.

/*
+------------------------------------------------------------------------+
¦ TIMER2.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Modificación de la frecuencia de funcionamiento del temporizador. ¦
¦ Se configura para trabajar a una frecuencia de 125KHZ. El bit de ¦
¦ mayor peso del temporizador se utiliza para hacer parpadear el led. ¦
¦ ¦
+------------------------------------------------------------------------+ */

#include "REGS6811.H"

unsigned int tempo;

main()
{
TMSK2|=0x03; /* Divir la señal E por 16 */

for (;;) {
tempo=TCNT; /* Leer valor del temporizador */
if (tempo & 0x8000) /* Si bit de mayor peso activo... */
PORTA=0x40; /* Encender el led. */
else PORTA=0x00; /* sino apagar el led. */
}
}

EJEMPLO 3: Interrupción de overflow del temporizador. Se utiliza la interrupción de overflow del


temporizador para hacer parpadear el LED de la CT6811.

/*
+------------------------------------------------------------------------+
¦ OVERFLOW.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦

45
Programación de la tarjeta CT6811 en lenguaje C

¦ Este programa se debe cargar en la RAM interna del 6811. ¦


¦ ¦
¦ Ejemplo del temporizador principal. Se utiliza la interrupción de ¦
¦ overflow del temporizador para hacer parpadear el LED de la CT6811. ¦
¦ Cada vez que el temporizador alcanza el valor $FFFF se cambia de ¦
¦ estado el led. Se configura el temporizador para que se produzca ¦
¦ overflow cada 524.3ms. ¦
¦ ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"
#include "vectint.h"

void ssioverf()
/*
+------------------------------------------------------+
¦ Subrutina de servicio de interrupción del overflow ¦
+------------------------------------------------------+ */
{
TFLG2|=0x80; /* Quitar flag de interrupción */
PORTA^=0x40; /* Cambiar de estado el led */
}

void rsioverf()
/*
+---------------------------------------------------+
¦ Rutina de servicio de interrupción del overflow ¦
+---------------------------------------------------+ */
{
ssioverf(); /* Llamar a la subrutina de servicio de interrupción */
asm (" RTI");
}

main()
{
TMSK2|=0x03; /* Velocidad del temporizador: E/16 */

/* ----------- Cambiar vector de interrupción ------------------ */


viot1=0x7E; /* Colocar instrucción JMP */
viot2=(unsigned int)rsioverf; /* Colocar dirección rutina servicio */

TMSK2|=0x80; /* Activar interrupción de overflow */


asm (" CLI"); /* Permitir las interrupciones */

for (;;) ; /* Bucle infinito */


}

46
Programación de la tarjeta CT6811 en lenguaje C

3.4.6.- PROGRAMACION DE LAS INTERRUPCIONES EN TIEMPO REAL

EJEMPLO 1: Interrupción en tiempo real mediante espera activa. Este programa hace cambiar de
estado el led de la tarjeta CT611 cada 32.7ms. Se realiza utilizando las interrupciones en tiempo real
mediante espera activa. En realidad no se utilizan interrupciones, sino que se trabaja con el flag de
interrupción. Cuando se pone a 1 quiere decir que han pasado 32.7ms.

/*
+------------------------------------------------------------------------+
¦ RTI.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de la interrupción en tiempo real. Se cambia el estado del ¦
¦ led cada 32.7ms. Se hace mediante espera activa. ¦
+------------------------------------------------------------------------+ */

#include "REGS6811.H"

main()
{
PACTL|=0x03; /* Interrupciones en tiempo real cada 32.7ms */
for (;;) {
while (!(TFLG2 & 0x40)); /* Esperar a que se active flag */
TFLG2|=0x40; /* Quitar flag. */
PORTA^=0x40; /* Cambiar de estado el led */
}
}

EJEMPLO 2: Interrupciones en tiempo real con interrupciones. Mismo programa que el anterior
pero realizado mediante interrupciones.

/*
+------------------------------------------------------------------------+
¦ RTII.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de las interrupciones en tiempo real. Se cambia el estado ¦
¦ del led cada 32.7ms. Se hace mediante interrupciones. ¦
¦ ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"
#include "vectint.h"

void ssirti()
/*
+------------------------------------------------------+
¦ Subrutina de servicio de interrupción en tiempo real ¦
+------------------------------------------------------+ */
{
TFLG2|=0x40; /* Quitar flag de interrupción */
PORTA^=0x40; /* Cambiar de estado el led */
}

void rsirti()
/*
+---------------------------------------------------+
¦ Rutina de servicio de interrupción en tiempo real ¦
+---------------------------------------------------+ */
{
ssirti(); /* Llamar a la subrutina de servicio de interrupción */
asm (" RTI");
}

main()
{
PACTL|=0x03; /* Int. tiempo real cada 32.7ms */

/* ----------- Cambiar vector de interrupción ------------------ */


virti1=0x7E; /* Colocar instrucción JMP */
virti2=(unsigned int)rsirti; /* Colocar dirección rutina servicio */

47
Programación de la tarjeta CT6811 en lenguaje C

TMSK2|=0x40; /* Activar interrupción de Tiempo real */


asm (" CLI"); /* Permitir las interrupciones */

for (;;) ; /* Bucle infinito */


}

48
Programación de la tarjeta CT6811 en lenguaje C

3.4.7.- PROGRAMACION DE LOS COMPARADORES

EJEMPLO 1: Utilización de los comparadores para realizar una pausa. LIBRERIA DELAY.H

En este ejemplo se presenta la función delay() que realiza una pausa, mediante espera activa, de
un número determinado de milisegundos. Esta función forma parte de la libreria DELAY.H

/*
+------------------------------------------------------------------------+
¦ DELAY.H (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Librería para realizar pausas. ¦
¦ ¦
¦ delay(t) --> Realizar una pausa de t milisegundo. ¦
¦ t=1000 Pausa de 1 segundo ¦
¦ ¦
+------------------------------------------------------------------------+ */

#include "REGS6811.H"

#define T1_MS 2000 /* Número de tics de reloj necesarios para generar un */


/* retraso de 1ms */

void delay(unsigned int time)


{
while (time!=0) {
time--;
TOC5=TCNT+T1_MS; /* Iniciar el comparador para que se active al cabo */
/* de 1ms de tiempo */
TFLG1|=0x08; /* Poner a cero flag del comparador 5 */
while (!(TFLG1 & 0x08)) ; /* Espear a que se active el flag */
}
}

EJEMPLO 2: Utilización de la función delay() de la librería DELAY.H. En este ejemplo se cambia


el estado del led de la CT6811 cada segundo exacto. Para ello se llama a la función delay con un
argumento de 1000 (1segundo = 1000 milisegundos).

/*
+------------------------------------------------------------------------+
¦ DELAY.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de la librería de pausa. Se cambia el estado del led de la ¦
¦ CT6811 cada 1 segundo. ¦
+------------------------------------------------------------------------+ */

#include "REGS6811.H"
#include "DELAY.H"

main()
{
for (;;) {
PORTA^=0x40; /* Cambiar led de estado */
delay(1000); /* Esperar un segundo */
}
}

EJEMPLO 3: Temporización mediante interrupciones. El programa enciende el led, activas las


interrupciones del comparador 4 y ejecuta un bucle infinito. Mediante interrupciones se temporizan 2
segundos y se apaga el led. El programa principal podría estar ejecutando cualquier otra operación. Al
cabo de 2 segundos el led se apagaría.
/*
+------------------------------------------------------------------------+
¦ TEMPO.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de utilización del comparador 4 para realizar temporiza- ¦
¦ ciones mediante interrupciones. El programa principal enciende el led,¦

49
Programación de la tarjeta CT6811 en lenguaje C

¦ activa la temporización y ejecuta un bucle infinito. Al cabo de 2 ¦


¦ segundos el led se apagará. ¦
¦ ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"
#include "vectint.h"

#define T1_MS 2000

unsigned int tiempo;

void ssioc4()
/*
+---------------------------------------------------------+
¦ Subrutina de servicio de interrupción del comparador 4 ¦
+---------------------------------------------------------+ */
{
TFLG1|=0x10; /* Quitar flag de interrupción */
TOC4=TCNT+T1_MS; /* Activar comparador 4 para que se dispare cada 1 ms */

if (tiempo==0) {
PORTA=0x00; /* Apagar el led */
TMSK1&=~0x10; /* Desactivar interrupción comparador 4 */
}
else tiempo--;

void rsioc4()
/*
+-----------------------------------------------------+
¦ Rutina de servicio de interrupción del comparador 4 ¦
+-----------------------------------------------------+ */
{
ssioc4(); /* Llamar a subrutina de servicio de interrupción */
asm (" RTI");
}

main()
{
/* ----------- Cambiar vector de interrupción ------------------ */
vioc41=0x7E; /* Colocar instrucción JMP */
vioc42=(unsigned int)rsioc4; /* Colocar dirección rutina servicio */

TMSK1|=0x10; /* Permitir las interrupciones del comparador 4 */


PORTA=0x40; /* Encender el led */
tiempo=2000; /* Esperar 2 segundos */
asm (" CLI"); /* Permitir las interrupciones */

for (;;) ; /* Bucle infinito */


}

EJEMPLO 4: Generación de señales cuadradas mediante interrupciones y salida hardware.

/*
+------------------------------------------------------------------------+
¦ ONDCUAD.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de utilización del comparador 2 con salida hardware para ¦
¦ generar señales cuadradas de una frecuencia determinada mediante ¦
¦ interrupciones. ¦
¦ ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"
#include "vectint.h"

#define TIEMPO 60000

void ssioc2()
/*
+---------------------------------------------------------+
¦ Subrutina de servicio de interrupción del comparador 2 ¦
+---------------------------------------------------------+ */

50
Programación de la tarjeta CT6811 en lenguaje C

{
TFLG1|=0x40; /* Quitar flag de interrupción */
TOC2=TCNT+TIEMPO; /* Activar comparador 2 */
asm (" RTI");
}

void rsioc2()
/*
+-----------------------------------------------------+
¦ Rutina de servicio de interrupción del comparador 2 ¦
+-----------------------------------------------------+ */
{
ssioc2(); /* Llamar a la subrutina de servicio de interrupción */
asm (" RTI");
}

main()
{
/* ----------- Cambiar vector de interrupción ------------------ */
vioc21=0x7E; /* Colocar instrucción JMP */
vioc22=(unsigned int)rsioc2; /* Colocar dirección rutina servicio */

TCTL1|=0x40; /* Activar salida hardware del comparador 2 */


TMSK1|=0x40; /* Permitir las interrupciones del comparador 4 */
asm (" CLI"); /* Permitir las interrupciones */

for (;;) ; /* Bucle infinito */


}

51
Programación de la tarjeta CT6811 en lenguaje C

52
Programación de la tarjeta CT6811 en lenguaje C

3.4.8.- PROGRAMACION DE LOS CAPTURADORES

EJEMPLO 1: Interrupción en flanco de bajada. En este ejemplo se utiliza el capturador 3 para


capturar flancos de bajada. Cada vez que se obtiene un flanco de bajada por el bit PA0 se cambia el
estado del led. Se hace mediante interrupciones.

/*
+------------------------------------------------------------------------+
¦ CAP.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de utilización del capturador de entrada 2 como entrada de ¦
¦ interrupciones configurada en flanco de bajada. Cada vez que se ¦
¦ obtenga un flanco de bajada por el pin PA1 se cambia el estado del ¦
¦ led. ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"
#include "vectint.h"

void ssiic2()
/*
+---------------------------------------------------------+
¦ Subrutina de servicio de interrupción del capturador 2 ¦
+---------------------------------------------------------+ */
{
TFLG1|=0x02; /* Quitar flag de interrupción */
PORTA^=0x40;
}

void rsiic2()
/*
+-----------------------------------------------------+
¦ Rutina de servicio de interrupción del capturador 2 ¦
+-----------------------------------------------------+ */
{
ssiic2();
asm (" RTI");
}

main()
{
/* ----------- Cambiar vector de interrupción ------------------ */
viic21=0x7E; /* Colocar instrucción JMP */
viic22=(unsigned int)rsiic2; /* Colocar dirección rutina servicio */

TCTL2|=0x08; /* Configurar capturador 2 para flanco de bajada */


TMSK1|=0x02; /* Permitir las interrupciones del capturador 2 */
asm (" CLI"); /* Permitir las interrupciones */

for (;;) ; /* Bucle infinito */


}

EJEMPLO 2: Utilización del comparador 2 para contar flancos de bajada. Cada vez que se reciban
5 flancos de bajada por el pin PA1 el led cambiará de estado.

/*
+------------------------------------------------------------------------+
¦ CAP2.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de utilización del capturador de entrada 2 como entrada de ¦
¦ interrupciones configurada en flanco de bajada. Cada vez que se ¦
¦ obtienen 5 flancos de bajada se cambia el estado del led. ¦
¦ ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"
#include "vectint.h"

53
Programación de la tarjeta CT6811 en lenguaje C

char cuenta;

void ssiic2()
/*
+---------------------------------------------------------+
¦ Subrutina de servicio de interrupción del capturador 2 ¦
+---------------------------------------------------------+ */
{
TFLG1|=0x02; /* Quitar flag de interrupción */
cuenta--;
if (cuenta==0) {
PORTA^=0x40;
cuenta=5;
}
}

void rsiic2()
/*
+-----------------------------------------------------+
¦ Rutina de servicio de interrupción del capturador 2 ¦
+-----------------------------------------------------+ */
{
ssiic2();
asm (" RTI");
}

main()
{
/* ----------- Cambiar vector de interrupción ------------------ */
viic21=0x7E; /* Colocar instrucción JMP */
viic22=(unsigned int)rsiic2; /* Colocar dirección rutina servicio */

TCTL2|=0x08; /* Configurar capturador 2 para flanco de bajada */


TMSK1|=0x02; /* Permitir las interrupciones del capturador 2 */
cuenta=5;
PORTC=cuenta << 4;
asm (" CLI"); /* Permitir las interrupciones */

for (;;) ; /* Bucle infinito */


}

54
Programación de la tarjeta CT6811 en lenguaje C

3.4.9.- PROGRAMACIÓN DEL ACUMULADOR DE PULSOS

EJEMPLO 1: Cuenta de 5 flancos de bajada. En este ejemplo cada 5 flancos de bajada recibidos por
el pin PA7 se cambia el estado del led.

/*
+------------------------------------------------------------------------+
¦ ACUM.C (C) GRUPO J&J. MAYO 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de utilización del acumulador de pulsos. Cada 5 flancos de ¦
¦ bajada en el pin PA7 se cambia el estado del led. ¦
¦ ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"
#include "vectint.h"

void ssiap()
/*
+------------------------------------------------------------------+
¦ Subrutina de servicio de interrupción del acumulador de pulsos ¦
+------------------------------------------------------------------+ */
{
TFLG1|=0x10;
if (PACNT==5) { /* Si se han producido 5 flancos de bajada */
PORTA^=0x40; /* Cambiar el estado del led */
PACNT=0; /* Inicializar acumulador de pulsos */
}
}

void rsiap()
/*
+--------------------------------------------------------------+
¦ Rutina de servicio de interrupción del acumulador de pulsos ¦
+--------------------------------------------------------------+ */
{
ssiap(); /* Llamar a subrutina de servicio de interrupción */
asm (" RTI");
}

main()
{
/* ----------- Cambiar vector de interrupción ------------------ */
viap1=0x7E; /* Colocar instrucción JMP */
viap2=(unsigned int)rsiap; /* Colocar dirección rutina servicio */

PACNT=0; /* Poner a cero el acumulador de pulsos */


PACTL|=0x40; /* Activar acumulador de pulsos. Modo cuenta de pulsos */
/* en flanco de bajada */
TMSK2|=0x10; /* Activar la interrupción del acumulador */
asm (" CLI"); /* Permitir las interrupciones */

for (;;) ; /* Bucle infinito */


}

EJEMPLO 2: Interrupción de overflow del acumulador de pulsos. En este ejemplo se cambia el


estado del led cada vez que se produce un desbordamiento en el acumulador de pulsos. Los
desbordamientos se producen cada 256 pulsos. Para hacer que ocurran sólo cada 5 pulsos se inicializa el
acumulador de pulsos con el valor $FB.

/*
+------------------------------------------------------------------------+
¦ ACUM2.C (C) GRUPO J&J. MAYO 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de utilización de la interrupción de overflow del acumula- ¦
¦ dor de pulsos. Cada vez que se produce overflow se cambia el estado ¦
¦ del led. El overflow se produce cada 256 flancos de bajada. Para ¦
¦ facilitar la prueba del programa, cada vez que se produce un over- ¦
¦ flow se coloca el valor $FB en el acumulador de pulsos para que se ¦
¦ produzca overflow cada 5 pulsos. ¦

55
Programación de la tarjeta CT6811 en lenguaje C

¦ ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"
#include "vectint.h"

void ssioap()
/*
+------------------------------------------------------------------+
¦ Subrutina de servicio de interrupción del overflow del acumulador¦
+------------------------------------------------------------------+ */
{
TFLG2|=0x20;
PORTA^=0x40;
PACNT=0xFB;
}

void rsioap()
/*
+-----------------------------------------------------------------+
¦ Rutina de servicio de interrupción del overflow del acumulador ¦
+-----------------------------------------------------------------+ */
{
ssioap(); /* Llamar a subrutina de servicio de interrupción */
asm (" RTI");
}

main()
{
/* ----------- Cambiar vector de interrupción ------------------ */
vioap1=0x7E; /* Colocar instrucción JMP */
vioap2=(unsigned int)rsioap; /* Colocar dirección rutina servicio */

PACNT=0xFB; /* Inicializar acumulador de pulsos */


PACTL|=0x40; /* Configurar acumulador de pulsos */
TMSK2|=0x20; /* Permitir la interrupción de overflow del acumulador */

asm (" CLI"); /* Permitir las interrupciones */

for (;;) ; /* Bucle infinito */


}

56
Programación de la tarjeta CT6811 en lenguaje C

3.4.10.- LA INTERRUPCION EXTERNA IRQ

EJEMPLO: IRQ configurada para flanco de bajada

/*
+------------------------------------------------------------------------+
¦ IRQ.C (C) GRUPO J&J. MAYO 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de utilización de la interrupción IRQ. Cada vez que se ¦
¦ recibe un flanco de bajada se cambia el estado del led. ¦
¦ ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"
#include "vectint.h"

void ssiirq()
/*
+------------------------------------------------+
¦ Subrutina de servicio de la interrupción irq ¦
+------------------------------------------------+ */
{
PORTA^=0x40;
}

void rsiirq()
/*
+--------------------------------------------+
¦ Rutina de servicio de la interrupción irq ¦
+--------------------------------------------+ */
{
ssiirq(); /* Llamar a subrutina de servicio de interrupción */
asm (" RTI");
}

main()
{
/* ----------- Cambiar vector de interrupción ------------------ */
viirq1=0x7E; /* Colocar instrucción JMP */
viirq2=(unsigned int)rsiirq; /* Colocar dirección rutina servicio */

OPTION|=0x20;
asm (" CLI"); /* Permitir las interrupciones */

for (;;) ; /* Bucle infinito */


}

57
Programación de la tarjeta CT6811 en lenguaje C

58
Programación de la tarjeta CT6811 en lenguaje C

3.4.11.- CONVERSOR ANALOGICO-DIGITAL (A/D)

EJEMPLO 1: En el siguiente ejemplo se toman muestras a través del canal 1 del conversor A/D. Estas
muestas se envían al PC a través del SCI.

/*
+------------------------------------------------------------------------+
¦ ADSCI.C (C) GRUPO J&J. MAYO 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de utilización del conversor A/D. Se leen muestras y se ¦
¦ envían a través del SCI. ¦
¦ ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"
#include "SCI.H"

main()
{
OPTION|=0x80; /* Encender el conversor */
ADCTL|=0x20; /* Configurar el conversor */

for (;;) {
while (!(ADCTL & 0x80)); /* Esperar a que termine conversion */
enviar_car(ADR1); /* Enviar muestra leida por el SCI */
}
}

EJEMPLO 2: Cuando la tensión de entrada supera un cierto umbral (2.5 voltios) se enciende el led. En
caso contrario se apaga.

/*
+------------------------------------------------------------------------+
¦ ADLED.C (C) GRUPO J&J. MAYO 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de utilización del conversor A/D. Cuando la tensión supere ¦
¦ los 2.5 voltios se enciende el led. ¦
¦ ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"

main()
{
OPTION|=0x80; /* Encender el conversor */
ADCTL|=0x20; /* Configurar el conversor */

for (;;) {
while (!(ADCTL & 0x80)); /* Esperar a que termine conversion */
if (ADR1>0x7F) PORTA=0x40;
else PORTA=0x00;
}
}

59
Programación de la tarjeta CT6811 en lenguaje C

60
Programación de la tarjeta CT6811 en lenguaje C

3.4.12.- PROGRAMACION DE LA EEPROM

EJEMPLO 1: Librería EEPROM.H para programación de la EEPROM

/*
+------------------------------------------------------------------------+
¦ EEPROM.H (C) GRUPO J&J. MAYO 1997 ¦
¦------------------------------------------------------------------------¦
¦ Librería para programación de la memoria EEPROM. ¦
¦ ¦
¦ * grabar(dato,dir) --> Grabar un dato en la dirección de EEPROM ¦
¦ especificada ¦
¦ * borrar(dir) --> Borrar la posición de EEPROM especificada ¦
¦ * borrar_eeprom() --> Borrar la eeprom completamente. ¦
¦ ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"
#include "delay.h"

void grabar(dato,dir)
char dato;
char *dir;
/* +------------------------------------------------------+
¦ Grabar un byte en la dirección de EEPROM indicada. ¦
+------------------------------------------------------+ */
{
PPROG=0x02;
*dir=dato;
PPROG=0x03;
delay(10);
PPROG=0x00;
}

void borrar(dir)
char *dir;
/* +------------------------------------------------------+
¦ Borrar un byte de la dirección de EEPROM indicada. ¦
+------------------------------------------------------+ */
{
PPROG=0x16;
*dir=0;
PPROG=0x17;
delay(10);
PPROG=0x00;
}

void borrar_eeprom()
/* +-----------------------------+
¦ Borrar la EEPROM entera. ¦
+-----------------------------+ */
{
PPROG=0x06;
(*(unsigned char *)0xB600)=0;
PPROG=0x07;
delay(10);
PPROG=00;
}

EJEMPLO 2: Manejo de la librería EEPROM.H

/*
+------------------------------------------------------------------------+
¦ EEPROM.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de manejo de la librería de programación de la EEPROM. ¦
¦ Se borra la EEPROM completamente y se graban datos. ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"
#include "eeprom.h"

unsigned char i;

main()

61
Programación de la tarjeta CT6811 en lenguaje C

{
borrar_eeprom(); /* Borrar la eeprom entera */

for (i=0; i<0xFF; i++) {


grabar(i,0xB600+i);
}
}

62
Programación de la tarjeta CT6811 en lenguaje C

4.- PROGRAMACION DE LA CT6811 EN MODO


AUTONOMO
4.1.- INTRODUCCION

Cuando se quiere que la tarjeta CT6811 funcione en modo autónomo es preciso grabar el código
en la memoria EEPROM. Las variables y la pila se deben situar en la memoria RAM interna. Por ello,
el código ya no está unificado. Se debe reservar un segmento en la RAM interna para las variables y un
segmentos en la EEPROM para el código.

Cuando se programa directamente en ensamblador es preciso modificar el código fuente para


adaptarlo a la memoria EEPROM. Sin embargo, cuando programamos en C el compilador hace todo el
trabajo por nosotros. El mismo código fuente en C servirá tanto para la RAM interna como para la
EEPROM. La única diferencia consistirá en la forma de compilar. Para compilar código para la RAM
interna se utilizará el fichero CINT.BAT. Para compilar para la EEPROM se utilizará el archivo
CEEPROM.BAT.

4.2.- CONFIGURACION DEL COMPILADOR

4.2.1.- El fichero de arranque y configuración CTEEPROM.S

* +------------------------------------------------------------------------+
* ¦ CTEEPROM.S (C) GRUPO J&J. MAYO 1997 ¦
* ¦------------------------------------------------------------------------¦
* ¦ Fichero de arranque y configuración para trabajar con la tarjeta ¦
* ¦ CT6811 en modo autónomo. ¦
* +------------------------------------------------------------------------+ */

SECT 0 ; Sección 0 : Segmento para el código


ORG $B600 ; El código se sitúa en la eeprom

SECT 1 ; Sección 1 : Segmento para los datos


ORG $0000 Los datos se sitúan en la RAM interna

SECT 0

jsr _main ; Saltar al programa principal


inf bra inf ; ¡Bucle infinito!

Figura 28: El fichero de arranque y configuración CTEEPROM.S

En la figura 28 se muestra el fichero CTEEPROM.S. Se definen dos secciones. La sección 0 se


corresponde con el segmento de código que lo situamos al comienzo de la EEPROM (Dirección $B600).
La sección 1 se corresponde con las variables que se sitúan en el comienzo de la RAM interna
(Dirección $0000).

El programa comienza en la línea 14 con la directiva SECT 0. Con esto se indica que lo que
viene a contianuación es código que se debe situar en el segmento de código. El código lo único que hace
es llamar al programa principal _main y después entrar en un bucle infinito.

4.2.2.- Situación de las variables al comienzo del fichero en ensamblador

Los programas para la EEPROM no deben estar unificados. Ya no es necesario utilizar el


programa UNIFICA.EXE para situar código y datos en el mismo segmento. Ahora el código se situará
en un segmento y los datos en otro.

Sin embargo, las variables siguen teniendo que estar al comienzo del fichero en ensamblador.
Por ello sigue siendo preciso utilizar el programa GETVARS.EXE. Pero esta vez habrá que utilizar el
parámetro -s para que aparezca la directiva SECT 1 justo delante de las variables.. En la figura 29 se
muestra cómo situar las variables al comienzo del archivo prueba.s

63
Programación de la tarjeta CT6811 en lenguaje C

C:\6811\ICC\CT68INT>getvars prueba.s temp.s -s > vars

C:\6811\ICC\CT68INT>type vars
SECT 1
_i:
RMB 2

C:\6811\ICC\CT68INT>copy vars+temp.s prueba.s


VARS
TEMP.S
1 archivo(s) copiado(s)

C:\6811\ICC\CT68INT>_

Figura 29: Situación de las variables al comienzo del fichero prueba.s

4.2.3.- Generación de archivos ejecutables .S19

Para generar el archivo .S19 final que se cargará en la EEPROM habrá que ensamblar los
ficheros .S junto con el archivo de arranque y configuración CTEEPROM.S. En la figura 30 se muestra
un ejemplo de generación del archivo prueba.s19 a partir del archivo prueba.s, que ya tiene las
variables al comienzo, y del fichero cteeprom.S

C:\6811\ICC\CT68INT>ias11 -o prueba cteeprom.s prueba.s

C:\6811\ICC\CT68INT>type prueba.s19
S108B600BDB60520FEAB
S123B605F610004FC840F71000CC0000DD007EB61DDC00C30001DD00DC001A83800025F137
S106B6257EB605E5
S9030000FC

C:\6811\ICC\CT68INT>_

Figura 30: Generación del archivo ejecutable PRUEBA.S19

También en la figura 30 se muestra el contenido del archivo prueba.S19. Si el lector entiende


este formato podrá comprobar que todas las direcciones están situadas en la memoria EEPROM. Estas
direcciones se han escrito en negrita.

4.2.4.- Resumen de los pasos necesarios para obtener ficheros ejecutables para la memoria
EEPROM.

• Compilar todos los archivos .C que integren el programa final. Para ello utilizar: ICC11 -S fichero.c
• Situar todas las variables al comienzo del código con el programa GETVARS.EXE
• Ensamblar todos los ficheros .S ya modificados junto con el archivo de arranque y configuración
CTEEPROM.S
• Ya se dispone de un archivo .S19 listo para ser grabado en la memoria EEPROM.

4.2.5.- El archivo CEEPROM.BAT para compilar programas para la EEPROM

En la figura 31 se muestra el archivo CEEPROM.BAT que se utilizará para generar código


ejecutable para ser grabado en la memoria EEPROM del 68HC11. El usuario puede utilizar este archivo
y se puede olvidar de todos los pasos intermedios.

Si se utiliza el archivo CINT.BAT se compilarán programas para la RAM interna. Una vez
que estos programas hayan sido probados y funcionen se compilarán con el programa CEEPROM.BAT
y se podrán grabar en la memoria EEPROM. En el apartado 4.3 se muestra un ejemplo completo de
compilación de programas para la EEPROM y su grabación utilizando el programa CTDIALOG.

64
Programación de la tarjeta CT6811 en lenguaje C

@REM
@REM ------------- Compilar de .c a .s ------------------
@REM
@icc11 -S %1.c
@REM
@REM ------------ Eliminación de las variables RMB ---------------
@REM
@getvars %1.s temp.s -s > %1.var
@REM
@REM ------------ Generación del fichero .s final -----------------
@REM
@copy %1.var+temp.s %1.s > NUL
@REM
@REM ------------- Borrar ficheros temporales --------
@REM del temp.s > NUL
@REM
@REM ------------ Generar fichero .S19 ---------------------
@REM
@ias11 -o %1 cteeprom.s %1.s

Figura 31: Fichero CEEPROM.BAT para compilar programas en C para la EEPROM

65
Programación de la tarjeta CT6811 en lenguaje C

66
Programación de la tarjeta CT6811 en lenguaje C

4.3.- EJEMPLOS DE PROGRAMAS PARA LA EEPROM

Todos los ejemplos desarrollados en la sección 3 sirven para ser grabados en la EEPROM. En
esta sección se va a presentar un ejemplo completo.

El programa de ejemplo a utilizar va a ser el programa TEMPO.C. Este programa se ha


presentado en la sección 3.4.7 como ejemplo de manejo de los comparadores mediante interrupciones. El
programa simplemente enciende un led y lo apaga al cabo de 2 segundos. Se ha elegido este programa
ejemplo para ser grabado en la eeprom porque utiliza interrupciones.

A continuación se presenta el código en C.

/*
+------------------------------------------------------------------------+
¦ TEMPO.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de utilización del comparador 4 para realizar temporiza- ¦
¦ ciones mediante interrupciones. El programa principal enciende el led,¦
¦ activa la temporización y ejecuta un bucle infinito. Al cabo de 2 ¦
¦ segundos el led se apagará. ¦
¦ ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"
#include "vectint.h"

#define T1_MS 2000

unsigned int tiempo;

void ssioc4()
/*
+---------------------------------------------------------+
¦ Subrutina de servicio de interrupción del comparador 4 ¦
+---------------------------------------------------------+ */
{
TFLG1|=0x10; /* Quitar flag de interrupción */
TOC4=TCNT+T1_MS; /* Activar comparador 4 para que se dispare cada 1 ms */

if (tiempo==0) {
PORTA=0x00; /* Apagar el led */
TMSK1&=~0x10; /* Desactivar interrupción comparador 4 */
}
else tiempo--;

void rsioc4()
/*
+-----------------------------------------------------+
¦ Rutina de servicio de interrupción del comparador 4 ¦
+-----------------------------------------------------+ */
{
ssioc4(); /* Llamar a subrutina de servicio de interrupción */
asm (" RTI");
}

main()
{
/* ----------- Cambiar vector de interrupción ------------------ */
vioc41=0x7E; /* Colocar instrucción JMP */
vioc42=(unsigned int)rsioc4; /* Colocar dirección rutina servicio */

TMSK1|=0x10; /* Permitir las interrupciones del comparador 4 */


PORTA=0x40; /* Encender el led */
tiempo=2000; /* Esperar 2 segundos */
asm (" CLI"); /* Permitir las interrupciones */

for (;;) ; /* Bucle infinito */


}

67
Programación de la tarjeta CT6811 en lenguaje C

En la figura 32 se muestra cómo compilar este programa para la ram interna y


como enviarlo a la CT6811 para ser ejecutado.

C:\6811\ICC\CT68INT>cint tempo

UNIFICA V1.0 (C) GRUPO J&J. Abril 1997.


Generación de código unificado en ensamblador

Fichero a Filtrar: tempo.s


Fichero destino : temp.s

C:\6811\ICC\CT68INT>
C:\6811\ICC\CT68INT>downmcu tempo -com2

DOWN-MCU. V1.0 (C) GRUPO J&J. Noviembre-1996.


Envío de programas a la entrenadora

Fichero a enviar: .\tempo.S19


Puerto serie: COM2

Pulse reset en la entrenadora...


Transmitiendo:
>>>>>..>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>................................................
.
...............................................................................
.
...............................OK!
Envío correcto
Tamaño del programa: 94 bytes

C:\6811\ICC\CT68INT>_

Figura 32: Compilación del programa TEMPO.C para la RAM interna y posterior
envío a la CT6811

Ahora se quiere grabar este programa en la EEPROM para que la CT6811 se convierta en una
tarjeta autónoma, independiente del PC. Primero se compila el programa utilizando el archivo
CEEPROM.BAT. Con ello obtenemos el archivo TEMPO.S19 listo para ser grabado en la EEPROM.
Para grabarlo en la eeprom se utilizará el programa CTDIALOG desarrollado por el Grupo J&J. Para
ejecutar este programa primero es preciso enviar a la CT6811 el programa servidor CTSERVER. Una
vez dentro del CTDIALOG, con el comando eeprom podremos grabar programas en la eeprom. En la
figura 33 se muestra el proceso completo.

Una vez grabado el programa en la eeprom, la CT6811 se convierte en una tarjeta autónoma.
Ahora, cada vez que se pulse el botón de reset3 se ejecutará el programa grabado en la EEPROM. Si se
ha grabado el ejemplo TEMPO.S19, cada vez que se pulse el botón de reset se encenderá el led y se
apagará al cabo de 2 segundos.

La figura 33 se encuentra en la siguiente página.

3
Se supone que el usuario a colocado el jumper JP5 de la CT6811 para configurarla en modo autónomo

68
Programación de la tarjeta CT6811 en lenguaje C

C:\6811\ICC\CT68INT>ceeprom tempo

C:\6811\ICC\CT68INT>downmcu ctserver -com2

DOWN-MCU. V1.0 (C) GRUPO J&J. Noviembre-1996.


Envío de programas a la entrenadora

Fichero a enviar: .\ctserver.S19


Puerto serie: COM2

Pulse reset en la entrenadora...


Transmitiendo: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>......OK!
Envío correcto
Tamaño del programa: 250 bytes

C:\6811\ICC\CT68INT>ctdialog -com2

CTDIALOG Versión 1.0 (C) GRUPO J&J. Diciembre 1996


Teclee HELP para obtener ayuda

Puerto actual: COM2


Estableciendo conexión con tarjeta..... conexión establecida

>eeprom tempo
Fichero a grabar en memoria EEPROM: TEMPO.S19
Transmitiendo: »---------------------------»»»
Grabación terminada
Número bytes grabados: 95

>g b600
Conexión perdida

*>quit
Programa terminado

C:\6811\ICC\CT68INT>_

Figura 33: Compilando y granbando en la EEPROM el programa TEMPO.C

69
Programación de la tarjeta CT6811 en lenguaje C

4.4.- CONSIDERACIONES A TENER EN CUENTA

La única precaución a tener en cuenta al generar programas para la EEPROM es que las
variables no se puden inicializar en su declaración, sino que se deben inicializar en el propio código.
A contianucación se muestra un fragmento de código que funcionaría bien para la RAM interna pero
que no se podría grabar en la EEPROM.

#include "REGS6811.H"

static char c=5;

main()
{
if (c==5) PORTA=0x40;
}

Figura 34: Ejemplo de programa que no se puede grabar en la EEPROM.

Si se envía a la RAM interna de la CT6811 el programa funciona correctamente y el led se


enciende. Sin embargo si se compila para la EEPROM y se intenta grabar utiliando el programa
CTDIALOG se obtendrá un mensaje de error como el indicado en la figura 35.

C:\6811\ICC\CT68INT>ctdialog -com2

CTDIALOG Versión 1.0 (C) GRUPO J&J. Diciembre 1996


Teclee HELP para obtener ayuda

Puerto actual: COM2


Estableciendo conexión con tarjeta..... conexión establecida

>eeprom wrong
Fichero a grabar en memoria EEPROM: WRONG.S19
Transmitiendo: -----»
Dirección 0000: Intento de acceso a memoria no EEPROM
Grabación no completada

>quit
Conexión terminada

C:\6811\ICC\CT68INT>

Figura 35: Mensaje de error al intentar grabar un programa incorrecto en la memoria EEPROM.

El programa correcto debe ser como el indicado en la figura 36:

#include "REGS6811.H"

static char c;

main()
{
c=5;

if (c==5) PORTA=0x40;
}

Figura 36: Programa corregido para poder ser grabado en la EEPROM.

La única diferencia está en que en el primer programa se ha inicializado la variable c en el


momento de la inicialización. En el segundo programa la inicialización se hace en el propio código.

70
Programación de la tarjeta CT6811 en lenguaje C

En la figura 37 se muestran los fichero .S19 correspondientes a los dos programas


anteriores.
C:\6811\ICC\CT68INT>type wrong.s19
S108B600BDB60520FEAB
S104000005F6
S116B605D6004F5D2A01431A8300052605C640F71000392B
S9030000FC

C:\6811\ICC\CT68INT>type right.s19
S108B600BDB60520FEAB
S11AB605C605D700D6004F5D2A01431A8300052605C640F710003985
S9030000FC

C:\6811\ICC\CT68INT>

Figura 37: Comparación de los ejecutables incorrecto y correcto para ser grabados en la
EEPROM.

Se han escrito en negrita las direcciones en las que se sitúa el código. En el caso del programa
incorrecto aparece código en la RAM interna (dirección $0000). En el caso del programa correcto todas
las direcciones se encuentran dentro de la EEPROM.

71
Programación de la tarjeta CT6811 en lenguaje C

72
Programación de la tarjeta CT6811 en lenguaje C

5.- LIBRERIAS EN ENSAMBLADOR


En esta sección se muestran una serie de librerías codificadas en ensamblador y adaptadas para
funcionar con el compilador de C. Estas librerías ocupan menos espacio que las correspondientes
codificadas en C. El interfaz para las librerías en C y en ASM es el mismo y por tanto se pueden usar
indistintamente unas u otras. No obstante, si se está trabajando con la RAM interna del 68HC11 o con la
EEPROM es conveniente uitlizar las librerías en ensamblador para ahorrar espacio.

5.1.- LIBRERIA SCIASM.H PARA MANEJO DEL SCI

Esta es la librería equivalente a SCI.H pero codificada en ensamblador. El interfaz es


exactamente el mismo para las dos librerías.

/*
+------------------------------------------------------------------------+
¦ SCIASM.H (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Rutinas de manejo del SCI mediante espera activa. ¦
¦ Las rutians tienen un interfaz en C pero están implementadas directa- ¦
¦ mente en ensamblador, por lo que estan MUY OPTIMIZADAS. ¦
¦ ¦
¦ leer_car() -----> Leer el carácter que venga por el SCI. ¦
¦ enviar_car(c) --> Enviar un carácter por el SCI ¦
¦ enviar(cad) ----> Enviar una cadena de caracteres por el SCI ¦
¦ ¦
+------------------------------------------------------------------------+ */

char leer_car()
/* +--------------------------------------------------------+
¦ Función que devuelve el carácter recibido por el SCI ¦
+--------------------------------------------------------+ */
{
asm (" PSHY");
asm (" LDY #$102E");
asm ("leer_car BRCLR 0,Y $10 leer_car");
asm (" LDAB $102F");
asm (" PULY");
}

void enviar_car(char c)
/* +------------------------------------------+
¦ Enviar un carácter por el puerto serie. ¦
+------------------------------------------+ */
{
asm(" PSHY");
asm(" LDY #$102E");
asm("enviar BRCLR 0,Y $80 enviar");
asm(" LDAB %c");
asm(" STAB 1,Y");
asm(" PULY ");
}

void enviar(char *cad)


/* +-------------------------------+
¦ Enviar una cadena por el SCI ¦
+-------------------------------+ */
{
asm (" LDY %cad ");
asm ("otro_car: ");
asm (" LDAB 0,Y");
asm (" TSTB ");
asm (" BEQ fin_enviar");
asm (" PSHX");
asm (" TSX");
asm (" STD 0,X");
asm (" JSR _enviar_car");
asm (" PULX");
asm (" INY");
asm (" BRA otro_car");
asm ("fin_enviar");
}

73
Programación de la tarjeta CT6811 en lenguaje C

A continuación se presenta la librería SCI.H. El ahorro en bytes que se consigue


utilizando la librería SCIASM.H en vez de SCI.H es de 50 bytes. Por el contrario la librería SCI.H es
mucho más legible y entendible.

/*
+------------------------------------------------------------------------+
¦ SCI.H (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Rutinas de manejo del SCI mediante espera activa. ¦
¦ ¦
¦ leer_car() -----> Leer el carácter que venga por el SCI. ¦
¦ enviar_car(c) --> Enviar un carácter por el SCI ¦
¦ enviar(cad) ----> Enviar una cadena de caracteres por el SCI ¦
¦ ¦
+------------------------------------------------------------------------+ */

#include "regs6811.h"

char leer_car()
/* +--------------------------------------------------------+
¦ Función que devuelve el carácter recibido por el SCI ¦
+--------------------------------------------------------+ */
{
while(!(SCSR & 0x10));
return SCDR;
}

void enviar_car(char c)
/* +------------------------------------------+
¦ Enviar un carácter por el puerto serie. ¦
+------------------------------------------+ */
{
while (!(SCSR & 0x40));
SCDR = c;
}

void enviar(char *cad)


/* +-------------------------------+
¦ Enviar una cadena por el SCI ¦
+-------------------------------+ */
{
static unsigned char i;

i=0;
while (cad[i]) {
enviar_car(cad[i]);
i++;
}
}

74
Programación de la tarjeta CT6811 en lenguaje C

5.2.- LIBRERIA SPIASM.H PARA MANEJO DEL SPI


/*
+------------------------------------------------------------------------+
¦ SPI.H (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Rutinas de manejo del SPI mediante espera activa. ¦
¦ ¦
¦ spi(c) --> Función que realizar un 'intercambio' por el SPI. Envía ¦
¦ El carácter c y devuelve lo que se reciba por el SPI. ¦
¦ spi_maestro() -> Macro para configurar el SPI en modo maestro. ¦
¦ spi_esclavo() -> Macro para configurar el SPI en modo esclavo ¦
¦ ¦
+------------------------------------------------------------------------+ */
#include "REGS6811.H"

/* +-------------------------------+
--------------------¦ Macros para configurar el SPI ¦-----------------
+-------------------------------+ */
#define spi_maestro() DDRD=0x38; SPCR=0x54; PORTD=0x00
#define spi_esclavo() DDRD=0x04; SPCR=0x44

char spi(char c)
/* +--------------------------------------------------------+
¦ Esta función realizar un 'intercambio' de información ¦
¦ por el SPI: Se envía el carácter indicado y se devuel- ¦
¦ ve lo que venga por el SPI. ¦
+--------------------------------------------------------+ */
{
asm (" PSHY");
asm (" LDY #$1029");
asm (" LDAA %c");
asm (" STAA 1,Y");
asm ("wspi BRCLR 0,Y $80 wspi");
asm (" LDAB 1,Y");
asm (" PULY");
}

Con esta librería se consigue un ahorro de 12 bytes.


A continuación se reproduce la librería SPI.H codificada en C.

/*
+------------------------------------------------------------------------+
¦ SPI.H (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Rutinas de manejo del SPI mediante espera activa. ¦
¦ ¦
¦ spi(c) --> Función que realizar un 'intercambio' por el SPI. Envía ¦
¦ El carácter c y devuelve lo que se reciba por el SPI. ¦
¦ spi_maestro() -> Macro para configurar el SPI en modo maestro. ¦
¦ spi_esclavo() -> Macro para configurar el SPI en modo esclavo ¦
¦ ¦
+------------------------------------------------------------------------+ */
#include "REGS6811.H"

/* +-------------------------------+
--------------------¦ Macros para configurar el SPI ¦-----------------
+-------------------------------+ */
#define spi_maestro() DDRD=0x38; SPCR=0x54; PORTD=0x00
#define spi_esclavo() DDRD=0x04; SPCR=0x44

char spi(char c)
/* +--------------------------------------------------------+
¦ Esta función realizar un 'intercambio' de información ¦
¦ por el SPI: Se envía el carácter indicado y se devuel- ¦
¦ ve lo que venga por el SPI. ¦
+--------------------------------------------------------+ */
{
SPDR=c; /* Enviar dato */
while (!(SPSR & 0x80)); /* Esperar a que el dato se envíe */
return SPDR; /* Devolver el dato recibido */
}

75
Programación de la tarjeta CT6811 en lenguaje C

76
Programación de la tarjeta CT6811 en lenguaje C

5.3.- LIBRERIA DELAYASM.H PARA REALIZAR PAUSAS


/*
+------------------------------------------------------------------------+
¦ DELAYASM.H (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Librería para realizar pausas. Se han implementado directamente ¦
¦ en ensamblador. ¦
¦ Se utiliza el comparador 5. ¦
¦ ¦
¦ delay(t) --> Realizar una pausa de t milisegundo. ¦
¦ t=1000 Pausa de 1 segundo ¦
¦ ¦
+------------------------------------------------------------------------+ */

void delay(unsigned int time)


{
asm (" PSHY");
asm ("bucle_oc5");
asm (" LDY %time");
asm (" CPY #0");
asm (" BEQ fin_delay");
asm (" DEY");
asm (" STY %time");
asm (" LDD $100E");
asm (" ADDD #2000");
asm (" STD $101E");
asm (" LDY #$1023");
asm (" BSET 0,Y $08");
asm ("oc5 BRCLR 0,Y $08 oc5");
asm (" BRA bucle_oc5");
asm ("fin_delay ");
asm (" PULY");
asm (" RTS");
}

Esta librería NO COMPENSA implementarla en ensamblador. El ahorro sólo es de 6 bytes y es


mucho más complicada de implementar que en C. A continuación se muestra la librería DELAY.H

/*
+------------------------------------------------------------------------+
¦ DELAY.H (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Librería para realizar pausas. ¦
¦ ¦
¦ delay(t) --> Realizar una pausa de t milisegundo. ¦
¦ t=1000 Pausa de 1 segundo ¦
¦ ¦
+------------------------------------------------------------------------+ */

#include "REGS6811.H"

#define T1_MS 2000 /* Número de tics de reloj necesarios para generar un */


/* retraso de 1ms */

void delay(unsigned int time)


{
while (time!=0) {
time--;
TOC5=TCNT+T1_MS; /* Iniciar el comparador para que se active al cabo */
/* de 1ms de tiempo */
TFLG1|=0x08; /* Poner a cero flag del comparador 5 */
while (!(TFLG1 & 0x08)) ; /* Espear a que se active el flag */
}
}

77

Das könnte Ihnen auch gefallen