Você está na página 1de 8

LIST P=PIC16F84A ; Pic a usar

#INCLUDE <P16F84A.INC> ; Lista de etiquetas de microchip

; Configuración opciones de hardware para la programación


__CONFIG _CP_OFF & _PWRTE_ON & _WDT_OFF & _XT_OSC

; Valores de constantes:
FRAC_INI D'12' ; Constante para inicio cuenta de fracciones de
; segundo
SEGS_INI D'196' ; Constante para inicio cuenta de segundos
MINS_INI D'196' ; Constante para inicio cuenta de minutos
HORS_INI D'232' ; Constante para inicio cuenta de horas
ADJMIN D'9' ; Número de "frac_sec" que se necesita sumar cada
; minuto para ajustar el tiempo
ADJHOR D'34' ; Número de "frac_sec" que se necesita restar cada
; hora para ajustar el tiempo
ADJDIA D'6' ; Número de "frac_sec" que se necesita sumar cada
; 24 horas para ajustar el tiempo
;Ajustes:
; Un "frac_sec" es aproximadamente 1 / 244 s
; 1 MHz / 16 = 62.500 Hz ; 62.500 Hz / 256 = 244,140625 Hz ; T = 0,004096 s
; 0,004096 s * 244 = 0,999424 s; dif 1 segundo = -0,000576 s
; 1 "minuto" = 0,999424 s * 60 = 59,96544 s
; 60 s - 59,96544 s = 0,03456 s ; 0,03456 s / 0,004096 s = 8,4375
; 1 "minutoadj" = 59,96544 s + (0,004096 s * 9) = 59,96544 s + 0,036864 s = 60,002304 s
; 1 "hora" = 60,002304 s * 60 = 3600,13824 s
; 3600 s - 3600,13824 s = -0,13824 s ; -0,13824 s / 0,004096 s = -33,75 s
; 1 "horaadj" = 3600,13824 s - (0,004096 s * 34) =
; = 3600,13824 s - 0,139264 s = 3599,998976 s
; 24 "horas" = 3599,998976 s * 24 = 86399,975424 s
; 86400 s - 86399,975424 s = 0,024576 s ; 0,024576 s / 0,004096 s = 6 ___________
; 24 "horasadj" = 86399,975424 s + 0,004096 s * 6 = 86399,975424 s + 0,024576 s = DISPLAY DECENA MIN / DECENA SEG -> RA,2 -|1 \__/ 18|- RA,1 <- DISPLAY UNIDAD HR
86400 s DISPLAY UNIDAD MIN / UNIDAD SEG -> RA,3 -|2 17|- RA,0 <- DISPLAY DECENA HR
NC -|3 16F84A 16|- XT
; Activación de RB1-3 para las entradas de los pulsadores MCLR/ -|4 15|- XT
PULSADOR B'00001110' ; RB1, RB2 y RB3 GND -|5 14|- Vcc
PUNTO dp -> RB,0 -|6 13|- RB,7 -> SEGMENTO g
; Asignación de banderas. Los pulsadores activos proporcionan un "1" PUL A (SEG) / SEGMENTO a -> RB,1 -|7 12|- RB,6 -> SEGMENTO f
CHG H'03' ; Indica que se ha activado un pulsador o que es PUL B (MIN) / SEGMENTO b -> RB,2 -|8 11|- RB,5 -> SEGMENTO e
; necesario actualizar los valores de la hora que tienen PUL C (HOR) / SEGMENTO c -> RB,3 -|9________10|- RB,4 -> SEGMENTO d
; que mostrarse en los displays
PSEG H'04' ; Pulsador A, modo segundero. PORTA, control displays 7 segmentos de cátodo común
PMIN H'05' ; Pulsador B, avance rápido minutos. PORTB, segmetos de los displays, led separadores, pulsadores como entrada
PHOR H'06' ; Pulsador C, avance rápido horas.
P_ON H'07' ; Un pulsador ha sido activado El pulsador A (conectado a RB1) muestra el segundero en tanto permanezca presionado.
El pulsador B (conectado a RB2) avanza rápidamente los minutos.
DSPOFF B'11111111' ; Displays apagados El pulsador C (conectado a RB3) avanza rápidamente las horas.

; Mapa de activación de segmentos para los displays (PORTB)


; a
; =========
; | |
; f | | b
; | g |
; ========= Configurar puertos como
; | | INICIO salidas, blanquear display
; e | | c
; | | RB Pull Up desconectadas
; ========= # p TMR0 en modo temporizador
; d (se utilizan los pulsos de reloj
; Configuración OPTION: internos, Fosc/4)
gfedcbap OPTION_REG = 10000011 Preescaler 1:16
CERO H'7E' ; 01111110
UNO H'0C' ; 00001100
DOS H'B6' ; 10110110 Bits PORTA como salidas
TRES H'9E' ; 10011110 Bits PORTB como salidas
CUATRO H'CC' ; 11001100 Puerto A apaga los displays
Configuración PUERTOS:
CINCO H'DA' ; 11011010 Con Puerto B todos los segmentos
TRISA = 0000 0000
SEIS H'FA' ; 11111010 apagados. Separador entre horas y
TRISB = 0000 0000
SIETE H'0E' ; 00001110 minutos encendido (RB0).
PORTA = DSPOFF (1111 1111)
OCHO H'FE' ; 11111110
PORTB = 0000 0001
NUEVE H'DE' ; 11011110
SEGM_OFF equ H'00' ; Todos los segmentos apagados. Separador
entre horas y minutos apagado (RB0).
Inicialización de variables: Pone 01h en TMR0
TMR0 = 1 Inicia display seleccionando
display = 1111 1110 (decena de hora) decena de hora
digito1 = “CERO” Los valores para digito1,
digito2 = “CERO” digito2, digito3 y digito4
digito3 = “CERO” permitirán que desde el
digito4 = SEGM_OFF primer momento aparezcan
; Posición de memoria de variables banderas = 0000 0000 las 0:00 en el display.

; Las variables de tiempo comienzan con un número que permite contar y ajustar el tiempo Variables de tiempo:
; Por ejemplo la variable "segundos" se inicia con 196 decimal, para que después de 60 frac_sec = FRAC_INI (12d)
; incrementos de 1 segundo se produzca un 0 (196 + 60 = 256 -> 0) segundos = SEGS_INI (196d)
frac_sec H'0C' ; Fracciones de segundo (1/244) minutos = MINS_INI (196d)
segundos H'0D' ; Segundos horas = HORS_INI (232d)
minutos H'0E' ; Minutos
horas H'0F' ; Horas
conta1 H'10' ; Variable 1 para bucle contador
;
display H'11' ; Indicador de display que debe actualizarse
digito1 H'12' ; Display unidad de minuto / unidad de segundo
PRINCIPAL Pag. 2
digito2 H'13' ; Display decena de minuto / decena de segundo
digito3 H'14' ; Display unidad de hora
digito4 H'15' ; Display decena de hora
banderas H'16' ; Banderas; 3-CHG, 4-PSEG, 5-PMIN, 6-PHOR, 7-P_ON
PRINCIPAL
TMR0 cuenta libremente
para no perder ciclos de
reloj escribiendo valores

TMR0_LLENO

Incremento de TMR0 se va incrementando líbremente con la señal de


TMR0 reloj a 1.000.000 MHz / 16 = 62.500 Hz

NO Se comprueba el bit Z de STATUS


TMR0=0
TMR0 se ha desbordado y se han contado 256 * 16 = 4096
ciclos de reloj, (4,096 ms)
SI La frecuencia es: 62.500 Hz / 256 = 244,140625 Hz

Se añade 1 a frac_sec Se activa separador horas-minutos (RB0)


frac_sec = frac_sec + 1
frac_sec comienza por 12, hasta desbordarse cuenta 244 Restaura la variable “frac_sec” para la próxima vuelta

NO SI RB0 = 1
frac_sec = 0
frac_sec = FRAC_INI (12d) Comprueba variables pulsadores
frac_sec = 0, se ha contado “1 segundo”
(0,999424 s)

COMPROBAR_PUL
El programa pasa por aquí cada 4,096
ms, esto es unas 244 veces por segundo No hay pulsadores activados
P_ON = 1
NO

Incrementar segundos, minutos y horas SI


Ajustes cada minuto, hora y 1/2 dia Se ha activado un pulsador
“CHG” se pone a 1 pero no es PSEG, debe ser
PMIN o PHOR
NO SI
INC_HORA PSEG = 0

Si está pulsado PSEG, (Pul


A) se mostrarán los
Pag. 7 segundos en el display

COMPROBAR_CHG Se comprueba el estado de “CHG” por si se ha activado algún


pulsador o es necesario actualizar los valores de la hora que
tienen que mostrarse en los displays Puesta en hora
Se actualiza hora, displays y pulsadores cada 4,096 ms (244 PMIN (Pul B) avanza los minutos PONER_RELOJ
veces por segundo) PHOR (Pul C) avanza las horas
NO SI
CHG = 1
Pag. 6

Se comprueba si se activo el
pulsador de segundos (Pul A) para
Si no se han activado pulsadores ni ha cambiado la COMPROBAR_SEG mostrar los segundos en el display
hora se salta a DISPLAY_PUL, que principalmente
refresca uno de los displays cada vez que se accede
a ella y escanea pulsadores.
SI NO
PSEG = 1

Se mostrarán los segundos en el Se guardan la hora y los


display de minutos minutos para su tratamiento
OBTENER_H_M
Se guarda temporalmente el número
de segundos en “digito1”
Resto de variables “digit” a 0
digito2 = 0 digito3 se utiliza temporalmente para
digito3 = 0 almacenar la hora, (Si la hora es 255, digito3 = horas – HORS_INI (232d)
digito4 = 0 digito3 sería 255 – 232 = 23 digit 1 = minutos – MINS_INI (196d)
digito1 = second – SEGS_INI (196d) digito1 se utiliza temporalmente para
almacenar los minutos

Divide los segundos o los minutos y las


Pag. 4 DIV_DIGITOS horas en digitos independientes, ejemplo,
[14] lo pasa a [1]-[4]

Convierte cada digito (digito1, digito2, digito3 y digito4)


Pag. 5 CONVER_COD_7S
en valores para los segmentos del display

Se borran los bits de flag para actualizar su estado


Escanea pulsadores, si alguno está activado se pone a 1 la
Pag. 3 DISPLAY_PUL bandera que le corresponda así como “P_ON” y “CHG”
Muestra los digitos correspondientes a los segundos o a los
minutos y horas en el display que corresponda.
Cada display se actualiza cada 244,14 Hz / 4 = 61,04 Hz.
Se borran los bits de flag para actualizar su estado
Escanea pulsadores, si alguno está pulsado se pone a 1 el pulsador
que le correspoda así como "P_ON" y "CHG"
DISPLAY_PUL Muestra los digitos correspondientes a los segundos o a los minutos y
horas en el display que corresponda.

banderas = 0000 0000


Se borran los bits de flag para actualizar su estado
PORTA = DSPOFF (1111 1111)
Apagar los segmentos respetando separador horas-minutos (RB0)
w = SEGM_OFF XOR PORTB
Se apagan los displays
w = w AND B'11111110'
Se configuran los bits 1, 2 y 3 de PORTB como entrada
PORTB = w XOR PORTB
Se almacena el estado de los pulsadores en var
TRISB = PULSADOR (0000 1110)

COMPROBAR_PSEG w = SEGM_OFF XOR PORTB


w = w AND B'11111110'
PORTB = w XOR PORTB

SI CHG = 1 Este código copia los bits del literal SEGM_OFF que
RB1 = 1 PSEG= 1 se quieran en PORTB, Se copiaran aquellos bits de
P_ON = 1 SEGM_OFF cuya posición coincida con un 1 en la
máscara que se utiliza con la función AND y se
NO
respetaran los valores de los bits PORTB que
coincidan con un 0 en la máscara. En este caso
SEGM_OFF = 00H y en la operación AND se utiliza
B'11111110' con lo que en PORTB se respetará el
COMPROBAR_PMIN valor de RB0 y se pondrán a cero el resto de bits.

En nuestro caso se podría simplificarse el proceso,


eliminando la primera XOR pero entonces no se
SI CHG = 1 podría trabajar con otros posibles valores de
RB2 = 1 PMIN= 1 SEGM_OFF
P_ON = 1
Ejemplos:
NO
Si PORTB es 1000 1110

w = SEGM_OFF XOR PORTB:


COMPROBAR_PHOR 0000 0000
1000 1110
---------------
1000 1110
SI CHG = 1
RB3 = 1 PHOR= 1
w = w AND B'11111110':
P_ON = 1
1000 1110
NO 1111 1110
--------------
1000 1110

PORTB = w XOR PORTB


ACTIVAR_SEGM 1000 1110
1000 1110
--------------
Puerto B como salida 0000 0000
TRISB = 0000 0000

Se determina que display debe actualizarse, es


decir, que dato debe presentarse en el puerto B y Si PORTB es 1000 1111
se establece el siguiente display
w = SEGM_OFF XOR PORTB:
0000 0000
Display es SI 1000 1111
w = digito4
XXXX XXX0 ---------------
1000 1111
NO
w = w AND B'11111110':
1000 1111
Display es SI 1111 1110
w = digito3
XXXX XX0X --------------
1000 1110
NO
PORTB = w XOR PORTB
1000 1110
Display es SI
w = digito2 1000 1111
XXXX X0XX --------------
0000 0001
NO

Display es SI
w = digito1
XXXX 0XXX

NO

Se entregar el valor de w en Para rotar el display a la próxima posición


w = w XOR PORTB
el puerto B respetando el se utiliza el siguiente código:
w = w AND B'11111110'
valor de RB0
PORTB = w XOR PORTB
rlf display,F ; Rota display 1 bit a la próxima
posición
bsf display,0 ; Asegura un 1 en la posición
más baja de display (luego se hará 0 si es
Se apagan los puntos de necesario)
NO separación. Se activó en btfss display,4 ; Comprueba si el último
Bit 7 de
RB0 = 0 INICIO y se activa cada vez display fué actualizado
frac_sec = 0
que frac_sec se hace 0. bcf display,0 ; Si lo fué, se vuelve a habilitar
el primer display
SI
La variable display va cambiando:
Se habilita el display correspondiente 1111 1101
PORTA = display Cada display se “enciende” con una 1111 1011
cadencia de 244 Hz / 4 = 61 Hz 1111 0111
1110 1110
1101 1101
1011 1011
En la variable display se va desplazando un cero a
Rota display a 0111 0111
la izquierda. Sólo se tendrán en cuenta los 4 bits
siguiente posición 1110 1110
menos significativos
Sólo valen los 4 bits menos significativos

PRINCIPAL Pag. 2
Divide los segundos o los minutos y las
DIV_DIGITOS horas en digitos independientes, ejemplo,
[14] lo pasa a [1]-[4]

Se ponen a cero las posiciones de las decenas para el caso de


digito4 = 0 que no se incrementen Se vuelve a comprobar si es
digito2 = 0 Bucle para convertir cada número (segundos o minutos y horas) necesario sumar uno a la
conta1 = 2 Dirección de digito1 en FSR para usar INDF decena cada vez que ésta
FSR = digito1 La primera vez, FSR = digito1 (minutos o segundos) y la segunda se ha incrementado
vez FSR = digito3 (horas)

Este LOOP se utiliza primero para los minutos o los segundos y


después para las horas
INC_DECENAS

LOOP
El puntero apunta a la
primera posición de las
Incf FSR,F decenas
Incf INDF,F Se añade 1 a las decenas
Averiguar cuantas “decenas” Decf FSR,F Se restaura el valor de INDF
INDF = INDF - 10 hay en el número. El número para la próxima resta hasta
menos diez en cada bucle. que se termine

CARRY = 1 SI

Se comprueba "CARRY",
NO que se pone a 1 si en la
resta no se ha producido
llevada
Si C = 1 se añadirá 1 a la
posición de las decenas

INDF = 10 + INDF
Este LOOP se C = 0, no se incrementan las
utiliza para las decenas y se suma 10 para
horas después de restaurar las unidades
trabajar con los
minutos o los
segundos

LOOP2

FSR = digito3
PROX_NUM

conta1 = conta1 -1 Próximo número:


Primero ha sido segundos o
minutos y luego horas

NO
conta1 = 0

SI

CONVER_COD_7S Pag. 5
Convierte cada dígito a
CONVER_COD_7S código 7 segmentos para los
displays

Coloca la dirección del primer


FSR = digito1 digito (digito1) en FSR
conta1 = 4 Prepara la variable conta1 para el
bucle de los 4 displays

PROX_DIGITO

Obtener el valor de la
w = INDF
variable "digito" actual

LLamar a la rutina de
Pag. 8 CODIGO_7S conversión a código 7
segmentos

Colocar en la variable "digito" actual el


INDF = w código 7 segmentos devuelto
FSR = FSR + 1 Incremente INDF para el próximo
conta1 = conta1 - 1 "digito"
Se resta 1 a conta1

NO Permitir que conta1 de sólo


conta1 = 0
4 vueltas

SI

BORRAR_CERO
Si hay un cero en el display de las
decenas de hora no se muestra (borrado
NO de los ceros a la izquierda)
¿digito4 = “0”?

SI

digito4 = SEGM_OFF
Si está pulsado PSEG no se muestra nada en el
display de la posición de la unidad de hora.
Contando con BORRAR_CERO, esto significa que
sólo se mostrarán los segundos.

BORRAR_CERO_SEG

SI
PSEG = 1

NO digito3 = SEGM_OFF

DISPLAY_PUL Pag. 3
Puesta en hora de horas y
PONER_RELOJ
minutos

Inicia los segundos cuando se


segundos = SEGS_INI (196d)
pone el reloj en hora

PONER_MINUTOS

Comprobar si se ha pulsado
PMIN (Pulsador minutos)

NO
PMIN = 1

SI

Avance rápido del tiempo


cuando se ajustan minutos frac_sec = 175d
frac_sec = 175 minutos = minutos + 1
Incrementar los minutos

NO
minutos = 0

SI

Iniciar minutos si al
incrementar se han minutos = MINS_INI
desbordado

PONER_HORAS

Comprobar si se ha pulsado
PHOR (Pulsador horas)

NO
PHOR = 1

SI

Avance rápido del tiempo


cuando se ajustan horas frac_sec = 127d
frac_sec = 127d horas = horas + 1
Incrementar las horas

NO
horas = 0

SI

horas = HORS_INI (232d)

OBTENER_H_M Pag. 2
Incrementar segundos, minutos y horas
INC_HORA
Ajustes cada minuto, hora y 24 horas

CHG = 1 Se especifica que se ha producido un cambio

Como ha pasado un segundo se incrementa


segundos = segundos + 1
“segundos”

NO
segundos = 0

SI

Se ha desbordado "segundos" y se reestablece el


valor inicial de “segundos” para la próxima vuelta
segundos = SEGS_INI (196d)
Se resta 9 a “frac_sec” cada minuto para los
frac_sec = frac_sec – ADJMIN (9d)
ajustes de tiempo
minutos = minutos + 1
El minuto será 9 “frac_sec” más largo.
Se añade 1 minuto

NO
minutos = 0

SI

Se reestablece el valor inicial de “minutos” para la


próxima vuelta
minutos = MINS_INI (196d)
Se suma 34 “frac_sec” a cada hora para los
frac_sec = frac_sec + ADJHOR (34d)
ajustes de tiempo
horas = horas + 1
La hora será 34 “frac_sec” más corta
Se añade 1 hora

NO
horas = 0

SI

Se reestablece el valor inicial de “horas” para la


próxima vuelta
horas = HORS_INI (232d)
Se resta 6 a “frac_sec” cada 24 horas para los
frac_sec = frac_sec – ADJDIA (6d)
ajustes de tiempo
Cada 24 horas se añadirán 6 "frac_sec"

COMPROBAR_CHG Pag. 2
SUBRUTINAS

CODIGO_7S
Devuelve el código 7
segmentos

addwf PCL,F
retlw CERO
retlw UNO
retlw DOS Devuelve en el acumulador
retlw TRES el valor de la constante
retlw CUATRO CERO a NUEVE según el
retlw CINCO valor que se hubiese
retlw SEIS colocado en w
retlw SIETE
retlw OCHO
retlw NUEVE