Professional Documents
Culture Documents
LA TARJETA CT6811 EN
LENGUAJE C
COMPILADOR CRUZADO DE C
IMAGECRAFT V0.47
MICROBÓTICA S.L.
Programación de la tarjeta CT6811 en lenguaje C
2
Programación de la tarjeta CT6811 en lenguaje C
INDICE
PROLOGO................................................................................................................................... 5
1.- INTRODUCCION.................................................................................................................... 7
1.1.- ¿Qué es un compilador cruzado?........................................................................................ 7
1.2.- Lenguajes de alto nivel VS lenguaje ensamblador............................................................... 7
1.3.- Objetivos............................................................................................................................ 7
1.4.- Cómo leer este libro............................................................................................................ 7
3
Programación de la tarjeta CT6811 en lenguaje C
4
Programación de la tarjeta CT6811 en lenguaje C
PROLOGO
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.
Nosotros apostamos por los sistemas autónomos e inteligentes, que poco a poco
se van abriendo camino a todos los niveles.
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?
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
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
• 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
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
C:\6811\ICC\PRUEBA>icc11 -S prueba.c
C:\6811\ICC\PRUEBA>ias11 prueba.s
C:\6811\ICC\PRUEBA>dir
C:\6811\ICC\PRUEBA>_
C:\6811\ICC\PRUEBA>dir
C:\6811\ICC\PRUEBA>_
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.
10
Programación de la tarjeta CT6811 en lenguaje C
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.
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
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.
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.
1. Si se escribe una instrucción en ensamblador hay que colocar por lo menos un espacio al comienzo
de la cadena, para indicar al ensamblador que es una instrucción y no una etiqueta. Ejemplos:
• Correcto: asm (“ RTI”);
• Incorrecto: asm (“RTI”);
2. Las etiquetas se deben escribir justo a la izquierda de la cadena, sin espacios intermedios:
• Correcto: asm (“bucle LDAA #$40”);
• Incorrecto: asm (“ bucle LDAA #$40”);
12
Programación de la tarjeta CT6811 en lenguaje C
main()
{
Es posible hacer referencia a variables en c desde la static char c;
instrucción asm. Para ello utilizamos el carácter %. En la
figura 7 se muestra un ejemplo muy simple. Queremos cargar c=leer_car();
asm (“ LDAA %c”);
en el acumulador A el valor de la variable c. La instrucción .
asm(“ LDAA %c”) lo soluciona. El carácter % hace que se .
}
le pase al ensamblador la etiqueta asociada a la variable
situada a continuación del carácter %, en vez del identificador Figura 7: Ejemplo de carga de la
de la propia variable. variable c en el acumulador A
A la hora de hacer rutinas de servicio de interrupción hay que tener en cuenta los tres puntos
siguientes:
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.
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”);
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.
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. ¦
+------------------------------------------------------------------------+ */
unsigned int i;
main()
{
for (;;) {
PORTA^=0x40;
for (i=0; i<0x8000; i++);
}
}
15
Programación de la tarjeta CT6811 en lenguaje C
16
Programación de la tarjeta CT6811 en lenguaje C
* +------------------------------------------------------------------------+
* ¦ CTRAMINT.S (C) GRUPO J&J. ABRIL 1997 ¦
* ¦------------------------------------------------------------------------¦
* ¦ Fichero de arranque y configuración para trabajar con la tarjeta ¦
* ¦ CT6811 en modo entrenador. ¦
* +------------------------------------------------------------------------+ */
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
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.
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.
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>_
Figura 14: Generación del fichero pruebaf.s con las variables al comienzo
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>dir programa.s19
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.
• Compilar todos los archivos .C que integren el programa final. Para ello utilizar: ICC11 -S fichero.c
Con esto conseguimos tener una serie de archivos .S en ensamblador.
• Aplicar a cada archivo .S la unificación mediante el programa UNIFICA.EXE
• Situar todas las variables al comienzo del código con el progrma GETVARS.EXE
• Ensamblar todos los ficheros .S ya modificados junto con el archivo de arranque y configuración
CTRAMINT.S
• Ya se dispone de un archivo .S19 listo para ser enviado a la tarjeta CT6811.
19
Programación de la tarjeta CT6811 en lenguaje C
COMPILADOR MODIFICACION DE
UNIFICACION
Fichero ledp.c DE C VARIABLES
UNIFICA ledp.s ledpu.s
getvars ledpu.s ledpv.s > vars
ICC11 -S ledp.c
copy vars+ledpv ledpf
ENSAMBLADOR
Fichero ledp.S19
IAS11 -o ledp ctramint.s ledpf
Figura 16: Pasos a realizar para crear el fichero ledp.S19 a partir del fichero ledp.C
Por si el lector tiene curiosidad, se van a presentar los distintos ficheros intermedios generados
en el ejemplo de la figura 16. En la figura 17 se muestra el programa ledp.C y en la figura 18 el fichero
ledp.S ya compilado.
/*
+------------------------------------------------------------------------+
¦ LEDP.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo para encender el led de la tarjeta CT6811. ¦
+------------------------------------------------------------------------+ */
unsigned int i;
main()
{
for (;;) {
PORTA^=0x40;
for (i=0; i<0x8000; i++);
}
}
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
20
Programación de la tarjeta CT6811 en lenguaje C
_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
_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:
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
@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
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
22
Programación de la tarjeta CT6811 en lenguaje C
C:\6811\ICC\CT68INT>cint ledp
C:\6811\ICC\CT68INT>
C:\6811\ICC\CT68INT>downmcu ledp -com2
C:\6811\ICC\CT68INT>
23
Programación de la tarjeta CT6811 en lenguaje C
24
Programación de la tarjeta CT6811 en lenguaje C
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.
char i;
main()
{
porta=0xFF; /* Envio de datos al puerto A */
i=porta; /* Lectura de datos del puerto A */
}
Figura 23: Ejemplo de acceso a los registros de control . Se envía el valor $FF al puerto A
Para facilitar el acceso a todos los registros de control, se han incluido todas las definiciones en
el fichero REGS6811.H, que se muestra a continuación.
/*
+------------------------------------------------------------------------+
¦ REGS6811.H (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Fichero que contiene todos los registros internos del 68HC11. ¦
¦ ¦
+------------------------------------------------------------------------+ */
25
Programación de la tarjeta CT6811 en lenguaje C
Los nombres utilizados para los registros de control son los mismo que se encuentran en el
manual del 68HC11 original. Utilizando el archivo REGS6811.H el programa de la figura 23 queraría
como se muestra en la figura 24.
#include “REGS6811.H”
char i;
main()
{
PORTA=0xFF; /* Envio de datos al puerto A */
i=PORTA; /* Lectura de datos del puerto A */
}
Figura 24: Ejemplo de utilización del fichero de definición de registros internos REGS6811.H
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.
void rsisci()
/* Rutina de atención a la interrupción del SCI */
{
......
......
main()
{
visci1=0x7E; /* Colocar instrucción JMP */
visci2=(unsigned int)rsisci; /* Colocar dirección rutina servicio */
....
....
}
Figura 25: Ejemplo de cambio del vector de interrupción de la interrupción del SCI
26
Programación de la tarjeta CT6811 en lenguaje C
/*
+------------------------------------------------------------------------+
¦ 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. ¦
+------------------------------------------------------------------------+ */
27
Programación de la tarjeta CT6811 en lenguaje C
#include “VECTINT.H”
void rsisci()
/* Rutina de atención a la interrupción del SCI */
{
......
......
main()
{
visci1=0x7E; /* Colocar instrucción JMP */
visci2=(unsigned int)rsisci; /* Colocar dirección rutina servicio */
....
....
}
Figura 26: Cambio del vector de interrupción del SCI utilizando el archivo VECTINT.H
28
Programación de la tarjeta CT6811 en lenguaje C
3.4.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:
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.
/*
+------------------------------------------------------------------------+
¦ 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
C:\6811\ICC\CT68INT>
C:\6811\ICC\CT68INT>downmcu ledon -com2
C:\6811\ICC\CT68INT>_
Este ejemplo simplemente hace parpadear el LED de la tarjeta CT6811. La novedad que se
introduce en este programa es que se ha definido la variable global i.
/*
+------------------------------------------------------------------------+
¦ LEDP.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo para encender el led de la tarjeta CT6811. ¦
+------------------------------------------------------------------------+ */
#include "REGS6811.H"
unsigned int i;
main()
{
for (;;) {
PORTA^=0x40; /* Cambiar de estado PA6 */
for (i=0; i<0x8000; i++); /* Realizar una pausa */
}
}
El bit 7 del puerto A por defecto está configurado como entrada. En este ejemplo se configura
como salida y se activa, de tal forma que si se conecta un led se enciende.
/*
+------------------------------------------------------------------------+
¦ PA7.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Se configura el bit 7 del puerto A para salida y se activa con ¦
¦ un '1'. ¦
30
Programación de la tarjeta CT6811 en lenguaje C
+------------------------------------------------------------------------+ */
#include "REGS6811.H"
main()
{
PACTL=0x80; /* Poner bit 7 del registro PACTL a '1' para configurar */
/* el bit 7 del puerto A como salida */
PORTA=0x80; /* Mandar un '1' por el bit 7 del puerto A */
}
En este ejemplo se refleja el estado del bit PA0 (bit de entrada) sobre el bit PA6 de salida. Si la entrada
PA0 se pone a ‘1’, el bit de salida PA6 se pondrá a ‘1’. Lo mismo con el estado ‘0’.
/*
+------------------------------------------------------------------------+
¦ PA0.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Programa ejemplo de la lectura del bit PA0. El estado de esta bit ¦
¦ se refleja sobre el bit de salida PA6. ¦
+------------------------------------------------------------------------+ */
#include "REGS6811.H"
char pa0;
main()
{
for (;;) {
pa0=PORTA & 0x01; /* Leer bit 0 del puerto A */
PORTA=(pa0 << 6); /* Enviar bit leido por el bit 6 del puerto A */
}
}
EJEMPLO 1: Activación rotativa de los 8 bits de l puerto B. En este ejemplo se activa primero el bit
0 del puerto B, después el 1,.... hasta el bit 8. Después se vuelve a comenzar.
/*
+------------------------------------------------------------------------+
¦ PUERTOB.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Activación rotativa de los bits del puerto B. ¦
+------------------------------------------------------------------------+ */
#include "REGS6811.H"
unsigned int i;
char b;
main()
{
b=0x01;
for (;;) {
PORTB=b; /* Actualizar puerto B */
for (i=0; i<0x8000; i++); /* Realizar una pausa */
b=b<<1;
if (b==0) b=1;
}
}
31
Programación de la tarjeta CT6811 en lenguaje C
EJEMPLO 1: Lectura y escritura con el puerto C. En este ejemplo se sonfiguran los 4 bits de menor
peso del puerto C para entradas y los 4 bits de mayor peso para salidas. El estado de las entradas se
refleja sobre los bits de salida.
/*
+------------------------------------------------------------------------+
¦ PUERTOC.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Los 4 bits de menor peso del puerto C se configuran para entrada y ¦
¦ los 4 bits de mayor peso del puerto C se configuran para salida. El ¦
¦ estado de la entrada se refleja sobre los bits de salida. ¦
+------------------------------------------------------------------------+ */
#include "REGS6811.H"
char c;
main()
{
DDRC=0xF0; /* Configurar el puerto C: Bits 0,1,2,3 entrada */
/* Los bits 4,5,6 y 7 para entradas */
for (;;) {
c=PORTC & 0x0F; /* Leer puerto C */
PORTC=(c << 4); /* Escribir en puerto C */
}
}
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
EJEMPLO 1: Reflejo del estado del bit PE0 sobre el bit PA6.
/*
+------------------------------------------------------------------------+
¦ PUERTOE.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ El estado del bit 0 del puerto E se refleja sobre el led de la ¦
¦ tarjeta CT6811. ¦
+------------------------------------------------------------------------+ */
#include "REGS6811.H"
char e;
main()
{
for (;;) {
e=PORTE & 0x01; /* Leer puerto E */
PORTA=(e << 6); /* Escribir en puerto A */
}
}
33
Programación de la tarjeta CT6811 en lenguaje C
34
Programación de la tarjeta CT6811 en lenguaje C
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.
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 */
}
}
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;
}
i=0;
while (cad[i]) {
enviar_car(cad[i]);
i++;
}
}
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
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 */
}
}
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;
}
}
}
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!!!!
/*
+------------------------------------------------------------------------+
¦ ECOASM.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Este programa hace lo mismo que el programa ECO.C pero se utilizan ¦
¦ las rutinas de la librería SCIASM.H en vez de SCI.H ¦
+------------------------------------------------------------------------+ */
#include "regs6811.h"
#include "sciasm.h" /* SE HA SUSTITUIDO POR #include “SCI.H” */
char c;
main()
{
for (;;) {
c=leer_car(); /* Esperar a que venga un carácter por el SCI */
PORTA^=0x40; /* Cambiar el led de estado */
enviar_car(c); /* Hacer eco del caracter recibido */
}
}
Puesto que el interfaz que ‘ve’ nuestro programa principal es el mismo para las dos librerías,
pero con la librería SCIASM.H conseguimos un ahorro de 50 bytes, es mejor utilizar esta librería. Esta
librería se describe con más detalle más adelante.
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;
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 */
39
Programación de la tarjeta CT6811 en lenguaje C
40
Programación de la tarjeta CT6811 en lenguaje C
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”
/*
+------------------------------------------------------------------------+
¦ SPI.H (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Rutinas de manejo del SPI mediante espera activa. ¦
¦ ¦
¦ spi(c) --> Función que realizar un 'intercambio' por el SPI. Envía ¦
¦ El carácter c y devuelve lo que se reciba por el SPI. ¦
¦ spi_maestro() -> Macro para configurar el SPI en modo maestro. ¦
¦ spi_esclavo() -> Macro para configurar el SPI en modo esclavo ¦
¦ ¦
+------------------------------------------------------------------------+ */
#include "REGS6811.H"
/* +-------------------------------+
--------------------¦ Macros para configurar el SPI ¦-----------------
+-------------------------------+ */
#define spi_maestro() DDRD=0x38; SPCR=0x54; PORTD=0x00
#define spi_esclavo() DDRD=0x04; SPCR=0x44
char spi(char c)
/* +--------------------------------------------------------+
¦ Esta función realizar un 'intercambio' de información ¦
¦ por el SPI: Se envía el carácter indicado y se devuel- ¦
¦ ve lo que venga por el SPI. ¦
+--------------------------------------------------------+ */
{
SPDR=c; /* Enviar dato */
while (!(SPSR & 0x80)); /* Esperar a que el dato se envíe */
return SPDR; /* Devolver el dato recibido */
}
Lo que más llama la atención de estas rutinas es que no exiten las típicas funciones de enviar y
recibir datos. Sólo existe una única función que realiza el intercambio de información. En los siguientes
ejemplos se muestra cómo se emplea esta función para enviar y recibir datos.
EJEMPLO 2: Envío de datos del maestro al esclavo. En este ejemplo se envían datos desde el maestro
al esclavo. El esclavo cambia de estado el led cada vez que recibe un dato por el SPI. Además, si se tiene
conectado un display de 7 segmentos en los 4 bits más significativos del puerto C se podrán ver los datos
recibidos. El programa maestro toma los datos del puerto serie. De esta forma, para que el probar que el
programa funciona correctamente el usuario envía los datos desde el teclado del PC hasta el 68HC11
maestro por medio del SCI. De aquí son enviados al 68HC11 esclavo vía el SPI.
PROGRAMA MAESTRO
/*
+------------------------------------------------------------------------+
¦ SPILEDM.C (C) GRUPO J&J. Abril 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Programa ejemplo de manejo del SPI. El micro se configura como ¦
¦ MAESTRO. Todos caracteres que se reciben por el SCI se envían a ¦
¦ través del SPI. ¦
¦ ¦
+------------------------------------------------------------------------+
41
Programación de la tarjeta CT6811 en lenguaje C
*/
#include "REGS6811.H"
#include "SCIASM.H"
#include "SPIASM.H"
char c;
main()
{
spi_maestro(); /* Configurar micro como maestro */
for (;;) {
c=leer_car(); /* Esperar a que se reciba un dato por SCI */
spi(c); /* Enviar carácter por el SPI */
}
}
PROGRAMA ESCLAVO:
/*
+------------------------------------------------------------------------+
¦ SPILEDE.C (C) GRUPO J&J. Febrero 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ PROGRAMA ESCLAVO ¦
¦ ¦
¦ Cada vez que se recibe un carácter por el SPI se cambia el estado ¦
¦ del led. Los 4 bits más bajos de carácter recibido se envían por los ¦
¦ 4 bits más altos del puerto C de tal manera que si se ha conectado ¦
¦ un display de 7 segmentos se pueden ver los números recibidos. ¦
+------------------------------------------------------------------------+
*/
#include "REGS6811.H"
#include "SPIASM.H"
char c;
main()
{
DDRC=0xF0; /* Configurar puerto C: Bits 7,6,5 y 4 salidas. */
PORTC=0x80; /* Mandar un 8 al display para que se encienda */
for (;;) {
c=spi(0); /* Recibir dato del maestro */
PORTC=(c << 4); /* Mandar dato al display 7-seg */
PORTA^=0x40; /* Cambiar led de estado */
}
}
Obsérverse cómo funciona la función spi. En el caso del maestro lo que queremos es transmitir
un dato. Por ello simplemente se llama a la función pasando como parámetro el dato a enviar: spi(c). En
el caso del esclavo lo que se quiere es recibir. La función spi() transmite y recibe a la vez. Por ello para
recibir un carácter transmitirmos un carácter ‘basura’ cualquiera. En el ejemplo se ha transmitido el
carácter 0: c=spi(0). Pero se podría haber transmitido cualquiera puesto que el maestro los ignora.
Es muy común que después de enviar datos al esclavo, el maestro se quede esperando a recibir
una respuesta del esclavo. En este ejemplo la respuesta del esclavo es un eco modificado de lo recibido
por el SPI. La modificación consiste en sumar una unidad al carácter recibido. De esta forma, si el
maestro envía una ‘A’, recibirá como eco una ‘B’(‘B’= ‘A’+ 1).
PROGRAMA MAESTRO
/*
+------------------------------------------------------------------------+
¦ SPIECOM.C (C) GRUPO J&J. Abril 1997 ¦
¦------------------------------------------------------------------------¦
42
Programación de la tarjeta CT6811 en lenguaje C
#include "REGS6811.H"
#include "SCIASM.H"
#include "SPIASM.H"
char c;
unsigned int i;
main()
{
spi_maestro(); /* Configurar micro como maestro */
for (;;) {
c=leer_car(); /* Esperar carácter por el SCI */
spi(c); /* Enviar el carácter leido */
for (i=0; i<2; i++); /* Pequeña pausa para que al esclavo tenga tiempo */
/* de procesar el dato */
c=spi(0); /* Recibir dato del esclavo */
enviar_car(c); /* Enviar dato por el SCI */
}
}
PROGRAMA ESCLAVO
/*
+------------------------------------------------------------------------+
¦ SPIECOE.C (C) GRUPO J&J. Febrero 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ PROGRAMA ESCLAVO: ¦
¦ ¦
¦ Se lee lo que viene por el SPI y se hace un ECO. El caracter enviado ¦
¦ es el recibido incrementado en una unidad. Si se recibe el carácter ¦
¦ 'A' se envía el carácter 'B'. Los 4 bits de menor peso del carácter ¦
¦ recibido se envían por los 4 bits de mayor peso del puerto C. Se ¦
¦ modifica el estado del led por cada carácter recibido por el SPI ¦
¦ ¦
+------------------------------------------------------------------------+
*/
#include "REGS6811.H"
#include "SPIASM.H"
char c;
main()
{
DDRC=0xF0; /* Configurar puerto C: 4 bits mayor peso como salidas */
PORTC=0x80; /* Enviar un 8 al display de 7 segmentos */
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
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"
main()
{
for (;;) {
leer_car();
tempo=TCNT; /* Leer valor del temporizador */
c=(char) (tempo & 0x00FF); /* Quedarse con el byte bajo del temporizador */
enviar_car(c);
}
}
/*
+------------------------------------------------------------------------+
¦ 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"
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. */
}
}
/*
+------------------------------------------------------------------------+
¦ 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
#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 */
46
Programación de la tarjeta CT6811 en lenguaje C
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 */
47
Programación de la tarjeta CT6811 en lenguaje C
48
Programación de la tarjeta CT6811 en lenguaje C
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"
/*
+------------------------------------------------------------------------+
¦ DELAY.C (C) GRUPO J&J. ABRIL 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de la librería de pausa. Se cambia el estado del led de la ¦
¦ CT6811 cada 1 segundo. ¦
+------------------------------------------------------------------------+ */
#include "REGS6811.H"
#include "DELAY.H"
main()
{
for (;;) {
PORTA^=0x40; /* Cambiar led de estado */
delay(1000); /* Esperar un segundo */
}
}
49
Programación de la tarjeta CT6811 en lenguaje C
#include "regs6811.h"
#include "vectint.h"
void ssioc4()
/*
+---------------------------------------------------------+
¦ Subrutina de servicio de interrupción del comparador 4 ¦
+---------------------------------------------------------+ */
{
TFLG1|=0x10; /* Quitar flag de interrupción */
TOC4=TCNT+T1_MS; /* Activar comparador 4 para que se dispare cada 1 ms */
if (tiempo==0) {
PORTA=0x00; /* Apagar el led */
TMSK1&=~0x10; /* Desactivar interrupción comparador 4 */
}
else tiempo--;
void rsioc4()
/*
+-----------------------------------------------------+
¦ Rutina de servicio de interrupción del comparador 4 ¦
+-----------------------------------------------------+ */
{
ssioc4(); /* Llamar a subrutina de servicio de interrupción */
asm (" RTI");
}
main()
{
/* ----------- Cambiar vector de interrupción ------------------ */
vioc41=0x7E; /* Colocar instrucción JMP */
vioc42=(unsigned int)rsioc4; /* Colocar dirección rutina servicio */
/*
+------------------------------------------------------------------------+
¦ 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"
void ssioc2()
/*
+---------------------------------------------------------+
¦ Subrutina de servicio de interrupción del comparador 2 ¦
+---------------------------------------------------------+ */
50
Programación de la tarjeta CT6811 en lenguaje C
{
TFLG1|=0x40; /* Quitar flag de interrupción */
TOC2=TCNT+TIEMPO; /* Activar comparador 2 */
asm (" RTI");
}
void rsioc2()
/*
+-----------------------------------------------------+
¦ Rutina de servicio de interrupción del comparador 2 ¦
+-----------------------------------------------------+ */
{
ssioc2(); /* Llamar a la subrutina de servicio de interrupción */
asm (" RTI");
}
main()
{
/* ----------- Cambiar vector de interrupción ------------------ */
vioc21=0x7E; /* Colocar instrucción JMP */
vioc22=(unsigned int)rsioc2; /* Colocar dirección rutina servicio */
51
Programación de la tarjeta CT6811 en lenguaje C
52
Programación de la tarjeta CT6811 en lenguaje C
/*
+------------------------------------------------------------------------+
¦ 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 */
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 */
54
Programación de la tarjeta CT6811 en lenguaje C
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 */
/*
+------------------------------------------------------------------------+
¦ 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 */
56
Programación de la tarjeta CT6811 en lenguaje C
/*
+------------------------------------------------------------------------+
¦ IRQ.C (C) GRUPO J&J. MAYO 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de utilización de la interrupción IRQ. Cada vez que se ¦
¦ recibe un flanco de bajada se cambia el estado del led. ¦
¦ ¦
+------------------------------------------------------------------------+ */
#include "regs6811.h"
#include "vectint.h"
void ssiirq()
/*
+------------------------------------------------+
¦ Subrutina de servicio de la interrupción irq ¦
+------------------------------------------------+ */
{
PORTA^=0x40;
}
void rsiirq()
/*
+--------------------------------------------+
¦ Rutina de servicio de la interrupción irq ¦
+--------------------------------------------+ */
{
ssiirq(); /* Llamar a subrutina de servicio de interrupción */
asm (" RTI");
}
main()
{
/* ----------- Cambiar vector de interrupción ------------------ */
viirq1=0x7E; /* Colocar instrucción JMP */
viirq2=(unsigned int)rsiirq; /* Colocar dirección rutina servicio */
OPTION|=0x20;
asm (" CLI"); /* Permitir las interrupciones */
57
Programación de la tarjeta CT6811 en lenguaje C
58
Programación de la tarjeta CT6811 en lenguaje C
EJEMPLO 1: En el siguiente ejemplo se toman muestras a través del canal 1 del conversor A/D. Estas
muestas se envían al PC a través del SCI.
/*
+------------------------------------------------------------------------+
¦ ADSCI.C (C) GRUPO J&J. MAYO 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de utilización del conversor A/D. Se leen muestras y se ¦
¦ envían a través del SCI. ¦
¦ ¦
+------------------------------------------------------------------------+ */
#include "regs6811.h"
#include "SCI.H"
main()
{
OPTION|=0x80; /* Encender el conversor */
ADCTL|=0x20; /* Configurar el conversor */
for (;;) {
while (!(ADCTL & 0x80)); /* Esperar a que termine conversion */
enviar_car(ADR1); /* Enviar muestra leida por el SCI */
}
}
EJEMPLO 2: Cuando la tensión de entrada supera un cierto umbral (2.5 voltios) se enciende el led. En
caso contrario se apaga.
/*
+------------------------------------------------------------------------+
¦ ADLED.C (C) GRUPO J&J. MAYO 1997 ¦
¦------------------------------------------------------------------------¦
¦ Programa ejemplo para ser ejecutado en la tarjeta CT6811. ¦
¦ Este programa se debe cargar en la RAM interna del 6811. ¦
¦ ¦
¦ Ejemplo de utilización del conversor A/D. Cuando la tensión supere ¦
¦ los 2.5 voltios se enciende el led. ¦
¦ ¦
+------------------------------------------------------------------------+ */
#include "regs6811.h"
main()
{
OPTION|=0x80; /* Encender el conversor */
ADCTL|=0x20; /* Configurar el conversor */
for (;;) {
while (!(ADCTL & 0x80)); /* Esperar a que termine conversion */
if (ADR1>0x7F) PORTA=0x40;
else PORTA=0x00;
}
}
59
Programación de la tarjeta CT6811 en lenguaje C
60
Programación de la tarjeta CT6811 en lenguaje C
/*
+------------------------------------------------------------------------+
¦ 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;
}
/*
+------------------------------------------------------------------------+
¦ 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 */
62
Programación de la tarjeta CT6811 en lenguaje C
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.
* +------------------------------------------------------------------------+
* ¦ 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
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.
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>type vars
SECT 1
_i:
RMB 2
C:\6811\ICC\CT68INT>_
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>type prueba.s19
S108B600BDB60520FEAB
S123B605F610004FC840F71000CC0000DD007EB61DDC00C30001DD00DC001A83800025F137
S106B6257EB605E5
S9030000FC
C:\6811\ICC\CT68INT>_
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.
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
65
Programación de la tarjeta CT6811 en lenguaje C
66
Programación de la tarjeta CT6811 en lenguaje C
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.
/*
+------------------------------------------------------------------------+
¦ 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"
void ssioc4()
/*
+---------------------------------------------------------+
¦ Subrutina de servicio de interrupción del comparador 4 ¦
+---------------------------------------------------------+ */
{
TFLG1|=0x10; /* Quitar flag de interrupción */
TOC4=TCNT+T1_MS; /* Activar comparador 4 para que se dispare cada 1 ms */
if (tiempo==0) {
PORTA=0x00; /* Apagar el led */
TMSK1&=~0x10; /* Desactivar interrupción comparador 4 */
}
else tiempo--;
void rsioc4()
/*
+-----------------------------------------------------+
¦ Rutina de servicio de interrupción del comparador 4 ¦
+-----------------------------------------------------+ */
{
ssioc4(); /* Llamar a subrutina de servicio de interrupción */
asm (" RTI");
}
main()
{
/* ----------- Cambiar vector de interrupción ------------------ */
vioc41=0x7E; /* Colocar instrucción JMP */
vioc42=(unsigned int)rsioc4; /* Colocar dirección rutina servicio */
67
Programación de la tarjeta CT6811 en lenguaje C
C:\6811\ICC\CT68INT>cint tempo
C:\6811\ICC\CT68INT>
C:\6811\ICC\CT68INT>downmcu tempo -com2
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.
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>ctdialog -com2
>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>_
69
Programación de la tarjeta CT6811 en lenguaje C
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"
main()
{
if (c==5) PORTA=0x40;
}
C:\6811\ICC\CT68INT>ctdialog -com2
>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.
#include "REGS6811.H"
static char c;
main()
{
c=5;
if (c==5) PORTA=0x40;
}
70
Programación de la tarjeta CT6811 en lenguaje C
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
/*
+------------------------------------------------------------------------+
¦ 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 ");
}
73
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;
}
i=0;
while (cad[i]) {
enviar_car(cad[i]);
i++;
}
}
74
Programación de la tarjeta CT6811 en lenguaje C
/* +-------------------------------+
--------------------¦ 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");
}
/*
+------------------------------------------------------------------------+
¦ 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
/*
+------------------------------------------------------------------------+
¦ 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"
77