Diseño con Microcontroladores Diseño de un Cronómetro Santiago González Tortosa (990285) Ana Esperanza Raposo Abreu (990287) 9 de febrero de 2005 ÍNDICE Índice 1 1 2 INTRODUCCIÓN 1. Introducción Se trata de construir un cronómetro, utilizando un microcontrolador. Las funciones que tendrá que cumplir dicho cronómetro son las siguientes: Tendrá dos contadores independientes de tiempos. Podrá recibir órdenes desde un PC a través del puerto serie o bien desde un teclado. Mostrará los tiempos por un LCD o por el ordenador a través del puerto serie. Podrá almacenar hasta tres tiempos parciales de cada contador. Tendrá un Reset para poner a cero el contador con el que se está trabajando. Para construir el cronómetro vamos a utilizar el microcontrolador 8052 (de la familia de los Intel), que nos proporciona tres contadores y suficientes puertos para realizar la E/S de una manera sencilla. 2. Esquema General del Cronómetro El esquema general del cronómetro es el siguiente: Fuente de Alimentacion 8052 Clock LCD Teclado Figura 1: Esquema del cronómetro 2.1. Conexión con el puerto serie Para realizar la conexión con el puerto serie, se ha utilizado el controlador Max232. El diagrama de conexión es el que se muestra en la figura 2. 2.2. Teclado Para simplificar lo más posible esta práctica, hemos utilizado un simple teclado a base de interruptores1 . Además, generamos la señal de interrupción con una puerta AND y la conectamos a INT0. Ası́ pues, el esquema es el que muestra la figura 3. 1 Este esquema no contiene las modificaciones necesarios para evitar problemas de repetir interrupciones debido al tiempo de pulsado de una tecla 2 3 ESQUEMA GENERAL DEL CRONÓMETRO 1 microF VCC 16 1 GND 15 2 Dout1 14DS14C2323 Rin1 13 4 Rout1 12 5 Din1 6 11 MAX232 7 10 9 8 8052 p3.0 p3.1 VCC C1+ V+ C1C2+ C2V- 1 microF 1 microF 1 microF Figura 2: Puerto Serie VCC 8052 p3.2 INT0 Teclado p0.0 p0.1 p0.2 p0.3 p0.4 p0.5 p0.6 p0.7 GND Figura 3: Teclado 2.3. LCD Utilizamos todo el puerto P1 como señales de datos y parte del P2 como señales de control de LCD. El esquema está detallado en la figura 4. 2 4 ESQUEMA GENERAL DEL CRONÓMETRO 8052 DATOS [0..7] p1.0 p1.1 p1.2 p1.3 p1.4 p1.5 p1.6 p1.7 p2.5 p2.6 p2.7 LCD RW RS EN Figura 4: LCD 2.4. Reloj, Reset y Fuente de Alimentación Utlizando los esquemas dados en clase, y el cristal que nos recomiendan para el 8052, quedan ası́ las conexiones: Xin Xout Cristal 33pF 33pF Figura 5: Reloj Para resetear el microcontrolador utilizamos el siguiente esquema: VCC 10microF 8,2KOhmios VCC 8052 RST VSS Figura 6: Reset Para la fuente usamos el esquema que aprendimos en clase: 3 5 CUENTAS Y CONTADORES LM7805 100nF VCC 100nF GND Figura 7: Fuente de Alimentación 3. Cuentas y Contadores El cronómetro poseerá dos cuentas. Los tiempos los contareoms con dos contadores diferentes, el contador 0 y el 1 del microcontrolador. Utilizamos los contadores para que vayan marcando las centésimas de segundo, que es el valor más pequeño que debemos manejar. Por cada interrupción del contador, iremos sumando uno a la cuenta de centésimas de la cuenta que esté activa (pueden estar ambas activas). 3.1. Configuración de los contadores Debemos tener cuidado con la elección del modo del temporizador, ya que nos interesa que el contador sea exacto. La forma que hemos encontrado mas exacta es la siguiente: Para que los contadores cuenten una centésima de segundo, tendremos que configurarlo de la siguiente manera: Elegimos el modo 2 del contador (8 bits con autorrecarga). Teniendo un cristal de 11,0592 MHz y sabiendo que el número de ciclos que se tarda en realizar un incremento de temporizador es 12, tenemos que el numero de incrementos por segundo son: 11,059,200 / 12 = 921,600. Ahora bien, sabemos que son 921600 incrementos por segundo, es decir, 9216 incrementos por centesima de segundo. Por tanto tendremos 921600 / 256 = 36 interrupciones por centesima de segundo. Por tanto para hallar 1 centesima de segundo exacta, debemos esperar 36 interrupciones del temporizador. 3.2. Cuentas Para almacenar los tiempos de cada cuenta, utilizamos la memoria del microcontrolador. Renombramos las direcciones para hacerlo más sencillo, y por cada cuenta almacenamos: El tiempo principal de la cuenta Los tres tiempos parciales que tengamos almacenados 3 CUENTAS Y CONTADORES 6 ;contador de interrupciones TICKS EQU 3Fh ; Tiempo del crono 0 Horas0 EQU 40h Minut0 EQU 41h Segus0 EQU 42h Cente0 EQU 43h ; 3 Tiempos parciales del crono 0 Horas0_1 EQU 44h Minut0_1 EQU 45h Segus0_1 EQU 46h Cente0_1 EQU 47h Horas0_2 EQU 48h Minut0_2 EQU 49h Segus0_2 EQU 4Ah Cente0_2 EQU 4Bh Horas0_3 EQU 4Ch Minut0_3 EQU 4Dh Segus0_3 EQU 4Eh Cente0_3 EQU 4Fh ; Tiempo del crono 1 Horas1 EQU 50h Minut1 EQU 51h Segus1 EQU 52h Cente1 EQU 53h ; 3 Tiempos parciales del crono 1 Horas1_1 EQU 54h Minut1_1 EQU 55h Segus1_1 EQU 56h Cente1_1 EQU 57h Horas1_2 EQU 58h Minut1_2 EQU 59h Segus1_2 EQU 5Ah Cente1_2 EQU 5Bh Horas1_3 EQU 5Ch Minut1_3 EQU 5Dh Segus1_3 EQU 5Eh Cente1_3 EQU 5Fh De esta manera, por cada 36 interrupciónes del contador correspondiente incrementaremos las centésimas y, si es necesario (al llegar a 100) las pondremos a cero e incrementaremos los segundos. Cuando los segundos lleguen a 60 los pondremos a cero e incrementaremos los minutos, y ası́ sucesivamente. Para que el cronómetro muestre las horas en dos dı́gitos, hemos establecido como lı́mite para las horas el valor 99. Para saber con qué cuenta estamos trabajando en cada momento, simplemente utilizamos un registro del microcontrolador, que valdrá 0 si estamos trabajando con la primera cuenta y 1 si estamos trabajando con la segunda. 4 COMUNICACIÓN CON PC, LCD Y TECLADO 4. 7 Comunicación con Pc, LCD y Teclado 4.1. Comunicación con el Pc por puerto serie La idea es enviar y recibir información utilizando un buffer interno del 8052. Para ello necesitamos activar las interupciones externas del puerto serie y utilizar el modo con UART. La UART utiliza el temporizador 2 en modo 2. El valor con el que contamos en el temporizador se halla de la siguiente forma: TH1 = 256 - ((Hz Crystal / 384) / Baud) Teniendo un cristal de 11.059 MHz y queriendo una conexion de 19.200 Baudios, tenemos que el valor inicial del temporizador es 253. Tenemos las señales TI y RI pertenecientes al registro de Control Serie del Micro. Cuando recibimos una interrupción del puerto serie y vemos que se recibe información (RI), atendemos lo que nos envı́an. Cuando enviamos algo por el puerto serie, se nos comunicará que se ha recibido con una interrupción e indicado en el registro TI. La forma de comunicarse el ordenador con el 8052 en nuestra práctica es la siguiente: Caracter ’S’: Start / Stop Caracter ’P’: Parada Caracter ’C’: Cambio Caracter ’R’: Reset Caracter ’L’: Mostrar Tiempo Principal Caracter ’1’: Mostrar Tiempo Parcial 1 Caracter ’2’: Mostrar Tiempo Parcial 2 Caracter ’3’: Mostrar Tiempo Parcial 3 4.2. Montaje del LCD En esta práctica vamos a utilizar el LCD HD44780U de Hitachi. Existen tres señales de control: EN, RS y RW. EN es la señal “Enable”. Esta señal indica al LCD que se están enviando datos. Para enviar datos al LCD, primero ponemos la señal EN a 1. Seguidamente realizamos el envı́o (y modificamos otras señales). Cuando se ha realizado la transferencia (el bit 76 de ACC está activo) debemos poner la señal a 0. RS es la señal “Register Select”. Cuando la señal está a 0, el dato que se está enviando es una instrucción especial (como por ejemplo posicionar el cursos del LCD o limpiar la pantalla). Cuando la señal está a 1, los datos que se están enviando son datos que se van a escribir por el Display. RW es la señal “Read/Write”. Cuando RW está a 0, los datos se escribirán en el LCD. Sólo se utiliza RW = 1 cuando se quiere saber el estado del LCD (ocupado o libre). Una vez explicados estos tres conceptos, contaremos los pasos realizados para la comunicación con el LCD: 5 MANEJO DEL CRONÓMETRO 8 Necesitamos declarar las siguientes variables: ;Datos para el LCD DB0 EQU P1.0 DB1 EQU P1.1 DB2 EQU P1.2 DB3 EQU P1.3 DB4 EQU P1.4 DB5 EQU P1.5 DB6 EQU P1.6 DB7 EQU P1.7 EN EQU P2.7 RS EQU P2.6 RW EQU P2.5 DATA EQU P1 Para cualquier operación con el LCD, debemos esperar hasta que el estado del mismo sea libre. Para ello utilizamos la rutina WAIT LCD. Iniciación del LCD: Debemos indicarle al LCD el modo de funcionamiento del mismo. Utilizando la documentación, sabemos los datos que debemos enviarle al LCD. La rutina de inicio es INIT LCD. Siempre que se quiera escribir en el LCD, se tendrá que limpiar antes la pantalla del Display. Para ello utilizamos la rutina CLEAR LCD. Para escribir en el LCD, utilizamos el registro de Acarreo (ACC). Insertamos en él el caracter a escribir y utilizamos la rutina WRITE LCD para escr¡bir por pantalla. 4.3. Montaje del teclado Para simplificar la práctica hemos decidido utilizar un conjunto de interruptores como teclado del cronómetro. La forma de tratar el teclado es una interrupción externa al micro (INT0). Debemos tener en cuenta que se pueden producir rebotes en el teclado, por tanto, si se produce una interrupcion externa (INT0 activada) debemos realizar un bucle escaneando los puertos y ni salir de ahi hasta que uno de ellos sea el que ha realizado la interrupción. 5. Manejo del Cronómetro Tanto si se maneja con el PC como con el teclado, el cronómetro debe obedecer a las siguientes interrupciones: Start / Stop Parada Cambio Reset Tiempo Principal Tiempo Parcial 1 Tiempo Parcial 2 5 MANEJO DEL CRONÓMETRO 9 Tiempo Parcial 3 El programa consiste en: poner todos los registros que se utilizarán a cero y preparar los contadores, y esperar a que se produzcan las interrupciones. 5.1. Interrupción de Start / Stop Es la que activa y desactiva el contador de la cuenta con la que se está trabajando. Si estaba activada, el contador se detiene y se muestra por LCD o por PC el valor en el que se ha detenido la cuenta (horas:minutos:segundos:centésimas). Si estaba parada, se activa y se muestra la cuenta por LCD o PC. Esta interrupción no hace que se modifiquen los tiempos parciales de la cuenta. 5.2. Interrupción de Parada Parcial y Almacenamiento Detiene el tiempo que se irá mostrando y lo almacena en los tiempos parciales, pero no detiene el contador. Esto quiere decir que podemos retener un tiempo parcial en la pantalla sin afectar a la cuenta total del cronómetro. 5.3. Interrupción de Cambio de Cuenta Cambia la cuenta activa y pasa a mostrar su tiemp principal en la pantalla del PC o en el LCD. 5.4. Interrupción de Reset Pone a cero el tiempo principal de la cuenta con la que estamos trabajando, pero no modifica sus tiempos parciales. También debe reiniciar el contador a D8F0 para empezar a contar bien. Si la cuenta estaba funcionando, es decir, contando, seguira haciendolo, pero si estaba parada, permanecerá a cero hasta que se pulse el Start. 5.5. Interrupción de Tiempo Principal y Tiempos Parciales Se pide que se muestre el tiempo principal de la cuenta con la que se está trabajando o que se muestre alguno de los tres tiempos parciales de la cuenta. En el caso de tener que mostrar el tiempo principal, si el cronómetro estaba activo, es decir, contando, habrá que realizar dos muestreos del tiempo por si entre medias se cambia de centésima (lo que puede acarrear un cambio de segundo, minuto y hora). Por tanto, lo primero que miraremos serán las centésimas, despues los segundos, minutos y horas, y por último volveremos a mirar las centésimas. Si no han cambiado, ya tenemos el valor correcto. Si han cambiado, se volverán a tomar todos los tiempos, operacion que lleva menos tiempo que la cuenta de otra centésima, con lo que esta vez estaremos seguros de que los tiempos son correctos. 5.6. Interrupción del Contador Cuando el contador alcance una centésima, se producirá una interrupción y debemos incrementar las centésimas de la cuenta correspondiente, Si ya hay 100, deberemos ponerlas a cero e 6 COMENTARIOS PERSONALES 10 incrementar los segundos. A su vez, si hay 60 segundos, los pondremos a cero e incrementaremos los minutos, y ası́ sucesivamente. Como ya hemos dicho, contaremos hasta 99 horas y luego los pondremos a cero. 6. Comentarios Personales Esta práctica se ha realizado con serias dificultades debido al escaso nivel para realizarla tanto en lo teórico, como en los circuitos fı́sicos que tenemos. Sin embargo, utilizando todos los medios disponibles, hemos conseguido suficiente documentación para hacer la práctica. No obstante seguimos pensando que el nivel que tenemos es bajo. Pensamos que se deberı́an mejorar algunos aspectos referidos, tanto a la asignatura, como a la práctica: Se deberı́a entregar un guion de práctica para tener claro los requisitos que se piden en ella. Se deberı́an realizar más ejercicios sobre microcontroladores. Convendrı́a explicar todo lo referido a los microcontroladores. No sólo a nivel fı́sico, sino también a nivel de programación. Se propone facilitar al alumno la documentación dada en clase, ejemplos y material de estudio (ejercicios, exámenes, etc. . . ) Nada más, sólo agradecer la respuesta a todas nuestras dudas por mail tan rápida y eficazmente. 7. Bibliografı́a La información que hemos utilizado para realizar la práctica ha sido la siguiente: Página Web www.8052.com Página Web www.National.com (National Semiconductors) Página Web www.ti.com (Texas Instruments) Curso de Microcontroladores (Dr. Alejandro Vega Salinas) Introducción al Microcontrolador 8051 (Facultad de Granada) Apuntes de Diseño con Microcontroladores (Facultad Politécnica de Madrid) 8 8. CÓDIGO DEL PROGRAMA Código del Programa EL código del programa es el siguiente: ; Contador de interrupciones TICKS0 EQU 3Eh TICKS1 EQU 3Fh ; Tiempo del crono 0 Horas0 EQU 40h Minut0 EQU 41h Segus0 EQU 42h Cente0 EQU 43h ; 3 Tiempos parciales del crono 0 Horas0_1 EQU 44h Minut0_1 EQU 45h Segus0_1 EQU 46h Cente0_1 EQU 47h Horas0_2 EQU 48h Minut0_2 EQU 49h Segus0_2 EQU 4Ah Cente0_2 EQU 4Bh Horas0_3 EQU 4Ch Minut0_3 EQU 4Dh Segus0_3 EQU 4Eh Cente0_3 EQU 4Fh ; Tiempo del crono 1 Horas1 EQU 50h Minut1 EQU 51h Segus1 EQU 52h Cente1 EQU 53h ; 3 Tiempos parciales del crono 1 Horas1_1 EQU 54h Minut1_1 EQU 55h Segus1_1 EQU 56h Cente1_1 EQU 57h Horas1_2 EQU 58h Minut1_2 EQU 59h Segus1_2 EQU 5Ah Cente1_2 EQU 5Bh Horas1_3 EQU 5Ch Minut1_3 EQU 5Dh Segus1_3 EQU 5Eh Cente1_3 EQU 5Fh ;****TIEMPO GENERAL PARA EL ENVIO**** Horas EQU 60h Minut EQU 61h Segus EQU 62h Cente EQU 63h ;************************************ ;Datos para el LCD DB0 EQU P1.0 DB1 EQU P1.1 DB2 EQU P1.2 11 8 CÓDIGO DEL PROGRAMA DB3 EQU P1.3 DB4 EQU P1.4 DB5 EQU P1.5 DB6 EQU P1.6 DB7 EQU P1.7 EN EQU P2.7 RS EQU P2.6 RW EQU P2.5 DATA EQU P1 ORG 0000h LJMP Inicio ; ; ; ; ; ; ; ; ; Registros utilizados r0 -> Indica si el contador 0 esta activo r1 -> Indica si el contador 1 esta activo r2 -> Indica que contador se esta utilizando r3 -> Indica si hay que ir actualizando el display r4 -> Indica si trabajamos con PC (1) o con teclado (0) r5 -> Indica cual de los 8 tpos anteriores hay que mostrar r6 y r7 registros temporales r8 y r9 -> para enviar numeros al LCD ; Vectores de interrupcion ORG 0003h LJMP ITeclado ORG 000Bh LJMP ITemp0 ORG 0013h LJMP ISerie ORG 001Bh LJMP ITemp1 ;INT0 ;T0 ;INT1 ;T1 Inicio: CLR r0 ; ponemos a cero los registros que utilizaremos CLR r1 CLR r2 CLR r3 CLR r4 CLR r5 CLR r6 CLR r7 CLR r8 CLR r9 SETB EA ; activamos las interrupciones SETB EX0 ; y los temporizadores SETB EX1 SETB ET0 SETB ET1 MOV TICKS0,#0 ;Ponemos a 0 los TICKS MOV TICKS1,#0 ;Ponemos a 0 los TICKS 12 8 CÓDIGO DEL PROGRAMA 13 MOV TMOD,#22h ; Ponemos los contadores en modo 2 MOV TL0,#000h ; Ponemos en TIMER0 1 centesima de Sec MOV TL1,#000h ; Ponemos en TIMER1 1 centesima de Sec SETB ES ; Activamos la interrupcion del puerto Serie ; Aqui inicializamos las conexiones con el Puerto Serie y el LCD ; RUTINA DE INICIALIZACION DEL LCD************************** INIT_LCD: SETB EN CLR RS MOV DATA,#38h CLR EN LCALL WAIT_LCD SETB EN CLR RS MOV DATA,#0Eh CLR EN LCALL WAIT_LCD SETB EN CLR RS MOV DATA,#06h CLR EN LCALL WAIT_LCD ;RUTINA DE INICIALIZACION DEL PUERTO SERIE********************** INIT_PS: CLR SM0 ;Pongo puerto Serie en Modo 1 SETB SM1 SETB T2MOD.2 ; Ponemos modo 2 al contador MOV TH2,#253 ; TH1 = 256 - ((Crystal / 384) / Baud)) ; siendo un cristal de 11.059MHz y queriendo una conexion de 19.200 Baudios SETB SMOD ;activamos el modo PCON.7 SETB TR2 ; EJECUTAMOS EL TIMER2! ;***********************PRINCIPAL*********************************** Ppral: ;Esperamos hasta que se produzca una interrupcion ;Las interrupciones se pueden producir por: ; el teclado ; los cronos ; el puerto serie ;Ya tenemos hecho la de los cronos y la del teclado. ;En el caso de interrupcion por los cronos: ;tenemos que mirar si el crono ha pedido congelacion o no ;en caso negativo tenemos que mirar que quieren que envie al LCD ; r3 -> Indica si hay que ir actualizando el display ; r4 -> Indica si trabajamos con PC (1) o con teclado (0) ; r5 -> Indica cual de los 8 tpos anteriores hay que mostrar JMP PPral ; el bucle principal es solo una espera 8 CÓDIGO DEL PROGRAMA ITemp0: ; Interrupcion del contador 0 INC TICKS0 CJNE TICKS0,#36,Sum10 RETI Sum10: MOV TICKS0,#0 ;Ponemos a 0 los ticks ; Sumo 1 a las centesimas (esta activo, si no no habria interrupcion) MOV r6,Cente0 INC r6 MOV Cente0,r6 CJNE r6,#100,ITemp0M ; Tengo que incrementar los segundos MOV r6,#00h ; nuevo valor de las centesimas = 0 MOV Cente0,r6 MOV r6,Segus0 ; incremento los segundos INC r6 MOV Segus0,r6 CJNE r6,#60,ITemp0M MOV r6,#00h ; nuevo valor de los segundos = 0 MOV Segus0,r6 MOV r6,Minut0 ; incremento los minutos INC r6 MOV Minut0,r6 CJNE r6,#60,ITemp0M MOV r6,#00h ; nuevo valor de los minutos = 0 MOV Minut0,r6 MOV r6,Horas0 ; incremento las horas INC r6 MOV Horas0,r6 CJNE r6,#100,ITemp0M ; Cuento hasta 100 horas MOV r6,#00h MOV Horas0,r6 ITemp0M:; Veo si tengo que mostrar CJNE r2,#00h,ITemp0F ; si no estamos usando este contador, acabar CJNE r5,#00h,ITemp0F ; si no estamos mostrando el tiempo principal del contador, acabar CJNE r3,#01h,ITemp0F ; si no hay que ir actualizando, acabar LJMP MOSTRAR0 ITemp0F:RETI ITemp1: ; Interrupcion del contador 1 INC TICKS1 CJNE TICKS1,#36,Sum11 RETI Sum11: MOV TICKS1,#0 14 8 CÓDIGO DEL PROGRAMA ; Sumo 1 a las centesimas (esta activo, si no no habria interrupcion) MOV r6,Cente1 INC r6 MOV Cente1,r6 CJNE r6,#100,ITemp1M ; Tengo que incrementar los segundos MOV r6,#00h ; nuevo valor de las centesimas = 0 MOV Cente1,r6 MOV r6,Segus1 ; incremento los segundos INC r6 MOV Segus1,r6 CJNE r6,#60,ITemp1M MOV r6,#00h ; nuevo valor de los segundos = 0 MOV Segus1,r6 MOV r6,Minut1 ; incremento los minutos INC r6 MOV Minut1,r6 CJNE r6,#60,ITemp1M MOV r6,#00h ; nuevo valor de los minutos = 0 MOV Minut1,r6 MOV r6,Horas1 ; incremento las horas INC r6 MOV Horas1,r6 CJNE r6,#100,ITemp1M ; Cuento hasta 100 horas MOV r6,#00h MOV Horas1,r6 ITemp1M:; Veo si tengo que mostrar CJNE r2,#01h,ITemp1F ; si no estamos usando este contador, acabar CJNE r5,#04h,ITemp1F ; si no estamos mostrando el tiempo principal del contador, acabar CJNE r3,#01h,ITemp1F ; si no hay que ir actualizando, acabar LJMP MOSTRAR4 ITemp1F:RETI ITeclado: CLR r4 ; Trabajamos con teclado JNB P0.0, StSt ; Esta pulsado Start/Stop JNB P0.1, Parada ; Dejar de actualizar display cronometro JNB P0.2, Cambio ; Cambio de contador JNB P0.3, Reset ; Pulsado Reset JNB P0.4, TPral ; Pulsado Tiempo Principal (Visualizar) JNB P0.5, Parcial1 ; Pulsado Tiempo Parcial 1 (Visualizar) JNB P0.6, Parcial2 ; Pulsado Tiempo Parcial 2 (Visualizar) JNB P0.7, Parcial3 ; Pulsado Tiempo Parcial 3 (Visualizar) ; Para los rebotes volvemos al inicio LJMP ITeclado MOSTRAR0: MOV MOV MOV ; hay que hacer dos muestreos por si ha cambiado la se~ nal Cente, Cente0 Segus, Segus0 Minut, Minut0 15 8 CÓDIGO DEL PROGRAMA 16 MOV Horas, Horas0 ;Segundo muestreo: solo necesario si cambian las centesimas MOV r6, Cente MOV r7, Cente0 CJNE r6,r7,SMuest0 LJMP MOSTRAR SMuest0: ; hay que volver a tomar los valores del contador 0 y ya seran definitivos MOV Cente, Cente0 MOV Segus, Segus0 MOV Minut, Minut0 MOV Horas, Horas0 LJMP MOSTRAR MOSTRAR1: MOV Cente, Cente0_1 MOV Segus, Segus0_1 MOV Minut, Minut0_1 MOV Horas, Horas0_1 LJMP MOSTRAR MOSTRAR2: MOV Cente, Cente0_2 MOV Segus, Segus0_2 MOV Minut, Minut0_2 MOV Horas, Horas0_2 LJMP MOSTRAR MOSTRAR3: MOV Cente, Cente0_3 MOV Segus, Segus0_3 MOV Minut, Minut0_3 MOV Horas, Horas0_3 LJMP MOSTRAR MOSTRAR4: ; hay que hacer dos muestreos por si ha cambiado la se~ nal MOV Cente, Cente1 MOV Segus, Segus1 MOV Minut, Minut1 MOV Horas, Horas1 ;Segundo muestreo: solo necesario si cambian las centesimas MOV r6, Cente MOV r7, Cente1 CJNE r6,r7,SMuest1 LJMP MOSTRAR SMuest1: ; hay que volver a tomar los valores del contador 1 y ya seran definitivos MOV Cente, Cente1 MOV Segus, Segus1 MOV Minut, Minut1 MOV Horas, Horas1 LJMP MOSTRAR MOSTRAR5: MOV Cente, Cente1_1 MOV Segus, Segus1_1 MOV Minut, Minut1_1 MOV Horas, Horas1_1 LJMP MOSTRAR MOSTRAR6: 8 CÓDIGO DEL PROGRAMA MOV Cente, Cente1_2 MOV Segus, Segus1_2 MOV Minut, Minut1_2 MOV Horas, Horas1_2 LJMP MOSTRAR MOSTRAR7: MOV Cente, Cente1_3 MOV Segus, Segus1_3 MOV Minut, Minut1_3 MOV Horas, Horas1_3 LJMP MOSTRAR MOSTRAR: ; lo muestra por LCD o por Serie JNB r4, LCD_TECL LJMP X_SERIE ; Interrupcion de Start/Stop (no almacena) StSt: JNB r2.0 StSt0 LJMP StSt1 StSt0: ; estoy usando el contador 0 JNB TR0 Timer0a1 CLR TR0 ; Desactivamos el Timer 0 LJMP StSt0a Timer0a1: SETB TR0 ; Activamos el Timer 0 StSt0a: XRL r0, #01h ; Cambiamos su estado XRL r3, #01h ; Hay/no hay que ir mostrando tiempos MOV r5, #00h ; voy al contador principal del contador 0 LJMP MOSTRAR0 StSt1: ; estoy usando el contador 1 JNB TR1 Timer1a1 CLR TR1 ; Desactivamos el Timer 1 LJMP StSt1a Timer1a1: SETB TR1 ; Activamos el Timer 1 StSt1a: XRL r1, #01h ; Cambiamos su estado XRL r3, #01h ; Hay/no hay que ir mostrando tiempos MOV r5, #04h ; voy al contador principal del contador 0 LJMP MOSTRAR4 ; Interrupcion de Parada parcial y almacenaje ; No deja de contar, solo de actualizar lo que muestra Parada: CLR r3 ; Dejo de actualizar la cuenta en pantalla JNB r2.0, Parad0 LJMP Parad1 Parad0: ; Desplazo las cuentas parciales: MOV Cente0_3, Cente0_2 MOV Segus0_3, Segus0_2 MOV Minut0_3, Minut0_2 17 8 18 CÓDIGO DEL PROGRAMA SToma0: SigoP0: Parad1: SToma1: SigoP1: MOV Horas0_3, Horas0_2 MOV Cente0_2, Cente0_1 MOV Segus0_2, Segus0_1 MOV Minut0_2, Minut0_1 MOV Horas0_2, Horas0_1 MOV Cente0_1, Cente0 MOV Segus0_1, Segus0 MOV Minut0_1, Minut0 MOV Horas0_1, Horas0 ;Segundo muestreo: solo necesario si cambian las centesimas MOV r6, Cente0 MOV r7, Cente0_1 CJNE r6,r7,SToma0 LJMP SigoP0 ; hay que volver a tomar los valores del contador 0 y ya seran definitivos MOV Cente0_1, Cente0 MOV Segus0_1, Segus0 MOV Minut0_1, Minut0 MOV Horas0_1, Horas0 MOV r5, #01h ; hay que mostrar el tiempo parcial 1 del contador 0 LJMP MOSTRAR1 ; Desplazo las cuentas parciales: MOV Cente1_3, Cente1_2 MOV Segus1_3, Segus1_2 MOV Minut1_3, Minut1_2 MOV Horas1_3, Horas1_2 MOV Cente1_2, Cente1_1 MOV Segus1_2, Segus1_1 MOV Minut1_2, Minut1_1 MOV Horas1_2, Horas1_1 MOV Cente1_1, Cente1 MOV Segus1_1, Segus1 MOV Minut1_1, Minut1 MOV Horas1_1, Horas1 ;Segundo muestreo: solo necesario si cambian las centesimas MOV r6, Cente1 MOV r7, Cente1_1 CJNE r6,r7,SToma1 LJMP SigoP1 ; hay que volver a tomar los valores del contador 1 y ya seran definitivos MOV Cente1_1, Cente1 MOV Segus1_1, Segus1 MOV Minut1_1, Minut1 MOV Horas1_1, Horas1 MOV r5, #05h ; hay que mostrar el tiempo parcial 1 del contador 1 LJMP MOSTRAR5 ; Interrupcion de Cambio de Contador Cambio: XRL r2, #01h ; Cambiamos el contador activo 8 19 CÓDIGO DEL PROGRAMA JNB r2.0, Cambio0 LJMP Cambio1 Cambio0:; esta activo el 0 MOV r3, r0 MOV r5, #00h LJMP MOSTRAR0 Cambio1:; esta activo el 1 MOV r3, r1 MOV r5, #04h LJMP MOSTRAR4 ; Solo debe ir actualizandose si esta activo ; Trabajamos con el tiempo principal del contador 0 ; Solo debe ir actualizandose si esta activo ; Trabajamos con el tiempo principal del contador 1 Reset: ; Miramos que cuenta esta activa CJNE r2,#0,Reset1 Reset0: MOV TL0,#0F0h MOV TH0,#0D8h CLR Horas0 CLR Minut0 CLR Segus0 CLR Cente0 MOV r3,r0 MOV r5,#00h LJMP MOSTRAR0 ; Ponemos en TIMER0 1 centesima de Sec ; Ponemos en TIMER0 1 centesima de Sec MOV TL1,#0F0h MOV TH1,#0D8h CLR Horas1 CLR Minut1 CLR Segus1 CLR Cente1 MOV r3,r1 MOV r5,#04h LJMP MOSTRAR4 ; Ponemos en TIMER0 1 centesima de Sec ; Ponemos en TIMER0 1 centesima de Sec ; Actualizare si estaba activo ; Mostraremos el tiempo principal Reset1: TPral: ; Actualizare si estaba activo ; Mostraremos el tiempo principal ; Se ha solicitado mostrar el tiempo principal del contador JNB r2.0, TPral0 LJMP TPral1 TPral0: ; Hay que mostrar el del contador 0 MOV r3,r0 ; Hay que ir actualizando si esta activo MOV r5,#00h ; Mostraremos el principal del contador 0 LJMP MOSTRAR0 TPral1: ; Hay que mostrar el del contador 1 MOV r3,r1 ; Hay que ir actualizando si esta activo MOV r5,#04h ; Mostraremos el principal del contador 1 LJMP MOSTRAR4 8 CÓDIGO DEL PROGRAMA Parcial1: ; Se ha solicitado mostrar el tiempo parcial 1 del contador JNB r2.0, TP1_0 LJMP TP1_1 TP1_0: ; Hay que mostrar el del contador 0 MOV r3,#00h ; No hay que actualizar MOV r5,#01h ; Mostraremos el parcial 1 del contador 0 LJMP MOSTRAR1 TP1_1: ; Hay que mostrar el del contador 1 MOV r3,#00h ; No hay que actualizar MOV r5,#05h ; Mostraremos el parcial 1 del contador 1 LJMP MOSTRAR5 Parcial2: ; Se ha solicitado mostrar el tiempo parcial 2 del contador JNB r2.0, TP2_0 LJMP TP2_1 TP2_0: ; Hay que mostrar el del contador 0 MOV r3,#00h ; No hay que actualizar MOV r5,#02h ; Mostraremos el parcial 2 del contador 0 LJMP MOSTRAR2 TP2_1: ; Hay que mostrar el del contador 1 MOV r3,#00h ; No hay que actualizar MOV r5,#06h ; Mostraremos el parcial 2 del contador 1 LJMP MOSTRAR6 Parcial3: ; Se ha solicitado mostrar el tiempo parcial 3 del contador JNB r2.0, TP3_0 LJMP TP3_1 TP3_0: ; Hay que mostrar el del contador 0 MOV r3,#00h ; No hay que actualizar MOV r5,#03h ; Mostraremos el parcial 3 del contador 0 LJMP MOSTRAR3 TP3_1: ; Hay que mostrar el del contador 1 MOV r3,#00h ; No hay que actualizar MOV r5,#03h ; Mostraremos el parcial 3 del contador 1 LJMP MOSTRAR7 ;************************* RUTINAS DE LCD************************* WAIT_LCD: SETB EN CLR RS SETB RW MOV DATA,#0FFh MOV A,DATA JB ACC.7,WAIT_LCD 20 8 CÓDIGO DEL PROGRAMA CLR EN CLR RW RET CLEAR_LCD: SETB EN CLR RS MOV DATA,#01h CLR EN LCALL WAIT_LCD RET WRITE_TEXT: SETB EN SETB RS MOV DATA,A CLR EN LCALL WAIT_LCD RET ;*************************RUTINA GENERAL DE LCD***************************** LCD_TECL: ;Ahora debo mirar que registro tengo que enviar al LCD LCALL CLEAR_LCD MOV r8,Horas MOV r9,10 DIV r8 r9 ; lo pasamos a base decimal: cociente queda en r8 y resto en r9 MOV A, r8 LCALL WRITE_TEXT MOV A, r9 LCALL WRITE_TEXT MOV A,#: LCALL WRITE_TEXT MOV r8,Minut MOV r9,10 DIV r8 r9 ; lo pasamos a base decimal: cociente queda en r8 y resto en r9 MOV A, r8 LCALL WRITE_TEXT MOV A, r9 LCALL WRITE_TEXT MOV A,#: LCALL WRITE_TEXT MOV r8,Segus MOV r9,10 DIV r8 r9 ; lo pasamos a base decimal: cociente queda en r8 y resto en r9 MOV A, r8 LCALL WRITE_TEXT MOV A, r9 LCALL WRITE_TEXT MOV A,#: LCALL WRITE_TEXT MOV r8,Cente 21 8 CÓDIGO DEL PROGRAMA MOV r9,10 DIV r8 r9 ; lo pasamos a base decimal: cociente queda en r8 y resto en r9 MOV A, r8 LCALL WRITE_TEXT MOV A, r9 LCALL WRITE_TEXT MOV A,#: LCALL WRITE_TEXT ;***********************RUTINA GENERAL DE SERIE************************ X_SERIE: ;Aqui tengo que enviarlo por el puerto serie! CLR MOV JNB CLR MOV JNB CLR MOV JNB CLR MOV JNB CLR MOV JNB CLR MOV JNB CLR MOV JNB TI ;Limpiamos la transmision de interrupciones SBUF,Horas ;Enviamos Horas por el puerto serie TI,$ ;Esperamos hasta que se active la interrupcion. TI SBUF,#: TI,$ TI ;Limpiamos la transmision de interrupciones SBUF,Minut ;Enviamos Minutos por el puerto serie TI,$ ;Esperamos hasta que se active la interrupcion. TI SBUF,#: TI,$ TI ;Limpiamos la transmision de interrupciones SBUF,Segus ;Enviamos Segundos por el puerto serie TI,$ ;Esperamos hasta que se active la interrupcion. TI SBUF,#: TI,$ TI ;Limpiamos la transmision de interrupciones SBUF,Cente ;Enviamos Centesimas por el puerto serie TI,$ ;Esperamos hasta que se active la interrupcion. ;*************************INTERRUPCION SERIE***************************** ; Ahora tenemos que tratar la interrupcion debido al puerto serie ISerie: JNB TI,INT_RI ;Si TI esta a 0 entonces RI esta a 1 ;En el caso en que TI = 1 RETI INT_RI: ; Realizamos la recepcion de Serie MOV A,SBUF ;Leemos el caracter CLR RI ; Ponemos a 0 la RI ;LOS CARACTERES QUE PUEDEN ENTRAR SON:*********** ; S -> Start/Stop ; P -> Parada ; C -> Cambio ; R -> Reset 22 8 CÓDIGO DEL PROGRAMA ; L -> Principal ; 1 -> Parcial 1 ; 2 -> Parcial 2 ; 3 -> Parcial 3 ;************************************************ CJNE A,#’S’,Mir_P ; Si no es S miramos el siguiente (que es P) ;Si es S tenemos que activar la vuelta X_SERIE y llamar a Start_Stop SETB r4 ; Vamos por PC LJMP StSt; Saltamos a Start_Stop Mir_P: CJNE A,#’P’,Mir_C ; Si no es P miramos el siguiente (que es C) ;Si es P tenemos que activar la vuelta X_SERIE y llamar a Pausa SETB r4 ; Vamos por PC LJMP Parada; Saltamos a Parada Mir_C: CJNE A,#’C’,Mir_R ; Si no es C miramos el siguiente (que es R) ;Si es C tenemos que activar la vuelta X_SERIE y llamar a Cambio SETB r4 ; Vamos por PC LJMP Cambio; Saltamos a Cambio Mir_R: CJNE A,#’R’,Mir_L ; Si no es R miramos el siguiente (que es L) ;Si es R tenemos que activar la vuelta X_SERIE y llamar a Reset SETB r4 ; Vamos por PC LJMP Reset; Saltamos a Reset Mir_L: CJNE A,#’L’,Mir_1; Si no es L nos vamos ;Si es L tenemos que activar la vuelta X_SERIE y llamar a Principal SETB r4 ; Vamos por PC LJMP TPral; Saltamos a mostrar el tiempo principal Mir_1: CJNE A,#’1’,Mir_2 ; Si no es 1 nos vamos SETB r4 ; Vamos por PC LJMP Parcial1; Saltamos a mostrar el parcial 1 Mir_2: CJNE A,#’2’,Mir_3 ; Si no es 2 nos vamos SETB r4 ; Vamos por PC LJMP Parcial2; Saltamos a mostrar el tiempo principal Mir_3: CJNE A,#’3’,No_Hay ; Si no es 3 nos vamos SETB r4 ; Vamos por PC LJMP Parcial3; Saltamos a mostrar el tiempo principal No_Hay: RETI 23