;********************************************************************** ; Este programa se distribuye según esta licencia: * ; * ; http://creativecommons.org/licenses/by-nc-sa/2.5/es/ * ; * ; léala antes de seguir adelante o de hacer uso de él * ; * ;********************************************************************** ; * ; Filename: CamarasVigilancia.asm * ; Date: 19-05-07 * ; * ; Author: Emilio Florido * ; * ;********************************************************************** ; * ; Files required: * ; 12F629.lkr * ; * ;********************************************************************** ; * ; Notas: Este programa comienza esperando como medio minuto hasta * ; que se inicialice el grabador. Luego, simula la pulsación de la * ; tecla de grabar y de ahí en adelente, de forma secuencial, va * ; pasando una por una por las vistas de las cámaras. Este proceso * ; solo termina si se pulsa en el botón de "mosaico". En ese * ; momento queda detenido a la espera de que se pulsa nuevamente en * ; "mosaico" para repetir el ciclo si así se hace. * ; * ;********************************************************************** depurar set 0 ; si vale 1 todo se acelera ;-) list p=12F629 ; list directive to define processor #include ; processor specific variable definitions errorlevel -302 ; suppress message 302 from list file __CONFIG _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT ; con _MCLRE_OFF se puede usar GP3 como entrada normal (en lugar de como reset) ; '__CONFIG' directive is used to embed configuration word within .asm file. ; The lables following the directive are located in the respective .inc file. ; See data sheet for additional information on configuration word settings. ;***** definición de equivalencias y variables que se usan en el código VECES1 equ 0x20 ; registros usados para los retardos VECES2 equ 0x21 VECES3 equ 0x22 NUMSEGUNDOS equ 0x23 ; para retardar los segundos que aquí diga SEGUNDOSxCICLO equ 0x24 ; cuantos segundos muestra cada cámara VISTASoREPOSO equ 0x25 ; si está en modo "vistas" (0x00) o en modo "reposo" (0x01) ;********************************************************************** RESET_VECTOR CODE 0x000 ; processor reset vector ; este call da muchos problemas si en el código no ha grabado previamente el valor del ; calibrado del oscilador interno, por lo que es mucho más sencillo programar el valor ; "a pelo" habiendo tenido la precaución de leerlo previamente, ¡claro! ; call 0x3FF ; retrieve factory calibration value ; por cierto, a la pregunta de icprog: ; "Valor del oscilador de calibración ausente, ¿desea ulizar el valor del fichero en su lugar?" ; hay que contestar _NO_ movlw 0x54 ; lo he leido previamente bsf STATUS,RP0 ; selecciona el banco 1 de registros movwf OSCCAL ; ajuste "fino" del reloj interno ; antes de nada, hay que configurar el circuito bcf STATUS,RP0 ; selecciona el banco 0 de registros movlw b'00000111' ; deshabilita el comparador interno (CM2=1,CM1=1, CM0=1) movwf CMCON ; ya que "por defecto" está habilitado movlw b'11111111' ; inicializa todo en uno, es decir, pulsadores "sueltos" movwf GPIO bsf STATUS,RP0 ; selecciona el banco 1 de registros movlw b'01111111' ; permite habilitar/deshabilitar los pull-ups de los GPIOs movwf OPTION_REG ; según lo que se indique luego en WPU movlw b'00000000' ; 1 -> habilita, 0 -> deshabilita el pull-up del GPIO que corresponda movwf WPU ; en este caso concreto, _todos_ movlw b'00011000' ; excepto GP4, todos los GPx de salida (0 -> salida, 1 -> entrada) movwf TRISIO ; GP0, GP1, GP2, GP5: vistas de las cámaras, GP4: mosaico/parar bcf STATUS,RP0 ; selecciona el banco 0 de registros de ahora en adelante ; ajusta algunos valores "por defecto" movlw b'11111111' ; inicialmente pulsadores "sueltos" movwf GPIO movlw 0x00 ; empezará en modo "vistas" movwf VISTASoREPOSO movlw d'7' ; cada cámara se mostrará 7 segundos movwf SEGUNDOSxCICLO ; (que en realidad serán unos 10 con el tiempo de proceso incluído) movlw d'25' ; espera unos 25 segundos para que arranque el grabador call espera_W_segundos ; en primer lugar, el "otro" uC pondrá a "grabar", así que espera un poco más movlw d'4' call espera_W_segundos ; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ; esta es la implementación del modo de "vistas" modo_vistas bcf GPIO,0 ; pulsa el botón de la cámara 1 call un_segundo bsf GPIO,0 ; y lo suelta un segundo después call espera_ciclo_segundos btfsc VISTASoREPOSO,0 ; ¿hay que cambiar a modo "reposo"? goto modo_reposo bcf GPIO,1 ; pulsa el botón de la cámara 2 call un_segundo bsf GPIO,1 ; y lo suelta un segundo después call espera_ciclo_segundos btfsc VISTASoREPOSO,0 ; ¿hay que cambiar a modo "reposo"? goto modo_reposo bcf GPIO,2 ; pulsa el botón de la cámara 3 call un_segundo bsf GPIO,2 ; y lo suelta un segundo después call espera_ciclo_segundos btfsc VISTASoREPOSO,0 ; ¿hay que cambiar a modo "reposo"? goto modo_reposo bcf GPIO,5 ; pulsa el botón de la cámara 4 call un_segundo bsf GPIO,5 ; y lo suelta un segundo después call espera_ciclo_segundos btfsc VISTASoREPOSO,0 ; ¿hay que cambiar a modo "reposo"? goto modo_reposo ; ahora hay que hacer algún que otro "malabarismo" con GP4 para convertirlo en salida, ; "pulsar" para cambiar a modo mosaico, y luego dejarlo de nuevo como estaba. En realidad ; "el problema" es esperar sin usar las rutinas de espera que ya tengo hechas, pues estas ; presuponen que GP4 será entrada y _no_ salida... por lo que no valen (y no quiero tener que ; reescribir el código completo solo por esto) bsf STATUS,RP0 ; selecciona el banco 1 de registros movlw b'00001000' ; todos los GPx de salida (0 -> salida, 1 -> entrada) movwf TRISIO ; incluido GP4 para poder cambiar a modo mosaico bcf STATUS,RP0 ; selecciona el banco 0 de registros bcf GPIO,4 ; pulsa el botón de mosaico call mantiene_pulsado_GP4 bsf GPIO,4 ; y lo suelta un segundo después bsf STATUS,RP0 ; selecciona el banco 1 de registros movlw b'00011000' ; vuelve a dejar los GPx como están normalmente movwf TRISIO ; GP0, GP1, GP2, GP5: vistas de las cámaras, GP4: mosaico/parar bcf STATUS,RP0 ; selecciona el banco 0 de registros que es como está normalmente call espera_ciclo_segundos btfsc VISTASoREPOSO,0 ; ¿hay que cambiar a modo "reposo"? goto modo_reposo goto modo_vistas ; repite el proceso mostrando de nuevo la cámara uno ; espera un segundo sin usar GP4 mantiene_pulsado_GP4 movlw 4 ; retarda un segundo (es decir 4 veces 250 milisegundos) movwf VECES3 un_segundo_pulsando_GP4_3 movlw d'250' ; retarda un cuarto de segundo (osea, 250 milisegundos) movwf VECES2 un_segundo_pulsando_GP4_2 movlw d'111' ; vueltas para un milisegundo movwf VECES1 un_segundo_pulsando_GP4_1 nop nop nop nop nop nop if depurar == 1 ; XXXXX para NO esperar XXXXXXXXXXXXXXXXX movlw 1 ; así vuelve de esta rutina muy deprisa ;-) movwf VECES1 movwf VECES2 movwf VECES3 endif decfsz VECES1 ; ¿ha pasado ya un milisegundo? goto un_segundo_pulsando_GP4_1 decfsz VECES2 ; ¿ha pasado ya un cuarto de segundo? goto un_segundo_pulsando_GP4_2 decfsz VECES3 ; ¿ha pasado ya un segundo? goto un_segundo_pulsando_GP4_3 retlw 0 ; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ; esta es la implementación del modo de "reposo" modo_reposo bsf STATUS,RP0 ; selecciona el banco 1 de registros movlw b'11111111' ; pone todos los GPx de entrada para que no sean "forzados" movwf TRISIO ; si se pulsan los botones de las cámaras mientras está en reposo bcf STATUS,RP0 ; selecciona el banco 0 de registros call evita_rebotes ; espera un poco para evitar "rebotes" del pulsador espera_cambio_modo btfss GPIO,4 ; ¿hay que cambiar a modo "vistas"? goto cambio_reposo_a_vistas ; nop ; pierde un par de microsegundos en cada vuelta nop goto espera_cambio_modo ; sigue esperando a que se pulse la tecla de cambio de modo cambio_reposo_a_vistas call evita_rebotes ; espera un poco para evitar "rebotes" del pulsador movlw 0x00 ; indica el cambio a modo de "vistas" movwf VISTASoREPOSO espera_tecla_suelta nop ; pierde un par de microsegundos en cada vuelta nop btfss GPIO,4 ; espera a que la tecla se haya sotado antes de ir al modo "vistas" goto espera_tecla_suelta ; ajusta los pulsadores como salidas para volver al modo vistas bsf STATUS,RP0 ; selecciona el banco 1 de registros movlw b'00011000' ; vuelve a dejar los GPx como están normalmente movwf TRISIO ; GP0, GP1, GP2, GP5: vistas de las cámaras, GP4: mosaico/parar bcf STATUS,RP0 ; selecciona el banco 0 de registros call un_segundo ; espera un poco antes de pasar a modo vistas goto modo_vistas ; espera un poco y se asegura de que el pulsador esté suelto para evitar "rebotes" ; no se puede usar la rutina "un_segundo" pues desde ahí también se comprueba el pulsador evita_rebotes movlw d'250' ; retarda un cuarto de segundo (osea, 250 milisegundos) movwf VECES2 rebote_2 movlw d'111' ; vueltas para un milisegundo movwf VECES1 rebote_1 nop nop nop nop nop nop if depurar == 1 ; XXXXX para NO esperar XXXXXXXXXXXXXXXXX movlw 1 ; así vuelve de la rutina de rebotes muy deprisa ;-) movwf VECES1 movwf VECES2 endif decfsz VECES1 ; ¿ha pasado ya un milisegundo? goto rebote_1 decfsz VECES2 ; ¿ha pasado ya un cuarto de segundo? goto rebote_2 btfss GPIO,4 ; ¿se ha soltado ya el pulsador? goto evita_rebotes ; si no fuese así, espera más retlw 0 ; espera el número de segundos que diga en SEGUNDOSxCICLO espera_ciclo_segundos movfw SEGUNDOSxCICLO ; esta rutina espera el número de segundos que diga en W espera_W_segundos movwf NUMSEGUNDOS ; guarda el valor que haya en W en NUMSEGUNDOS quedansegundos call un_segundo ; espera un segundo decfsz NUMSEGUNDOS ; decrementa NUMSEGUNDOS, y si aún no es cero, espera un segundo goto quedansegundos retlw 0 ; vuelve si ya ha llegado a cero ; esta rutina espera un segundo cada vez que se llama un_segundo movlw 4 ; retarda un segundo (es decir 4 veces 250 milisegundos) movwf VECES3 vuelta_3 movlw d'250' ; retarda un cuarto de segundo (osea, 250 milisegundos) movwf VECES2 vuelta_2 movlw d'111' ; vueltas para un milisegundo movwf VECES1 vuelta_1 ; hay 6 microsegundos para hacer los cálculos que hagan falta ; es decir, testear si se pulsa en GP4 (el botón de mosaico) y si es así "retocar" ; NUMSEGUNDOS = 1 para volver como mucho un segundo después (así da tiempo a "soltar" el botón ; que "mueve" GP4) y "marcar" que se debe entrar en "modo reposo" ; y si no se pulsa GP4... pues nada ;-) btfss GPIO,4 goto cambio_vistas_a_reposo btfsc VISTASoREPOSO,0 ; ¿hay que cambiar a modo "reposo"? (se revisa porque podria goto cambio_vistas_a_reposo ; estar activado de una llamada previa a "espera_segundo") vuelta ; los 4 nop's siguientes cubren los 4 microsegundos restantes hasta los 6 de espera nop nop nop nop if depurar == 1 ; XXXXX para NO esperar XXXXXXXXXXXXXXXXX movlw 1 ; así vuelve de la rutina de espera muy deprisa ;-) movwf VECES1 movwf VECES2 movwf VECES3 movwf NUMSEGUNDOS endif decfsz VECES1 ; ¿ha pasado ya un milisegundo? goto vuelta_1 decfsz VECES2 ; ¿ha pasado ya un cuarto de segundo? goto vuelta_2 decfsz VECES3 ; ¿ha pasado ya un segundo? goto vuelta_3 retlw 0 ; vuelve de la rutina de retardo cambio_vistas_a_reposo movlw 0x01 ; indica el cambio a modo de "reposo" movwf VISTASoREPOSO movwf VECES1 ; fijando todo a 1 termina enseguida el bucle de retardo movwf VECES2 movwf VECES3 movwf NUMSEGUNDOS goto vuelta ; sigue por donde iba ; un poco de propaganda para la posteridad :-) data '*','E','m','i','l','i','o','*' data '(','1','9','-','0','5','-','0','7',')' end ; directiva de fin de programa