;*************************************************************
; RELOJ DE 24 HORAS
;*************************************************************
;
; Programa original:  CLOCK54.ASM
;      Dan Matthews
;      Microchip Technology Inc.
;      16 de enero de 1997
;      [URL="http://www.microchip.com"]www.microchip.com[/URL], AN590.PDF
; Revisión:    RELOJ24H.ASM
;      Emilio Toboso
;      I.E.S. "La Fuensanta" Córdoba
;      Abril de 2005
; Programa para PIC16F84A
; Frecuencia de reloj: 4 MHz
; Instrucción: 1Mz = 1 us
; Perro Guardián: OFF
; Tipo de Reloj: XT
; Protección de código: OFF
; POR: ON
; 
;*************************************************************
; DESCRIPCIÓN DEL PROGRAMA
;*************************************************************
;
; Este programa funciona en un PIC16F84A y se trata de un reloj
; de 24 horas que muestra horas y minutos.
; Dispone de dos displays LED para las horas y otros dos para los
; minutos.
; Para programar la hora se dispone de un pulsador de avance rápido
; de horas y de otro para avance rápido de minutos.
; También se dispone de un tercer pulsador que se utiliza para mostrar
; los segundos mientras permanezca pulsado. 
;  
; DESCRIPCIÓN DEL HARDWARE
;  
; VISUALIZACIÓN:  
;
; La hora se muestra mediante cuatro displays de 7 segmentos de cátodo
; común multiplexados. Los segmentos de cada display se unen y estan
; controlados a través de resistencias por salidas del PIC. Cada cátodo
; común de cada display es controlado por el PIC a través de un transistor.
; El reloj presenta las horas y minutos por dos puntos (88:88). Los
; segmentos se asignan al puerto B.
; Los dos puntos se realizan mediante dos LED en serie con una resistencia
; y se conectan a RB0.
; Los segmentos de los displays, de "a" hasta "f" se asignan a las salidas
; de RB1 a RB7.  
; Los cuatro cátodos comunes se controlan mediante el puerto A a través de
; los transistores.  
; RA0 controla la decena de hora, RA1 la unidad de hora; RA2 la decena de
; minuto y RA3 la unidad de minuto.  
;  
; PULSADORES:  
;
; Sobre los tres pulsadores:
; Pulsador avance rápido de horas conectado a RB3
; Pulsador avance rápido de minutos conectado a RB2
; Pulsador para mostrar los segundos conectado a RB1
;
; Debido a que todas las patillas E/S (salvo RA4) están utilizadas,  
; se debe comprobar el estado de los pulsadores estableciendo como salidas
; o como entradas alternativamente las patillas a las que están conectados.
; Los pulsadores utilizan el Puerto B que cambiará a entrada durante un
; instante para comprobar el estado de los pulsadores.  
;
;
;
;
;
;
;
;
;
;
;
;
;*************************************************************
; PATILLAS
;*************************************************************
;                                           ___________
; DISPLAY DECENA MIN / DECENA SEG -> RA,2 -|1   \__/ 18|- RA,1 <- DISPLAY UNIDAD HR
; DISPLAY UNIDAD MIN / UNIDAD SEG -> RA,3 -|2        17|- RA,0 <- DISPLAY DECENA HR
;                                      NC -|3 16F84A 16|- XT          
;                                   MCLR/ -|4        15|- XT
;                                     GND -|5        14|- Vcc
;                        PUNTO dp -> RB,0 -|6        13|- RB,7 -> SEGMENTO g
;        PUL A (SEG) / SEGMENTO a -> RB,1 -|7        12|- RB,6 -> SEGMENTO f
;        PUL B (MIN) / SEGMENTO b -> RB,2 -|8        11|- RB,5 -> SEGMENTO e
;        PUL C (HOR) / SEGMENTO c -> RB,3 -|9________10|- RB,4 -> SEGMENTO d      
;
; PORTA, control displays 7 segmentos de cátodo común
; PORTB, segmetos de los displays, led separadores, pulsadores como entrada
;
; El pulsador A (conectado a RB1) muestra el segundero en tanto permanezca presionado.
; El pulsador B (conectado a RB2) avanza rápidamente los minutos.
; El pulsador C (conectado a RB3) avanza rápidamente las horas.
;
;*************************************************************
 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       
;
;**************************************************************
; Lista de constantes y variables para el uso del programa
;**************************************************************
;
; Valores de constantes ***************************************
;
FRAC_INI equ  D'12' ; Constante para inicio cuenta de fracciones de segundo
SEGS_INI equ  D'196' ; Constante para inicio cuenta de segundos
MINS_INI equ  D'196' ; Constante para inicio cuenta de minutos
HORS_INI equ  D'232' ; Constante para cuenta de horas
ADJMIN  equ  D'9' ; Número de "frac_sec" que se necesita sumar cada minuto
       ; para ajustar el tiempo
ADJHOR  equ  D'34' ; Número de "frac_sec" que se necesita restar cada hora
       ; para ajustar el tiempo
ADJDIA  equ  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 = 86400 s
;
; Activación de RB1-3 para las entradas de los pulsadores
PULSADOR equ  B'00001110' ; RB1, RB2 y RB3
;
; Asignación de banderas. Los pulsadores activos proporcionan un "1"
CHG   equ  H'03' ; Indica que se ha activado un pulsador o que es necesario
       ; actualizar los valores de la hora que tienen que mostrarse
       ; en los displays
PSEG  equ  H'04' ; Pulsador A, modo segundero.
PMIN  equ  H'05' ; Pulsador B, avance rápido minutos.
PHOR  equ  H'06' ; Pulsador C, avance rápido horas.
P_ON  equ  H'07' ; Un pulsador ha sido activado
;
DSPOFF  equ  B'11111111' ; Displays apagados (PORTA)
;
; Mapa de activación de segmentos para los displays (PORTB)
;         a
;   =========
;   |       |
; f |       | b
;   |   g   |
;   =========
;   |       |
; e |       | c
;   |       |
;   ========= # p
;         d
;
       ; gfedcbap
CERO  equ  H'7E' ; 01111110
UNO   equ  H'0C' ; 00001100
DOS   equ  H'B6' ; 10110110
TRES  equ  H'9E' ; 10011110
CUATRO  equ  H'CC' ; 11001100
CINCO  equ  H'DA' ; 11011010
SEIS  equ  H'FA' ; 11111010
SIETE  equ  H'0E' ; 00001110
OCHO  equ  H'FE' ; 11111110
NUEVE  equ  H'DE' ; 11011110
SEGM_OFF equ  H'00' ; Todos los segmentos apagados. Separador entre horas
       ; y minutos apagado (RB0).
;
; Posición de memoria de variables ************************************
; Las variables de tiempo comienzan con un número que permite contar y ajustar el tiempo  
; Por ejemplo la variable "segundos" se inicia con 196 decimal, para que después de 60
; incrementos de 1 segundo se produzca un 0 (196 + 60 = 256 -> 0)
frac_sec equ  H'0C' ; Fracciones de segundo (1/244)
segundos equ  H'0D' ; Segundos
minutos  equ  H'0E'   ; Minutos
horas  equ  H'0F'   ; Horas
conta1  equ  H'10' ; Variable 1 para bucle contador
;
display  equ     H'11' ; Indicador de display que debe actualizarse
digito1  equ  H'12' ; Display unidad de minuto / unidad de segundo
digito2  equ  H'13' ; Display decena de minuto / decena de segundo
digito3  equ  H'14' ; Display unidad de hora
digito4  equ  H'15' ; Display decena de hora
banderas equ     H'16' ; Banderas; 3-CHG, 4-PSEG, 5-PMIN, 6-PHOR, 7-P_ON
;
;**************************************************************
 ORG 0x00  ;Vector de Reset
 goto INICIO
 org 0x05  ;Salva el vector de interrupción
;**************************************************************
; SUBRUTINAS
;**************************************************************
CODIGO_7S ; Devuelve el código 7 segmentos
 addwf PCL,F
 retlw CERO
 retlw UNO
 retlw DOS
 retlw TRES
 retlw CUATRO
 retlw CINCO
 retlw SEIS
 retlw SIETE
 retlw OCHO
 retlw NUEVE
;**************************************************************
;
;
;
;
;
;
;
;
;
;
;**************************************************************
; Comienzo del programa
;**************************************************************
;
INICIO
;  Configurar puertos como salidas, blanquear display
 bsf  STATUS,RP0 ; Activa el banco de memoria 1.
 movlw B'10000011' ; Configuración del registro Option, RB Pull Up desconectadas
 movwf OPTION_REG ; TMR0 en modo temporizador (uso de pulsos de reloj internos, Fosc/4)
      ; prescaler TMR0 a 1:16 
 movlw B'00000000'
 movwf TRISA  ; Pone todas las patillas del puerto A como salidas
 movwf TRISB  ; Pone todas las patillas del puerto B como salidas
 bcf  STATUS,RP0 ; Activa el banco de memoria 0.
;
; Establecer estados iniciales de las salidas
 movlw DSPOFF
 movwf PORTA  ; Apaga los displays
 movlw B'00000001' ; Todos los segmentos apagados. Separador 
 movwf PORTB  ; entre horas y minutos encendido (RB0).
;
; Inicialización de variables:
 movlw H'01'
 movwf TMR0  ; Pone 01h en TMR0
 movlw B'11111110' 
 movwf display  ; Inicia display seleccionando decena de hora
 movlw CERO
 movwf digito1  ; Aparecerá un "0" en el display unidad de minutos
 movwf digito2  ; Aparecerá un "0" en el display decena de minutos
 movwf digito3  ; Aparecerá un "0" en el display unidad de hora
 ;movlw SEGM_OFF ======================= EDITADO =======================
 movwf digito4  ; No aparecerá nada en el display decena de hora
 movlw B'00000000'
 movwf banderas ; Coloca todas las banderas a 0
;
; Inicia las variables de tiempo
 movlw FRAC_INI
 movwf frac_sec ; 12
 movlw SEGS_INI
 movwf segundos ; 196
 movlw MINS_INI
 movwf minutos  ; 196
 movlw HORS_INI
 movwf horas  ; 232
;
;**************************************************************
PRINCIPAL ; Rutina principal cíclica
;**************************************************************
;
;  Esperar al desbordamiento de TMR0
TMR0_LLENO
; 4 MHz -> 1 MHz
;   1.000.000 Hz / 16 = 62.500 Hz
;   62.500 Hz / 256 = 244,140625 Hz -> 4,096 ms
 movf TMR0,W
 btfss STATUS,Z ; TMR0 cuenta libremente para no perder ciclos del reloj
      ; escribiendo valores
 goto TMR0_LLENO
;
; Se ha desbordado TMR0 y se han contado 256.
; Tarda en desbordarse 4.096 ciclos de reloj, 4,096 ms
 incfsz frac_sec,F  ; Se añade 1 a frac_sec
 goto 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
;
; Se ha desbordado frac_sec y se han contado 244 "frac_sec", 1 segundo.
; Tarda en desbordarse 4.096 ciclos de reloj, 4,096 ms * 244 = 999,424 ms
; Al no consegirse exactamente 1 segundo sino 0,999424 s, luego se necesitan ajustes
 bsf  PORTB,0  ; Se activa separador horas-minutos
 movlw FRAC_INI
 movwf frac_sec  ; Restaura la variable frac_sec para la próxima vuelta
;
COMPROBAR_PUL ; Comprueba variables pulsadores
 btfss banderas,P_ON ; Si no se ha pulsado nada, se pasa a INC_HORA
 goto INC_HORA  ; Incrementa segundos, minutos y horas. Ajustes y “CHG” a 1
 btfsc banderas,PSEG ; Comprobar si se ha pulsado PSEG (Pulsador segundos)
 goto INC_HORA  ; Se ha pulsado PSEG, (Pul A) y se mostrarán
       ; los segundos en el display
;
PONER_RELOJ
 movlw SEGS_INI ; 196d
 movwf segundos ; Inicia los segundos cuando se pone el reloj en hora
;
PONER_MINUTOS
 btfss banderas,PMIN ; Comprobar si se ha pulsado PMIN (Pulsador minutos)
 goto PONER_HORAS     ; No se ha pulsado PMIN, ir a comprobar estado de PHOR
 movlw H'AF'   ; 175d
 movwf frac_sec     ; Avance rápido del tiempo cuando se ajustan minutos frac_sec = 175
 incfsz minutos,F  ; Incrementar los minutos
 goto PONER_HORAS
 movlw MINS_INI
 movwf minutos   ; Iniciar minutos si al incrementar se han desbordado
;
PONER_HORAS
 btfss banderas,PHOR ; Comprobar si se ha pulsado PHOR (Pulsador horas)
 goto OBTENER_H_M  ; No se ha pulsado PHOR, no se cambian las horas
 movlw H'7F'   ; 127d
 movwf frac_sec  ; Avance rápido del tiempo cuando se ajustan horas frac_sec = 127
 incfsz horas,F   ; Incrementar la hora
 goto OBTENER_H_M
 movlw HORS_INI
 movwf horas   ; Iniciar la hora si al incrementar se han desbordado
 goto OBTENER_H_M   
;
INC_HORA ; Incrementar segundos, minutos y horas
   ; Ajustes cada minuto, hora y 24 horas
 bsf  banderas,CHG ; Se especifica que se ha producido un cambio
;
 incfsz segundos,F   ; Como ha pasado un segundo se incrementa "segundos"
 goto COMPROBAR_CHG
 movlw SEGS_INI     ; Se ha desbordado "segundos" y se reestablece el valor inicial
 movwf segundos  ; de "segundos" para la próxima vuelta
;
 movlw ADJMIN   ; Se resta 9 a "frac_sec" cada minuto para los ajustes de tiempo 
 subwf frac_sec,F   ; El minuto será 9 "frac_sec" más largo
;
 incfsz minutos,F    ; Se añade 1 minuto
 goto COMPROBAR_CHG
 movlw MINS_INI  ; Se ha desbordado "minutos" y Se reestablece el valor inicial
 movwf minutos     ; de "minutos" para la próxima vuelta
;
 movlw ADJHOR   ; Se suma 34 a "frac_sec" cada hora para los ajustes de tiempo 
 addwf frac_sec,F  ; La hora será 34 "frac_sec" más corta
;
 incfsz horas,F     ; Se añade 1 hora
 goto COMPROBAR_CHG
 movlw HORS_INI  ; Se ha desbordado "horas" y se reestablece el valor inicial
 movwf horas     ; de "horas" para la próxima vuelta
 movlw ADJDIA   ; Se resta 6 a "frac_sec" cada 24 horas para los ajustes de tiempo
 subwf frac_sec,F   ; Cada 24 horas se añadirán 6 "frac_sec"
;
; 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
; Se actualiza hora, displays y pulsadores cada 4,096 ms (244 veces por segundo)
COMPROBAR_CHG  
 btfss banderas,CHG ; Si no se han activado pulsadores ni ha cambiado la hora
  goto DISPLAY_PUL  ; se salta a DISPLAY_PUL, que principalmente refresca uno de los
       ; displays cada vez que se accede a ella y escanea pulsadores.
;
COMPROBAR_SEG ;  Se comprueba si se activo el pulsador de segundos (Pul A)
    ; para mostrar los segundos en el display
 btfss banderas,PSEG
 goto OBTENER_H_M  ; No estaba pulsado PSEG
 movlw H'00'   ; Se mostrarán los segundos en el display de minutos
 movwf digito2   ; Variables "digito2" a 0
 movwf digito3   ; Variables "digito3" a 0
 movwf digito4   ; Variables "digito4" a 0
 movlw SEGS_INI
 subwf segundos,W
 movwf digito1   ; Se guarda temporalmente el número de segundos en “digito1”
 goto DIV_DIGITOS  
;
OBTENER_H_M
 movlw HORS_INI
 subwf horas,W
 movwf digito3  ; La variable digito3 almacena temporalmente el valor para las horas
 movlw MINS_INI
 subwf minutos,W
 movwf digito1  ; La variable digito1 almacena temporalmente el valor para los minutos
;
DIV_DIGITOS  ; Divide los segundos o los minutos y las horas en dígitos independientes
    ; ejemplo, [14] lo pasa a [1]-[4]
 movlw H'00'
 movwf digito4  ; Se ponen a cero las posiciones de las decenas
 movwf digito2  ; para el caso de que no se incrementen
 movlw H'02'
 movwf conta1  ; Bucle para convertir cada número (segundos o minutos y horas)
 movlw digito1  ; Dirección de digito1 en FSR para usar INDF
 movwf FSR   ; La primera vez, FSR = digito1 (minutos o segundos) y la segunda vez FSR = digito3 (horas)
 goto LOOP  
;
LOOP2 ; Este LOOP se utiliza para las horas después de trabajar con los minutos o los segundos
 movlw digito3
 movwf FSR   
;
LOOP ; Este LOOP se utiliza primero para los minutos o los segundos y después para las horas
 movlw D'10'   ; Averiguar cuantas "decenas" hay en el número
 subwf INDF,F   ; En cada LOOP restar 10 al número
 btfsc STATUS,C        ; Se comprueba "C", que se pone a 1 si en la resta no se ha
       ; producido llevada
 goto INC_DECENAS    ; C = 1 por lo que se añade 1 a la posición de las decenas
 addwf INDF,F   ; C = 0, no se incrementan las decenas y se suma 10 para restaurar
       ; las unidades
 goto PROX_NUM
;
INC_DECENAS
 incf FSR,F  ; El puntero apunta a la primera posición de las decenas
 incf INDF,F  ; Se añade 1 a las decenas
 decf FSR,F    ; Se restaura el valor de INDF para apuntar al número
 goto    LOOP  ; para la próxima resta hasta que se termine
      ; Con "goto LOOP" se vuelve a comprobar si es necesario
      ; sumar uno a la decena cada vez que esta se ha incrementado
;
PROX_NUM ; Próximo número, primero ha sido segundos o minutos y luego horas
 decfsz conta1,F
 goto LOOP2
;
CONVER_COD_7S ; Convierte cada dígito a código 7 segmentos para los displays
 movlw digito1 
 movwf FSR  ; Coloca la dirección del primer digito (digito1) en FSR
 movlw H'04'
 movwf conta1 ; Prepara la variable conta1 para el bucle de los 4 displays
;
PROX_DIGITO
 movf INDF,W  ; Obtener el valor de la variable "digito" actual
 call CODIGO_7S ; LLamar a la rutina de conversión a código 7 segmentos
 movwf INDF  ; Colocar en la variable "digito" el código 7 segmentos devuelto
 incf FSR,F  ; Incremente INDF para el próximo "digito"
 decfsz conta1,F ; Permitir que conta1 de sólo 4 vueltas
 goto PROX_DIGITO
;
BORRAR_CERO  ; Si hay un cero en el display de las decenas de hora
    ; no se muestra (borrado de los ceros a la izquierda)
 movlw CERO
 subwf digito4,W
 btfss STATUS,Z
 goto BORRAR_CERO_SEG
 ;movlw SEGM_OFF ;         =================================================
 movlw CERO ; EDITADO =================================================
 movwf digito4
;
BORRAR_CERO_SEG
 btfss banderas,PSEG ; Si está pulsado PSEG no se muestra nada en el display de la
 goto DISPLAY_PUL  ; posición de la unidad de hora.
 movlw SEGM_OFF  ; Contando con BORRAR_CERO, esto significa que sólo se
 ;movlw CERO ; EDITADO =================================================
 movwf digito3   ; mostrarán los segundos.
 movwf digito4   ; ====== EDITADO ======.
;
DISPLAY_PUL  ; 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"
    ; Muestra los dígitos correspondientes a los segundos o a
    ; los minutos y horas en el display que corresponda.
;
 movlw B'00000000'
 movwf banderas ; Se borran los bits de flag para actualizar su estado
;
 ; Apagar los displays
 movlw DSPOFF
 movwf PORTA  
;
 ; Apagar los segmentos respetando separador horas-minutos
 movlw SEGM_OFF ; Respeta valor RB0
 xorwf PORTB, w
 andlw B'11111110' ;  Poner "1" el la posición del bit a copiar
 xorwf PORTB, f
;
 ; Configurar los bits 1, 2 y 3 de PORTB como entrada
 bsf  STATUS,RP0 ; Activa el banco 1.
 movlw PULSADOR
 movwf TRISB  ; Se configuran los bits 1, 2 y 3 de PORTB como entrada
 bcf  STATUS,RP0 ; Activa el banco 0.
 nop  ; Las instrucciones "nop" pueden no ser necesarias.
 nop  ; En principio proporcionan el tiempo suficiente para que los
 nop  ; estados anteriores de las salidas se actualicen a través de
 nop  ; las resistencias de 10K (y de las de 820 ohm si está activado
 nop  ; algún pulsador) antes de leer las patillas del puerto.
;
COMPROBAR_PSEG ; Se comprueba Pulsador PSEG
 btfss PORTB,1
 goto COMPROBAR_PMIN
 bsf  banderas,CHG
 bsf  banderas,PSEG
 bsf  banderas,P_ON
;
COMPROBAR_PMIN ; Se comprueba Pulsador PMIN
 btfss PORTB,2
 goto COMPROBAR_PHOR
 bsf  banderas,CHG
 bsf  banderas,PMIN
 bsf  banderas,P_ON
;
COMPROBAR_PHOR ; Se comprueba Pulsador PHOR
 btfss PORTB,3
 goto ACTIVAR_SEGM
 bsf  banderas,CHG
 bsf  banderas,PHOR
 bsf  banderas,P_ON
;
ACTIVAR_SEGM ; Se coloca en PORTB el valor para los segmentos del display actual
 bsf  STATUS,RP0 ; Activa el banco 1.
 movlw H'00'
 movwf TRISB  ; Puerto B como salida
 bcf  STATUS,RP0 ; Activa el banco 0.
;
 ; Se determina que display debe actualizarse, es decir, que dato debe
 ; presentarse en el puerto B y se establece el siguiente display
 btfss display,0 ; Si es el primer display (decena de hora) tomar digito4
 movf digito4,W
 btfss display,1 ; Si es el segundo display (unidad de hora) tomar valor digito3
 movf digito3,W
 btfss display,2 ; Si es el tercer display (decena de min/seg) tomar valor digito2
 movf digito2,W
 btfss display,3 ; Si es el cuarto display (unidad de min/seg) tomar valor digito1
 movf digito1,W
;
 ; Entregar el valor en puerto B y respetar valor RB0
 xorwf PORTB, w
 andlw B'11111110' ;  Poner "1" el la posición del bit a copiar
 xorwf PORTB, f
;
 btfsc frac_sec,7 ; Establecer el separador de horas y minutos a un 50% 
 bcf  PORTB,0  ; del ciclo (1/2 segundo encendido, 1/2 segundo apagado)
;
 movf display,W ; Tomar el valor del display que debe habilitarse
 movwf PORTA  ; Cada display se “enciende” con una cadencia de 244 Hz / 4 = 61 Hz   
 ; Cada display se “enciende” con una cadencia de 244 Hz / 4 = 61 Hz   
 ; En este momento están encendidos los segmentos correspondientes
;
 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 necesario)
 btfss display,4 ; Comprueba si el último display fue actualizado
 bcf  display,0 ; Si lo fue, se vuelve a habilitar el primer display
      ; La variable display va cambiando:
      ; 1111 1101
      ; 1111 1011
      ; 1111 0111
      ; 1110 1110
      ; 1101 1101
      ; 1011 1011
      ; 0111 0111
      ; 1110 1110
      ; Sólo valen los 4 bits menos significativos
;
 goto    PRINCIPAL ; Volver a realizar todo el proceso
;
    END