Arduino UNO Sniffer Telefónico

Hola a toda la comunidad, que tal? Quiero compartir con ustedes este proyecto que encontré sumamente interesante. El concepto original fué elaborado por Matías Nahuel Heredia, el cual modifiqué para guardar la información en una tarjeta Micro SD.
Me encuentro con un inconveniente en la etapa final, ojalá puedan ayudarme y demás está decir que esta información es totalmente libre y pueden utilizarla como prefieran.

El circuito receptor DTMF para monitorear los tonos que se transmiten por la línea telefónica es el siguiente:

dtmf_receiver_circuit.gif
La conexión de los pines de salida del HT9170B/D a la placa Arduino UNO es la siguiente:

HT9170B/D --> Arduino UNO
D0(Pin 11) --> Arduino UNO (Pin 2)
D1(Pin 12) --> Arduino UNO (Pin 3)
D2(Pin 13) --> Arduino UNO (Pin 4)
D3(Pin 14) --> Arduino UNO (Pin 5)

El terminal con la etiqueta "Tone" se conecta directamente a un terminal de la línea telefónica y el otro terminal de la línea telefónica se conecta a GND.

La alimentación para este circuito se obtiene directamente de la placa Arduino UNO. Existe en dicha placa un terminal que provee 5V.

Ver Receptor DTMF

El circuito para conectar una tarjeta Micro SD a la placa Arduino UNO es el siguiente:
arduino_sdcard_circuit.gif
Los pines 10, 11, 12 y 13 corresponden a los pines de la placa Arduino UNO.
La alimentación para este circuito se obtiene directamente de la placa Arduino UNO. Existe en dicha placa un terminal que provee 3.3V.
Este circuito lo construí sobre un adaptador Micro SD a SD como se puede observar en la siguiente imagen.

Ver Adaptador SD a Arduino UNO

Con ambos circuitos armados procedemos a interconectar las tres placas como se observa en la siguiente imagen.

Ver Arduino UNO + Receptor DTMF + Adaptador SD

Habiendo interconectado exitosamente las tres placas procedemos a escribir el programa cuya función será leer el estado de las 4 entradas (Pin 2 a Pin 5) y almacenar el valor obtenido a un archivo de texto en la tarjeta Micro SD.

Antes de continuar la lectura recomiendo ver la Tabla de Códigos DTMF

Código:
#include <SD.h>

File myFile;
byte digit;

void setup()
{
	pinMode(2, INPUT);
	pinMode(3, INPUT);
	pinMode(4, INPUT);
	pinMode(5, INPUT);
	pinMode(10, OUTPUT);
	
	digit = 0;
	
	if (!SD.begin(10))
	{
		return;
	}
}

void loop()
{
	if (digitalRead(2) == HIGH)
	{
		digit = digit + 1;
	}
	if (digitalRead(3) == HIGH)
	{
		digit = digit + 2;
	}
	if (digitalRead(4) == HIGH)
	{
		digit = digit + 4;
	}
	if (digitalRead(5) == HIGH)
	{
		digit = digit + 8;
	}
	
	if(digit > 0)
	{
		myFile = SD.open("log.txt", FILE_WRITE);
		
		if(myFile)
		{
			myFile.print(digit);
			myFile.print("-");
			myFile.close();
		}
		
		digit = 0;
	}
	
	delay(50);
}

Ahora se presenta el siguiente inconveniente:

Cuando el circuito integrado HT9170B/D recibe un tono DTMF, el mismo persiste indefinidamente en las salidas (D0 - D3), por lo tanto el programa siempre obtiene un valor de las entradas (Pin 2 - Pin 5) y continúa escribiendo este valor indefinidamente en el archivo de texto. Por ejemplo:

Si marcamos en el teclado del teléfono los números: 0351 (el último numero, 1 en este ejemplo, se almacena indefinidamente).

Un intento por solucionar este problema, fué conectar el pin 15 del HT9170B/D al pin 10 del mismo (es la línea de puntos en el circuito receptor).

Pin 15: DV (Data Valid). Mantiene un nivel lógico alto cuando se detecta un tono válido y matiene su nivel lógico alto mientras se encuentre presente el tono, caso contrario mantiene un nivel lógico bajo.

Pin 10: OE (Output Enable). Controla la habilitación o alta impedancia de las compuertas tri-state de las salidas (D0 - D3). Con un nivel lógico alto se habilitan las compuertas y con un nivel lógico bajo se mantienen en estado de alta impedancia.

Lógicamente, si conectamos el pin 10 al pin 15 debería solucionarse el problema de la persistencia del tono en las salidas (D0 - D3), pero lamentablemente con las salidas en estado de alta impedancia la placa Arduino UNO, por razones que todavía desconozco, interpreta el estado de alta impedancia como si fuera un nivel lógico alto y, en consecuencia se obtiene una lectura errónea. Si analizamos el código fuente, con todas las entradas en nivel lógico alto, veremos que se cumplen todas las condiciones IF, obteniendo como resultado final 15 (1+2+4+8)...y la pregunta es: ¿Como podría solucionarse este inconveniente?

Exceptuando este inconveniente el proyecto es completamente funcional y el código fuente se encuentra libre de errores.

Muchas Gracias.
Saludos cordiales.
 
Nunca usé estos integrados ni arduino, y mi respuesta por eso mismo es tratar de dar alguna idea.

Pero no podía dejar de querer aportar algo viendo un mensaje TAN BIEN ESCRITO :aplauso:, con toda la información necesaria para entender cuál es el problema, qué es lo que se intenta lograr, qué herramientas se usan, cual es el enfoque utilizado, etc. Con código fuente, esquemáticos del hardware, y hasta fotos!!!!
Un ejemplo de lo que debería ser una buena consulta en contraste con mucha gente que espera que le resuelvan las cosas sin aprender nada en el medio.

Bueno, basta de cháchara.
Intentaría sería utilizar la línea data valid o EST con el Arduino. Cuál de las dos utilizar depende si uno quiere captar tonos de corta duración en la línea (EST) o solo leer tonos que tengan una separación de tiempo "aceptable" entre sí (parámetros tia y tir) -> línea DV.
Ver la diferencia en la figura 3 de la hoja de datos (adjunto imagen). La línea EST "capta" el tono de corta duración al principio y también la separación entre los 2 últimos tonos. Por el contrario, la línea DV no capta el primer tono por ser demasiado corto, y los 2 últimos tonos los ve como uno solo.

Siendo que es una aplicación de un micro y la intención creo que debería ser ver todo lo que pasa en la línea, yo usaría la línea EST.

Haría el monitoreo de esa línea en el programa del arduino, conectando EST a un pin de entrada cualquiera.
El programa dentro del loop sería algo como:

Código:
while(digitalRead(EST_PIN) == LOW); //esperar el flanco ascendente: que la línea cambie de 0 a 1

//En este punto sabemos que hay un dato válido en la línea
//Leer las lineas D0,D1,D2,D3 y hacer la escritura a SD,
//lo mismo que hacés en void loop() excepto el delay(50)

while(digitalRead(EST_PIN) == HIGH); //esperar el flanco descendente: que la línea cambie de 1 a 0, para evitar re-leer el dato que ya guardamos

//No usar delay(50)
Entonces de esta manera se guarda 1 dato y sólo 1 cuando hay un flanco ascendente en la línea EST, es decir, cuando se detecta un nuevo tono.

Aún así este código tiene limitaciones, que pasa si hay un nuevo tono mientras se está escribiendo el dato en la SD? -> lo perdemos.
¿Que tan grande es esa ventana? -> depende de lo que tarde la rutina de escritura de datos a la SD que es la que más demora. Siendo que se usa un sistema de archivos para escribir esa demora puede ser grande (hablando en forma relativa, unos 50 milisegundos por ejemplo).

¿Se podría cambiar el código para que no tenga tonos perdidos?: sí, hay que usar interrupciones para detectar los flancos en la línea EST y guardar los datos en un buffer (dentro de la misma interrupción), y luego en el código del loop escribirlos a la SD. Pero eso sería si realmente uno quiere captar tonos con una separación de - por ejemplo - 1 milisegundo o menos, lo que puede no ser necesario.

También estaría bueno guardar el tiempo de duración del tono, que se podría hacer leyendo el tiempo inicial inmediatamente después del primer while (flanco ascendente) y el tiempo final inmediatamente después del 2do while (flanco descendente). Pero que quede para después de haber logrado no grabar tonos repetidos.

Suerte!!!
 

Adjuntos

  • ht9170 figura 3.png
    ht9170 figura 3.png
    53.6 KB · Visitas: 7
Gracias a la ayuda de Ardogan y mi amigo Werner, el inconveniente ha sido solucionado. El sniffer ahora funciona correctamente.

A continuación publico nuevamente el tutorial para aquellos que deseen construirlo desde cero. Es completamente funcional y libre de errores.

Quiero compartir con ustedes este proyecto que encontré sumamente interesante. El concepto original fué elaborado por Matías Nahuel Heredia, el cual modifiqué para guardar la información en una tarjeta Micro SD.

El circuito receptor DTMF para monitorear los tonos que se transmiten por la línea telefónica es el siguiente:

dtmf_receiver_circuit.gif

HT9170B/D Datasheet

La conexión de los pines de salida del HT9170B/D a la placa Arduino UNO es la siguiente:

HT9170B/D --> Arduino UNO
D0(Pin 11) --> Arduino UNO (Pin 2)
D1(Pin 12) --> Arduino UNO (Pin 3)
D2(Pin 13) --> Arduino UNO (Pin 4)
D3(Pin 14) --> Arduino UNO (Pin 5)
DV(Pin 15) --> Arduino UNO (Pin 6)

El terminal con la etiqueta "Tone" se conecta directamente a un terminal de la línea telefónica y el otro terminal de la línea telefónica se conecta a GND.

La alimentación para este circuito se obtiene directamente de la placa Arduino UNO. Existe en dicha placa un terminal que provee 5V.

Ver Receptor DTMF

El circuito para conectar una tarjeta Micro SD a la placa Arduino UNO es el siguiente:
arduino_sdcard_circuit.gif
Los pines 10, 11, 12 y 13 corresponden a los pines de la placa Arduino UNO.
La alimentación para este circuito se obtiene directamente de la placa Arduino UNO. Existe en dicha placa un terminal que provee 3.3V.
Este circuito lo construí sobre un adaptador Micro SD a SD como se puede observar en la siguiente imagen.

Ver Adaptador SD a Arduino UNO

Con ambos circuitos armados procedemos a interconectar las tres placas como se observa en la siguiente imagen.

Ver Arduino UNO + Receptor DTMF + Adaptador SD

Habiendo interconectado exitosamente las tres placas procedemos a escribir el programa cuya función será leer el estado de las 5 entradas (Pin 2 a Pin 6) y almacenar el valor obtenido a un archivo de texto en la tarjeta Micro SD.

Antes de continuar la lectura recomiendo ver la Tabla de Códigos DTMF

Código:
#include <SD.h>

File myFile;
byte digit;

void setup()
{
	pinMode(2, INPUT); //D0
	pinMode(3, INPUT); //D1
	pinMode(4, INPUT); //D2
	pinMode(5, INPUT); //D3
	pinMode(6, INPUT); //DV
	pinMode(10, OUTPUT); //SD Card SS
	
	if (!SD.begin(10))
	{
		return;
	}
}

void loop()
{
	while(digitalRead(6) == LOW)
	{
		;
	}
	
	digit = 0;
	
	if (digitalRead(2) == HIGH)
	{
		digit = digit + 1;
	}
	if (digitalRead(3) == HIGH)
	{
		digit = digit + 2;
	}
	if (digitalRead(4) == HIGH)
	{
		digit = digit + 4;
	}
	if (digitalRead(5) == HIGH)
	{
		digit = digit + 8;
	}
	
	myFile = SD.open("log.txt", FILE_WRITE);
	
	if(myFile)
	{
		myFile.print(digit);
		myFile.print("-");
		myFile.close();
	}
	
	while(digitalRead(6) == HIGH)
	{
		;
	}
}

Lógicamente es perfectible y cada uno puede adaptarlo a sus necesidades particulares.
 
Atrás
Arriba