;**********************************************************************
; MANEJO DE SERVOS - Programa Básico 2 - Manejo con interrupciones
; Por Eduardo J. Carletti, Robots Argentina, 2007
;**********************************************************************

	list      p=16F628A	; definir procesador

#include <p16F628A.inc>		; definiciones de variables específicas del procesador

	ERRORLEVEL 1;-302	; para evitar los mensajes de cambio de
				; banco en el resultado del compilador

	__CONFIG   _CP_OFF & _WDT_OFF & _LVP_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF

;***** DEFINICIÓN DEL NOMBRE DE ENTRADAS Y SALIDAS

#define SERVO1	 	PORTA,0		; puerto de salida de servo 1
#define PULSADOR1 	PORTA,1		; puerto de entrada de pulsador 1
#define PULSADOR2 	PORTA,2		; puerto de entrada de pulsador 2
#define PULSADOR3 	PORTA,3		; puerto de entrada de pulsador 3

;***** VARIABLES

	CBLOCK	0x20
	acum_A		; variable momentánea
	Posic		; posición servo
	fase		; fase de programa para interrupción
	Guardar_STATUS	; Guardar Status
	Guardar_W	; Guardar W
	ENDC

;***********************************************************************************

	org	0x000
	goto	principal
	org	0x004
	goto	interrupcion

;***********************************************************************************
; Principal
;***********************************************************************************

principal
		movlw b'00000111' 	; deshabilita comparadores. Esto es
		movwf CMCON		; algo importante en el PIC 16F628A

		clrf PORTA		; inicia ports
		clrf PORTB		; inicia ports

		bsf STATUS,RP0		; Apunta a banco 1

		movlw b'00001110' 	; PORTA 
		movwf	TRISA		; salidas menos 1, 2 y 3, entradas

		MOVLW b'00000000' 	; PORTB 
		movwf	TRISB		; salidas

		movlw	b'00000010'	; Configuración para TMR0
		movwf	OPTION_REG	; preescaler 2, 1:8 con CLK interno (que es
					; de 1 MHz si el oscilador es de 4 MHz).
					; El contador cuenta cada 8 useg

	        bcf STATUS,RP0          ; Apunta a banco 0

		clrf	TMR0		; inicia registro de timer en 0

		movlw	d'133'		; inicia valor de posición de servo (centro)
		movwf	Posic

		clrf	fase		; inicia para que comience con la fase 0

		movlw	b'10100000'	; Interrupciones habilitadas
					; GIE (global), T0IE (timer 0)
		movwf	INTCON		; Interrupción General, Interrupción Timer 0


;***********************************************************************************
; Lazo principal
;***********************************************************************************

lazo
		movf	fase,f
		bz	fase0
		goto	lazo

;***********************************************************************************
; Rutina de apoyo
;***********************************************************************************

; Fase 0: Los servos actúan con un pulso de control que va entre 0,5 ms y 2,5 ms.
; En el bloque que sigue se inicia en 1 el pulso de control y se espera un 
; retardo fijo de aproximadamente 0,5 ms, que es el valor mínimo del pulso.
; Con este valor de longitud de pulso y una longitud cero en la parte variable, 
; el servo está parado al máximo hacia la izquierda (sentido antihorario).

fase0		bsf	SERVO1		; pone la señal de servo en 1
		bcf	INTCON,T0IF	; borra el flag de timer
		movlw	d'192'		; (256-192 = 64) 64 * 8 us = 0,512 ms
		movwf	TMR0		; valor al registro de timer
		incf	fase,f		; pasa a fase 1
		goto	lazo

;***********************************************************************************
; Manejo interrupciones
;***********************************************************************************

interrupcion

; Salva todo
		bcf	INTCON,T0IE	; deshabilita interrupción de timer
		movwf	Guardar_W
		swapf	STATUS, w
		movwf	Guardar_STATUS

; distribuidor
		movf	fase,w
		xorlw	0x01		; ¿fase 1?
		bz	fase1		; sí
		movf	fase,w		 
		xorlw	0x02		; ¿fase 2?
		bz	fase2		; sí
		movf	fase,w
		xorlw	0x03		; ¿fase 3?
		bz	fase3		; sí

		goto	salidaint	; ninguna de ellas, sale

; Fase 1: Aquí comienza el tiempo variable del pulso. Esto permite que
; el recorrido completo, de 180 grados (valores de pulso entre 0,5 ms
; y 2,5 ms), se divida en 256 segmentos (256 * 8 us = 2,048 ms).
; La parte variable del pulso de control varía entre 0 y 2 ms

fase1		movf	Posic,w		; 256-nn x 8 uS = 1 ms, 1,5 ms, 2,5 ms
		movwf	TMR0		; valor al registro de timer
		incf	fase,f		; pasa a fase 2
		goto	salidaint

; Fase 2: Retardo de 20 ms, que es el tiempo estándar que debe separar los pulsos 
; de control para los servos comunes de RC

fase2		bcf	SERVO1		; pone la señal de servo en 0
		bsf	STATUS,RP0	; Apunta a banco 1
		movlw	b'00000111'	; Configuración para TMR0
		movwf	OPTION_REG	; preescaler 7, 1:256 con CLK interno (que es
					; de 1 MHz si el oscilador es de 4 MHz).
					; El contador cuenta cada 256 useg
	        bcf STATUS,RP0          ; Apunta a banco 0
		movlw	d'249'		; (256-249 = 7) 7 * 256 us = 17,92 ms + 2 ms pulso
		movwf	TMR0		; valor al registro de timer
		incf	fase,f		; pasa a fase 3
		goto	salidaint

; Fase 3: Como en el bloque de la fase 2 cambió el prescaler del timer a 7, ahora 
; debe reponerlo al valor de un conteo cada 8 useg, y volver al estado de fase = 0, 
; con lo cual el ciclo se reinicia. También hemos insertado en esta fase, que se 
; ejecuta cada 20 ms aproximadamente, la lectura de los pulsadores.

fase3		
		bsf STATUS,RP0		; Apunta a banco 1
		movlw	b'00000010'	; Configuración para TMR0
		movwf	OPTION_REG	; preescaler 2, 1:8 con CLK interno (que es
					; de 1 MHz si el oscilador es de 4 MHz).
					; El contador cuenta cada 8 useg
	        bcf	STATUS,RP0	; Apunta a banco 0
		clrf	fase		; pasa a fase 0

pulsadores	; lee órdenes a través de pulsadores
		btfss	PULSADOR1
		goto	iniciaPos	; servo en posición central
		btfss	PULSADOR2
		goto	incPos		; incrementa Posic
		btfss	PULSADOR3
		goto	decPos		; decrementa Posic
		goto	salidaint

;***********************************************************************************
; Rutinas de apoyo
;***********************************************************************************


iniciaPos	movlw d'133'		; 256-133 = 123, 123 * 8 us = 984 us + 512 us
		movwf Posic		; posición central en esta disposición
		goto salidaint		; y sale

decPos		movf Posic,f		; se fija si Posic ya es cero
		bz sale1		; si es cero no decrementa
		decf Posic,f		; si no es cero, decrementa
sale1		goto salidaint		; y sale

incPos		movlw 0xFF		; se fija si Posic no es 0xFF
		xorwf Posic,w		; que es el valor máximo
		bz sale2		; si es el valor máximo, no incrementa
		incf Posic,f		; si no es el valor máx, incrementa
sale2		goto salidaint		; y sale

; Regresa todo
salidaint
		bcf	INTCON,T0IF	; borra el flag de timer
		swapf	Guardar_STATUS, w
		movwf	STATUS
		swapf	Guardar_W, f
		swapf	Guardar_W, w
		bsf	INTCON,T0IE	; habilita interrupción de timer
		retfie			; retorna

		END

