;*********************************************************************************************; ;Version para conectar con el CMX602B ;-El uC se inicializa y se queda dormido para despertar con RB0 conectado al CMX en su pin DET(pin 13), ; de modo que despertará con un flanco de Subida. Habra un pulso de Subida con cada ring (y despues ; uno de bajada). ;-Al despertar el uC : ; .Pone a '1' el pin RXCK del CMX conectado a su pin 7 (RB1) para desbloquearlo la salida de datos, ; y asi recibir la informacion en RA2 (pin1 para RX a 1200bps). ; .Comprueba si el ring es el primero, verificando si hay varias 'U' seguidas, si no es asi, se ; duerme de nuevo. ; .Si hay varias 'U' recibe el mensaje FSK completo, y manda el pulso al rele a traves de ; RB7(pin 13 del uC) si la llamada era oculta. ; .Tanto si hay mensaje como si no, espera 1 segundo, y despues vuelve a poner a '0' al pin RXCK ; del CMX. ;-El uC vuelve a dormir en un bucle infinito. ;...............................................................................................; ;-Para ser mas didactico, el programa recaba Toda la informacion presente en la llamada, incluyendo ; datos que no son necesarios para bloquear las llamadas ocultas. Si se conecta un PC al pin ; etiquetados como "Test" (pin 2 RA3 del PIC y masa), puede leerse la informacion via serie con el ; "Hyperterminal" a 1200bps. ; (Se guardan primero los datos en memoria y al finalizar la recepcion, se envian por el pin 2 (RA3). ; ;..............................................................................................; ; Author: Gustavo (cyberian@orangecorreo.es, robotico@iespana.es, tel. 915270969) ; El autor imparte clases particulares de programacion e informatica en Madrid. ; ; Fecha: entre el 2007 y el 2009 aprox. ; ; * Otros comentarios: ; Se supone que el programa es compatible con PIC16F84/PIC16F28 o de la familia para 18 patas. ; Compilar con MPASM V1.50 (o superior) ; Hay que usar un cristal (XT) de 3.579545 Mhz. Si no, los retardos no iran bien, y la.. ;.. transmision/recepcion serie tampoco. ;Port Allocation (los puertos) ; A2[pin 1] (entrada) <- serial RX ; A3[pin 2] (salida) -> serial TX ; BO[pin 6] (entrada) <- wake up on ring (line event sensed) ; B1[pin 7] (salida) -> control del pin14 RXCK del CMX602B ; B7[pin 13](salida) -> para el Rele ;*********************************************************************************************; __CONFIG _XT_OSC&_WDT_OFF&_CP_OFF ;esto es para que icprog aparezca con XT y sin WatchDog #Include ;este archivo esta en la carpeta del MPASM.exe ;constantes para el mensaje (presentacion) TIPOMSG_ESTABLECIMIENTO EQU 80h ;[ tipo_parametro | longitud | informacion ] TIPOPARAM_FECHAHORA EQU 01h ;debe ser de 8 bytes de longitud TIPOPARAM_ID_LLAMANTE EQU 02h ;tendra entre 9 y 20 caracteres (telefono) TIPOPARAM_ID_AUSENTE EQU 04h ;un mamon oculta la llamada SEGUNDO EQU 05h ;un segundo mas o menos CTE_RETARDO EQU 5*SEGUNDO ;para producir un pulso de unos 5sg en el rele. RB_CMX_RXCK EQU 1 ;RB1 se usa para conectar con la salida RXCK del CMX602 ;Constantes para Transmision-Recepcion con el PC. (PC-Link Pin allocation) ; Half Duplex Asynchronous Communication - 1200 Baud for 3.579545MHz resonator RX equ 2 ; PC-Link Receive Pin ( Bit 2 of Port A ) TX equ 3 ; PC-Link Transmit Pin ( Bit 3 of Port A ) Same equ 1 MSB equ 7 ; Following code sets the delay times for the selected baudrate ; X is the unknown delay ; Values below are for 1200bd on a 3.579545MHz resonator ; BAUD_4 is half the reqd 1.25B delay so delay4 is repeated BAUD_1 equ .248 ; 3+3X = CLKOUT/Baud BAUD_2 equ .247 ; 6+3X = CLKOUT/Baud BAUD_3 equ .123 ; 3+3X = 0.5*CLKOUT/Baud BAUD_4 equ .150 ; 3+3X = 1.25*CLKOUT/Baud BAUD_X equ .245 ; 11+3X = CLKOUT/Baud BAUD_Y equ .246 ; 9 +3X = CLKOUT/Baud ;................................. ;Podemos usar ram especificando la direccion del registro a partir de 0Ch (12 en decimal) ;hasta la 4Fh incluida (68 bytes de 'mielda' en el PIC16F84A). ;REGISTROS msg_len EQU 0Ch ;longitud del mensaje FSK param_len_id_llamante EQU 0Dh ;maximo 20 (tipico 9) param_len_id_ausente EQU 0Eh ;1 byte param_len_fechahora EQU 0Fh ;debera ser 8 "09300012" (mes,dia,hora,minuto) param_fechahora EQU 010h ;10h,11h,12h,13h,14h,15h,16h,17H param_id_llamante EQU 018h ;18h-2Bh (20 bytes) param_id_ausente EQU 02Ch DlyCnt EQU 02Dh ; Delay used in pause routine ASCIIBYTE EQU 02Eh Count EQU 02Fh RcvReg EQU 030h ; Serial Data receive register XmtReg EQU 031h ; Serial Data to be transmitted (se usa W) param_len EQU 032h ;para retransmitir al PC bOculta EQU 033h ;booleano que indica que hay llamada oculta cont_int EQU 034h ;para producir retardo cont_ext EQU 035h ;para producir retardo cont_outer EQU 036h ;para producir retardo(anidado triple) ;saber si viene un mensaje (descartar los ring sin informacion FSK) contU EQU 037h ;cuenta las 'U' (010101...) contCh EQU 038h ;cuenta los caracteres recibidos bHayMensaje EQU 039h ;el ring lleva un mensaje ;---------------- MACROS_BEGIN -------------------------------------------------; #define BANCO0 BCF STATUS,5 #define BANCO1 BSF STATUS,5 ;estas dos macro salvan el registro de 'curro' W y el de STATUS (se usa en interrupciones) push_macro macro movwf W_TEMP swapf STATUS,w movwf STATUS_TEMP endm pop_macro macro swap STATUS_TEMP movwf STATUS swapf W_TEMP,f swapf W_TEMP,w endm ;---------------- MACROS_END -------------------------------------------------; BEGIN ;================ Comienzo programa principal, las rutinas estan despues (al final) ============; init ;configurando los pines de los puertos como entradas o salidas. ;RB0 entrada para despertar, ira conectada a la salida DET (pin13) del CMX602. ;RB1 salida, que ira conectado a la salida RXCK (pin 14) del CMX602 para ponerla a cero y asi bloquear/desbloquear datos. ;RB7 salida para el rele (daremos un pulso positivo de unos 5 segundos) ;El CMX se bloquea si ponemos a '0' su pin RXCK, por eso hay que volver a ponerlo a '1' para recibir. movlw B'00000001' ;del puerto B solo sera entrada RBO (wake-up) tris PORTB ;eso mismo clrf PORTB ;limpieza movlw B'00000100' ;del puerto A solo sera entrada RA2 (RX) tris PORTA ;eso mismo ;configurar para que el PIC se despierte si hay un cambio en RB0 (no es una interrupcion) BANCO1 ;usaremos la salida DET del CMX602B en su flanco de Subida. movlw B'11000000' ;sin pull-ups en puerto B, y activar con flanco de subida(cero en reposo) movwf OPTION_REG BANCO0 ;.............................................. ;bucle de recepcion de los mensajes FSK. bucle_mensajes movlw B'00010000' ;el bit 4 es para RB0 en INTCON, y el bit 2 (flag de interrupcion por RB0) debemos.. movwf INTCON ;..ponerlo a 0 si no queremos que se quede despierto. bcf PORTB,RB_CMX_RXCK ;el pin RB1 se pondra a '0' para recibir solo la señal IRQN (el cmx no envia datos) call tx_dormido sleep ;a joder la marrana.. bsf PORTB,RB_CMX_RXCK ;el pin RB1 se pondra a '1' para desbloquear la salida de datos del CMX call tx_despierto ;al menos que se vea que esta funcionando ;comprobar si es un ring sin informacion call isFSKMSG ;bHayMensaje=1 MensajeFSK; bHayMensaje=0 mierda. btfss bHayMensaje,0 ;con mirar el primer bit es suficiente goto bm_end ;no hubo suerte ;.,.,.,.,.,.,.,.,.,.,.; call RecibirMensaje ;<-Aqui esta lo importante ;.,.,.,.,.,.,.,.,.,.,.; movlw SEGUNDO ;un pequeño retardo (1sg) para evitar sobresaltos. call hyper_retardo bm_end ;volver al bucle de mensajes goto bucle_mensajes ;.............................................. ;============ Fin del programa principal =====================================================; ;============ Rutinas_begin ==================================================================; ;Esta rutina verifica que se han recibido al menos cuatro 'U' seguidas, para así descartar la ;basura que viene cuando se despierta por un ring sin informacion util. ;Si se reciben cuatro 'U' seguidas la rutina devuelve un 1 en bHayMensaje ;Si se reciben 32 caracteres, y no hubo cuatro 'U' seguidas la rutina devuelve un 0 en bHayMensaje isFSKMSG ;iniciar contadores a cero movlw 0 movwf contU movwf contCh isfsk_scan call Recibir ;el caracter aparece en 'RcvReg' incf contCh,F ;otro caracter mas movlw 'U' subwf RcvReg,0 ;RcvReg - W, que se guardara en W btfss STATUS,Z ;el bit 2 es el cero como resultado goto isfsk_not_U ;no es una 'U' incf contU,F ;la cosa va bien.. btfss contU,2 ;el bit 2 es un cuatro goto isfsk_scan ;faltan aun para darlo por bueno movlw 1 movwf bHayMensaje call tx_SI ;;depuracion return ;mensaje encontrado!! isfsk_not_U movlw 0 movwf contU ;resetear el contador de 'U' (deben ser seguidas) ;comprobar si llevamos 32 caracteres de basura btfss contCh,5 ;el bit 5 es un 32 goto isfsk_scan ;aun se puede seguir buscando movlw 0 movwf bHayMensaje call tx_NO ;;depuracion return ;ring sin informacion (solo basura) ;........................................................................................... ;Esta rutina hace lo siguiente: ;-busca donde empieza el mensaje FSK ;-descompone los datos y guarda fecha,telefono/oculta ;-manda por el pin 2 (RA3) la informacion ya extraida a 1200bps (para el PC) ;-activa el rele si era una llamada oculta poniendo a '1' RB7 (pin 13) durante 5 segundos RecibirMensaje ;iniciar contador de caracteres a cero movlw 0 movwf contCh ;buscar el establecimiento rm_buscar_establecimiento call Recibir ;el caracter aparece en 'RcvReg' incf contCh,F ;otro caracter mas movlw TIPOMSG_ESTABLECIMIENTO ;080h subwf RcvReg,0 ;RcvReg - W, que se guardara en W btfsc STATUS,Z ;el bit 2 es el cero como resultado goto rm_hay_mensaje ;estaba en set (encontrado) ;comprobar si llevamos 32 caracteres de basura btfss contCh,5 ;el bit 5 es un 32 goto rm_buscar_establecimiento ;aun se puede buscar return ;ring sin informacion (solo basura) rm_hay_mensaje: ;iniciar longitudes a cero movlw 0 movwf param_len_fechahora movwf param_len_id_llamante movwf param_len_id_ausente movwf bOculta ;justo detras esta la longitud total del mensaje call Recibir ;el caracter aparece en 'RcvReg' movf RcvReg,0 ;tiene que estar en W para restar movwf msg_len ;longitud del mensaje que viene a continuacion ;Lo que sigue son parametros [ tipo_parametro | longitud | informacion ] parametros_mensaje ;tipo del parametro call Recibir ;el caracter aparece en 'RcvReg' decf msg_len,1 ;decrementar 1 la longitud mensaje ;switch(param_tipo) param_is_fechahora movlw TIPOPARAM_FECHAHORA ;0x1 debe ser de 8 bytes de longitud subwf RcvReg,0 ;RcvReg - W, que se guardara en W btfss STATUS,Z ;si no es, comprobar si es id_llamante goto param_is_id_llamante ;guardar la longitud del parametro call Recibir ;el caracter aparece en 'RcvReg' movf RcvReg,0 movwf param_len_fechahora ;longitud del mensaje que viene a continuacion (debe ser un 8) decf msg_len,1 ;decrementar 1 la longitud mensaje ;guardar parametro movlw 010h ;w apunta a param_fechahora movwf FSR ;FSR apunta a param_fechahora movf param_len_fechahora,0 ;w:=param_len_fechahora movwf param_len ;param_len:=param_len_fechahora ;restar la longitud del parametro al mensaje subwf msg_len,1 ;msg_len - W, que se guardara en msg_len call guardar_parametro goto param_end_switch param_is_id_llamante movlw TIPOPARAM_ID_LLAMANTE ;0x2 tendra entre 9 y 20 caracteres (telefono) subwf RcvReg,0 ;RcvReg - W, que se guardara en W btfss STATUS,Z ;si no es, comprobar si es id_ausente goto param_is_id_ausente ;guardar la longitud del parametro call Recibir ;el caracter aparece en 'RcvReg' movf RcvReg,0 movwf param_len_id_llamante ;longitud del mensaje que viene a continuacion (debe ser un 9) decf msg_len,1 ;decrementar 1 la longitud mensaje ;guardar parametro movlw 018h movwf FSR ;FSR apunta a param_id_llamante movf param_len_id_llamante,0 movwf param_len ;restar la longitud del parametro al mensaje subwf msg_len,1 ;msg_len - W, que se guardara en msg_len call guardar_parametro goto param_end_switch param_is_id_ausente movlw TIPOPARAM_ID_AUSENTE ;0x4 un mamon oculta la llamada subwf RcvReg,0 ;RcvReg - W, que se guardara en W btfss STATUS,Z goto param_end_switch ;si no es, ya no comprobar nada mas ;guardar la longitud del parametro call Recibir ;el caracter aparece en 'RcvReg' movf RcvReg,0 movwf param_len_id_ausente ;longitud del mensaje que viene a continuacion (debe ser un 9) decf msg_len,1 ;decrementar 1 la longitud mensaje ;guardar parametro movlw 02Ch movwf FSR ;FSR apunta a param_id_ausente movf param_len_id_ausente,0 movwf param_len ;restar la longitud del parametro al mensaje subwf msg_len,1 ;msg_len - W, que se guardara en msg_len call guardar_parametro ;ademas activar booleano indicandolo movlw 1 movwf bOculta ;bOculta:=1 param_end_switch ;comprobar si msg_len es cero movf msg_len,0 ;W:=msg_len iorwf msg_len,0 ;or consigo mismo btfss STATUS,Z ;salir del bucle de mensajes si es cero goto parametros_mensaje ;fin del mensaje FSK ;Ahora se pueden transmitir los datos call tx_msg ;tenemos un mensaje de establecimiento de llamada ;fecha-hora call tx_fecha movlw 010h ;w->param_fechahora movwf FSR ;FSR apunta a param_fechahora movf param_len_fechahora,0 ;w:=param_len_fechahora movwf param_len ;param_len:=param_len_fechahora call retransmitir_parametro ;DD-MM HH:MM ;O hay llamante o bien es oculta (se excluyen) movf bOculta,0 ;W:=bOculta iorwf bOculta,0 ;or consigo mismo btfss STATUS,Z goto es_oculta ;llamante (la llamada no fue ocultada) call tx_llama movlw 018h ;w->param_id_llamante movwf FSR ;FSR apunta a param_id_llamante movf param_len_id_llamante,0 ;w:=param_len_id_llamante movwf param_len ;param_len:=param_len_id_llamante call retransmitir_parametro ;ej: 649348904 goto bucle_mensajes es_oculta ;llamada ocultada call tx_mamon movlw 02Ch ;w->param_id_ausente movwf FSR ;FSR apunta a param_id_ausente movf param_len_id_ausente,0 ;w:=param_len_id_ausente movwf param_len ;param_len:=param_len_id_ausente call retransmitir_parametro ;"P" o "O" call send_pulse ;aqui ademas enviamos un pulso positivo de unos 5sg al rele return ;.......................................................................................... ;Envia un pulso de unos 5sg al rele: RB7 (pin13 del chip) ; sabiendo que cada instruccion tarda 1.17uS, salen unas 2115^2 instrucciones send_pulse bsf PORTB,7 ;efectuar un retardo de unos 5sg sabiendo que cada instruccion tarda 1.17uS movlw CTE_RETARDO call hyper_retardo bcf PORTB,7 return ;.......... ;Rutina de retardo. ;Recibe en W la constante del bucle mas externo (CTE_RETARDO) en el caso del pulso del rele. ;esto es un bucle anidado triple hyper_retardo movwf cont_outer ;cont_outer tiene el control sp_outer movlw 0FFh movwf cont_ext ;cont_ext:=255 sp_externo movlw 0FFh movwf cont_int ;cont_int:=255 sp_interno decfsz cont_int,1 goto sp_interno decfsz cont_ext,1 goto sp_externo decfsz cont_outer,1 goto sp_outer return ;................................................... ;Guarda los bytes de un parametro ;FSR apuntara al principio del parametro (puntero leido con INDF) ;param_len debe contener el numero de bytes a transmitir (longitud) guardar_parametro gp_bucle call Recibir ;el caracter aparece en 'RcvReg' movf RcvReg,0 ;W movwf INDF ;guardar donde apunta FSR incf FSR,F ;siguiente caracter del parametro decfsz param_len,F ;longitud del parametro goto gp_bucle return ;................................................... ;Tansmite al PC cada caracter recibido ;FSR apuntara al principio del parametro (puntero leido con INDF) ;param_len debe contener el numero de bytes a transmitir (longitud) retransmitir_parametro ;comprobar si es cero la longitud movf param_len,0 ;W:=param_len iorwf param_len,0 ;or consigo mismo btfsc STATUS,Z ;salta a rp_bucle si no es cero la longitud return rp_bucle movf INDF,0 ;en W para transmitir call Transmitir incf FSR,F ;siguiente caracter del parametro decfsz param_len,F ;longitud del parametro goto rp_bucle return ;................................................... ; 1200 baud Receiver routine. ;-Espera al bit de 'start' (en el pin RX que es el A2) ;-cada caracter recibido aparecera en el registro 'RcvReg' ;................................................... Recibir clrf RcvReg ; Clear all bits of RcvReg btfsc PORTA,RX ; check for a Start Bit on local RX pin (norm btfsc) goto Recibir ; delay for B (833uS for 1200Bd) call Delay4 ; delay for 1.25 B call Delay4 ; delay for 1.25 B ; Receiver Routine Rcvr movlw 8 ; 8 Data bits movwf Count R_next bcf STATUS,C rrf RcvReg,Same ; to set if MSB first or LSB first btfsc PORTA,RX bsf RcvReg,MSB call DelayY decfsz Count,Same goto R_next movf RcvReg,0 ; Get Received character in w return ;................................................... ; 1200 baud Transmitter ; Transmitter Routine has has stop/start and data bits inverted for MAX232 level converter ; Si estos datos van al PC, es mejor dejar esta rutina como esta aunque no se use el MAX232. ; En caso contrario retocarla. ;-cada caracter a transmitir debe encontrarse en el registro W. ('XmtReg' se usa aqui dentro) ;................................................... Transmitir MOVWF XmtReg Xmtr movlw 8 movwf Count bcf PORTA,TX ; Send Start Bit call DelayB X_next bcf STATUS,C rrf XmtReg,Same ; Send LSB first btfsc STATUS,C bsf PORTA,TX btfss STATUS,C bcf PORTA,TX call DelayX decfsz Count,Same goto X_next bsf PORTA,TX ; Send Stop Bit call DelayB RETURN ;**************************************************************************************** ;* Various Delays for serial timing * ;* For variable delays, w can be loaded with delay constant and then call routine "save"* ;* Subroutine returns after given delay of 5 + 3N cycles * ;**************************************************************************************** DelayY movlw BAUD_Y goto save DelayX movlw BAUD_X goto save Delay4 movlw BAUD_4 goto save DelayB movlw BAUD_1 ;833uS for 1200Bd goto save Delay2 movlw BAUD_2 save movwf DlyCnt redo decfsz DlyCnt,Same goto redo retlw 0 ;********************************************** tx_msg movlw "*" call Transmitir movlw "M" call Transmitir movlw "S" call Transmitir movlw "G" call Transmitir movlw ":" call Transmitir return ;................................................... tx_despierto movlw "*" call Transmitir movlw "D" call Transmitir movlw "e" call Transmitir movlw "s" call Transmitir movlw "p" call Transmitir movlw "i" call Transmitir movlw "e" call Transmitir movlw "r" call Transmitir movlw "t" call Transmitir movlw "o" call Transmitir movlw "!" call Transmitir return ;................................................... tx_dormido movlw "*" call Transmitir movlw "D" call Transmitir movlw "o" call Transmitir movlw "r" call Transmitir movlw "m" call Transmitir movlw "i" call Transmitir movlw "d" call Transmitir movlw "o" call Transmitir movlw "." call Transmitir return ;................................................... tx_fecha movlw "-" call Transmitir movlw "F" call Transmitir movlw "E" call Transmitir movlw "C" call Transmitir movlw "H" call Transmitir movlw "A" call Transmitir movlw ":" call Transmitir return ;................................................... tx_llama movlw "-" call Transmitir movlw "L" call Transmitir movlw "L" call Transmitir movlw "A" call Transmitir movlw "M" call Transmitir movlw "A" call Transmitir movlw ":" call Transmitir return ;................................................... tx_mamon movlw "-" call Transmitir movlw "M" call Transmitir movlw "A" call Transmitir movlw "M" call Transmitir movlw "O" call Transmitir movlw "N" call Transmitir movlw ":" call Transmitir return ;................................................... tx_SI movlw "{" call Transmitir movlw "S" call Transmitir movlw "I" call Transmitir movlw "}" call Transmitir return ;................................................... tx_NO movlw "{" call Transmitir movlw "N" call Transmitir movlw "O" call Transmitir movlw "}" call Transmitir return ;................................................... END ;*********************************************************************************************;