; ARCHIVO RTC V4F628.ASM
; CODIGO FUENTE PARA EL MICROCONTROLADOR PIC16F628 
; SE INTRODUCE LA HORA A TRAVES
; DEL TECLADO INTRODUCIENDO LOS DIGITOS EN FORMA CONSECUTIVA
; EL LCD ESCRIBE LA PALABRA "SET:" Y DEBE ESCRIBIRSE 
; CON EL FORMATO (EJEMPLO) 074534
; PARA PONER LA HORA 07:45:34
; (DEBE DARSE ANTES RESET AL MODULO)
; PROGRAMA PARA IMPLEMENTAR UN RELOJ DE TIEMPO REAL MOSTRANDO
; LA HORA, MINUTOS Y SEGUNDOS EN UN DISPLAY LCD DE 16 X 1. 
; SE USO COMO BASE EL PROGRAMA
; "MINUTO.ASM" QUE UNA BASE DE TIEMPO EXACTA DE UN MINUTO
; POR INTERRUPCIONES. 
; SE USA EL TEMPORIZADOR TMR0 Y SU PREESCALADOR PARA GENERAR 
; 65.536 MILISEGUNDOS POR CADA CICLO DE INTERRUPCION.



; VERSION PARA OSCILADOR CRISTAL 4 MHZ

; CPU configuration
; 	(It's a 16F628, XT OSCILADOR
; 	watchdog timer off, power-up timer on)

	processor 16f628
	include	  <p16f628.inc> 

	__config _XT_OSC & _WDT_OFF & _PWRTE_OFF & _MCLRE_ON & _BODEN_OFF & _LVP_OFF 

#DEFINE	BANCO0	BCF	STATUS,RP0
#DEFINE	BANCO1	BSF	STATUS,RP0
#DEFINE	GLOB	INTCON,7			;BANDERA GLOBAL INTERRUPT ENABLE
#DEFINE	TIE	INTCON,5			;BANDERA TMR0 INTERRUPT ENABLE
#DEFINE	TOCS	OPTION_REG,5			;BANDERA PARA USAR CLOK INTERNO EN TMR0
#DEFINE	ZERO	STATUS,2			;BANDERA "Z" EN STATUS
#DEFINE	FLAG	INTCON,2			;BANDERA DE INTERRUPCION DE TEMPO
#DEFINE	RELE	PORTA,0				;BIT DEL RELEVADOR

;localidades de memoria usadas por el RTC

CONT1	EQU	H'20'		;CONTADOR DE CICLOS DE 65.5 MILISEGUNDOS. 
				;15 CICLOS ES APROX. UN SEGUNDO
CONT2	EQU	H'21'		;CONTADOR DE UNIDADES DE SEGUNDOS. 
CONT3	EQU	H'22'		;CONTADOR DECENAS DE SEGUNDOS
CONT4	EQU	H'23'		;CONTADOR UNIDADES DE MINUTO
CONT5	EQU	H'24'		;CONTADOR DECENAS DE MINUTO
CONT6	EQU 	H'25'		;CONTADOR UNIDADES DE HORA
CONT7	EQU 	H'26'		;CONTADOR DECENAS DE HORA
DUMMY	EQU 	H'27'	
DILEY	EQU	H'28'		;CONTADOR DELAY PARA AJUSTE FINO
L	EQU	H'29'		;variable subrutina delay
M	EQU	H'2A'		;variable subrutina delay

;localidades de memoria usadas por el teclado

I		EQU	H'30'		;valor columna (RB0...RB3)
J		EQU	H'31'		;contador 4 rotaciones
K		EQU	H'32'		;valor renglón (RB4..RB7)
P		EQU	H'33'		;variable subrutina delay
Q		EQU	H'34'		;variable subrutina delay
R		EQU	H'35'		;variable para checar tecla liberada
N		EQU H'36'
DIG		EQU H'37'		;LOCALIDAD PARA CONTAR DIGITOS EN SETIME


;valores usados por el LCD

eight		equ	H'38'		
clear		equ	H'01'
home		equ	H'03'
cursor		equ	H'0F'
renglon1	equ 	H'80'
renglon2	equ 	H'C0'

PUERTOS		MACRO		;INICIALIZA PUERTOS A Y B
		MOVLW	H'07'
		MOVWF	CMCON
		BANCO1		;ELIJE EL BANCO 1
		CLRF	VRCON
		MOVLW	H'00'	;RB0..RB7=SALIDAS, RA0...RA4=SALIDAS
		MOVWF	TRISB
		MOVWF	TRISA
		ENDM

LCD		MACRO		;INICIALIZA LCD
		BANCO0
		movlw	eight	;envía 4 comandos
		call 	puco
		movlw	clear
		call 	puco
		movlw	home
		call 	puco
		movlw	cursor
		call 	puco
		movlw	renglon1
		call 	puco
		movlw	renglon2
		call	puco
		ENDM	

;aquí inicia el programa
		org	H'0'
inicio		goto	begin		;salta a inicio del programa

;aquí inicia la subrutina de interrupción

		org 	H'4'		;subrutina de interrupción en la dirección 4				
int		BANCO0			;aquí inicia la subrutina de interrupción
		call	diley		;retraso para ajuste fino del tiempo
		call	diley
		clrf	TMR0
		bcf	FLAG		;apaga bandera de interrupción del TMR0		
		incf	CONT1,f		;incrementa contador de 65.5 ms.
		movlw	D'15'
		subwf	CONT1,w		;prueba si la cuenta es igual a 15
		btfss	ZERO		;bandera Z encendida?
		goto	retfi
seg1		BANCO0	
		incf	PORTB,f		;cuenta segundos en el puerto B
		clrf	CONT1		;CONT1=0
		incf	CONT2,f		;incrementa contador de segundos
		movlw	H'C7'
		call	puco
		movlw	H'30'
		addwf	CONT2,w
		call	verify		;verifica si es '3A'
		call	puda
		movlw	D'10'
		subwf	CONT2,w		;prueba si la cuenta es igual a 9
		btfss	ZERO		;Z = 1 ?
		goto	retfi
seg10		clrf	CONT2	
		incf	CONT3,f	
		movlw	H'C6'
		call	puco
		movlw	H'30'
		addwf	CONT3,w
		call	verify2
		call	puda			
		movlw	D'6'
		subwf	CONT3,w
		btfss	ZERO
		goto	retfi
min1		clrf	CONT3
		incf	CONT4,f
		movlw	H'C4'
		call	puco
		movlw	H'30'
		addwf	CONT4,w
		call	verify
		call	puda
		movlw	D'10'
		subwf	CONT4,w
		btfss	ZERO
		goto	retfi
min10		clrf	CONT4
		incf	CONT5,f
		movlw	H'C3'
		call	puco
		movlw	H'30'
		addwf	CONT5,w
		call	verify2
		call	puda
		movlw	D'6'
		subwf	CONT5,w
		btfss	ZERO
		goto	retfi
hora1		clrf	CONT5
		incf	CONT6,f
		movlw	H'C1'
		call	puco
		movlw	H'30'
		addwf	CONT6,w
		call	verify
		call	puda
		movlw	D'10'
		subwf	CONT6,w
		btfss	ZERO
		goto	retfi	
hora10		clrf	CONT6
		incf	CONT7,f
		movlw	H'C0'
		call	puco
		movlw	H'30'
		addwf	CONT7,w
		call	puda
		goto	retfi	
retfi		bsf	TIE		;reactiva la interrupción
		retfie

ceros		clrf	CONT1		;pone en ceros todos los contadores
		clrf	CONT2
		clrf	CONT3
		clrf	CONT4
		clrf	CONT5
		clrf	CONT6
		clrf	CONT7
		return

hora24		movlw	D'4'		;verifica si llegó a 24:00:00
		subwf	CONT6,w
		btfss	ZERO
		goto	sigue
		movlw	D'2'
		subwf	CONT7,w
		btfss	ZERO
		goto	sigue
		call	ceros
		call	write
		return	

diley		movlw	D'187'		;subrutina de retraso para ajuste fino 187
		movwf	DILEY
malla		decfsz	DILEY
		goto 	malla
		return
verify		movwf	DUMMY
		movlw	H'3A'
		subwf	DUMMY,w
		btfss	ZERO
		goto 	salto2	
		movlw	H'30'
		return
salto2		movfw	DUMMY
		return
verify2		movwf	DUMMY
		movlw	H'36'
		subwf	DUMMY,w
		btfss	ZERO
		goto 	salto3	
		movlw	H'30'
		return
salto3		movfw	DUMMY
		return

;aquí inicia el programa principal

begin	PUERTOS
		LCD
		
		call	setime		;recibe hora del teclado y la pone en contadores
	
		call	write		;escribe contenido de contadores en LCD	
		movlw	B'00000111'	;HABILITA TEMPORIZADOR Y CLOCK INTERNO
					;preescalador divide entre 256
		BANCO1
		movwf	OPTION_REG
		BANCO0
		bcf	RELE		;APAGA RELEVADOR
		clrf	PORTB
		movlw	D'00'
		movwf	TMR0		;INICIALIZA TEMPORIZADOR=00	
		bsf	GLOB		;habilita interrupciones global
		bsf	TIE		;habilita interrupción del temporizador.
		clrf	PORTB
sigue		call	hora24
		goto	sigue

;modifique estos parámetros si desea cambiar la hora de inicio y vuelva a
;aplicar el comando "quickbuild" para ensamblar el programa.


write	movlw	h'c7'		;escribe la hora, contenido de contadores en el LCD
		call	puco
		movlw	h'30'
		addwf	CONT2,w		;convierte a ASCII
		call 	puda
		movlw	h'c6'
		call	puco
		movlw	h'30'
		addwf 	CONT3,w
		call	puda
		movlw	h'c5'
		call	puco
		movlw	':'
		call	puda
		movlw	h'c4'
		call	puco
		movlw	h'30'
		addwf	CONT4,w
		call 	puda
		movlw	h'c3'
		call	puco
		movlw	h'30'
		addwf	CONT5,w
		call 	puda
		movlw	h'c2'
		call	puco
		movlw	':'
		call	puda
		movlw	h'c1'
		call	puco
		movlw	h'30'
		addwf	CONT6,w
		call	puda
		movlw	h'c0'
		call	puco
		movlw	h'30'
		addwf	CONT7,w
		call	puda
		movlw	h'80'
		call 	puco
		movlw	'T'
		call	puda
		movlw	'I'
		call	puda
		movlw	'M'
		call	puda
		movlw	'E'
		call	puda
		return
		
;aquí inician subrutinas para el manejo del LCD

puco		movwf	PORTB		;escribe comando en puertoB
		call 	delay		;50 milisegundos
		movlw	H'04'		;RS=0, EN=1
		movwf	PORTA
		call 	delay
		movlw	H'00'		;RS=0, EN=0
		movwf	PORTA
		call 	delay
		movlw	H'04'
		movwf	PORTA
		call 	delay
		return
puda		movwf	PORTB		;escribe dato en puertoB
		call 	delay		;50 milisegundos
		movlw	H'06'		;RS=1, EN=1
		movwf	PORTA
		call 	delay
		movlw	H'02'		;RS=1, EN=0
		movwf	PORTA
		call 	delay
		movlw	H'06'
		movwf	PORTA
		call 	delay
		return

;aquí inician las subrutinas de retraso

delay		movlw	D'25'		;10 milisegundos
		movwf	M
malla3		movwf	L
malla2		decfsz	L,f
		goto	malla2	
		decfsz	M,f
		goto	malla3
		return	
delay2		movlw	D'250'		;250 milisegundos
		movwf	M
malla5		movwf	L
malla4		decfsz	L,f
		goto	malla4	
		decfsz	M,f
		goto	malla5
		return
delay3		call	delay2		;1 segundo
		call	delay2
		call	delay2

;------------------------------------------------------------------------
;AQUI USUARIO INTRODUCE LA HORA INICIAL DESDE EL TECLADO
;GUARDA LOS DATOS EN CONTADORES
	
setime:	movlw	h'80'
		call 	puco
		movlw	'S'
		call	puda
		movlw	'E'
		call	puda
		movlw	'T'
		call	puda
		movlw	':'
		call	puda
		movlw	h'C0'
		call 	puco
		movlw	6		;inicializa número de dígitos en la hora
		movwf	DIG		;guarda en localidad
		movlw	CONT7	;INICIALIZA PRIMER DIGITO
		movwf	FSR		;direccionamiento indirecto
malla8:	movlw	3		
		movwf	PCLATH	;elije página 3 para tabla			
		BSF	STATUS,RP0	;ELIJE EL BANCO DE REGISTROS ESPECIALES 1
		MOVLW	H'F0'		;RB0..RB3=SALIDAS, RB4...RB7=ENTRADAS
		MOVWF	TRISB
		BCF	OPTION_REG,7	;RB4...RB7 CON RESISTENCIAS DE PULL UP
		BCF	STATUS,RP0	;ELIGE EL BANCO 0
vuelta1:	movlw	H'EF'		;listo para iniciar rotación
		movwf	I
		movwf	PORTB
		movlw	D'4'
		movwf	J		;contador de 4 corrimientos
vuelta2:	rrf	I,f		;rotación de bits RB0..RB3 en puerto B
		movfw	I
		movwf	PORTB
		call	delay		;50 ms
		movfw	PORTB		;lee el puerto B
		iorlw	H'0F'		;conserva solo los bits RB4...RB7
		movwf	K
		comf	K,f
		btfss	STATUS,2	;si la lectura es 0, continúa
		goto	teclazo		;si la lectura diferente de 0, teclazo
		decfsz	J,f
		goto	vuelta2
		goto 	vuelta1
teclazo:	movfw	PORTB		;verifica que tecla haya sido liberada
		iorlw	H'0F'
		movwf	N
		comf	N,f
		btfss	STATUS,2
		goto	teclazo		;continúa en loop si tecla aún oprimida
		BANCO1					
		movlw	H'00'
		movwf	TRISB		;programa bits de puerto B como salidas
		BANCO0
		comf	I,f
		movfw	I		;toma valor salida puerto B
		andlw	H'0F'		;solo los bits RB0...RB3
		movwf	I		;regresa el valor a I
		movf	K,w		;lee localidad con contenido de rotación
		andlw	H'F0'		;solo bits D4...D7
		iorwf	I,f		;suma I y K resultado en I
		movf	I,w		;suma I y K, resultado en W
		movwf	PORTB		;escribe puerto B, CODIGO RENGLON COLUMNA
ide:		movlw	D'17'		;pasa a la parte de identificación
		movwf	K		;K = contador de caracteres en la tabla 
loop:		decf	K,f		;decrementa K
		movf	K,w		;transfiere a W
		call	tabla
		subwf	I,w		;regresa de la tabla con caracter
		btfss	STATUS,2	;si I=caracter, se va a etiqueta "found"
		goto 	loop
found:		movf	K,w
		movwf	PORTB		;muestra en leds contenido de offset.
		movlw	D'16'			
		addwf	K,w		;añade 16 localidades a offset
		call	tabla		;trae valor ASCII en tabla
		movwf	PORTB		;despliega en puerto B
		movwf	I		;guarda caracter ASCII en I
lcd:		movlw	H'00'		;inicia rutina escribir caracter en LCD
		BANCO1			;BANCO 1
		movlw	H'00'
        	movwf	TRISB		;bits de puerto B, salidas
		BANCO0			;BANCO 0	  
		movf	I,w		;prepara caracter en W
		addlw	H'D0'	;RESTA 30H EN COMPLEMENTO A DOS
		movwf	INDF		;guarda dígito en ASCII en contadores
		addlw	H'30'		;suma 30H para conservar código ASCII
		call 	puda		;escribe caracter en LCD
		decf	FSR			;DIRECCIONAMIENTO INDIRECTO DE CONTADOR
		decfsz	DIG,f			;cuenta los dígitos
		goto 	malla8		;va de nuevo a leer teclado
		return			;fin de rutina, continúa con programa

org 300H					;posiciona tabla en página 3
tabla		addwf	PCL,f	
		retlw	H'11'		;'0'AQUI EMPIEZAN CODIGOS RENGLON COLUMNA
		retlw	H'12'		;'1'
		retlw	H'14'		;'2'
		retlw	H'18'		;'3'
		retlw	H'21'		;'4'
		retlw	H'22'		;'5'
		retlw	H'24'		;'6'
		retlw	H'28'		;'7'
		retlw	H'41'		;'8'
		retlw	H'42'		;'9'
		retlw	H'44'		;'A'
		retlw	H'48'		;'B'
		retlw	H'81'		;'C'
		retlw	H'82'		;'D'
		retlw	H'84'		;'E'
		retlw	H'88'		;'F'
		retlw	H'30'		;'0'AQUI EMPIEZAN CODIGOS 
		retlw	H'31'		;'1'
		retlw	H'32'		;'2'
		retlw	H'33'		;'3'
		retlw	H'34'		;'4'
		retlw	H'35'		;'5'
		retlw	H'36'		;'6'
		retlw	H'37'		;'7'
		retlw	H'38'		;'8'
		retlw	H'39'		;'9'
		retlw	H'41'		;'A'
		retlw	H'42'		;'B'
		retlw	H'43'		;'C'
		retlw	H'44'		;'D'
		retlw	H'45'		;'E'
		retlw	H'46'		;'F'
			
		end

			
			
		
	

	



		

