http://www.ferduino.es/callerid/#funcionamiento
En resumen puede proporcionar a arduino a través de una señal serie la información CallerID y a través de un pin la señal de RING.
La señal de CallerID de 1200 baud es procesada como en los demás proyectos del bloqueador de llamadas que he hecho, con ligeras diferencias para el formateo de los datos recibidos.
El código final es el siguiente:
/* Proyecto de discriminador de llamadas telefonicas no deseadas. Tras la llamada se identifica el
numero llamante y se compara con los que están anotados en un fichero almacenado en una tarjeta SD. Si
coincide con alguno, la llamada es bloqueada. Graba automáticamente los números que han llamado
en un fichero en la tarjeta SD, que posteriormente pueden seleccionarse con la botonadura para ser bloqueados.
Se necesitan dos RING para poder leer el CALLERID. Lleva un buzzer incorporado que suena a partir del tercer RING,
para evitar que suenen los telefonos siempre un par de veces (hacer mute en los telefonos para evitar el ring).
LLeva un rele que activa o desactiva la linea telefonica saliente a solicitud del programa (para poder asi evitar
los 2 RING necesarios antes de la deteccion de callerID y bloquear la llamada entrante). Pero no es conveniente
usar este metodo de bloqueo, ya que no detecta el estado HOLD o llamada atendida, o en curso, con lo cual corta
la linea tras un periodo corto de tiempo y corta la llamada en curso o la atendida. Para evitar esto hay
que implementar un detector de HOLD y conectarlo a un PIN de arduino y generar el codigo de monitorización del
estado de dicho pin.
El hardware necesario es un Arduino Uno, un escudo Ferduino CaallerID, una tarjeta SD, un modulo LCD de 16x2,
una botonadura tipo Keypad DIY de resistencias (una botonadura simple con tres resistencias de 3K en serie
conectando GND a Pin A0, p.e.) y un rele. Todo el conjunto va metido en una caja.
El proyecto esta en : http://http://aestradadiy.blogspot.com.es/
Agradecimientos a callerid@ferduino.es por el hardware CallerID y el software de lectura serie.
La cadena del Caller ID detectada por el modem es siempre del tipo siguiente:
DATE = 0422 //MMDD
TIME = 1945 //HHMM
NMBR = 659278358 //Numero llamante
Conexion modulo Ferduino CallerID a Arduino es :
Pin 1 Ferduino RX a RX Arduino
Alimentación es por 5V. desde Arduino.
Pin 3 Ferduino a pin A3 de Arduino
http://www.ferduino.es/callerid/#funcionamiento
Conexion pines modulo SD a Arduino:
modulo: GND 3.3v 5v. CS MOSI SCK MISO GND
Arduino:GND 3.3V 5V. 10 11 13 12 GND
Conexion pines modulo LCD 1602 a Arduino:
(X)En modulo unir 1 y 3 con Resitencia 3K.
modulo: 1 2 3 4 5 6 ....11 12 13 14 15 16
Arduino:GND 5v(X) 2 GND 3 ....4 5 6 7 5v GND
La botonadura es del tipo resistencias en serie unidas a pin A0 y GND, y boton uniendo PIN RESET a GND.
El buzzer está conectado a: Pin A1 - GND - 5v
El rele esta conectado a pin A2.
El pin A3 RING del ferduino callerID esta conectado a pin A3.
*/
//Sample using LiquidCrystal library
#include <LiquidCrystal.h>
#include <SdFat.h>//CS en pin 10
SdFat sd;
SdFile myFile;
// select the pins used on the LCD panel
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
// define some values used by the panel and buttons
int lcd_key = 0;
int adc_key_in = 0;
#define btn3 0
#define btnUP 1
#define btn2 2
#define btnLEFT 3
#define btn1 4
#define btnNONE 5
String Version = "V.1.12.04";//Version actual del sketch
String CadenaSerial = "";//Crea la cadena de caracteres vacia que va a ser leida por puerto serie
String reportString = ""; //Crea la cadena de caracteres vacia comparadora
unsigned long SerialMillis = millis();
unsigned long RingMillis = millis();
unsigned long CounterMillis = millis();
boolean SerialFin = false; //bandera de control de lectura del puerto serie
boolean SerialOn = false; //Bandera de activado del puerto serie
boolean ReleOn = false;//byte de control del rele (por defecto apagado)
boolean BloqueoOn = false;//byte condicion de bloqueo de llamadas
String NumeroTelefono;
String stringOne;
int ringer = 0;
long ringerfin = 1;
int counter = 0;
// Guardamos en que entrada de arduino esta conectado el pin CS del modulo.
const int chipSelect = 10;
char numerotst[10];
char numllam[10];
char charBuf[10];
char charBuf2[10];
char charThree[10];
int numblock = 50;//cantidad de lineas de numeros del fichero
int i = 0;
int i2 = 0;
int llamadas = 0;// Contador de llamadas, debe ser 0. Otro valor es para pruebas.
int llamadasb = 0;// acumulador temporal de llamadas
int pin = A1;//pin conexion buzzer
int rele = A2;// pin conexion rele
int pulsado =0;//valor control pulsado boton para evitar sucesos
int comparador = 0; //Bandera de cumplimiento de ser un valor numerico
int a = 0;// Contador de digitos de un numero normal (9)
String stringThree;
unsigned long tAntes = 0;
unsigned long tAntes2 = 0;
unsigned long tAntes3 = 0;
unsigned long tAntes4 = 0;
unsigned long tAntes5 = 0;
unsigned long tAntes6 = 0;
long time_now = 0;
//Sonido del buzzer
void playNote(int noteInt, long length, long breath = 20) {
length = length - breath;
buzz(pin, 2000 , length); // Valor 2000 es agudo y fuerte, 50 es grave y flojo
if(breath > 0) { //take a short pause or 'breath' if specified
delay(breath);
}
}
void setup()
{
lcd.begin(16, 2); // start the library
pinMode(A0, INPUT_PULLUP); // sets analog pin for input
pinMode(rele, OUTPUT); // set analog pin for output
digitalWrite(rele, HIGH);// Activa rele para que NO suene llamada
//digitalWrite(pin, HIGH);//Produce ruido de fondo en waiting call
//pinMode(pin, OUTPUT); // set a pin for buzzer output
lcd.setCursor(0,0);
lcd.print("LCD Activado"); // print a simple messag
lcd.setCursor(0,1);
lcd.print(Version);
delay (2000);
// Configuramos el puerto serie (esta version NO usa Serie Virtual)
Serial.begin(1200);// Se configura a 1200 baud
while (!Serial) {
; // Espera para conexion puerto serie, solo necesario para leonardo
}
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Setup is Ready");
delay(2000);
//Iniciamos la SD
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Iniciando SD...");
// El pin CS por defecto de la placa arduino debe ser configurado como salida
// aunque no se use (10 en la mayoria de las placas, 53 en Arduino Mega).
pinMode(10, OUTPUT);
// Si ha habido error al leer la tarjeta informamos por el puerto serie.
if (!sd.begin(chipSelect, SPI_HALF_SPEED))
{
lcd.setCursor(0,1);
lcd.print("Error SD...");
sd.initErrorHalt();
delay(2000);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("PULSE RESET");
pinMode(10, INPUT);
delay(1000);
return;
}
lcd.setCursor(0,1);
lcd.print("SD ini...OK");
delay(2000);
//REcreando fichero RECIB.TXT
if (!myFile.open("RECIB.TXT", O_RDWR)) {
lcd.setCursor(0,1);
lcd.print("error SD write");
delay(2000);
}
myFile.println("111111111");
delay(200);
myFile.close();// close the file:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("RECIB.TXT ini");
delay(2000);
lcd.setCursor(0,1);
lcd.print("OK");
delay(2000);
// Beep de OK de fin de Setup
digitalWrite(pin, HIGH);
pinMode(pin, OUTPUT); // set a pin for buzzer output
delay(2000);
playNote(1,100);
digitalWrite(pin, HIGH);
//digitalWrite(pin, LOW);
}
// Fin Setup
void loop()
{
buttonselect();// Selector botones
a = 0; //Restablece contador de caracteres del numero llamante
comparador = 0; // Restablece a 0 el comparador
reportString = "";// Restablece a 0 el numero comparado
// Inicio lectura puerto serie y deteccion numero llamante
char ch;
if(SerialFin == true)
{
SerialFin = false;
SerialOn = false;
String NumeroTelefono = CadenaSerial.substring(14,23);//Lee el número llamante de la cadena leida
CadenaSerial = ""; //Restablecemos a 0 la cadena creada al leer el puerto serie
reportString = NumeroTelefono;
//Compara cada uno de los 9 digitos (un numero normal)
while (a <= 9){
a++;//Añade otro caracter al comparador
if (isDigit(reportString.charAt(a))){ //detecta si cada caracter del numero es un valor numerico
comparador++;
}
else{
comparador = 0;//Caracter no numerico encontrado
break;
}
if (comparador = 9){//se han leido los 9 caracteres y eran numeros
break;
}
} //Fin del while
if (ringer >> 0 && comparador >> 0)//Se activa si se recibe una llamada y es un numero valido
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Num.llamante:");
stringOne = NumeroTelefono;//convierte numero char a string
stringOne.toCharArray(charBuf, 10);//convierte el numero string a char para strcmp
lcd.setCursor(0,1);
lcd.print(charBuf);// Presenta en pantalla el numero llamante
//Inicio codigo escritura llamadas recibidas
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
// if the file opened okay, write to it:
if (!myFile.open("RECIB.TXT", O_RDWR | O_CREAT | O_AT_END)) {
lcd.setCursor(0,1);
lcd.print("Error SD write");
}
myFile.println(stringOne);// escribe el numero en el fichero
delay (200);
myFile.close();// close the file:
lcd.setCursor(12,1);
lcd.print("WCOK");// Indica en el display que la llamada ha sido grabada en el fichero de Recibidas
BloqueoOn = false;//Byte Activando el desbloqueo de la llamada grabada
//Mantiene el tiempo a 0 mientras se pulsa boton lectura
long time_now = millis();
tAntes = time_now;
tAntes2 = time_now;
tAntes3 = time_now;
tAntes4 = time_now;
// Calcula el acumulado de numero de llamadas
llamadasb = llamadas;
llamadas++;
lcd.setCursor(0,1);
//lcd.print("Llamadas.....");
//lcd.setCursor(13,1);
//lcd.print(llamadas);
// fin codigo escritura llamadas recibidas
//Inicio seccion lectura fichero numeros bloqueados.
char Ruta[9] = {'B', 'L', 'O', 'Q', '.', 'T', 'X', 'T', '\0'};//establece nombre fichero tlfs bloqueados
for(int i = 0; i < numblock; i++)// secuencialmente se lee cada una de los numeros del fichero
{
//Leemos linea de archivo en la SD
String numerotst = ReadFile(i,Ruta);
String stringTwo = numerotst;
stringTwo.toCharArray(charBuf2, 10);// convertimos string to char para strcmp
if(strcmp(charBuf, charBuf2) == 0)// comparamos el numero detectado con el leido en el fichero
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Numero BLOCK:");
lcd.setCursor(0,1);
lcd.print(charBuf); // Muestra el numero bloqueado
// Desativador del Rele
//digitalWrite(rele, LOW);
ReleOn = false;// BYTE DE DESACTIVACION DE RELE
BloqueoOn = true;// BYTE DE ACTIVACION DE BLOQUEO
}// Fin deteccion numero bloqueado
}//Fin bucle lectura numeros bloqueados SD
//ReleOn = true;// BYTE DE ACTIVACION DE RELE
}//Fin lectura buffer serie
} // Fin deteccion numero llamante valido
// lectura puerto serie
if(Serial.available())
{
SerialOn = true;
ch = Serial.read();
//Serial.print(ch);//comprobador datos serie
CadenaSerial += ch;//crea la cadena de caracteres leidos por el puerto serie
SerialMillis = millis();
}
if(SerialOn == true && (millis() - SerialMillis) > 10)//Temporizador para recoger el numero llamante
{
SerialFin = true;
SerialOn = false;
}
// Fin lectura y deteccion de numeros
// Sistema de deteccion y conteo de rings por sensor de voltaje en pin ferduino
/* testeo de rings por lcd
lcd.setCursor(9,0);
lcd.print(ringer);
lcd.setCursor(10,0);
lcd.print(counter);
*/
int voltaje = analogRead(A3);//Pin lectura de voltaje para deteccion de rings
//int ring = voltaje * (5.0 / 1023.0);//Conversion de medicion de voltaje a valor comparable
int ring = voltaje;
/* //Muestra el valor de voltaje
lcd.setCursor(0,0);
lcd.print("Volt");
lcd.setCursor(6,0);
lcd.print(ring);
*/
//contador de rings detectados, 1 ring cada 2 segundos
if ( ring == 0 && (millis() - RingMillis) > 2000 )
{
//delay(3000);
ringer++;
RingMillis = millis();
CounterMillis = millis();
//lcd.setCursor(12,0);
//lcd.print(ringer);
if (BloqueoOn == false){
//Buzzer hace sonar un ring
digitalWrite(pin, HIGH);
playNote(1,100);
playNote(1,200);
playNote(1,100);
playNote(1,200);
playNote(1,100);
playNote(1,200);
playNote(1,100);
playNote(1,200);
playNote(1,100);
playNote(1,200);
playNote(1,100);
playNote(1,200);
digitalWrite(pin, HIGH);
//digitalWrite(pin, LOW);
}
}
//contador medidor de cadencia teorica de 1 rings cada 2.2 segundos para detectar fin de rings
if (ringer > 0 && ( millis() - CounterMillis) > 2250 ){
counter++;
CounterMillis = millis();
ringerfin = 0;
//lcd.setCursor(15,0);
//lcd.print(counter);
}
//Comprobador de activado de rings
if (ringer > 1 && BloqueoOn == false)
{
ReleOn = true;//Activa el rele y permite que suene la llamada
}
// comprobador de final de rings (teoricos menos recibidos)
if(counter > 0 && (counter - ringer) > 1){
ringer = 0;
counter = 0;
BloqueoOn = true;
RingMillis = millis();
CounterMillis = millis();
ringerfin = 1;
}
//comprobador para desactivado de rings
if (BloqueoOn == true)
{
ReleOn = false;//Mantiene el rele desactivado por defecto
}
if(ReleOn == true)//Activador del rele
{
digitalWrite(rele, LOW);// Activa rele y permite suene llamada
}
if(ReleOn == false)//Desactivador del rele
{
digitalWrite(rele, HIGH);// Desactiva rele e impide suene llamada
}
}// Fin LOOP
// Codigo de lectura de los ficheros de telefonos de la SD
String ReadFile(int Linea,char Ruta[]){
int Lin=0;
String Resultado;
byte Bin;
if (!myFile.open(Ruta, O_RDWR)) {
lcd.setCursor(0,1);
lcd.print("Read Error");
delay (2000);
myFile.close();return Resultado;
}
while (myFile.available()){
Bin=myFile.read();
if (Bin==13){Lin++;myFile.read();}
else
{
if (Lin==Linea){Resultado=Resultado+(char(Bin));}
if (Lin>Linea){myFile.close();return Resultado;}
}
}
myFile.close();return Resultado;
}
/// MENU CONTROL BOTONADURA Y GRABADO NUMEROS BLOQUEADOS SD
void buttonselect()
{
lcd.setCursor(0,1); // move to the begining of the second line
lcd_key = read_LCD_buttons(); // read the buttons
switch (lcd_key) // depending on which button was pushed, we perform an action
{
case btn3:
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Numero");
lcd.setCursor(0,1);
lcd.print("Bloqueado");
bloquear();
pulsado = 1;
delay(500);
break;
}
case btn2:
{
//lcd.print(adc_key_in);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Bloquear Num?");
lcd.setCursor(0,1);
lcd.print("NO");
lcd.setCursor(7,1);
lcd.print("SI");
pulsado = 1;
delay(500);
break;
}
case btn1:
{
leer();
pulsado = 1;
break;
}
case btnNONE:
{
long time_now = millis();
if ((ringerfin == 1 && (long)(time_now - tAntes) > 10000)) // regulador de tiempo presentacion lcd
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Waiting call...");
lcd.setCursor(0,1);
lcd.print("Llamadas....");
lcd.setCursor(13,1);
lcd.print(llamadas);
tAntes = time_now;
pulsado = 0;
}
if ((pulsado == 0 && ringerfin == 1 && (long)(time_now - tAntes2) > 3000))//Blink de * para indicar funcionamiento normal
{
lcd.setCursor(13,1);
lcd.print(llamadas);
tAntes2 = time_now;
}
if ((pulsado == 0 && ringerfin == 1 && (long)(time_now - tAntes3) > 3500))
{
lcd.setCursor(13,1);
lcd.print(" ");
tAntes3 = time_now;
}
//Reponedor a 0 de lectura llamadas si inactividad en botones
if ((long)((time_now - tAntes4) > 10000))
{
i2 = 0;
tAntes4 = time_now;
}
break;
}
}
}
// Funcion de lectura de numeros en fichero de llamadas recibidas
void leer()
{
char Ruta[10] = {'R', 'E', 'C', 'I', 'B', '.', 'T', 'X', 'T', '\0'};//establece nombre fichero num tlfs recibidos
String numllam = ReadFile(i2,Ruta);//Leemos linea de archivo como char en la SD
//Proceso conversion de string to char para poder grabar los datos leidos
String stringThree = numllam; //convertir char to string
stringThree.toCharArray(charThree, 10);// convertimos string to char
delay(500);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Numero Leido...");
lcd.setCursor(14,0);
lcd.print((llamadas + 5)- i2);//Se ponen 5 números mas a leer para evitar no poder leer tras cortes de luz
lcd.setCursor(0,1);
lcd.print(charThree); // Muestra el numero leido
//lcd.setCursor(12,1);
//lcd.print("..");
//delay (500);
i2++;
//Mantiene el tiempo a 0 mientras se pulsa boton lectura
long time_now = millis();
tAntes = time_now;
tAntes2 = time_now;
tAntes3 = time_now;
tAntes4 = time_now;
if (i2 == (llamadas + 5))
{
lcd.setCursor(0,1);
lcd.print("Borra Recib.txt"); // Advierte borrado Recib.txt
}
if (i2 > (llamadas + 5))
{
i2 = 0;
llamadas = 0;
delay (1000);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Borrando las");
lcd.setCursor(0,1);
lcd.print("LLamadas...");
if (!myFile.open("RECIB.TXT", O_RDWR | O_CREAT)) {
lcd.setCursor(0,1);
lcd.print("error SD write");
delay(2000);
lcd.clear();
lcd.setCursor(0,1);
lcd.print("PULSE RESET");
delay(2000);
}
//Borrando fichero RECIB.TXT
myFile.remove();//borra fichero
delay(2000);
myFile.close();
//REcreando fichero RECIB.TXT
if (!myFile.open("RECIB.TXT", O_RDWR | O_CREAT)) {
lcd.setCursor(0,1);
lcd.print("error SD write");
delay(2000);
lcd.clear();
lcd.setCursor(0,1);
lcd.print("PULSE RESET");
delay(2000);
}
myFile.println("111111111");
delay(200);
myFile.close();// close the file:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("RECIB.TXT ini");
delay(2000);
lcd.setCursor(0,1);
lcd.print("OK");
delay(2000);
}
}
//funcion para escribir el número leido de RECIB.TXT y grabarlo en
//el fichero de numeros bloqueados BLOQ.TXT
void bloquear()
{
if (!myFile.open("BLOQ.TXT", O_RDWR | O_CREAT | O_AT_END)){
lcd.setCursor(0,1);
lcd.print("Error SD write");
sd.initErrorHalt();
delay(2000);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("PULSE RESET");
pinMode(10, INPUT);
delay(1000);
}
myFile.println(charThree);
delay(200);
myFile.close();
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Numero bloqueado");
lcd.setCursor(0,1);
lcd.print("*********"); // Limpia espacio numero
lcd.setCursor(0,1);
lcd.print(charThree); // Muestra el numero bloqueado
lcd.setCursor(12,1);
lcd.print("BQ");
delay(2000);
}
// read the buttons
int read_LCD_buttons()
{
adc_key_in = analogRead(0); // read the value from the sensor
//Valores para botonadura simple de 3 resistencias de 3k Ohm en serie
if (adc_key_in > 1000) return btnNONE; // Ningun boton pulsado
if (adc_key_in < 95 && adc_key_in > 90) return btn3;
//if (adc_key_in < 250) return btnUP;
if (adc_key_in < 175 && adc_key_in > 150) return btn2;
//if (adc_key_in < 650) return btnLEFT;
if (adc_key_in > 200 && adc_key_in < 300) return btn1;
return btnNONE; // when all others fail, return this...
}
// FIN READ BUTTONS
// sonido del buzzer
void buzz(int targetPin, long frequency, long length) {
long delayValue = 1000000/frequency/2; // calculate the delay value between transitions
//// 1 second's worth of microseconds, divided by the frequency, then split in half since
//// there are two phases to each cycle
long numCycles = frequency * length/ 1000; // calculate the number of cycles for proper timing
//// multiply frequency, which is really cycles per second, by the number of seconds to
//// get the total number of cycles to produce
for (long i=0; i < numCycles; i++){ // for the calculated length of time...
digitalWrite(targetPin,HIGH); // write the buzzer pin high to push out the diaphram
delayMicroseconds(delayValue); // wait for the calculated delay value
digitalWrite(targetPin,LOW); // write the buzzer pin low to pull back the diaphram
delayMicroseconds(delayValue); // wait againf or the calculated delay value
}
}