;******************************************************************************************************
;	Proyecto:		PEHXXXX-SIR Sensor Infra-Rojo con PIC.
;	Descripción:	Programa  para generar el tren de pulsos de 38KHz usando TMR0 durante 33 ms cada 333ms.
;	Programa: 		 ||||________||||________||||________
;	PIC:			16F628A a 4 MHz
; 	Revisión:		0.1
;	Fecha:			Junio 13, 2011
;*****************************************************************************************************
;	Para determinar la temporización se necesita el tiempo de un ciclo de instrucción, (1 us para 4MHz)
;	el valor del divisor de frecuencia, que seleccionamos con los bits: PS2, PS2 y PS0 y el complemento del
;	valor cargado en TMR0, (255 - TMR0).
;   Para producir 38KHz, tenemos que T = 1/f = 1/38000 = 26.3 us, como T = ta + tb y haciendo ta = tb = 13us
;	aproximadamente, además deseamos que dure 33 ms presentes y 300 ms en 0V de manera cíclica.
; 	El mínimo valor del divisor de frecuencia es 2 y el valor offset del TMR0 es 250, teóricamente 12 us?
;   Que pasaría si no le pongo prescaler y hago el Offset de: 255 - 13 = 242 ? voy a realizar pruebas...
;*****************************************************************************************************
	list p=16F628A
	#include P16F628A.inc
	__CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT & _LVP_OFF & _MCLRE_OFF
;*****************************************************************************************************
;   Definicion de variables ****
;******************************************************************************************************
	CBLOCK		H'20'		; Seleccionamos en la memoria RAM (GPR)			
PDel0						; Para LEDD para pruebas solamente, por el momento.
PDel1
BUCLE1						; Contadores para detectar desbordes de TMR0.
BUCLE2						; y generar asi los diferentes tiempos del tren de pulsos.
BUCLE3
BUCLE4
Contador
W_Temp						; Registro para guardar temporalmente W.
STATUS_Temp					; Registro para guardar temporalmete STATUS
	ENDC
#define LED PORTA,0			; Definimos LED como bit 0 para el PORTA, implica usarlo: bsf LED o bcf LED.
#define LEDD PORTA,1		; Definimos LEDD como bit 1 para el PORTA.
;******************************************************************************************************
;   Inicio del Micro 
;******************************************************************************************************
Reset	org	0x00			; Aquí comienza el micro.
	goto	Inicio			; Salto a inicio del programa.
;******************************************************************************************************
; 	Vector de Interrupcion 
;******************************************************************************************************
	org	0x04				; Atiende Interrupcion.
	goto	Inicio_ISR
;******************************************************************************************************
;  	Programa Principal 
;	Configuración de puertos 
;******************************************************************************************************
	org	0x05				; Origen del código de programa.
Inicio		
	errorlevel      -302    ; Elimina "bank warning".
	bsf	STATUS,RP0 			; Pasamos de Banco 0 a Banco 1.
	movlw	b'11111100'		; RA0 como salida para LED y RA1 para LEDD, las demás las dejamos como entradas.
	movwf	TRISA
	movlw	b'11111111'		; Puerto B todas entradas.
	movwf	TRISB
	movlw	b'00000000'		; Se selecciona TMR0 y preescaler de 2.  
;******************************************************************************************************
;	NOTAS EXPLICATIVAS:
;	OPTION setup

;	movlw b'10001000'	;
		;  x-------		; 7, 0=enable, 1=disable, portb pullups
		;  -x------		; 6, 1=/, int edge select bit
		;  --x-----		; 5, timer0 source, 0=internal clock, 1=ext pin.
		;  ---x----		; 4, timer0 ext edge, 1=\
		;  ----x---		; 3, prescaler assign, 1=wdt, 0=timer0
		;  -----x--		; 2,1,0, timer0 prescaler rate select
		;  ------x-		;   000=2, 001=4, 010=8, 011=16, etc.
		;  -------x		; 
						; Nota: En este ejemplo el  prescaler asignado a wdt, asi TMR0
						; no tiene prescaler y se desborda cada 256 
						; instrucciones y hace un interrupt.	

;	movlw b'00000000'	; Para nuestro caso	00000000 Pullups habilitadas, no seleccionamos flanco,
						; reloj interno para el timer0... prescaler 000 = 2., etc.			
;******************************************************************************************************
	movwf	OPTION_REG		; Cargamos el dato en OPTION_REG
	bcf	STATUS,RP0			; Paso del Banco 1 al Banco 0
	movlw	0x07			; Deshabilitamos los comparadores analógicos
	movwf	CMCON			; para poder usar los pines RA0 - RA3 como E/S digitales.
	bcf		LED				; El LED comienza apagado.
	movlw	.250			; Cargamos 250 en TMR0 (checar si este es el valor de offset del TMR0?)
							; queremos lograr 12 useg. solamente. ( en realidad 13 useg.)
	movwf	TMR0
	clrf	Contador		; Iniciamos contadores.
	movlw	.10				; Valores iniciales de los BUCLES 1-2-3-4.
	movwf	BUCLE1
	movlw	.125
	movwf	BUCLE2
	movlw	.10
	movwf	BUCLE3
	movlw	.125
	movwf	BUCLE4
	movlw	b'10100000'		; Habilitamos GIE y T0IE (interrupción del TMR0)
	movwf	INTCON
;******************************************************************************************************
;	Control de Led - Pograma - 
;******************************************************************************************************
Bucle		
	bsf		LEDD			; Pongo a parpadear LEDD para visualizar que esta operando el circuito.
	call 	Retardo			; Esto lo cambiaré por el programa de detección una vez que pueda generar
	bcf		LEDD			; el tren de pulsos de 38KHz. ||||________||||________||||________
	call 	Retardo
	goto	Bucle			 
;******************************************************************************************************
; 	Rutina de servicio de Interrupcion.
;******************************************************************************************************
;  Guardado de registro W y STATUS.
;******************************************************************************************************
Inicio_ISR
	movwf	W_Temp			; Copiamos W a un registro Temporal.
	swapf	STATUS, W		; Invertimos los nibles del registro STATUS.
	movwf	STATUS_Temp		; Guardamos STATUS en un registro temporal.
;******************************************************************************************************
;	Interrupción por TMR0 
;******************************************************************************************************
ISR
	btfss	INTCON,T0IF		; Consultamos si es por TMR0.
	goto	Fin_ISR			; No, entonces restauramos valores.
	movlw	.10				; Si, consultamos si se han producido 10 desbordes
	subwf	Contador,0		; para obtener t deseado.
	btfss	STATUS,Z		;
	goto	LED_Apagado		; No es Contador = 10.
	goto	PULSOS			; Si es Contador = 10.
LED_Apagado
	bcf		LED				; Apago LED
	decfsz	BUCLE4,1		; Decremento BUCLE4 y preguntamos si es 0?
	goto	Actualizo_TMR0	; No, cargo TMR0.
	decfsz	BUCLE3,1		; Si es 0, decremento BUCLE3 y preguntamos si es 0?
	goto	Restauro_BUCLE4	; No, restauro valor de BUCLE4 para el loop y actualizo TMR0.
	incf	Contador,0		; Incrementamos contador
	goto	Actualizo_TMR0
Restauro_BUCLE4
	movlw	.125
	movwf	BUCLE4
	goto	Actualizo_TMR0
PULSOS
	btfss	LED				; Si esta apagado, prendo y viseversa.
	goto	Prendo_led
	bcf		LED				; Apago Led.
	goto	TIEMPOS							
Prendo_led
	bsf		LED				; Prendo Led.
TIEMPOS
	decfsz	BUCLE2,1		; Decremento BUCLE2 y preguntamos si es 0?
	goto	Actualizo_TMR0	; No, cargo TMR0.
	decfsz	BUCLE1,1		; Si es 0, decremento BUCLE1 y preguntamos si es 0?
	goto	Restauro_BUCLE2	; No, restauro valor de BUCLE2 para el loop y actualizo TMR0.
							; Restauramos valores de los bucles y contador.
	clrf	Contador		; Valores iniciales Contador = 0 y de los BUCLES 1-2-3-4.
	movlw	.10				 
	movwf	BUCLE1
	movlw	.125
	movwf	BUCLE2
	movlw	.10
	movwf	BUCLE3
	movlw	.125
	movwf	BUCLE4
	goto	Actualizo_TMR0
Restauro_BUCLE2
	movlw	.125
	movwf	BUCLE4
	goto	Actualizo_TMR0
Actualizo_TMR0				; Actualizo TMR0 para obtener una temporizacion deseada.
	movlw	.250			; 
	movwf	TMR0
	bcf	INTCON,T0IF			; Borro bandera de control de Interrupcion.
	goto	Fin_ISR			; Restauro valores.
							; Restauramos los valores de W y STATUS.
Fin_ISR
	swapf	STATUS_Temp,W	; Invertimos lo nibles de STATUS_Temp.
	movwf	STATUS
	swapf	W_Temp, f		; Invertimos los nibles y lo guardamos en el mismo registro.
	swapf 	W_Temp,W		; Invertimos los nibles nuevamente y lo guardamos en W.
	retfie					; Salimos de interrupción.
;******************************************************************************************************
Retardo
  		movlw     .100      ; 1 set numero de repeticion  (B)
        movwf     PDel0     ; 1 |
PLoop1  movlw     .100      ; 1 set numero de repeticion  (A)
        movwf     PDel1     ; 1 |
PLoop2  clrwdt              ; 1 clear watchdog
PDelL1  goto PDelL2         ; 2 ciclos delay
PDelL2  goto PDelL3         ; 2 ciclos delay
PDelL3  clrwdt              ; 1 ciclo delay
        decfsz    PDel1, 1  ; 1 + (1) es el tiempo 0  ? (A)
        goto      PLoop2    ; 2 no, loop
        decfsz    PDel0,  1 ; 1 + (1) es el tiempo 0  ? (B)
        goto      PLoop1    ; 2 no, loop
PDelL4  goto PDelL5         ; 2 ciclos delay
PDelL5  goto PDelL6         ; 2 ciclos delay
PDelL6  goto PDelL7         ; 2 ciclos delay
PDelL7  clrwdt              ; 1 ciclo delay
        return              ; 2+2 Fin.
;******************************************************************************************************
	end
