;*****************************************************
; Cronomêtro 999 - Conta 999 minutos ou 999 segundos
; Desenvolvido por Márcio José Soares
; Revista Eletrônica Total - 104
; http://www.eletronicatotal.com.br
;
; Microcontrolador: PIC16F628A
; Compilador: MPASM
; IDE: MPLAB 7.0
;
;*****************************************************

		radix dec					;padrao->valores decimal se nao informado outro
		include <P16F628A.INC>		;inclue arquivo

	__CONFIG _LVP_OFF & _MCLRE_ON & _BODEN_OFF & _CP_OFF & _PWRTE_OFF &  _WDT_OFF & _INTOSC_OSC_NOCLKOUT  ;configura bits

;*****************************************************
;* Definições
;*****************************************************

#DEFINE bank0	BCF	STATUS,RP0	;seta banco 0 da memória
#DEFINE bank1	BSF	STATUS,RP0	;seta banco 1 da memória

PICRES      equ 0x00		;endereço de reset
PICRAM		equ 0x20		;começo da RAM
PICINT		equ	0x04		;endereço das ints

DISPLAY		equ	PORTB		;endereço do display (dados)
CTRL_DISP	equ	PORTA		;endereço da porta de controle (catodos) do display
DISP1		equ	0x02		;bit na porta A que controla o catodo do display 1
DISP2		equ	0x01		;bit na porta A que controla o catodo do display 2
DISP3		equ	0x00		;bit na porta A que controla o catodo do display 3

BEEP		equ	0x03		;bit na porta A que controla o buzzer

CHAVES		equ	PORTA		;endereço das chaves
CHV2		equ	0x06		;bit na porta A que controla chave programa
CHV3		equ	0x07		;bit na porta A que controla chave minutos/segundos

PORTBEEP	equ	PORTA		;porta do beep
PORTLED		equ	PORTA		;porta do LED
LED			equ	0x04		;bit do led igado na porta A

							;flags (bits) para MEU_FLAG
LED_FLG		equ	0x00		;bit para controle de LED aceso
MINSEG		equ	0x01		;bit para determinar minuto/segundo	(1-minuto, 0 segundo)
SETCFG		equ	0x02		;bit que informa configuração do tempo em andamento
EEPROM		equ	0X03		;bit que informa se há dados na EEPROM (1 - dados, 0 - sem dados)

;*****************************************************
;* Variáveis
;*****************************************************
		org	PICRAM			;inicio da RAM
CHAR		res	1			;variavel para caracter
TEMP		res	1			;variavel de uso geral

T1			res	1			;variáveis para uso na temporização
T2			res	1			;espera ocupada
T3			res	1
T4			res	1

VAR1		res	1			;variáveis para display 1
VAR2		res	1			;2
VAR3		res	1			;3 (valores de 0 a 9)

VAR1_1		res 1			;variáveis onde sera guardado
VAR2_1		res	1			;o tempo desejado, em minutos ou segundos
VAR3_1		res	1			;valores de 0 a 9

VAR_AUX		res	1			;variável auxiliar
MEU_FLG		res	1			;variável para meus flags

INT_60		res 1			;variável para contar interrupções
MIN			res	1			;variável utilizada apenas para contagem em minutos

W2			res 1			;variáveis backup para salvar contexto
PCLATH2		res	1			;durante uma INT
STATUS2		res	1			;

ADRR		res	1			;endereço para escrita/leitura na EEPROM
DADO		res	1			;dado para escrita/leitura na EEPROM

TEMPO		res	1			;variável para contar tempo de 3 segundos
							;ao final da entrada de dados

;**************************************************************
;*define memoria de programa e vetor de reset
;**************************************************************

	org     PICRES      	;reset
meureset:
    goto    config_pic      	;desvia do endereco 0x04 - interrupcao

;**************************************************************
;* endereço e rotina de interrupção
;**************************************************************
    org     PICINT         	;toda interrupção aponta para este endereço
minhaint:
	movwf	W2				;salva W, STATUS e PCLATH
	swapf	STATUS,W		;
	movwf	STATUS2			;
	movf	PCLATH,W		;
	movwf	PCLATH2			;
	clrf	PCLATH			;limpa PCLATH
	clrf	STATUS			;limpa status

IntRB0:
	btfss 	INTCON,INTF		;interrupção em RB0?
	goto	OutraInt		;não, então checa outra
	bcf		INTCON,GIE		;desabilita INTs
	bcf		INTCON,INTF		;limpa registro de interrupção
	call	conta			;conta int
	goto	IntEnd			;fim das interrupções

OutraInt:
	goto	$+1

IntEnd:
	movf	PCLATH2,W		;lê PCLATH2
	movwf	PCLATH			;restaura PCLATH com PCLATH2
	swapf	STATUS2,W		;
	movwf	STATUS			;restaura STATUS
	swapf	W2,F			;
	swapf	W2,W			;restaura W
    retfie              	;retorno de interrupção

;
;**************************************************************
;* inicio do programa
;**************************************************************
config_pic:

	movlw   0x00        	;ajuste para os bits INTCON
    movwf   INTCON
        
	clrf	PORTA			;limpa portas
 	clrf	PORTB

    bank1			    	;seleciona banco 1 para options e tris
    movlw   b'11100000' 	;ajusta os bits RA5, RA6 e RA7 como entrada. 
    movwf   TRISA			;O resto é saída
    movlw   0x01        	;ajusta os bits em B como saida. Apenas RB0 eh entrada
    movwf   TRISB			;
    bank0               	;volta ao banco 0... (padrão do reset)

	movlw	0x07			;desliga os comparadores internos
	movwf	CMCON

	bsf	INTCON,INTE			;habilita int em RB0

	bank1	
	bsf	OPTION_REG,INTEDG 	;interrupçao na transiçao 1->0
	bank0

	clrf	INT_60			;limpa variáveis importantes
	clrf	VAR1
	clrf	VAR2
	clrf	VAR3
	clrf	MEU_FLG
	clrf	TEMPO
	clrf	MIN

	call	minuto_segundo	;verifica se contagem será em minutos ou segundos
	call	le_dados		;lê valores inserido na EEPROM (três posições)
	call	_1000ms			;temporiza para iniciar

	btfsc	MEU_FLG,EEPROM	;tinha dados na EEPROM?!
	bsf		INTCON,GIE		;sim, então habilita interrupçoes (Global)
	
;
;**************************************************************
;* loop principal
;**************************************************************
loop:
	call	mostra_disp		;mostra valores
	call	ve_chave		;verifica se existe chave pressionada
	goto 	loop			;aguarda tecla ou INT sempre

;
;**************************************************************
;* verifica se conta em minutos ou segundos 
;**************************************************************
minuto_segundo:
	btfss	PORTA,CHV3		;testa tecla 3 - minutos/segundos
	goto	eh_segundo		;seta contagem em segundos
	goto	eh_minuto		;seta contagem em minutos
eh_segundo:
	bcf		MEU_FLG,MINSEG	;limpa flag
	goto	fim_minseg		;desvia
eh_minuto:
	bsf		MEU_FLG,MINSEG	;seta flag
fim_minseg:
	return

;
;**************************************************************
;* vê chave - verifica se a chave de programação foi pressionada
;**************************************************************
ve_chave:
	btfss	PORTA,CHV2		;testa tecla 2 - programa
	goto	ve_tecla2		;verifica se tecla 1 pressionada
	goto	fim_teclas		;retorna
ve_tecla2:
	btfsc	MEU_FLG,SETCFG	;testa se já iniciou a configuração
	goto	evita_repiq
	call	_1000ms			;aguarda 2 segundos
	call	_1000ms
evita_repiq:
	call	_200ms			;aguarda 300ms
	call	_100ms
	btfss	PORTA,CHV2		;testa tecla 2 novamente - evita repique
	goto	seta_valor		;verifica se tecla 1 pressionada
	goto	fim_teclas		;retorna
fim_teclas:
	btfss	MEU_FLG,SETCFG	;testa se iniciou a configuração
	return					;retorna
	movf	TEMPO,W			;carrega contagem do tempo (3 segundos máximos)
	xorlw	0x96			;compara com 150
	btfss	STATUS,Z		;é igual
	goto	fim_soma		;não... apenas temporiza e incrementa
	call	grava			;grava valor presente no display
	call	pisca			;pisca display e trava!
fim_soma:
	call	_20ms			;0,02 x 150 = 3 segundos
	incf	TEMPO,F			;incrementa tempo
	return

;
;**************************************************************
;* seta valor - permite setar um valor para contagem
;**************************************************************
seta_valor:

	btfsc	MEU_FLG,SETCFG	;testa se inicio da configuração
	goto	seta1			;configuração iniciada anteriormente
	bcf		INTCON,GIE		;desliga ints
	clrf	VAR1			;limpa variáveis do display
	clrf	VAR2
	clrf	VAR3
	bsf		MEU_FLG,SETCFG	;avisa que configuração começou

seta1:
	movf	VAR1,W			;prepara para comparar
	xorlw	0x09			;com valor máximo para cada uma
	btfsc	STATUS,Z		;valor máximo?
	goto	seta2			;sim, continua incremento na próxima
	incf	VAR1,F			;incrementa variável
	goto	fim_seta		;não, desvia e continua

seta2:
	clrf	VAR1			;limpa variável 1
	movf	VAR2,W			;prepara para comparar
	xorlw	0x09			;com valor máximo para cada uma
	btfsc	STATUS,Z		;valor máximo?
	goto	seta3			;sim, continua incremento na próxima
	incf	VAR2,F			;incrementa variável
	goto	fim_seta		;não, desvia e continua

seta3:
	clrf	VAR2			;limpa variável 2
	movf	VAR3,W			;prepara para comparar
	xorlw	0x09			;com valor máximo para cada uma
	btfsc	STATUS,Z		;valor máximo?
	goto	seta4			;sim, vira tudo e zera!!!
	incf	VAR3,F			;incrementa variável
	goto	fim_seta		;não, desvia e continua

seta4:
	clrf	VAR1			;limpa variáveis do display
	clrf	VAR2
	clrf	VAR3

fim_seta:
	return					;volta
	
;****************************************************************
; subrotina - mostra display
;*****************************************************************
mostra_disp:
	movf	VAR1,W			;pega valor display 1
	movwf	VAR_AUX			;salva na variável auxiliar
	call	prep_ret		;prepara valor de retorno
	movwf	DISPLAY			;coloca valor no display
	bsf		CTRL_DISP,DISP1	;ativa catodo do display
	call	_5ms			;temporiza
	bcf		CTRL_DISP,DISP1	;desliga catodo 

	movf	VAR2,W			;pega valor display 2
	movwf	VAR_AUX			;salva na variável auxiliar
	call	prep_ret		;prepara valor de retorno
	movwf	DISPLAY			;coloca valor no display
	bsf		CTRL_DISP,DISP2	;ativa catodo do display
	call	_5ms			;temporiza
	bcf		CTRL_DISP,DISP2	;desliga catodo 

	movf	VAR3,W			;pega valor display 3
	movwf	VAR_AUX			;salva na variável auxiliar
	call	prep_ret		;prepara valor de retorno
	movwf	DISPLAY			;coloca valor no display
	bsf		CTRL_DISP,DISP3	;ativa catodo do display
	call	_5ms			;temporiza
	bcf		CTRL_DISP,DISP3	;desliga catodo

fimmostra:
	return

;****************************************************************
; subrotina - prepara retorno do display
;
; Entrada - valor decimal
; Saida   - valor adaptado para 7 segmento
;****************************************************************
prep_ret:
	movf	VAR_AUX,W		;coloca variavel auxiliar em W
	addwf	PCL,F			;soma W a PCL
	retlw	B'01111110'		; 00 no display
	retlw	B'00011000'		; 01 no display
	retlw	B'10110110'		; 02 no display
	retlw	B'10111100'		; 03 no display
	retlw	B'11011000'		; 04 no display
	retlw	B'11101100'		; 05 no display
	retlw	B'11101110'		; 06 no display
	retlw	B'00111000'		; 07 no display
	retlw	B'11111110'		; 08 no display
	retlw	B'11111000'		; 09 no display

	retlw	0x00			; erro retorna 0
	retlw	0x00			; erro retorna 0
	retlw	0x00			; erro retorna 0
	retlw	0x00			; erro retorna 0
	retlw	0x00			; erro retorna 0
	retlw	0x00			; erro retorna 0
	
	clrf	VAR_AUX			; apenas previne erro de desvio no PCL
	return

;*********************************************************
; Conta - conta numero de ints
;
; Preparada para contar segundos ou minutos
;*********************************************************
conta:
	incf	INT_60,F		;incrementa: cada 60 pulsos 1 segundo
	movf	INT_60,W		;move para W
	xorlw	0x1E			;compara com 30
	btfss	STATUS,Z		;continua contagem
	goto	conta2

	btfss	MEU_FLG,MINSEG	;testa para saber se minuto ou segundo
	call	inverte_led		;pisca o led se segundo

conta2:
	movf	INT_60,W		;move 1/60 para W
	xorlw	0x3C			;compara com 60
	btfss	STATUS,Z		;
	goto	fim_conta		;menor, apenas volta
	movlw	0x00			;zera 1/60 SEG
	movwf	INT_60
	call	inverte_led		;pisca led se segundo ou minuto

	btfss	MEU_FLG,MINSEG	;contagem em minutos ou segundos?
	goto	decvar1			;em segundos
	incf	MIN,F			;incrementa contagem em minutos
	movf	MIN,W			;em minutos, verifica se 60 (1s x 60 = 1 minuto)
	xorlw	0x3C			;compara
	btfss	STATUS,Z	
	goto	fim_conta		;ainda não
	clrf	MIN				;limpa registro e atualiza display

decvar1:
	decf	VAR1,F			;decrementa primeiro digito
	
;*****************************************************
; prepara para comparar todas com zero
;*****************************************************
	movf	VAR1,W			;move para W
	xorlw	0x00			;compara com zero
	btfss	STATUS,Z		;testa
	goto	contdecv1		;continua decremento
	movf	VAR2,W			;
	xorlw	0x00			;compara com zero
	btfss	STATUS,Z		;testa
	goto	contdecv1		;continua decremento
	movf	VAR3,W			;
	xorlw	0x00			;compara com zero
	btfss	STATUS,Z		;testa
	goto	contdecv1		;continua decremento
	goto	decvar3			;todos zero; hora de finalizar

contdecv1:
	movf	VAR1,W			;move para W
	xorlw	0xFF			;compara com FF para ver se virou
	btfss	STATUS,Z		;
	goto	fim_conta		;não, apenas volta
	movlw	0x09			;sim, VAR1 = 9
	movwf	VAR1

decvar2:
	decf	VAR2,F			;decrementa segundo digito
	movf	VAR2,W			;move para W
	xorlw	0xFF			;compara com FF para ver se virou
	btfss	STATUS,Z		;
	goto	fim_conta		;não, apenas volta
	movlw	0x09			;sim, VAR2 = 9
	movwf	VAR2

decvar3:
	decf	VAR3,F			;decrementa segundo digito
	movf	VAR3,W			;move para W
	xorlw	0xFF			;compara com FF para ver se virou
	btfss	STATUS,Z		;
	goto	fim_conta		;não, apenas retorna
	bcf		INTCON,GIE		;sim, desabilita ints
	call 	buzzer			;toca beep avisando final da contagem

fim_conta:
	return

;*********************************************************
; Inverte_led - inverte o estado do LED a cada 1 segundo
;*********************************************************
inverte_led:
	btfsc	MEU_FLG,LED_FLG		;testa flag
	goto	desliga_led			;liga led

liga_led:
	bsf		MEU_FLG,LED_FLG		;liga led
	bsf		PORTLED,LED
	goto	fim_inverte

desliga_led:
	bcf		MEU_FLG,LED_FLG		;desliga led
	bcf		PORTLED,LED

fim_inverte:
	return						;volta

;*********************************************************
; rotina para ler dados da EEPROM
;*********************************************************
le_dados:
	movlw	0x01				;prepara para ler posição 1
	movwf	ADRR
	call	le_EEPROM			;lê dado
	movf	DADO,W				;pega dado lido
	xorlw	0xFF				;verifica se tinha algo
	btfss	STATUS,Z			;
	goto	$+2					;tinha dado, continua
	goto	fim_dados
	movf	DADO,W
	movwf	VAR3				;carrega variável na posição

	movlw	0x02				;prepara para ler posição 2
	movwf	ADRR
	call	le_EEPROM			;lê dado
	movf	DADO,W				;pega dado lido
	xorlw	0xFF				;verifica se tinha algo
	btfss	STATUS,Z			;
	goto	$+2					;tinha dado, continua
	goto	fim_dados
	movf	DADO,W
	movwf	VAR2				;carrega variável na posição

	movlw	0x03				;prepara para ler posição 3
	movwf	ADRR
	call	le_EEPROM			;lê dado
	movf	DADO,W				;pega dado lido
	xorlw	0xFF				;verifica se tinha algo
	btfss	STATUS,Z			;
	goto	$+2					;tinha dado, continua
	goto	fim_dados
	movf	DADO,W
	movwf	VAR1				;carrega variável na posição

	bsf		MEU_FLG,EEPROM		;avisa que tem dado

fim_dados:
	return						;apenas retorna

;*********************************************************
; rotina para gravar dados da EEPROM
;*********************************************************
grava:
	movlw	0x01				;primeira posição de memória
	movwf	ADRR
	movf	VAR3,W				;dado a ser gravado na posição
	movwf	DADO
	call	grava_EEPROM		;grava dado

	movlw	0x02				;segunda posição de memória
	movwf	ADRR
	movf	VAR2,W				;dado a ser gravado na posição
	movwf	DADO
	call	grava_EEPROM		;grava dado
		
	movlw	0x03				;terceira posição de memória
	movwf	ADRR
	movf	VAR1,W				;dado a ser gravado na posição
	movwf	DADO
	call	grava_EEPROM		;grava dado

	return						;volta

;*******************************************************************
; Le byte na EEPROM
; em ADRR endereço na EEPROM                                           
; em DADO byte encontrado na posição de memória
;*******************************************************************
le_EEPROM:
	bank0						;volta ao banco 0
	movf	ADRR,W				;pega qual endereço deve ler
	bank1						;vai para banco 1						
	movwf	EEADR				;carrega endereço a ser lido
	bsf		EECON1,RD			;habilita leitura
	movf	EEDATA,W			;carrega W com byte lido da memória EEPROM
	bank0						;volta para banco 0
	movwf	DADO				;carrega variável para consulta posterior
	return

;*******************************************************************
; Grava byte na EEPROM
; em DADO byte a ser gravado
; em ADRR endereço na EEPROM                                           
;*******************************************************************
grava_EEPROM:
	bank0						;volta ao banco 0
	movf	ADRR,W				;carrega endereço em W
	bank1						;vai para banco 1
	movwf	EEADR				;carrega registrador
	bank0						;volta ao banco 0
	movf	DADO,W				;carrega em W dado a escrever
	bank1						;vai para banco 1
	movwf	EEDATA				;carrega registrador
	bcf		INTCON,GIE			;desabilita ints
	bsf		EECON1,WREN			;habilita a escrita
	movlw	0x55				
	movwf	EECON2				;escreve 0x55 em EECON2 (obrigatório)
	movlw	0xAA	
	movwf	EECON2				;escreve 0xAA em EECON2	(obrigatório)
	bsf		EECON1,WR			;inicia a escrita
	bcf		EECON1,WREN			;desabilita escrita
	btfsc	EECON1,WR			;verifica se escreveu
	goto	$-1
	bank0						;volta ao banco 0 antes de retornar
	return						;volta para quem chamou

;*********************************************************
; rotina para fazer o display piscar
; ao entrar nesta subrotina
; o microcontrolador trava aqui (não ha retorno da mesma)
;*********************************************************
pisca:
	bsf		PORTLED,LED		;apaga LED
	clrf	TEMPO
pisca1:
	incf	TEMPO,F			;incrementa tempo
	movf	VAR1,W			;pega valor display 1
	movwf	VAR_AUX			;salva na variável auxiliar
	call	prep_ret		;prepara valor de retorno
	movwf	DISPLAY			;coloca valor no display
	bsf		CTRL_DISP,DISP1	;ativa catodo do display
	call	_5ms			;temporiza
	bcf		CTRL_DISP,DISP1	;desliga catodo 

	movf	VAR2,W			;pega valor display 2
	movwf	VAR_AUX			;salva na variável auxiliar
	call	prep_ret		;prepara valor de retorno
	movwf	DISPLAY			;coloca valor no display
	bsf		CTRL_DISP,DISP2	;ativa catodo do display
	call	_5ms			;temporiza
	bcf		CTRL_DISP,DISP2	;desliga catodo 

	movf	VAR3,W			;pega valor display 3
	movwf	VAR_AUX			;salva na variável auxiliar
	call	prep_ret		;prepara valor de retorno
	movwf	DISPLAY			;coloca valor no display
	bsf		CTRL_DISP,DISP3	;ativa catodo do display
	call	_5ms			;temporiza
	bcf		CTRL_DISP,DISP3	;desliga catodo

	movf	TEMPO,W			;carrega variável
	xorlw	0x43			;compara com 67 (67 x 0,015 = 1 segundo)
	btfss	STATUS,Z		;é igual
	goto	pisca1			;não... continua acesso
	call	_1000ms			;é... aguarda 1 segundo apagado
	goto	pisca			;e volta novamente

;*********************************************************
; rotina para tocar beep
; ao entrar nesta subrotina
; o microcontrolador trava aqui (não ha retorno da mesma)
;*********************************************************
buzzer:
	clrf	VAR1			;faz todas VAR = 0
	clrf	VAR2
	clrf	VAR3
	bsf		PORTLED,LED		;apaga LED
	clrf	TEMPO			;zera variável
buzzer1:
	incf	TEMPO,F
	bsf		CTRL_DISP,DISP1	;liga catodo disp1
	bsf		PORTBEEP,BEEP	;liga beep
	call	_1ms			;aguarda 1 ms
	bcf		PORTBEEP,BEEP	;desliga beep
	call	_1ms			;aguarda 1 ms
	bcf		CTRL_DISP,DISP1	;desliga catodo disp1

	bsf		CTRL_DISP,DISP2	;liga catodo disp2
	bsf		PORTBEEP,BEEP	;liga beep
	call	_1ms			;aguarda 1 ms
	bcf		PORTBEEP,BEEP	;desliga beep
	call	_1ms			;aguarda 1ms
	bcf		CTRL_DISP,DISP2	;desliga catodo disp2
	
	bsf		CTRL_DISP,DISP3	;liga catodo disp3
	bsf		PORTBEEP,BEEP	;liga beep
	call	_1ms			;aguarda 1 ms
	bcf		PORTBEEP,BEEP	;desliga beep
	call	_1ms			;aguarda 1 ms
	bcf		CTRL_DISP,DISP3	;desliga catodo disp3

	movf	TEMPO,W			;carrega variável
	xorlw	0xA7			;compara com 167 (167 x 0,06 = 1 segundo)
	btfss	STATUS,Z		;é igual
	goto	buzzer1			;não... continua beep
	call	_1000ms			;é... aguarda 1 segundo apagado e beep no silêncio
	goto	buzzer			;faz novamente
	

;*********************************************************
; rotinas de temporização
;*********************************************************
_1ms:
    movlw   0x02               	;carrega W com 01
	movwf	T1					;carrega T1 com W
	movlw	0x00				;carrega T4 com 0
	movwf	T4
	goto	car_1

_5ms:
    movlw   0x06              	;carrega W com 06
	movwf	T1					;carrega T1 com W
	movlw	0x00				;carrega T4 com 0
	movwf	T4
	goto	car_1

_10ms:
    movlw   0x0C              	;carrega W com 12
	movwf	T1					;carrega T1 com W
	movlw	0x00				;carrega T4 com 0
	movwf	T4
	goto	car_1

_20ms:
    movlw   0x18      	       	;carrega W com 24
	movwf	T1					;carrega T1 com W
	movlw	0x00				;carrega T4 com 0
	movwf	T4
	goto	car_1

_30ms:
   	movlw   0x24  	           	;carrega W com 36
	movwf	T1					;carrega T1 com W
	movlw	0x00				;carrega T4 com 0
	movwf	T4
	goto	car_1

_100ms:
    movlw   0x2B                ;carrega W com 43
	movwf	T1					;carrega T1 com W
	movlw	0x00				;carrega T4 com 0
	movwf	T4
	goto	car_1

_200ms:
    movlw   0x56                ;carrega W com 86
	movwf	T1					;carrega T1 com W
	movlw	0x00				;carrega T4 com 0
	movwf	T4
	goto	car_1

;aguarda 1 segundo com clock de 4MHz
_1000ms:
	movlw	0x06				;carrega W com 6
	movwf	T3					;carrega T3 com 6
	movlw	0x01				;carrega T4 com 1
	movwf	T4
	
car:
    movlw   0xff	            ;carrega W com 255
	movwf	T1					;carrega T1 com W
	btfsc	T4,0				;testa bit 0 de T4
	decfsz	T3,F				;decrementa T3
	goto 	car_1
	return

car_1:
    movlw   0xFF               	;carrega W com 255
	movwf	T2					;carrega T2 com 255
dec_1:
	decfsz 	T2,1				;decrementa T2
	goto	dec_1				;255 x T1 vezes
	decfsz 	T1,1				;decrementa T1
	goto 	car_1				;volta a carregar T2
	btfsc	T4,0				;testa bit 0 de T4
	goto	car					;retorna 0 em W
	return

;****************************************************************
; fim do programa
;****************************************************************
	end
