; CLK[cubo] ; por Adrian Bulnes [Urriellu] ; clk3 @ urriellu . net ; Aviso: todos los comentarios estan escritos sin tildes porque MPLAB solo soporta archivos en ASCII (y en teoria tambien UTF16, pero no está bien implementado y su uso es inutil, culpa de Microchip ;-) LIST P=16F877A, R=hex, W=-302, W=-208 ;elegimos modelo de PIC, raiz hexadecimal, eliminamos avisos 302 (registros en bancos !=0) y 208 (etiquetas demasiado largas) INCLUDE P16F877A.INC __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _LVP_OFF & _DEBUG_OFF & _WRT_OFF & _CPD_OFF & _BODEN_ON ;mirar el archivo de cabecera. Brown-Out Reset activado para que ante caidas de tension no siga funcionando y que se consideren algunos botones como pulsados ;aliases para pines PuertoAlarma EQU PORTB BitAlarma EQU 1 PuertoPulsadores EQU PORTB BitPulsadorHm1 EQU 4 ;pulsador que aumenta una hora BitPulsadorMm1 EQU 5 ;pulsador que aumento un minuto BitPulsadorHora EQU 6 ;pulsador para configurar la hora BitPulsadorAlarma EQU 7 ;pulsador para configurar la hora de la alarma PuertoHoras EQU PORTA PuertoMinutos EQU PORTC PuertoSegundos EQU PORTD ;variables GPR HORA_REAL_S EQU 20 HORA_REAL_M EQU 21 HORA_REAL_H EQU 22 HORA_ALARMA_S EQU 23 ;realmente siempre estara a b'00000000' pero es mas comodo a la hora de programar si existe esta variable HORA_ALARMA_M EQU 24 HORA_ALARMA_H EQU 25 BitsSueltos EQU 26 ;un byte en el que se usaran bits sueltos para configurar distintas cosas BitRecienReseteado EQU 0 BitAlarmaActivada EQU 1 ;activado si la alarma está activada EstamosProcesandoMinutos EQU 2 ContadorH EQU 3 ;Contador deben ser 9 bits, así que usamos 8 de ContadorL y 1 de BitsSueltos W_TEMP EQU 27 STATUS_TEMP EQU 28 ContadorL EQU 29 MomentoFinRebote EQU 2A ORG 0x00 GOTO CONFIGURACION ORG 0x04 GOTO INTERRUPCIONES ORG 0x05 CONFIGURACION ;=== CONFIGURACION === CLRF PORTA ;necesario segun especificaciones de Microchip CLRF PORTB CLRF PORTC CLRF PORTD CLRF PORTE BSF STATUS,RP0 MOVLW b'00000111' MOVWF ADCON1 ;configuramos PORTA como E/S digitales ;configuramos RB4:7 como entradas, todos los demas como salidas. Los pines no usados se configuran como salidas para poder dejar al aire CLRF TRISA MOVLW b'11110000' MOVWF TRISB CLRF TRISC CLRF TRISD CLRF TRISE MOVLW b'00000101' ;el primer bit esta puesto a cero para activar las pull-up de RB4:7 MOVWF OPTION_REG MOVLW b'10100000' MOVWF INTCON ; activamos interrupciones para desbordamiento de TMR0. (INTCON es accesible desde todos los bancos) BCF STATUS,RP0 CLRF BitsSueltos CLRF ContadorL CLRF HORA_REAL_S CLRF HORA_REAL_M CLRF HORA_REAL_H CLRF HORA_ALARMA_S CLRF HORA_ALARMA_M CLRF HORA_ALARMA_H ;=== FIN DE LA CONFIGURACION === ; se espera a que se pulse una tecla para empezar a funcionar, mientras tanto todos los LEDs encendidos y no cuenta el tiempo BCF INTCON,RBIF BucleInicial BSF PuertoAlarma,BitAlarma MOVLW b'11111111' MOVWF PuertoSegundos MOVWF PuertoMinutos MOVWF PuertoHoras CLRF TMR0 CLRF ContadorL BTFSS INTCON,RBIF GOTO BucleInicial ;=========== PROGRAMA PRINCIPAL =========== BUCLE ;=== Mostramos la hora real o la hora configurada para la alarma === BCF STATUS,IRP ;elegimos el primer banco de la RAM para direccionamiento indirecto MOVLW HORA_REAL_S BTFSS PuertoPulsadores,BitPulsadorAlarma MOVLW HORA_ALARMA_S ;si el pulsador de configurar alarma está pulsado (nivel BAJO) entonces elegimos la direccion de la RAM donde esta configurada la hora de la alarma, de lo contrario se eligio anteriormente la direccion de la hora real MOVWF FSR ;...entonces ahora direccionamos indirectamente hacia los segundos de la hora real o de la alarma. MOVF INDF,W ;cogemos el valor de los segundos que debemos mostrar... MOVWF PuertoSegundos ;...y lo mostramos INCF FSR,F ;ahora elegimos la siguiente direccion de memoria RAM, que sera el de los minutos de lo que se deba mostrar MOVF INDF,W ;cogemos el valor de los minutos que debemos mostrar... MOVWF PuertoMinutos ;...y lo mostramos INCF FSR,F MOVF INDF,W MOVWF PuertoHoras ;=== Comprobarmos si la hora actual es igual a la hora configurada para que suene la alarma === CALL ComprobarAlarma ;=== Activamos la alarma si debe estarlo === BTFSC BitsSueltos,BitAlarmaActivada BSF PuertoAlarma,BitAlarma BTFSS BitsSueltos,BitAlarmaActivada BCF PuertoAlarma,BitAlarma ;Nota: hacer lo anterior es absurdo porque seria mas eficiente trabajar directamente sobre PuertoAlarma, pero de esta manera se puede reutilizar el programa y solo con modificar esta parte se pueden hacer otras cosas, como por ejemplo que suene a intervalos ;=== Chequeo del estado de los pulsadores === BTFSC INTCON,RBIF CALL TeclaCambioDeValor ;=== Procesar el temporizador === BTFSC INTCON,TMR0IF CALL InterrupcionTMR0 GOTO BUCLE ;=========== FIN DEL PROGRAMA PRINCIPAL =========== ;=========== Funciones sueltas =========== TeclaCambioDeValor BCF BitsSueltos,BitAlarmaActivada ; al pulsar cualquier tecla apagamos la alarma CALL EvitarRebotes ;antes de procesar los pulsadores esperamos a que se estabilicen MOVF PuertoPulsadores,W ;hacemos esto para poder poner a cero RBIF, que DEBE hacerse aqui, no al final de TeclaCambioDeValor BCF INTCON,RBIF BTFSC BitsSueltos,BitRecienReseteado GOTO ComprobarSiPodemosAumentarTiempo ; detectamos cual es el pulsador accionado (se activan en nivel BAJO) BTFSS PuertoPulsadores,BitPulsadorHm1 GOTO TeclaHorasMas1pulsada BTFSS PuertoPulsadores,BitPulsadorMm1 CALL AumentarUnMinuto RETURN ;Cuando se acaba de resetear el tiempo entonces en lugar de procesar si se debe aumentar una hora o un minuto comprobamos que las teclas H+1 y M+1 esten sueltas (valor logico alto) y si lo estan entonces podemos salir del estado "RecienReseteado" ComprobarSiPodemosAumentarTiempo BTFSS PuertoPulsadores,BitPulsadorMm1 RETURN BTFSS PuertoPulsadores,BitPulsadorMm1 RETURN BCF BitsSueltos,BitRecienReseteado ;ponemos a cero este bit cuando ambos pulsadores estan a UNO RETURN ;si HORA_ALARMA_M==HORA_ALARMA_H==0 entonces no hacer que suene ComprobarAlarma MOVF HORA_ALARMA_M,W XORLW 0 BTFSS STATUS,Z GOTO ComprobarAlarma1 MOVF HORA_ALARMA_H,W XORLW 0 BTFSC STATUS,Z RETURN ;Funciones para comprobar si la hora configurada es la misma que la hora actual y entonces se debe activar la alarma ComprobarAlarma1 MOVF HORA_REAL_S,W XORWF HORA_ALARMA_S,W BTFSC STATUS,Z ;si Z==1 entonces los segundos de la alarma configurada son iguales a los de la hora real CALL ComprobarAlarma2 RETURN ComprobarAlarma2 MOVF HORA_REAL_M,W XORWF HORA_ALARMA_M,W BTFSC STATUS,Z ;si Z==1 entonces los minutos de la alarma configurada son iguales a los de la hora real CALL ComprobarAlarma3 RETURN ComprobarAlarma3 MOVF HORA_REAL_H,W XORWF HORA_ALARMA_H,W BTFSC STATUS,Z ;si Z==1 entonces las horas de la alarma configurada son iguales a los de la hora real BSF BitsSueltos,BitAlarmaActivada ;hora de alarma==hora real, asi que encendemos alarma RETURN TeclaHorasMas1pulsada ;BTFSS PuertoPulsadores,TeclaMinutosMas1puldasa BTFSS PuertoPulsadores,BitPulsadorMm1 GOTO ResetearHora ; si hay nivel bajo en TeclaMinutosMas1puldasa entonces estan pulsadas las teclas de aumentar minutos y horas ; BTFSC PuertoPulsadores,BitPulsadorHm1 CALL AumentarUnaHora ;si hay nivel alto en TeclaMinutosMas1puldasa entonces solo esta pulsada la tecla de aumentar horas, asi que aumentamos una hora RETURN AumentarUnMinuto ;NOTA: si los pulsadores de configurar hora y configurar alarma estan ambos apretados se muestra la hora configurada para la alarma, asi que si se aprieta el pulsador de aumentar un minuto a la vez que los otros dos nombrados, solo se cambiara el de la hora configurada para la alarma BTFSS PuertoPulsadores,BitPulsadorAlarma GOTO AumentarUnMinutoDeLaAlarmaConfigurada BTFSS PuertoPulsadores,BitPulsadorHora GOTO AumentarUnMinutoDeLaHoraReal RETURN AumentarUnMinutoDeLaAlarmaConfigurada BCF STATUS,IRP MOVLW HORA_ALARMA_M BSF BitsSueltos,EstamosProcesandoMinutos ;EstamosProcesandoMinutos se usa como parametro para AumentarUnMinutoOsegundoDeLoElegido para decidir si se esta trabajando con segundos o con minutos GOTO AumentarUnMinutoOsegundoDeLoElegido AumentarUnMinutoDeLaHoraReal BCF STATUS,IRP MOVLW HORA_REAL_M BSF BitsSueltos,EstamosProcesandoMinutos GOTO AumentarUnMinutoOsegundoDeLoElegido AumentarUnMinutoOsegundoDeLoElegido MOVWF FSR ;anteriormente se eligio lo que se debe aumentar INCF INDF,F ;ahora comprobaremos si nos pasamos de 9 en las unidades, es decir, si hay d'10' (b'xxxx1010') BTFSS INDF,1 GOTO NoSeSalioDelRango ;si el bit 1 de los minutos esta a cero entonces no nos salimos del rango BTFSS INDF,3 GOTO NoSeSalioDelRango ;si los bits 1 y 3 estan activados entonces ponemos las unidades a cero y aumentamos una decena BCF INDF,1 BCF INDF,3 MOVLW b'00010000' ADDWF INDF,F ;ahora comprobaremos si nos pasamos de 5 en las decenas, es decir, si hay d'6' (b'x110xxxx') BTFSS INDF,5 GOTO NoSeSalioDelRango BTFSS INDF,6 GOTO NoSeSalioDelRango ;si los bits 5 y 6 estan activados entonces ponemos las decenas a cero y aumentamos un minuto o una hora BCF INDF,5 BCF INDF,6 BTFSC BitsSueltos,EstamosProcesandoMinutos CALL AumentarUnaHoraDeLoElegidoPorDesbordamiento ;como estamos procesando minutos, entonces ahora debemos aumentar una hora BTFSS BitsSueltos,EstamosProcesandoMinutos GOTO AumentarUnMinutoDeLoElegidoPorDesbordamiento NoSeSalioDelRango RETURN ;NOTA: este return pertenece a AumentarUnMinuto y al CALL que viene desde las interrupciones, no a AumentarUnMinutoDeLoElegido porque en AumentarUnMinuto no se debe aumentar un minuto cuando ninguno de los pulsadores de configurar hora real ni alarma estan pulsados AumentarUnMinutoDeLoElegidoPorDesbordamiento INCF FSR,W BSF BitsSueltos,EstamosProcesandoMinutos GOTO AumentarUnMinutoOsegundoDeLoElegido AumentarUnaHora MOVLW HORA_REAL_H BTFSS PuertoPulsadores,BitPulsadorAlarma MOVLW HORA_ALARMA_H MOVWF FSR GOTO AumentarUnaHoraDada AumentarUnaHoraDeLoElegidoPorDesbordamiento INCF FSR,F ;como antes estaban puestos en el FSR los minutos que debian aumentarse ahora ponemos las horas AumentarUnaHoraDada INCF INDF,F ;aumentamos una hora ;si está a 10 en binario lo ponemos en BCD MOVF INDF,W XORLW b'00001010' BTFSC STATUS,Z GOTO PonerINDFaBCD10 ;si son las 19h+1 lo ponemos en BCD MOVF INDF,W XORLW b'00011010' BTFSC STATUS,Z GOTO PonerINDFaBCD20 ;si son las 24h lo reseteamos MOVF INDF,W XORLW b'00100100' BTFSC STATUS,Z CLRF INDF HoraCorregida RETURN PonerINDFaBCD10 MOVLW b'00010000' MOVWF INDF GOTO HoraCorregida PonerINDFaBCD20 MOVLW b'00100000' MOVWF INDF GOTO HoraCorregida ; Rutina para esperar sin hacer nada. ; Sabemos que entre cada valor consecutivo de ContadorL van a pasar 3ms, asi que si esperamos a que ContadorL aumente 7 unidades estaremos esperando entre 18ms y 21ms, no necesitamos exactitud EvitarRebotes MOVF ContadorL,W ADDLW d'7' MOVWF MomentoFinRebote EsperandoFinRebote MOVF MomentoFinRebote,W XORWF ContadorL,W BTFSS STATUS,Z GOTO EsperandoFinRebote RETURN ResetearHora MOVLW HORA_REAL_S BTFSS PuertoPulsadores,BitPulsadorAlarma MOVLW HORA_ALARMA_S ;si BitPulsadorAlarma está a cero entonces debemos elegir la alarma BCF STATUS,IRP MOVWF FSR ;elegimos para direccionar indirectamente los segundos de lo que debe ser borrado CLRF INDF ;borramos los segundos INCF FSR,F ;elegimos la siguiente posicion de la RAM, que seran los minutos CLRF INDF ;borramos los minutos INCF FSR,F ;elegimos las horas CLRF INDF ;borramos las horas BSF BitsSueltos,BitRecienReseteado RETURN ;=========== fin de funciones sueltas =========== ;===== INTERRUPCIONES ===== INTERRUPCIONES MOVWF W_TEMP MOVF STATUS,W MOVWF STATUS_TEMP BTFSC INTCON,TMR0IF GOTO InterrupcionTMR0 FinInterrupcion MOVF STATUS_TEMP,W MOVWF STATUS MOVF W_TEMP,W RETFIE InterrupcionTMR0 BCF INTCON,TMR0IF ;Tenemos que contar 306 desbordamientos del TMR0 INCF ContadorL,F MOVF ContadorL,W XORLW 0 BTFSC STATUS,Z BSF BitsSueltos,ContadorH ;ContadorL se desbordo asi que aumentamos ContadorH ;comprobamos si Contador es 305 MOVF ContadorL,W XORLW b'00110001' ;100110000 es 305, siendo ContadorH el MSB BTFSS STATUS,Z GOTO FinInterrupcion ;si Z es 0 entonces "Contador" NO es 305 y podemos terminar de procesar la interrupcion BTFSS BitsSueltos,ContadorH GOTO FinInterrupcion ;si Contador H es 0 entonces "Contador" NO es 305 y podemos terminar de procesar la interrupcion ;ContadorL es 00110001 y ContadorH es 1, asi que estamos en 305 para "Contador", aumentamos un segundo y configuramos todo para que cuente otro segundo MOVLW HORA_REAL_S BCF STATUS,IRP BCF BitsSueltos,EstamosProcesandoMinutos CALL AumentarUnMinutoOsegundoDeLoElegido BCF BitsSueltos,ContadorH CLRF ContadorL MOVLW d'211' MOVWF TMR0 GOTO FinInterrupcion END