;Contador de 4 digitos con displays de 7 segmentos
;Se utilizan los ocho pines del puerto B para manejar el display
;y los cinco del puerto a para controlar el sistema

indir	equ	0x00		;Registro de direccionamiento indirecto
estado	equ	0x03		;Registro de estados
puntero	equ	0x04		;Puntero de direccionamiento indirecto
ptoa	equ	0x05		;Puerto A
ptob	equ	0x06		;Puerto B
loop1	equ	0x10		;Utilizados para las demoras
loop2	equ	0x11
loop3	equ	0x12
disp	equ	0x13		;Indicador de display activo
dig1	equ	0x14		;Acumuladores de conteo
dig2	equ	0x15
dig3	equ	0x16
dig4	equ	0x17

#define	Carry	estado, 0	;Define el flag Carry
#define	Zero	estado, 2	;Define el flag Zero
#define RP0	estado, 5	;Define el bit selector de pagina
#define	Jump1	ptoa, 0		;Jumper 1 para seleccion de tiempo del anti rebote
#define	Jump2	ptoa, 1		;Jumper 2 para seleccion de tiempo del anti rebote
#define	SelAR	ptoa, 2		;Entrada de seleccion de anti rebote
#define	EntA	ptoa, 3		;Entrada de disparo por flanco ascendente
#define EntD	ptoa, 4		;Entrada de disparo por flanco descendente

	bsf	RP0		;Configura los puertos
	movlw	0x00		;Puerto B completo como salidas
	movwf	ptob
	movlw	0x1f		;Puerto A completo como entradas
	movwf	ptoa
	bcf	RP0

	clrf	dig1		;Inicializa los acumuladores
	clrf	dig2
	clrf	dig3
	clrf	dig4
	clrf	ptob		;Apaga los cuatro digitos

ciclo	btfss	EntD		;Bajo la linea de disparo por flanco descendente ?
	call	increm		;Incrementa en uno la cuenta
	btfsc	EntA		;Subio la linea de disparo por flanco ascendente ?
	call	increm		;Incrementa en uno la cuenta
	call	display		;Muestra la cuenta en los displays
	goto	ciclo

increm	incf	dig1, 1		;Incrementa la cuenta de unidades
	movf	dig1, 0		;Carga en W la cuenta de unidades
	sublw	d'10'		;Le resta 10 para ver si tiene que acarrear
	btfsc	Zero		;Si el indicador de cero esta bajo no acarrea
	call	mas10		;Ejecuta la rutina de acarreo
	btfss	SelAR		;Esta en alto el selector de anti rebote ?
	call	ART		;Ejecuta el anti rebote por tiempo
	btfsc	SelAR		;Esta en bajo el selector de anti rebote ?
	call	ARLR		;Ejecuta el anti rebote por linea en reposo
	return

ART	movlw	d'25'		;W arranca con 25
	btfss	Jump1		;Debe agregar 25 a W ?
	addlw	d'25'		;Le agrega 25 a W si corresponde
	btfss	Jump2		;Debe agregar 100 a W ?
	addlw	d'100'		;Le agrega 100 a W si corresponde
	movwf	loop3
	call	display
	decfsz	loop3, 1
	goto	$ - 2
	return

ARLR	call	display		;Muestra la cuenta en los displays
	btfss	EntD		;Espera que vuelva al estado de reposo la linea
	goto	$ - 2
	call	display		;Muestra la cuenta en los displays
	btfsc	EntA		;Espera que vuelva al estado de reposo la linea
	goto	$ - 2
	return

mas10	clrf	dig1		;Pone a cero el contador de unidades
	incf	dig2, 1		;Incrementa el contador de decenas
	movf	dig2, 0		;Carga en W la cuenta de decenas
	sublw	d'10'		;Le resta 10 para ver si tiene que acarrear
	btfsc	Zero		;Si el indicador de cero esta bajo no acarrea
	call	mas100		;Ejecuta la rutina de acarreo
	return

mas100	clrf	dig2		;Pone a cero el contador de decenas
	incf	dig3, 1		;Incrementa el contador de centenas
	movf	dig3, 0		;Carga en W la cuenta de centenas
	sublw	d'10'		;Le resta 10 para ver si tiene que acarrear
	btfsc	Zero		;Si el indicador de cero esta bajo no acarrea
	call	mas1000		;Ejecuta la rutina de acarreo
	return

mas1000	clrf	dig3		;Pone a cero el contador de centenas
	incf	dig4, 1		;Incrementa el contador de millares
	movf	dig4, 0		;Carga en W la cuenta de millares
	sublw	d'10'		;Le resta 10 para ver si tiene que acarrear
	btfsc	Zero		;Si el indicador de cero esta bajo no acarrea
	clrf	dig4		;Pone en cero el contador de millares
	return

display	movlw	0x01		;iniciar un 1 en el registro de rotacion
	movwf	disp
	movlw	dig1		;Apunta al primer acumulador (unidades)
	movwf	puntero
otro	movf	indir, 0	;Carga en W el contenido de registro apuntado
	movwf	ptob		;Carga eb el puerto B el contenido de W
	btfsc	disp, 0		;Debe encender el display de x1 ?
	bsf	ptob, 4
	btfsc	disp, 1		;Debe encender el display de x10 ?
	bsf	ptob, 5
	btfsc	disp, 2		;Debe encender el display de x100 ?
	bsf	ptob, 6
	btfsc	disp, 3		;Debe encender el display de x1000 ?
	bsf	ptob, 7
	call	delay		;Espera a que los datos se fijen en los leds
	clrf	ptob		;Apaga el display
	btfsc	disp, 3		;Llego al ultimo display ?
	return			;Vuelve al programa principal
	bcf	Carry		;Limpia el carry
	rlf	disp, 1		;Rota a la izquiera el indicador de display
	incf	puntero, 1	;Incrementa en 1 el puntero
	goto	otro

delay	movlw	d'3'		;Rutina de demora de aprox. 3ms
	movwf	loop1
top2	movlw	d'110'
	movwf	loop2
top	nop
	nop
	nop
	nop
	nop
	nop
	decfsz	loop2, 1
	goto	top
	decfsz	loop1, 1
	goto	top2
	return

	end
