18
MICROPROCESADORES II Practica 2do Parcial EJERCICIO 1: Teclado matricial y LCD de caracteres: reloj de ajedrez Planteamiento del diseño: Basándose en el empleo de un microcontrolador PIC16F877 se desea realizar un reloj digital para el desarrollo de partidas de ajedrez Dicho reloj deberá mostrar el tiempo de partida restante para la realización de jugadas tanto para el jugador que lleva las piezas blancas (BL) como para el que conduce las negras (NG), y todo ello con una precisión que permita mostrar hasta las décimas de segundo. La información aparecerá en un display de cuarzo líquido (LCD) de 2 filas y 16 caracteres visibles por fila, este LCD es compatible con el HD44780U de Hitachi. Para establecer la configuración de tiempo para cada jugador (editar dicho tiempo al principio), iniciar la partida, pararla y jugar existe un teclado matricial de 4 filas x 4 columnas cuyas teclas aparecen en la figura 2. Funcionamiento esperado (Especificaciones): Inicialmente cuando se alimenta o resetea el equipo, aparecen ambos relojes parados y mostrando un tiempo restante de 5 minutos para cada uno de los jugadores. En ese estado, es posible modificar los tiempos de cada jugador mediante las teclas numéricas y las flechas de desplazamiento a derecha e izquierda presentes en el teclado. La posición del número que se pueda editar en cada momento deberá aparecer resaltado de alguna manera (mediante el parpadeo del mismo o la presencia de un cursor debajo de esa posición). Durante la edición, para saltar de una línea a otra del LCD, se utilizan las teclas B (edición del tiempo del jugador de blancas) y N (para la edición del tiempo del jugador de negras). Para iniciar el juego, se actúa sobre la tecla de inicio (I) y empezará a descontar el tiempo del jugador al que le corresponde hacer el movimiento. Durante el tiempo de juego, no resulta posible editar los tiempos de los jugadores. Una marca (<) a la derecha del tiempo de uno de ellos indicará siempre a quién le corresponde realizar la jugada. En el transcurso de la partida, cada jugador realizará el movimiento

Practica Segundo Parcial MICROPROCESADORES II.docx

Embed Size (px)

DESCRIPTION

El documento ejemplifica la resolucion de un programa que regula la velocidad de algunos LEDS usando un microcontrolador PIC

Citation preview

Page 1: Practica Segundo Parcial MICROPROCESADORES II.docx

MICROPROCESADORES II

Practica 2do Parcial

EJERCICIO 1: Teclado matricial y LCD de caracteres: reloj de ajedrez

Planteamiento del diseño:

Basándose en el empleo de un microcontrolador PIC16F877 se desea realizar un reloj digital para el desarrollo de partidas de ajedrez

Dicho reloj deberá mostrar el tiempo de partida restante para la realización de jugadas tanto para el jugador que lleva las piezas blancas (BL) como para el que conduce las negras (NG), y todo ello con una precisión que permita mostrar hasta las décimas de segundo.

La información aparecerá en un display de cuarzo líquido (LCD) de 2 filas y 16 caracteres visibles por fila, este LCD es compatible con el HD44780U de Hitachi.

Para establecer la configuración de tiempo para cada jugador (editar dicho tiempo al principio), iniciar la partida, pararla y jugar existe un teclado matricial de 4 filas x 4 columnas cuyas teclas aparecen en la figura 2.

Funcionamiento esperado (Especificaciones):

Inicialmente cuando se alimenta o resetea el equipo, aparecen ambos relojes parados y mostrando un tiempo restante de 5 minutos para cada uno de los jugadores.

En ese estado, es posible modificar los tiempos de cada jugador mediante las teclas numéricas y las flechas de desplazamiento a derecha e izquierda presentes en el teclado. La posición del número que se pueda editar en cada momento deberá aparecer resaltado de alguna manera (mediante el parpadeo del mismo o la presencia de un cursor debajo de esa posición).

Durante la edición, para saltar de una línea a otra del LCD, se utilizan las teclas B (edición del tiempo del jugador de blancas) y N (para la edición del tiempo del jugador de negras).

Para iniciar el juego, se actúa sobre la tecla de inicio (I) y empezará a descontar el tiempo del jugador al que le corresponde hacer el movimiento.

Durante el tiempo de juego, no resulta posible editar los tiempos de los jugadores.

Una marca (<) a la derecha del tiempo de uno de ellos indicará siempre a quién le corresponde realizar la jugada. En el transcurso de la partida, cada jugador realizará el movimiento cuando le toque y a continuación actuará sobre la tecla que corresponda al color de sus piezas (B ó N) para activar el reloj del adversario que deberá proceder también de idéntica manera.

Cuando el tiempo de un jugador llegue a cero, aparecerá un asterisco a la izquierda de su tiempo y sonará una alarma (mediante el zumbador piezoeléctrico presente en la PICDEM2 plus) durante 2 segundos que advertirá de tal circunstancia.

Durante el desarrollo de una partida, se puede actuar sobre la tecla de parada (P), en cuyo caso se detendrá el reloj del jugador al que le correspondía mover. En ese estado, si se pulsa por segunda vez esa tecla, se vuelve a los tiempos de configuración inicial establecidos para la partida en curso. En cualquiera de los dos estados, sí que resultaría posible editar los tiempos restantes para cada jugador.

El microcontrolador PIC16F877 emplea un reloj de frecuencia 4 MHz, dispone de la alimentación y de la circuitería necesaria para su funcionamiento además de las conexiones de los distintos elementos, que son las que aparecen en la figura 1.

En estas condiciones se pide:

Page 2: Practica Segundo Parcial MICROPROCESADORES II.docx

a) Explique cómo sería el proceso global que se pretende implementar en el microcontrolador con los diversos bloques internos que se van a utilizar

b) Desglose en pseudo-código o similar el proceso anteriormente referido

c) Realice el paso al código fuente y verifique el resto de los pasos necesarios para conseguir el funcionamiento de dicho código en la tarjeta de aplicación hardware disponible.

Page 3: Practica Segundo Parcial MICROPROCESADORES II.docx

EJERCICIO 2: Convertidor A/D: realización de un voltímetro digital

Realizar un programa que se encargue de medir continuamente una tensión analógica comprendida entre 0 y 5V y mostrar su valor en voltios, en 3 displays de 7 segmentos de ánodo común (con segmento adicional de punto decimal). La medida se realizará mediante un canal de entrada del módulo de conversión Analógico a Digital de un microcontrolador PIC16F877 (ó en su versión PIC16F877A) que dispone de un oscilador de 4MHz.

La tensión se introduce en la entrada analógica 0 del PORTA (RA0) que se puede variar mediante un potenciómetro. Para conseguir la visualización en los displays, a la placa de entrenamiento se le añade una placa de circuito impreso mediante un conector vertical, esta placa responde al esquema eléctrico que se adjunta en la figura 2 (es la que se ha usado en prácticas anteriores).

Figura 1.- Elementos a utilizar para la práctica

Page 4: Practica Segundo Parcial MICROPROCESADORES II.docx

Un posible planteamiento:

Se utiliza el módulo A/D para realizar la conversión de la entrada de tensión del canal analógico 0.

Se configura el módulo A/D para que utilice el reloj basado en la red RC interna independiente del oscilador del microcontrolador (valor nominal de Tad de 4µs y con una variación posible entre 2µs y 6µs). Se lanza la conversión con el canal seleccionado y se activa la generación de interrupciones cuando finalice dicha conversión.

El módulo A/D puede proporcionar el resultado con una resolución de 10 bits (de b9 a b0) en dos registros: ADRESH y ADRESL, pudiendo realizarse la “justificación del resultado” a la izquierda, con este resultado:

o bien con justificación a la derecha y con este otro formato:

Dado que la precisión de 8 bits resulta suficiente, configuraremos el resultado con justificación a la izquierda y tomaremos el resultado proporcionado en los 8 bits del registro ADRESH, despreciando los dos bits menos significativos de la conversión presentes en ADRESL.

En el programa de tratamiento de la interrupción se recoge el valor resultante de la conversión en el registro ADRESH de 8 bits y se convierte el valor a su “equivalente de tensión en voltios”. Como la tensión de referencia es de 5V, la resolución del convertidor empleando 8 bits es de

5V/256 = 0,0195V/bit (195E-4 V). Realizando el producto (subprograma que se desarrollará posteriormente) del valor resultante por 195 obtendremos un valor de tensión analógica comprendida entre 0 y 49725 diezmilésimas de voltio (0 y 49725*10-4 V). Empleando las diezmilésimas de voltio como unidad de medida, se puede almacenar el valor en binario en dos bytes y lo podemos descomponer en sus 5 dígitos BCD (con un subprograma que se detallará posteriormente) para la representación en los displays, únicamente de los 3 dígitos más significativos (voltios, décimas y centésimas).

El programa principal ejecutará un bucle continuo de barrido de los 3 displays que representan los voltios con dos decimales, se asegura la permanencia de cada dígito durante 5ms mediante una temporización realizada con el módulo TMR0.

El bucle de barrido recogerá los valores a mostrar de unas posiciones denominadas BCD2 y BCD1 que serán cargadas mediante el subprograma que realiza la conversión del dato binario de 16 bits que representa las diezmilésimas de voltio a BCD:

Estas posiciones serán modificadas por tanto tras la conversión del resultado digital en el programa de tratamiento de interrupción.

Nos debemos asegurar que hayan transcurrido 2Tad (8µs) y el tiempo de adquisición antes de lanzar la nueva conversión (el propio programa de tratamiento lo asegura), pondremos a cero el flag de indicación de fin de conversión (ADIF) y arrancaremos una nueva conversión antes de retornar del programa de tratamiento.

• Detalle del Subprograma que realiza la multiplicación de dos bytes (PRODUCTO_2)

Page 5: Practica Segundo Parcial MICROPROCESADORES II.docx

Realiza el producto de los 8 bits contenidos en FACTOR1 por los 8 bits almacenados en la posición FACTOR2 y el resultado en conjunto, va a parar a dos posiciones denominadas: BIN_ALTO + BIN_BAJO

FACTOR2 = b7 b6 b5 b4 b3 b2 b1 b0

FACTOR1 = a7 a6 a5 a4 a3 a2 a1 a0

Operación a realizar para la multiplicación en binario:

Resultado = FACTOR1 * FACTOR2 = b0 * FACTOR1 + b1 * (2 * FACTOR1) +

+ b2 * (2 * (2 * FACTOR1)) + ...+ b7 * (2*(2*(2*(2*(2*(2*(2*FACTOR1)))))))

Cada multiplicación por 2 en binario consiste en realizar un desplazamiento a la izquierda introduciendo un cero por la derecha, tras cada desplazamiento se realiza la suma o no en función del bit b correspondiente a FACTOR2

La operación total a realizar desde dentro hacia fuera sería:

Para realizar estas operaciones que se irán acumulando, debemos operar con los bytes BIN_ALTO y BIN_BAJO en conjunto:

BIN_ALTO BIN_BAJOLas sucesivas multiplicaciones por 2 de FACTOR1 se almacenan en dos bytes encadenados que se denominan SUMA_ALTO (parte alta a sumar) & SUMA_BAJO (parte baja a sumar):

SUMA_ALTO SUMA_BAJO

• Subprograma de conversión de Binario a BCD (BINBCD)

Se puede utilizar cualquiera de los ejemplos de conversión de Binario a BCD que están disponible.

Algoritmo desarrollado:

INICIALIZACIÓN

• CONVERTIDOR A/D:

Page 6: Practica Segundo Parcial MICROPROCESADORES II.docx

-Entrada RA0 como analógica y referencia de 5V, resto entradas digitales. El resultado de la conversión lo recogeremos ajustado a la izquierda (los 8 bits más significativos en el registro ADRESH)

-Reloj de conversión Tad basado en red RC interna (4µs)

-Canal analógico de entrada: canal 0.

• PUERTOS:

-PORTA (RA1, RA2 y RA3 con salidas para activación de los displays, resto de las líneas como entradas).

-PORTD (salida para control de los segmentos)

• TMR0: definido en modo temporizador y con prescaler de 32 para temporizar posteriormente 5 ms.

• INTERRUPCIONES: habilitar las de fin de conversión A/D con la máscara particular ADIE en PIE1, máscara de periféricos PEIE y global GIE en registro INTCON. Se borra a su vez el flan ADIF del registro PIR1.

• Inicializamos variables BCD2 y BCD1 (valores a mostrar en los displays) hasta que se acabe la primera conversión

• Se lanza la primera conversión A/D poniendo el bit GO a 1 (en el registro ADCON0)

BUCLE DE BARRIDO DE LOS DISPLAYS

Centésimas de voltio:

• Activación del display poniendo la combinación de entrada adecuada en el PORTA

• Extraemos el valor de la parte baja de BCD1

• Búsqueda en la tabla de los led a iluminar y los sacamos al PORTD (Subprograma TABLALED)

• Espera durante 5 ms (llamada a Subprograma ESPERA)

• Tiempo muerto: apagamos todos los segmentos

Décimas de voltio: ídem extrayendo los 4 bits altos de BCD1

Unidades de voltio: ídem extrayendo los 4 bits bajos de BCD2. Además, para las unidades de voltio se activa el punto decimal del display para marcar la separación (RD7 se pone a 0)

• Se vuelve al inicio del bucle de barrido de los displays

SUBPROGRAMA ESPERA

• Se precarga TMR0 con un valor de 100 para conseguir desbordamiento al cabo de 5 ms:

5ms ˜ 4/4MHz * 32 * (256-100)

• Se pone a 0 el flag T0IF

• Nos situamos en un bucle de espera hasta que T0IF se ponga a 1

• Retornamos del subprograma

PROGRAMA DE TRATAMIENTO DE LA INTERRUPCIÓN

• Comprobamos que el flag ADIF está a 1 (fin de conversión A/D)

• Se salva el contexto del programa principal (W, STATUS y PCLATH)

• Tomamos el resultado de la conversión en ADRESH

Page 7: Practica Segundo Parcial MICROPROCESADORES II.docx

• Lo cargamos en la posición FACTOR1

• Cargamos 195 en FACTOR2

• Llamamos a subprograma PRODUCTO_2 para realizar la multiplicación de FACTOR1 por FACTOR2

• Se recoge el resultado en dos bytes (BIN_ALTO – BIN_BAJO) y se descompone en sus 5 dígitos decimales con el subprograma BINBCD

• Finalizamos el programa de tratamiento poniendo a 0 el flag ADIF

• Recuperamos el contexto (PCLATH, STATUS y W)

• Lanzamos una nueva conversión poniendo de nuevo GO a 1

Subprograma PRODUCTO_2

Realiza el producto de los 8 bits contenidos en FACTOR1 por los 8 bits almacenados en la posición FACTOR2 y el resultado en conjunto, va a parar a dos posiciones denominadas: BIN_ALTO + BIN_BAJO (véase detalle del algoritmo en el planteamiento inicial);; Subprograma que realiza el producto de dos bytes FACTOR1 y FACTOR2 y el resultado ; lo almacena en dos posiciones denominadas: BIN_ALTO y BIN_BAJO; ; Para probarlo, cargar en FACTOR1 y FACTOR2 unos valores; y llamar al subprograma;

LIST p=16F877 include "p16f877.inc" ;Fichero de inclusión

CBLOCK 0x20FACTOR1, FACTOR2 ;Posiciones donde se guardan los datos de entradaSUMA_ALTO, SUMA_BAJO ;Posiciones para ir cargando FACTOR1 desplazado

BIN_ALTO,BIN_BAJO ;Definición posiciones del dato CONTADOR ;Contador de desplazamientos

ENDC; Esta parte de código sólo llama al subprograma y se queda esperando en un bucle infinito; hasta que detengamos el programa desde el entorno MPLAB para comprobar el resultado que; se obtiene en BIN_ALTO y BIN_BAJO

ORG 0CALL PRODUCTO_2

ESPERA GOTO ESPERA

;Inicio del subprograma

ORG 0x120;***************************************************************************; Subprograma de multiplicación de dos bytes;; Recibe los valores en posiciones FACTOR1 y FACTOR2; y entrega el resultado en dos bytes: BIN_ALTO & BIN_BAJO;***************************************************************************PRODUCTO_2

clrf SUMA_ALTO ;Ponemos a cero parte alta del sumandoclrf BIN_ALTO ;Ponemos a cero el acumulador declrf BIN_BAJO ;los resultadosmovlw 0x08 ;Cargamos 8 en el contador de operacionesmovwf CONTADOR ;de rotación

movf FACTOR1,W ;Cargamos FACTOR1 en la parte baja de sumandomovwf SUMA_BAJO ;para efectuar rotaciones

A_SUMAR rrf FACTOR2 ;Rotamos a la derecha para comprobarbtfss STATUS,C ;en el carry el bit que "toque"goto OTRO_BIT ;si el carry quedó a 0 es que no hay que sumarmovf SUMA_BAJO,W ;si quedó a 1 es que hay que sumaraddwf BIN_BAJO,F ;la parte baja del acumulador con el sumando

;que corresponde al FACTOR1 desplazado a la izq.btfsc STATUS,C ;comprobamos si hubo acarreo en esa sumaincf BIN_ALTO ;si hubo, sumamos 1 al siguiente bytemovf SUMA_ALTO,W ;sumamos la parte alta del acumulador conaddwf BIN_ALTO,F ;el FACTOR1 desplazado

OTRO_BITdecfsz CONTADOR,F ;Decrementamos el contador de operaciones parciales

Page 8: Practica Segundo Parcial MICROPROCESADORES II.docx

goto A_ROTAR ;si no hemos llegado a cero, seguimos rotandoreturn ;si ya hemos hecho 8 veces la operación, retorno

A_ROTAR bcf STATUS,C ;Para rotar FACTOR1 a la izquierda, ponemos a 0 el carryrlf SUMA_BAJO,F ;rotamos encadenando la parte bajarlf SUMA_ALTO,F ;con la parte altagoto A_SUMAR ;y vamos a comprobar si es necesario sumar o no

END

Subprograma BINBCD

Se encarga de tomar los 16 bits almacenados en las posiciones BIN_ALTO y BIN_BAJO y devuelve los 5 dígitos BCD correspondientes a la representación decimal de ese valor que almacena en 3 posiciones de RAM:

;; Programa que realiza la conversión de un dato binario de 16 bits a un; formato BCD almacenándolo en 5 dígitos que ocupan medio byte cada uno;; El dato binario está almacenado en dos bytes contiguos: BIN_ALTO y BIN_BAJO; y el resultado va a parar a 3 bytes también consecutivos que son de mayor; a menor peso: BCD2, BCD1 y BCD0; Estos almacenan los 5 dígitos, estando presente en los 4 bits más bajos de ; BCD2 únicamente el dígito más significativo

; Esta versión realiza sucesivas restas por diez mil, mil, cien y diez ; hasta que el resultado sea inferior a estos valores para ir obteniendo ; los sucesivos dígitos decimales

;; Posiciones Auxiliares:

CBLOCK 0x20MINU_ALTOMINU_BAJOSUSTRA_ALTOSUSTRA_BAJORESTO_ALTORESTO_BAJOAUXILIAR

BIN_ALTOBIN_BAJOBCD2, BCD1, BCD0ENDC

list p=16f877 ;Microcontrolador PIC16f877 include "p16f877.inc" ;Fichero de inclusión

ORG 0

CALL BIN16BCDv2 ;Llamamos al subprograma ESPERA GOTO ESPERA ;y nos quedamos esperando a la vuelta

ORG 0x100 ;Coloco el subprograma a partir de la 0x100BIN16BCDv2

clrf BCD2 ;Pongo a cero clrf BCD1 ;las posiciones finalesclrf BCD0 ;donde irán a parar los dígitos decimales

DEC_MIL movf BIN_ALTO,W ;Empezamos cargando el número de partida movwf MINU_ALTO ;en el minuendo en su parte altamovf BIN_BAJO,W ;y en su parte bajamovwf MINU_BAJO

movlw 0x27 ;Cargamos d'10000' en el sustraendomovwf SUSTRA_ALTO ;descompuesto en dos bytes= 0x2710movlw 0x10 ;de la parte alta y la parte bajamovwf SUSTRA_BAJO

RESTADM call RESTA16 ;Llamamos al subprograma que hace la resta de dos bytesbtfss STATUS,C ;Si carry queda a 1 es que el resultado es >= 0goto UN_MIL ;si no, vamos a obtener las unidades de milincf BCD2 ;si era positivo incrementamos decenas de mil y seguimosmovf RESTO_ALTO,W ;Paso el resultado al minuendomovwf MINU_ALTO ;en su parte altamovf RESTO_BAJO,W ;y también en su parte bajamovwf MINU_BAJO

Page 9: Practica Segundo Parcial MICROPROCESADORES II.docx

goto RESTADM ;Volvemos a restar ya que el resultado es mayor de d'10000'

UN_MIL movlw 0x03 ;Cargamos ahora mil en el sustraendomovwf SUSTRA_ALTO ;que cabe en dos bytes de parte altamovlw 0xE8 ;y parte bajamovwf SUSTRA_BAJO

RESTAUM call RESTA16 ;Llamamos al subprograma de resta de dos bytesbtfss STATUS,C ;Si carry queda a 1 es que el resultado es >= 0goto CENTENAS ;si no, vamos a las CENTENASmovlw 0x10 ;si era positivo incrementamos unidades de mil y seguimosaddwf BCD1movf RESTO_ALTO,W ;Cargo el resultado en el minuendo para repetir la restamovwf MINU_ALTOmovf RESTO_BAJO,Wmovwf MINU_BAJOgoto RESTAUM ;Volvemos a restar porque el resultado es mayor que d'1000'

CENTENAS ;Vamos a obtener las centenasclrf SUSTRA_ALTO ;Cargamos d'100'=0x0064 en el sustraendomovlw 0x64movwf SUSTRA_BAJO

RESTACN call RESTA16 ;Resta de dos bytes de nuevobtfss STATUS,C ;Si carry queda a 1 es que el resultado es >= 0goto DECENAS ;si no, vamos a las DECENASincf BCD1 ;si era positivo incrementamos centenas y seguimosmovf RESTO_ALTO,W ;Cargamos el resultado en el minuendo para otra restamovwf MINU_ALTOmovf RESTO_BAJO,Wmovwf MINU_BAJOgoto RESTACN ;Repetimos por ser el resultado mayor que d'100'

DECENAS movlw 0x0A ;Cargamos diez en el sustraendosubwf MINU_BAJO,W ;Y se lo restamos al minuendo, al ser ahora menor

;que d'100', cabe en un bytebtfss STATUS,C ;Si carry queda a 1 es que el resultado es >= 0goto FINAL ;si no, acabamos y vamos con las UNIDADESmovwf MINU_BAJO ;Cargamos el resultado en el minuendomovlw 0x10 ;Incrementamos las decenasaddwf BCD0 ;si era positivo y seguimosgoto DECENAS

FINAL movf MINU_BAJO,W ;Lo que quedó son ya unidadesaddwf BCD0,F ;que situamos en BCD0return

;***************************************************************************************; Subprograma que realiza la resta en 16 bits:; Resta minuendo(16 bits) menos sustraendo(16 bits) y el resultado va al resto (16 bits); (MINU_ALTO & MINU_BAJO)-(SUSTRA_ALTO & SUSTRA_BAJO) -> (RESTO_ALTO & RESTO_BAJO);***************************************************************************************RESTA16 MOVF SUSTRA_ALTO,W ;Cargamos parte alta del SUSTRAENDO en posición AUXILIAR

MOVWF AUXILIARMOVF SUSTRA_BAJO,W ;Cargo la parte baja del sustraendo en WSUBWF MINU_BAJO,W ;y hago la resta de parte bajaBTFSS STATUS,C ;observo cómo quedó el CarryINCF AUXILIAR ;Si quedó a 0 es que "debo" una a la parte

;alta del minuendo y corrijo sumando 1 a la parte alta ;del sustraendo

MOVWF RESTO_BAJO ;Guardo la parte baja del resultado

MOVF AUXILIAR,W ;Cargo la parte alta del sustraendo en WSUBWF MINU_ALTO,W ;y hago la resta de parte alta

MOVWF RESTO_ALTO ;El resultado lo guardo en la parte alta del restoRETURN

;********************************************************************************END

Page 10: Practica Segundo Parcial MICROPROCESADORES II.docx

EJERCICIO 3: Interface con Pantallas de Cristal Líquido (LCD) de Caracteres Representación del tiempo para un cronómetro digital

Se trata de realizar el diseño del programa encargado de realizar el interface con una pantalla de cristal líquido del tipo matriz de puntos que dispone de un driver HD44780 o compatible para implementar un cronómetro digital que dispone de pulsadores de MARCHA y PARADA. En caso de que ambos pulsadores se encuentren activados, debe prevalecer el pulsador de MARCHA sobre el de PARADA. Si estando el cronómetro parado, se actúa por segunda vez sobre el pulsador de PARADA, se reseteará la cuenta de tiempo (se pondrá a cero).

El crono representará en la primera línea de la pantalla del LCD Horas:Minutos:Segundos.Décimas de Segundo y será posible completar hasta 24 horas de cuenta. Si se llegaran a completar las 24 horas, el crono se resetearía y se pararía. En la segunda línea del LCD aparecerá el estado del cronómetro, con uno de los siguientes mensajes: Crono contando o Crono Parado según proceda. El diseño se basa en el empleo de un microcontrolador PIC16F877 con un oscilador de 4MHz. El interface se realizará con las 4 líneas más altas de datos del LCD: DB7, DB6, DB5 y DB4 y las 3 líneas de control E, RS y R/W, según se muestra en la figura.

Se facilitan también los ficheros que incluyen los subprogramas para interface con el LCD.

Las CONEXIONES de entradas y salidas al microcontrolador podrían ser las siguientes:

A continuación se adjunta un posible algoritmo para el programa correspondiente a la solución propuesta.

Un posible planteamiento

El programa principal consiste en un bucle donde se exploran permanentemente el estado de los pulsadores de MARCHA y de PARADA, si alguno de ellos está activado

Se utiliza TMR1 y el módulo CCP1 en modo comparación con evento especial de disparo para realizar temporizaciones de 0,1 s mediante la sucesiva generación de interrupciones. Con cada interrupción se modifican las posiciones que almacenan Décimas, Segundos, Minutos y Horas

Page 11: Practica Segundo Parcial MICROPROCESADORES II.docx

en BCD y se envían al LCD como caracteres a representar. Al LCD sólo se envían los caracteres cuando se necesita cambiar la representación y se envían todos, aunque también podría ser posible situar el puntero de direcciones de la DDRAM del LCD y enviar sólo los que cambian.

El temporizador TMR1 se configurará en modo temporizador con un prescaler de 8 y será reseteado por el módulo CCP1 cuando alcance el valor de 16 bits que se haya cargado entre los registros CCPR1H y CCPR1L

Los registros del módulo CCP1 deben cargarse por tanto con un valor tal que

0,1 s = 4/4MHz * 8 * CCPR1H_CCPR1L

de donde CCPR1 = 12500 (0x30D4), luego CCPR1H = 0x30 y CCPR1L = 0xD4

Para el envío de caracteres y comandos al LCD se utilizan los subprogramas presentes en el fichero s2_lcd4b_p2p.asm ya que en este caso el interface se realiza con 4 bits y se emplean las 4 líneas más bajas del puerto D. El fichero necesario que contiene los subprogramas se incluye en el código fuente total mediante la correspondiente directiva include.

Se distinguen tres estados posibles en el funcionamiento del sistema, con las transiciones que se indican con el estado de los pulsadores

Algoritmo utilizado:

INICIALIZACIÓN

• Puertos: PORTD de entrada en sus 4 líneas altas e inicialmente de salida en sus 4 líneas más bajas para enviar datos y comandos al LCD, aunque será de entrada en algunos intervalos para leer estado del LCD (flag BF por ejemplo)

• PORTA será de salida en 3 de sus bits (RA1, RA2 y RA3) para manejar las líneas de control del LCD (RS,R/W y E), son salidas permanentemente. Resto de líneas del PORTA de entrada

• Definimos todas entradas como digitales en el PORTA . Aunque RA1, RA2 y RA3 vayan a ser líneas de salida, se van a utilizar instrucciones del tipo BSF y BCF sobre ellas. Estas instrucciones “leen” primero todo el puerto y vuelven a sacar valores: modifican el bit al que afecta la instrucción y el resto de los bits vuelven a salir con el valor que se ha leído. Si están activas las entradas como analógicas, éstas serán leídas siempre como “ceros” (véase esquema del PORTA) y saldrán siempre como tales ceros en los bits del PORTA no afectados por la instrucción

Page 12: Practica Segundo Parcial MICROPROCESADORES II.docx

• Resto de los Puertos como entradas

• Reseteamos por software el LCD por si la alimentación no cumple con los valores requeridos para asegurar el “reset” inicial.

• Inicializamos el LCD: datos de 4 bits, las 2 líneas del LCD activas, display activo, sin cursor, limpiamos DDRAM e incremento en escritura y lectura del LCD

• CCP1 en modo comparación con evento especial de disparo

• Carga de CCPR1H con 0x30 y CCPR1L con 0xD4

• TMR1: modo temporizador, prescaler de 8 y parado al principio

• Puesta a cero de TMR1H y TMR1L

• INTERRUPCIONES: habilitamos las del módulo CCP1

• Variables del algoritmo a cero: DECIMAS, SEGUNDOS, MINUTOS Y HORAS

• Activamos interrupciones globales y de periféricos (GIE y PEIE)

• Llamamos al subprograma encargado de enviar los caracteres ASCII de lo que queremos sacar en el LCD (SACATIEMPO) al principio

• Llamamos a un subprograma (MENSAJE) que envía a la línea 2 del LCD un mensaje que mostraría “Crono Parado”, que es el estado inicial.

• Registramos en ANTES_B el estado previo del PORTB con el pulsador libre

BUCLE PRINCIPAL

• Llamamos a subprograma que realiza una espera de 50ms para evitar muestreos demasiado próximos en los pulsadores que harían que los rebotes fueran considerados como nuevas pulsaciones (ESPERA_50ms)

• Exploramos el estado de RA4 (pulsador de marcha):

Si está pulsado, RA4==0 entonces

Se pone en marcha TMR1

Se marca ANTES_B a 1 (como libre)

Volvemos al principio del bucle sin mirar el otro pulsador (es prioritario el de marcha)

• Exploramos el estado de RB0 (pulsador de parada):

Si está pulsado, RB0== 0 entonces

Se comprueba cómo estaba antes el pulsador (ANTES_B)

Si antes no estaba pulsado (ANTES_B.0==1) entonces

Si el crono estaba parado (TMR1ON==0) entonces

Reseteamos tiempo total (HORAS, MINUTOS,…)

Mostramos el tiempo (SACATIEMPO)

Se saca el mensaje de la segunda línea (“Crono Parado”)

Se para el temporizador TMR1: TMR1ON=0

• Guardamos el valor actual del PORTB en ANTES_B para la próxima detección de cambio en la pulsación de RB0

Page 13: Practica Segundo Parcial MICROPROCESADORES II.docx

• Volvemos al principio del bucle principal

PROGRAMA DE TRATAMIENTO DE LA INTERRUPCIÓN DE CCP1

• Se comprueba que el flag CCP1IF está a 1

• Salvaguarda del contexto (W y STATUS, PCLATH no es necesario)

• Incremento de DECIMAS

• Si hemos llegado a 10, ponemos a 0 DECIMAS e incrementamos SEGUNDOS si no, vamos directamente a la salida del programa de tratamiento

• Se incrementa SEGUNDOS en una unidad

• Se extraen los 4 bits más bajos (unidades)

• Si unidades=0x0A entonces sumamos 6 a SEGUNDOS (para hacer el ajuste a BCD) si no, vamos directamente a la salida del programa de tratamiento

• Se extraen los 4 bits más altos de SEGUNDOS (decenas de segundo)

• Si hemos llegado a 6 entonces se pone a cero SEGUNDOS y se incrementan los minutos (MINUTOS) si no, vamos directamente a la salida del programa de tratamiento

• Se extraen los 4 bits más bajos de MINUTOS (unidades de minuto)

• Si unidades=0x0A entonces se suma 6 a MINUTOS (para hacer el ajuste a BCD) si no, vamos directamente a la salida del programa de tratamiento

• Se extraen los 4 bits más altos de MINUTOS (decenas de minuto)

• Si se ha llegado a 6 entonces ponemos a cero MINUTOS y se incrementan las horas (HORAS) si no, vamos directamente a la salida del programa de tratamiento

• Se extraen los 4 bits más bajos de HORAS (unidades de hora)

• Si unidades=0x0A entonces se suma 6 a HORAS (para hacer el ajuste a BCD)

• Salida del programa de tratamiento:

• Se comparan las HORAS con 24 si las hemos alcanzado:

Ponemos HORAS a cero, paramos TMR1 y mostramos en la segunda línea el mensaje:

“Crono parado”

si no las hemos alcanzado:

Mostramos en la segunda línea el mensaje: “Crono contando”

• Llamamos al Subprograma que saca el tiempo total para actualizar el LCD

• Se pone el flag de CCP1 a cero (CCP1IF=0)

• Recuperación del contexto

• Retorno de interrupción

SUBPROGRAMA SACATIEMPO

Se encarga de tomar los valores almacenados en DECIMAS, SEGUNDOS, MINUTOS Y HORAS y enviarlos al LCD en formato ASCII, se intercalan también caracteres de separación ‘:’ (dos puntos) entre horas y minutos y entre minutos y horas y ‘.’ (punto) entre segundos y décimas

Page 14: Practica Segundo Parcial MICROPROCESADORES II.docx

• Se coloca el cursor en “casa” (esquina superior izquierda)

• Enviamos 3 espacios en blanco para “centrar” en pantalla

• Extraemos decenas de horas, le añadimos el ASCII del cero y lo enviamos al LCD con el subprograma LCDPUTCHAR

• Lo mismo con las unidades de horas

• Enviamos el ASCII de ‘:’

• Envío del ASCII de las decenas de minutos

• Envío del ASCII de las unidades de minutos

• Enviamos el ASCII de ‘:’

• Envío del ASCII de las decenas de segundos

• Envío del ASCII de las unidades de segundos

• Enviamos el ASCII de ‘.’

• Envío del ASCII de las décimas de segundo

• Retorno de subprograma

SUBPROGRAMA ESPERA_50ms

• Se precarga TMR0 con d’60’ para que desborde al cabo de 50ms con un prescaler de 256: 50 ms = 1µs * 256 * (256 – 60)

• Se pone a cero el flag de TMR0: T0IF

• Espera a que T0IF ==1

• Retorno de subprograma

SUBPROGRAMA MENSAJE

Sitúa el contador de direcciones de la DDRAM del LCD al principio de la segunda línea y va enviando al LCD los caracteres almacenados en una de las dos tablas alternativas almacenadas en la memoria de programa. El final de las tiras de caracteres guardadas en las tablas se identifican mediante el carácter especial ‘_’.

En función del valor almacenado en la posición TIRA se recogen los caracteres de la tabla que indica “Crono parado” (si TIRA==0) ó bien de la que dice: “Crono contando” (si TIRA==1).

Para recoger los caracteres se incrementa un puntero, que se carga en W antes de hacer la llamada a la tabla. Volvemos de la tabla trayendo en W l correspondiente carácter.

Para almacenar la tira de caracteres se emplea la directiva DT que va situando sucesivas instrucciones RETLW con el código ASCII de cada uno.