Autor Tema: Identificador de llamadas telefónicas  (Leído 7821 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Spock_Andaluz

  • PIC10
  • *
  • Mensajes: 3
Identificador de llamadas telefónicas
« en: 18 de Diciembre de 2003, 04:00:00 »
Hola:
Ante todo, aviso, y pido disculpas por ello, de que este mensaje es muy largo, para que se entienda el proyecto.
Tengo poca experiencia con los PIC y he intentado diseñar un circuito que identifique el número del teléfono que nos llama de forma que pueda usar teléfono móvil para llamar al teléfono de mi casa y se encendiera una luz, pero quisiera que la luz solo se encendiera si el que llama soy yo y que NO se encienda si llama cualquier otro.
Tengo contratado el servicio de identificación de llamadas y utilizo un par de pantallas par ello, concretamente el modelo IDI de Telefónica que regalaba hace un tiempo.
El problema es que con estas pantallas se ve el número del que llama,
pero no me sirven para encender una luz al recibir un número concreto.
He estado buscando por Internet y he encontrado varias páginas que
hablan sobre los circuitos para identificar las llamadas (lo que en
inglés se llama “caller id”) y he encontrado varios esquemas, pero están pensando para mostrar el número en la pantalla, pero no para hacer lo que yo quiero.
Aquí hay varios enlaces sobre esto:
http://www.shout.net/~wildixon/callerid/callerid.html
http://matthieu.benoit.free.fr/cidfr.htm
http://www.ainslie.org.uk/callerid/cli_faq.htm
http://www.pablin.com.ar/electron/circuito/telefon/callerid/
Viendo alguno de estos circuitos, he pensado en usar uno de los
integrados que hay que se conectan a la línea telefónica y entregan las
señales de identificación en forma TTL en serie y después tratarlas con
un PIC para extraer el número del que llama y compararlo con el de mi
móvil y encender la luz en caso de que coincidan.
Mirando por Internet he encontrado otra página interesante sobre este tema:
http://members.kolp.at/clix/
Han montado un identificador completo usando un CMX602B, el mismo chip
que he usado yo, pero como micro usan un Atmel AT90S8515 en vez de un
PIC como he utilizado yo.
He adaptado el programa que se usa en ese proyecto para un PIC con el compilador de C de CCS, pero he llegado a un punto en que no avanzo, pues el micro solo captura algunos caracteres (solo dos o tres) y pierde los demás.
Para descartar problemas con el CMX602B, lo configuré para que no usara el “data retiming” y “escupiera” los caracteres según los decodificara, viéndolos en el PC previo paso por un MAX232.
El resultado es que se recibía perfectamente todo el mensaje, con los
bytes de control,  fecha, hora y número de teléfono completos, aunque
antes y después del mensaje se colaban algunos caracteres aleatorios, de ruido, pero fácilmente eliminables.
Mirando el montaje aparecido en “Todo electrónica”, me di cuenta de que algunos componentes que rodean al CMX eran diferentes respecto a los que aparecen en el data sheet del fabricante, concretamente los del amplificador operacional que incluye, y que es el que amplifica la señal FSK antes de demodularla. Están ajustados de forma que tenga menos ganancia. Lo probé así y se reciben menos caracteres de “ruido” al principio y final del mensaje, pero los datos útiles se reciben
perfectamente de las dos formas. Así descarté que el problema estuviera aquí. Después he dejado los componentes del montaje de “Todo
electrónica” para que capte menos ruido.
Después vuelvo a montarlo con el PIC y el CMX configurado en modo “data retiming” y pensé que el problema pudiera estar en que el programa del PIC fuera demasiado lento y no fuera capaz de seguir el ritmo que le imponía el CMX,  por lo que cambié el PIC por uno más rápido, pues estaba usando un 16F84A con la misma señal de reloj del CMX, concretamente a 3,579545 Mhz. Lo he cambiado por un 16F876A con un cristal de 20 Mhz, pues el 16F84A que tenía es de 4 Mhz.
El resultado es exactamente el mismo, captura los mismos pocos caracteres.
Sospeché que pudiera ser problema de falta de velocidad porque
originalmente el programa era para un Atmel AVR, que como sabréis, son
unas cuatro veces más rápidos que un PIC a la misma frecuencia de reloj, pues ejecutan una instrucción por cada pulso de reloj, mientras que los PIC necesitan cuatro.
Así pues, como mis escasos conocimientos de los PIC no dan para más,
incluyo el listado a continuación por si alguno quiere perder un rato en estudiarlo, por si detecta algún error o se le ocurre alguna idea para mejorarlo.
El montaje es el siguiente:
La pata 10 (MODE) del CMX la he unido a la RB3 del PIC. La pata 11 del
CMX (ZP) la he puesto a masa La pata12 (IRQN) a la RB0, la de interrupción externa. La pata 13 (DET) del CMX no la he usado. La pata
14 (RXCK) va a RB2 y la pata 15 (RXD) a RB1.
En cuanto al programa, en la función main() he hecho un bucle sin fin
que solo hace que cambie de color un LED bicolor conectado a las patas
RB6 y RB7, que puse para asegurarme de que el programa estaba
funcionando. En la pata RB4 he puesto un pulsador para parar el programa y grabar en la EEPROM una serie de variables que he usado para saber hasta donde llega la decodificación.
Después de recibir la llamada, la variable CMX_State me suele alcanzar
el valor 2 y cont alcanza 5, aunque si cambio el retardo al principio de la rutina de interrupción (delay_cycles (8)) a un valor muy bajo (0 o 1) o muy alto (mayor de 16) CMX_State solo alcanza 1, o cont solo llega a 2 o 3. En el mejor de los casos, la matriz x solo me captura unas dos “U”, a veces tres, y después caracteres sin sentido, pues sabéis que antes del mensaje principal, se envía una ráfaga de caracteres U (unas 15 o 20).
Como veréis, la mayor parte del trabajo se hace en la rutina de interrupción.
El programa es tal vez demasiado complicado y confuso, pero como ya dije, no lo he hecho yo, sino que lo he “fusilado” del que hay en
http://members.kolp.at/clix/ , limitándome a “traducirlo” de un AVR a
PIC. Es el siguiente:

---------------------------------------------------------------
// Based on Reinhard Kapeller (http://members.kolp.at/clix/)

#include <16F876A.h>
#fuses   HS, NOPROTECT,NOWDT,NOPUT,NOLVP,NOBROWNOUT,NOCPD,NODEBUG,WRT
#use delay (clock=20000000)

#BIT INTEDG = 0x81.6

 //Signals of CMX602B - pins of port B of PIC16F876A
#DEFINE IRQN PIN_B0
#DEFINE RXD  PIN_B1
#DEFINE RXCK PIN_B2
#DEFINE MODE PIN_B3

#define DTMAX 8  // buffer length for datetime
#define NBMAX 20  // buffer length for number
 // CMX602B CMX_States
#define IDLE       0
#define RCV        1
#define RCV_U      2
#define RCV_MSGLEN 3
#define RCV_MSG    4
#define RCV_DTLEN  5
#define RCV_DT     6
#define RCV_NBLEN  7
#define RCV_NB     8
#define RCV_ARLEN  9
#define RCV_AR    10
#define RCV_XLEN  11
#define RCV_DONE  12
#define RCV_ERROR 13

char DateTime[DTMAX];
char Number[NBMAX];
byte CMX_State = IDLE;
byte NBLen;
byte DTLen;
byte MsgLen;
byte MsgPos;
byte BufPos;
byte Checksum;
byte AbsenceR;

  byte cont = 0;
  byte i, RX_Byte;
  char x[8];

void Init()
{
   set_tris_a (0);
   set_tris_b (0b00010011);
   set_tris_c (0);
   output_low (MODE);
   output_low (RXCK);
   ext_int_edge (H_TO_L);     //IRQ on falling edge
   enable_interrupts (INT_EXT); //enable interrupt (RB0)
   enable_interrupts (global);
//  CMX_State = IDLE;
}

/* interrupt service routine */
#int_ext
void ext_int_handler(void)
{
   if ((CMX_State >= RCV) && (CMX_State < RCV_DONE))
   {
     /* receive bits */
     RX_Byte = 0;
     for (i = 8; i > 0; i--)
     {
       delay_cycles (8);
       output_high (RXCK);
       RX_Byte >>= 1;
       if (input (RXD)) /* get bit */
         RX_Byte |= 0x80;
       output_low (RXCK);
     }
     x[cont]=RX_Byte;
     cont++;
     if (CMX_State >= RCV_MSGLEN)
       Checksum += RX_Byte;       /* calculate checksum */
     if (CMX_State >= RCV_MSG)
     {
       MsgPos++;    /* current message position */
       if (MsgPos > MsgLen)  /* last byte: checksum */
       {
         if (Checksum == 0)
        CMX_State = RCV_DONE;
         else
           CMX_State = RCV_ERROR;
         output_bit (MODE, 0);  /* FSK receive mode off */
       }
     }

     switch (CMX_State)   /* process RX_Byte */
     {
       case RCV:
         if (RX_Byte == "U")
         {
           MsgPos = 0;
           DTLen = 0;
           NBLen = 0;
           AbsenceR = 0;
           CMX_State = RCV_U;  /* -> RCV_U state */
         }
       break;
       case RCV_U:
         if (RX_Byte == 0x80)  /* "call setup" message */
         {
           Checksum = RX_Byte;  /* start calculating checksum */
           CMX_State = RCV_MSGLEN; /* -> RCV_MSGLEN state */
         }
       break;
       case RCV_MSGLEN:
         MsgLen = RX_Byte;  /* message length */
         CMX_State = RCV_MSG;  /* -> RCV_MST state */
       break;
       case RCV_MSG:
         switch (RX_Byte)
         {
           case 0x01:   /* "date/time" parameter */
             CMX_State = RCV_DTLEN; /* -> RCV_DTLEN state */
           break;
           case 0x02:   /* number parameter */
             CMX_State = RCV_NBLEN; /* -> RCV_NBLEN state */
           break;
           case 0x04:   /* "absence reason" parameter */
             CMX_State = RCV_ARLEN; /* -> RCV_ARLEN state */
           break;
           default:   /* unused/unknown parameter */
             CMX_State = RCV_XLEN;     /* -> RCV_XLEN state */
         }
       break;
       case RCV_DTLEN:
         if (RX_Byte == DTMAX) /* valid "date/time" length */
         {
           DTLen = RX_Byte;
           BufPos = 0;
           CMX_State = RCV_DT;  /* -> RCV_DT state */
         }
         else
           CMX_State = RCV_MSG; /* -> RCV_MSG state */
       break;
       case RCV_DT:
         DateTime[BufPos] = RX_Byte; /* store "date/time" byte */
         BufPos++;
         if (BufPos >= DTMAX)  /* end of "date/time" parameter */
           CMX_State = RCV_MSG;      /* -> RCV_MSG state */
       break;
       case RCV_NBLEN:
         NBLen = RX_Byte;  /* store "RX" length */
         BufPos = 0;
         CMX_State = RCV_NB;  /* -> RCV_NB state */
       break;
       case RCV_NB:
         Number[BufPos] = RX_Byte; /* store "RX" byte */
         BufPos++;
         if ((BufPos >= NBLen) || (BufPos >= NBMAX))
           CMX_State = RCV_MSG; /* end of "RX" parameter -> RCV_MSG state */
       break;
       case RCV_ARLEN:
         if (RX_Byte == 1)  /* valid "absence reason" length */
           CMX_State = RCV_AR;  /* -> RCV_AR state */
         else
           CMX_State = RCV_MSG; /* -> RCV_MSG state */
       break;
       case RCV_AR:
         AbsenceR = RX_Byte;  /* absence reason */
         CMX_State = RCV_MSG;  /* -> RCV_MSG state */
       break;
       case RCV_XLEN:
         CMX_State = RCV_MSG;  /* -> RCV_MSG state */
       break;
     }
   } /* if ((CMX_State >= RCV) && (CMX_State < RCV_DONE)) */
   else if (INTEDG) /* rising edge => end of ring indication */
   {
     delay_ms (2);
     output_high (MODE); /* FSK receive mode */
     CMX_State = RCV;
     disable_interrupts (INT_EXT);
     ext_int_edge (H_TO_L);  /* IRQ on falling edge */
     enable_interrupts (INT_EXT);
   }
   else     /* falling edge => ring indication */
   {
     disable_interrupts (INT_EXT);
     ext_int_edge (L_TO_H);  /* IRQ on rising edge */
     enable_interrupts (INT_EXT);
   }
}

void main()
{
//  int i;
   Init();
   while (input(PIN_B4))
   {
     output_high (PIN_B7);
     output_low (PIN_B6);
     delay_ms (250);
     output_low (PIN_B7);
     output_high (PIN_B6);
     delay_ms (250);
   }
   for (i=0; i<DTMAX; i++)
     write_eeprom (i, DateTime);
   write_eeprom (DTMAX, "#");
   for (i=0; i<NBMAX; i++)
     write_eeprom (DTMAX + 1 + i, Number);
   write_eeprom (0x30, CMX_State);
   write_eeprom (0x32, cont);
   write_eeprom (0x34, RX_Byte);
   for (i=0; i<8; i++)
     write_eeprom (0x20 + i, x);
}
---------------------------------------------------------------

Salu2 y gracias.

Desconectado karlosguay

  • PIC10
  • *
  • Mensajes: 41
RE: Identificador de llamadas telefónicas
« Respuesta #1 en: 18 de Diciembre de 2003, 10:18:00 »
Y porque para encender una luz, en vez de un caller-id no te montas un decodificador de dtmf, y al llamar a tu casa, le metes varios tonos en secuencia (una especie de clave) que hacen que se encienda o apague la luz?

Salud

Desconectado Ignite

  • PIC16
  • ***
  • Mensajes: 107
RE: Identificador de llamadas telefónicas
« Respuesta #2 en: 19 de Diciembre de 2003, 04:02:00 »
Buenas!!!
Primero de todo te digo que yo uso otro compilador para progamar los pics(hi-tech).Lo digo porque es algo distinto a este.
Bueno pues yo he utilizado varias veces el pic 16f84 junto con unas rutinas que vienen como ejemplo en el Hi-tech para poder transmitir via RS232.Si no recuerdo mal el máximo que he llegado a probar ha sido a 9600 y sin problemas.
Por tanto si con esta velocidad te sirve,solo tienes que hacer un copy/paste del código que viene como ejemplo y ya ta.Siento no poderte ayudar más,pero es que no he utilizado nunca un identificador de llamada.
Saludos.
Ignite

Desconectado Spock_Andaluz

  • PIC10
  • *
  • Mensajes: 3
RE: Identificador de llamadas telefónicas
« Respuesta #3 en: 23 de Diciembre de 2003, 03:12:00 »
Para Ignite y los que les pueda interesar, decir que las diferencias del montaje que yo he hecho, siguiendo la revista “todo electrónica”, respecto al original del fabricante del CMX602B (http://www.cmlmicro.com/Products/WTelecom/CMX602B.htm) es la siguiente:
Entre la unión de C6 y R6 se pone una resistencia de 470K a masa.
Entre la unión de C7 y R7 se pone una resistencia de 470K a masa.
La resistencia R9 se quita.
La resistencia R8 se pone de 100K.
La resistencia R10 se pone de 100K.
El resto de componentes son iguales que en el original de CML Micro.

Hay otra solución más barata y mejor para hacer un identificador de llamadas, pero para hacerlo hay que tener más conocimientos de la programación de los PIC que la que tengo yo.
Se puede hacer todo con solo un PIC, sin ningún otro chip.
Un tal Ken Boak, el administrador del grupo rat_ring (http://groups.yahoo.com/group/rat_ring/) ha hecho un programa en ASM para un PIC16F84 que decodifica los tonos del caller id, es decir, que se comporta igual que el CMX cuando está configurado como demodulador FSK, por lo que teniendo esas rutinas, se le pueden añadir el resto para tener el decodificador caller id completo con el PIC y unos pocos componentes pasivos externos.
El problema es que yo soy principiante con los PIC, pero si alguno tiene más experiencia, tal vez lo pueda conseguir.
Si con el 16F84 no hay bastante memoria, se podría usar un 16F628, que vale lo mismo y además tiene comparadores analógicos que serían de utilidad.
Mirad la página de Ken Boak aquí:

http://puggy.symonds.net/~catalyticideas/rat_ring/index.php?page=guide

El mismo Ken me escribió hace unos días sobre esto y me dijo:

“It is possible to demodulate the Caller ID signal just using a PIC16F84A at
3.58MHz using an interrupt driven routine to time the "zero-crossing" time
intervals.
I have done this with a PIC16F84A, 4 diodes for a bridge, an NPN
transistor and a few resistors.
The circuit is in the rat_ring files area, and it works as well as any
Caller ID chip.
Better results possible if you use the PIC16F628 or F88 which has a
comparator to make the input signal into a square wave with clean edges.
I will shortly be releasing an application note with asm code showing how to
do this,
Ken”

Si consegís algo, os agradecería que me lo dijérais.
También os puede ser de utilidad la página del alemán:
http://members.kolp.at/clix
Salu2.

Desconectado RGL

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 634
RE: Identificador de llamadas telefónicas
« Respuesta #4 en: 24 de Diciembre de 2003, 17:09:00 »
En www.melabs.com tienen una placa de entrenamiento con todos estos chip (caller id, DTMF, ....). Los ejemplos estan en PBP, pero el hardware te puede servir para ver como lo hacen ellos.

Saludos
Ricky

Desconectado ZorroCibernetico

  • PIC10
  • *
  • Mensajes: 4
RE: Identificador de llamadas telefónicas
« Respuesta #5 en: 11 de Diciembre de 2004, 21:49:00 »
Hola que tal, he trabajados con micros pero mas en la area de electronica, y no estoy muy empapado con lo que son los DTMF.
Necesito hacer un identificador de llamadas con un DTMF, y la verdad casi no tengo muchas ideas, si alguien me pudiera ayudar se lo agradeceria muchisimo.
De todos modos yo les seguire informando de como va mi proyecto.