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................................................................................................................................... 1.- INTRODUCCION.................................................................................................................... 1.1.- ¿Qué es un compilador cruzado?........................................................................................ 1.2.- Lenguajes de alto nivel VS lenguaje ensamblador............................................................... 1.3.- Objetivos............................................................................................................................ 1.4.- Cómo leer este libro............................................................................................................ 2.- EL COMPILADOR DE C DE IMAGECRAFT...................................................................... 2.1.- Características del compilador........................................................................................... 2.2.- Ficheros que componen el compilador................................................................................ 2.3.- Funcionamiento del compilador......................................................................................... 2.4.- Fichero de arranque y configuración CRT.S....................................................................... 2.5.- Implementación de los tipos de variables............................................................................ 2.5.1.- Variables estáticas y automáticas............................................................................. 2.5.2.- Los tipos de variables CHAR e INT......................................................................... 2.6.- Interfaz entre el C y el lenguaje ensamblador...................................................................... 2.6.1.- Llamadas a funciones en ensamblador..................................................................... 2.6.2.- Inclusión de instrucciones en ensamblador en el código en C................................... 2.7.- Rutinas de servicio de interrupción..................................................................................... 2.7.1.- Cambio del vector de interrupción........................................................................... 2.7.2.- Activación de las interrupciones.............................................................................. 2.7.3.- Rutina de servicio de la interrupción........................................................................ 2.8.- Un ejemplo......................................................................................................................... 3.- PROGRAMACION DE LA CT6811 EN MODO ENTRENADOR....................................... 3.1.- INTRODUCCION.............................................................................................................. 3.2.- CONFIGURACION DEL COMPILADOR......................................................................... 3.2.1- El fichero de arranque y configuración CTRAMINT.S............................................. 3.2.2.- Unificación de programas en ensamblador............................................................... 3.2.3.- Situación de las variables al comienzo del fichero en ensamblador........................... 3.2.4.- Generación de archivos ejecutables .S19.................................................................. 3.2.5.- Resumen de los pasos necesarios para obtener ficheros ejecutables para la RAM interna.................................................................................................................. 3.2.6.- El archivo CINT.BAT para compilar programas en C para la RAM interna de la CT6811.................................................................................................................. 3.2.7.- Un ejemplo.............................................................................................................. 3.3.- REGISTROS DE CONTROL Y VECTORES DE INTERRUPCION................................. 3.3.1.- Acceso a los registros de control del 68HC11.......................................................... 3.3.2.- Acceso a los vectores de interrupción...................................................................... 3.4.- PROGRAMACION DE LOS RECURSOS DEL 68HC11.................................................. 3.4.1.- Introducción.......................................................................................................... 3.4.2.- Los puertos de ENTRADA/SALIDA...................................................................... 3.4.2.1.- Programación del puerto A...................................................................... 3.4.2.2.- Programación del puerto B...................................................................... 3.4.2.3.- Programación del puerto C...................................................................... 3.4.2.4.- Programación del puerto D...................................................................... 3.4.2.5.- Programación del puerto E...................................................................... 3.4.3.- Programación del SCI........................................................................................... 3.4.4.- Programación del SPI........................................................................................... 3.4.5.- Programación del temporizador principal............................................................. 3.4.6.- Programación de las interrupciones en tiempo real............................................... 3.4.7.- Programación de los comparadores...................................................................... 3.4.8.- Programación de los capturadores......................................................................... 3.4.9.- Programación del acumulador de pulsos............................................................... 5 7 7 7 7 7 9 9 9 9 10 11 11 12 12 12 12 13 13 13 13 14 17 17 17 17 18 18 19 19 22 22 25 25 26 29 29 29 29 31 32 32 33 35 41 45 47 49 53 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.......................................... 4.1.- INTRODUCCION............................................................................................................. 4.2.- CONFIGURACION DEL COMPILADOR........................................................................ 4.2.1.- El fichero de arranque y configuración CTEEPROM.S........................................... 4.2.2.- Situación de las variables al comienzo del fichero en ensamblador.......................... 4.2.3.- Generación de archivos ejecutables .S19................................................................. 4.2.4.- Resumen de los pasos necesarios para obtener ficheros ejecutables para la memoria EEPROM............................................................................................................... 4.2.5.- El archivo CEEPROM.BAT para compilar programas para la EEPROM................ 4.3.- EJEMPLOS DE PROGRAMAS PARA LA EEPROM....................................................... 4.4.- CONSIDERACIONES A TENER EN CUENTA............................................................... 5.- LIBRERIAS EN ENSAMBLADOR........................................................................................ 5.1.- Librería SCIASM.H para manejo del SCI.......................................................................... 5.2.- Librería SPIASM.H para manejo del SPI........................................................................... 5.3.- Librería DELAYASM.H para realizar pausas.................................................................... 63 63 63 63 63 64 64 64 67 70 73 73 73 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 .C

COMPILADOR

Ficheros en ensamblador .S

ENSAMBLADOR

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

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

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 _ledon LDAA #$40 STAA $1000 RTS ; Comienzo rutina ledon()

Si se definiese una función con parámetros de entrada la cosa sería un poco más complicada.

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

Es posible hacer referencia a variables en c desde la instrucción asm. Para ello utilizamos el carácter %. En la figura 7 se muestra un ejemplo muy simple. Queremos cargar 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 de la propia variable.

main() { static char c; c=leer_car(); asm (“ LDAA %c”); . . }

Figura 7: Ejemplo de carga de la 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 muestra el modelo a seguir para la puesta en funcionamiento de las rutinas de servicio de interrupción. 2.7.1.- Cambio del vector de interrupción
/* Vector de interrupción */ #define vint (*(unsigned int *)0xFFD6) /* Rutina de servicio de interrupción */ void rsi() { . . . 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 Obsérvese que existen dos secciones. En la sección 0 se encuentra el código. En la sección 1 se encuentra la única variable que hay en el programa. Esta variable es global. Ensamblando directamente el programa LEDP.S no conseguimos obtener el ejecutable LEDP.S19 deseado. Debemos ensamblarlo junto con un fichero .S de configuración que indique la posicón en memoria de las dos secciones.
_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 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 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 tarjeta CT6811. 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 Para poder utilizar el compilador de C tendremos que configurarlo para que se genere código para este mapa de memoria. El código debe empezar en la dirección $0000 y no puede sobrepasar la dirección $FF, o de lo contrario desbordaremos la memoria interna del 68HC11. Tanto el código, como los datos y la pila se deben situar en la RAM interna. Por ello podemos hablar de un único segmento de trabajo.
RAM INTERNA

RGISTROS DE CONTROL

EEPROM

BOOTSTRAP ROM

$E000
ROM

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 inf jsr _main bra inf ; Comienzo de la RAM interna ; Saltar al programa principal ; ¡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

Fichero ledp.c

COMPILADOR DE C ICC11 -S ledp.c

UNIFICACION UNIFICA ledp.s ledpu.s

MODIFICACION DE VARIABLES getvars ledpu.s ledpv.s > vars 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; i=porta; }

/* Envio de datos al puerto A */ /* 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 #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define PORTA PIOC PORTC PORTB PORTCL DDRC PORTD DDRD PORTE CFORC OC1M OC1D TCNT TIC1 TIC2 TIC3 TOC1 TOC2 TOC3 TOC4 TOC5 TCTL1 TCTL2 TMSK1 TFLG1 TMSK2 TFLG2 PACTL PACNT SPCR SPSR SPDR BAUD SCCR1 SCCR2 SCSR SCDR ADCTL ADR1 (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned char char char char char char char char char char char char int int int int int int int int int char char char char char char char char char char char char char char char char char char *)0x1000) *)0x1002) *)0x1003) *)0x1004) *)0x1005) *)0x1007) *)0x1008) *)0x1009) *)0x100A) *)0x100B) *)0x100C) *)0x100D) *)0x100E) *)0x1010) *)0x1012) *)0x1014) *)0x1016) *)0x1018) *)0x101A) *)0x101C) *)0x101E) *)0x1020) *)0x1021) *)0x1022) *)0x1023) *)0x1024) *)0x1025) *)0x1026) *)0x1027) *)0x1028) *)0x1029) *)0x102A) *)0x102B) *)0x102C) *)0x102D) *)0x102E) *)0x102F) *)0x1030) *)0x1031)

25

Programación de la tarjeta CT6811 en lenguaje C #define #define #define #define #define #define #define #define #define #define ADR2 ADR3 ADR4 OPTION COPRST PPROG HPRIO INIT TEST1 CONFIG (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned (*(unsigned char char char char char char char char char char *)0x1032) *)0x1033) *)0x1034) *)0x1039) *)0x103A) *)0x103B) *)0x103C) *)0x103D) *)0x103E) *)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; i=PORTA; }

/* Envio de datos al puerto A */ /* 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) #define visci2 (*(unsigned int *)0xC5) /* SCI */

void rsisci() /* Rutina de atención a la interrupción del SCI */ { ...... ...... asm (" } main() { visci1=0x7E; visci2=(unsigned int)rsisci; .... .... } RTI");

/* Colocar instrucción JMP */ /* 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) #define visci2 (*(unsigned int *)0xC5) #define vispi1 (*(char *)0xC7) #define vispi2 (*(unsigned int *)0xC8) #define viap1 #define viap2 (*(char *)0xCA) (*(unsigned int *)0xCB) /* SCI */ /* SPI */ /* Acumulador de Pulsos */ /* Overflow en acumulador de pulsos */ /* Overflow en temporizador */ /* Comparador 5 */ /* Comparador 4 */ /* Comparador 3 */ /* Comparador 2 */ /* Comparador 1 */ /* Capturador 3 */ /* Capturador 2 */ /* Capturador 1 */ /* Tiempo real */

#define vioap1 (*(char *)0xCD) #define vioap2 (*(unsigned int *)0xCE) #define viot1 #define viot3 (*(char *)0xD0) (*(unsigned int *)0xD1)

#define vioc51 (*(char *)0xD3) #define vioc52 (*(unsigned int *)0xD4) #define vioc41 (*(char *)0xD6) #define vioc42 (*(unsigned int *)0xD7) #define vioc31 (*(char *)0xD9) #define vioc32 (*(unsigned int *)0xDA) #define vioc21 (*(char *)0xDC) #define vioc22 (*(unsigned int *)0xDD) #define vioc11 (*(char *)0xDF) #define vioc12 (*(unsigned int *)0xE0) #define viic31 (*(char *)0xE2) #define viic32 (*(unsigned int *)0xE3) #define viic21 (*(char *)0xE5) #define viic22 (*(unsigned int *)0xE6) #define viic11 (*(char *)0xE8) #define viic12 (*(unsigned int *)0xE9) #define virti1 (*(char *)0xEB) #define virti2 (*(unsigned int *)0xEC)

27

Programación de la tarjeta CT6811 en lenguaje C

#define viirq1 (*(char *)0xEE) #define viirq2 (*(unsigned int *)0xEF) #define vixirq1 (*(char *)0xF1) #define vixirq2 (*(unsigned int *)0xF2) #define viswi1 (*(char *)0xF4) #define viswi2 (*(unsigned int *)0xF5) #define viiop1 (*(char *)0xF7) #define viiop2 (*(unsigned int *)0xF6) #define visf1 (*(char *)0xFA) #define visf2 (*(unsigned int *)0xFB) #define vicopf1 (*(char *)0xFD) #define vicopf2 (*(unsigned int *)0xFE)

/* IRQ /* XIRQ

*/ */

/* Interrupción Software */ /* Instrucción ilegal */ /* Fallo del sistema */ /* Fallo en el monitor del reloj */

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 (" } main() { visci1=0x7E; visci2=(unsigned int)rsisci; .... .... } RTI");

/* Colocar instrucción JMP */ /* 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; for (i=0; i<0x8000; i++); } }

/* Cambiar de estado PA6 */ /* 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; PORTA=0x80; }

/* Poner bit 7 del registro PACTL a '1' para configurar */ /* el bit 7 del puerto A como salida */ /* 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 ‘ , el bit de salida PA6 se pondrá a ‘ . Lo mismo con el estado ‘ . 1’ 1’ 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; PORTA=(pa0 << 6); } }

/* Leer bit 0 del puerto A */ /* 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; for (i=0; i<0x8000; i++); b=b<<1; if (b==0) b=1; } }

/* Actualizar puerto B */ /* Realizar una pausa */

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 /* Leer puerto C */ /* Escribir en puerto C */

*/ */

for (;;) { c=PORTC & 0x0F; PORTC=(c << 4); } }

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; PORTA=(e << 6); } }

/* Leer puerto E */ /* 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 ‘ nuestro programa principal es el mismo para las dos librerías, ve’ 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; c=SCDR; PORTA^=0x40; } /* Quitar flag de interrupción */ /* 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; asm (" CLI"); for (;;) ; } /* Activar interrupción de DATO recibido del SCI */ /* Permitir las interrupciones */ /* 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(); for (;;) { c=leer_car(); spi(c); } }

/* Configurar micro como maestro */ /* Esperar a que se reciba un dato por SCI */ /* 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; PORTC=0x80; spi_esclavo();

/* Configurar puerto C: Bits 7,6,5 y 4 salidas. /* Mandar un 8 al display para que se encienda /* Configurar micro como esclavo */ /* Recibir dato del maestro */ /* Mandar dato al display 7-seg */ /* Cambiar led de estado */

*/ */

for (;;) { c=spi(0); PORTC=(c << 4); PORTA^=0x40; } }

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 ‘ , recibirá como eco una ‘ (‘ = ‘ + 1). A’ B’ B’ A’ 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(); for (;;) { c=leer_car(); spi(c);

/* Configurar micro como maestro */ /* Esperar carácter por el SCI */ /* Enviar el carácter leido */ /* Pequeña pausa para que al esclavo tenga tiempo */ /* de procesar el dato */ /* Recibir dato del esclavo */ /* Enviar dato por el SCI */

for (i=0; i<2; i++); c=spi(0); enviar_car(c); } }

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; PORTC=0x80; spi_esclavo();

/* Configurar puerto C: 4 bits mayor peso como salidas */ /* Enviar un 8 al display de 7 segmentos */ /* 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; c=(char) (tempo & 0x00FF); enviar_car(c); } }

/* Leer valor del temporizador */ /* Quedarse con el byte bajo del temporizador */

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; asm (" CLI"); for (;;) ; } /* Activar interrupción de overflow */ /* Permitir las interrupciones */ /* 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; asm (" CLI"); for (;;) ; } /* Activar interrupción de Tiempo real */ /* Permitir las interrupciones */ /* 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; delay(1000); } }

/* Cambiar led de estado */ /* 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; TMSK1&=~0x10; } 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; PORTA=0x40; tiempo=2000; asm (" CLI"); for (;;) ; } /* /* /* /* Permitir las interrupciones del comparador 4 */ Encender el led */ Esperar 2 segundos */ Permitir las interrupciones */ /* Bucle infinito */ /* Apagar el led */ /* Desactivar interrupción comparador 4 */

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; TOC2=TCNT+TIEMPO; 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; TMSK1|=0x40; asm (" CLI"); for (;;) ; } /* Activar salida hardware del comparador 2 */ /* Permitir las interrupciones del comparador 4 */ /* Permitir las interrupciones */ /* Bucle infinito */ /* Quitar flag de interrupción */ /* Activar comparador 2 */

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; TMSK1|=0x02; asm (" CLI"); for (;;) ; } /* Configurar capturador 2 para flanco de bajada */ /* Permitir las interrupciones del capturador 2 */ /* Permitir las interrupciones */ /* 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; TMSK1|=0x02; cuenta=5; PORTC=cuenta << asm (" CLI"); for (;;) ; } /* Configurar capturador 2 para flanco de bajada */ /* Permitir las interrupciones del capturador 2 */ 4; /* Permitir las interrupciones */ /* 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; PACTL|=0x40; TMSK2|=0x10; asm (" CLI"); for (;;) ; } /* /* /* /* /* Poner a cero el acumulador de pulsos */ Activar acumulador de pulsos. Modo cuenta de pulsos en flanco de bajada Activar la interrupción del acumulador */ Permitir las interrupciones */ /* 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; PACTL|=0x40; TMSK2|=0x20; asm (" CLI"); for (;;) ; } /* Inicializar acumulador de pulsos */ /* Configurar acumulador de pulsos */ /* Permitir la interrupción de overflow del acumulador */ /* Permitir las interrupciones */ /* 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"); for (;;) ; } /* Permitir las interrupciones */ /* 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; ADCTL|=0x20;

/* Encender el conversor */ /* Configurar el conversor */ /* Esperar a que termine conversion */ /* Enviar muestra leida por el SCI */

for (;;) { while (!(ADCTL & 0x80)); enviar_car(ADR1); } }

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; ADCTL|=0x20;

/* Encender el conversor */ /* 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 ORG $B600 SECT 1 ORG $0000 SECT 0 inf jsr _main bra inf ; Saltar al programa principal ; ¡Bucle infinito! ; Sección 0 : Segmento para el código ; El código se sitúa en la eeprom ; Sección 1 : Segmento para los datos Los datos se sitúan en la RAM interna

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; TMSK1&=~0x10; } 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; PORTA=0x40; tiempo=2000; asm (" CLI"); for (;;) ; } /* /* /* /* Permitir las interrupciones del comparador 4 */ Encender el led */ Esperar 2 segundos */ Permitir las interrupciones */ /* Bucle infinito */ /* Apagar el led */ /* Desactivar interrupción comparador 4 */

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

Sign up to vote on this title
UsefulNot useful