TITLE "Temporizador general programable"
;
; Autor: Hugo Erhard, <hugoerhard@yahoo.de>
; Inicio: 23-08-2002
; Terminado: 25-08-2002
;
; Revisiones: 1.00 23-08-2002 Initial release
; 1.01 25-08-2002 Se define constante para Xtal 3.57 MHz
;
;===============================================================================
;
;===============================================================================
;
errorlevel -215, -302, -301
list p=pic16f84
include "p16f84.h"
__CONFIG 0x3FF1
;
;-------------------------------------------------------------------------------
; DEFINICION DE VARIABLES
;
CBLOCK 0x0E
;
T0_ADJ; para correccion de error en timer
T0_SEG; post scaler para 1 segundo
MIL50; contador de 50 milisegundos
CNT_SEG; contador de segundos
CNT ; contador general
;
ENDC
;
; DEFINICION DE PINES
;
#DEFINE SELECT PORTA,0; selector base de tiempo
#DEFINE START_SW PORTA,1; pulso de inicio
#DEFINE OUT PORTA,2; salida, 1 mientras temporiza
#DEFINE BUZZER PORTA,3; zumbador
#DEFINE LED PORTA,4; led
;
; DEFINICION DE CONSTANTES
;
XTAL EQU .10 ; si usas xtal de 4 MHz declaralo aqui
;
if XTAL == .4
;
COUNTS EQU .61 ; 61 -> Xtal = 4 MHz // 81 -> Xtal = 3.57 MHz
K_1seg EQU .20 ; 20 cuentas de 50 µseg = 1 seg
;
else
;
COUNTS EQU .159; 159 -> Xtal = 10 MHz
K_1seg EQU .100; 100 cuentas de 10 µseg = 1 seg
;
endif
;
;-------------------------------------------------------------------------------
;
ORG 0
POR
GOTO MAIN ; reset, salto al programa principal
;
ORG 4
ISR
MOVWF SAVE_W ; salvo W
SWAPF STATUS,W; cargo STATUS
MOVWF SAVE_S ; y salvo
CLRF STATUS ; para asegurar que este en banco 0
BTFSC T0IF ; interrupcion de timer ?
GOTO T0ISR ; si, atiendo...
INTEND
SWAPF SAVE_S,W; recupero STATUS invirtiendo nibbles
MOVWF STATUS ;
SWAPF SAVE_W,F; recupero W de esta manera para no afectar
SWAPF SAVE_W,W; los bits de STATUS
RETFIE ; y salgo de interrupcion habilitandolas
;-------------------------------------------------------------------------------
;
; T0 INTERRUPT SERVICE ROUTINE
;
; Cristal = 4 MHz
; Ciclo = 1 µseg, prescaler = 256
; TMR0 se incrementa cada 1 µseg * 256 = 256 µseg
; Para llegar a 50 mseg -> 50000 µseg / 256 µseg = 195.31 -> 195 cuentas
; Cargando TMR0 con 256 - 195 = 61, se genera una interrupcion cada 195
; cuentas, es decir cada 195 * 256 µseg = 49.92 mseg.
; Esto genera un error de 50000 µseg - 49920 µseg = 80 µseg.
;
; NOTA: si se utiliza un cristal de 3.579545 MHz, se tiene:
; temporizador MINUTOS cuenta cada 1.11746 minutos
; temporizador HORAS cuenta cada 1h 7' 2"
; Si se utiliza este cristal, para conservar los tiempos de temporizacion,
; cargar TMR0 con 81 (175 cuentas) en lugar de 61 (195 cuentas).
; Se agrega un error de 3 mseg por segundo de temporizacion.
; *** VER EN DECLARACION CONSTANTES ***
;
; CONSTANTES PARA CRISTAL DE 10 MHz
;
; Cristal = 10 MHz
; Ciclo = 0.4 µseg, prescaler = 256
; TMR0 se incrementa cada 0.4 µseg * 256 = 102.4 µseg
; Para llegar a 50 mseg -> 50000 µseg / 102.4 µseg = 488.28 -> 488 cuentas
;
; Me pase, puedo tener maximo 256 cuentas!!!!!!!
; Probamos con temporizacion de 10 mseg = 10000 µseg:
;
; Para llegar a 10 mseg -> 10000 µseg / 102.4 µseg = 97.65 -> 97 cuentas
;
; Cargando TMR0 con 256 - 97 = 159, se genera una interrupcion cada 97
; cuentas, es decir cada 97 * 102.4 µseg = 9.9328 mseg.
; Esto genera un error de 10000 µseg - 9932.8 µseg = 67.2 µseg.
; Este error corresponde a 67.2 µseg / 0.4 µseg = 168 instrucciones
;
T0ISR
if XTAL == .4
;
; Se compila si se usa XTAL de 4 MHz
;
NOP ; este lazo genera una demora de 80 µseg
MOVLW .15 ; para compenzar el error del timer
MOVWF T0_ADJ ;
GOTO $+1 ; para gastar 2 ciclos ahorrando memoria
DECFSZ T0_ADJ,1;
GOTO $-2 ;
;
else
;
; Se compila si se usa XTAL de 10 MHz (o distinto de 4 MHz OJO!!!)
;
GOTO $+1 ; para compenzar error
GOTO $+1 ;
MOVLW .30 ; para compenzar el error del timer
MOVWF T0_ADJ ;
GOTO $+1 ; para gastar 2 ciclos ahorrando memoria
DECFSZ T0_ADJ,1;
GOTO $-2 ;
;
endif
;
MOVLW COUNTS ; cargo TMR0 para N cuentas
MOVWF TMR0 ;
DECF MIL50,1 ;
DECFSZ T0_SEG,1; decremento post-scaler de 1 segundo
GOTO T0END ; si falta salgo
;
MOVLW K_1seg ; valor de recarga de post-scaler de 1 segundo
MOVWF T0_SEG ;
DECF CNT_SEG,1; decremento contador de segundos
T0END
BCF T0IF ; rehabilito interrupcion de timer
GOTO INTEND ; y salgo
;-------------------------------------------------------------------------------
;
; Aqui salta despues de un reset, se inicializan todos los registros
;
MAIN
CLRF STATUS ; borro STATUS para saber como inicializo
BSF RP0 ; banco 1
MOVLW b'00000011'; PORTA -> xxxOOOII
MOVWF TRISA ;
MOVLW b'11111111'; PORTB -> IIIIIIII
MOVWF TRISB ;
MOVLW b'00000111'; RB pull up enabled, x, TMR0 ck internal,
MOVWF OPTION_REG; x, prescaler to TMR0, prescaler = 256
BCF RP0 ; banco 0
CLRF PORTA ; borro puerto A
MOVLW K_1seg ; inicializo base de tiempos de segundos
MOVWF T0_SEG ;
MOVLW COUNTS ; inicializo timer 0
MOVWF TMR0 ;
MOVLW b'10100000'; habilito interrupciones, solo timer 0
MOVWF INTCON ;
;-------------------------------------------------------------------------------
;
; Lazo principal, salida permanece baja por 58 seg y alta por 2 seg
; La salida se refleja en el led
;
MAIN_LOOP
BCF OUT ; salida en 0
BSF LED ; led apagado
MOVLW .58 ; preparo demora de 58 seg
MOVWF CNT_SEG ;
WAIT_LOW
TSTF CNT_SEG ;
BNZ WAIT_LOW; espero a que pasen los 58 seg
BSF OUT ; salida en 1
BCF LED ; led encendido
MOVLW .2 ; preparo demora de 2 seg
MOVWF CNT_SEG ;
WAIT_HIGH
TSTF CNT_SEG ;
BNZ WAIT_HIGH; espero a que pasen los 2 seg
GOTO MAIN_LOOP; y repito for ever...
;
END