Como la plataforma Xively /Pachube ha dejado de servir gratuitamente como repositorio de los datos de dispositivos IOT, he decidido migrar el sketch a Thingspeak. Esta nueva plataforma exige como Xively el crear una cuenta y definir en ella los campos a mostrar. Existen muchos tutoriales en la web para crear una cuenta en Thingspeak, asi que no entrare en ese tema. Lo único a destacar en la modificación del sketch es la parte que corresponde a la subida de datos y a la definición de los nombres de los campos de datos a subir, pues en Thingspeak el formato de nombres para la subida es fijo y es del tipo "field(numero)". El esquema de hardware del proyecto es el mismo que ya esta en el blog para Xively/Pachube, y solo cambia el sketch en la parte relacionada con la adaptacion a la subida de datos a Thingspeak. La compilacion es para el IDE arduino 1.0.4 .
El sketch es el siguiente:
// Sistema de control de temperaturas usando modulo ethernet ENC28J60 y sensor DS18B20
// 2011-07-08 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
//Compilado con Arduino IDE 1.0.4
//PIN CONNECTION FOR ENC28J60 ETHERNET CARD
//CS...8
//SI...11
//SO...12
//SCK..13
//VCC...3.3v
//GND...GND
// Conexion del sensor DS18B20:
// Se ha elegido el modo de alimentación parásita que consiste en conectar VCC (+3,3v) y GND
//juntos y unir DATA a +3,3v con una resistencia de 4K7 Ohm.Este modo permite conectar los
//tres polos a un conector GND-DATA-VCC actuando como desequivocador, ya que DATA nunca cambia
//de posicion central.
// arduino +3.3v-----R 4K7Ohm----DATA------Pin Digital 2 Arduino
// ****************************DS18B20***************************
// Arduino GND------------------VCC-GND
#include <EtherCard.h>
#include <stdio.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(9, 10, 4, 5, 6, 7);
float tempmin = 2; //Variable donde guardamos la temperatura minima registrada
float tempmax = 8; //Varibale donde guardamos la temperatura maxima registrada
float teston = 0; //Variable del testeo de DNS ON
float teston1 = 0; //Variable de presentacion testeo OK
float temp01; //Varibale donde guardamos la temperatura actual sensor 01
float temp02; //Varibale donde guardamos la temperatura actual sensor 02
float temp03; //Varibale donde guardamos la temperatura actual sensor 02
//Timers
unsigned long tAntes = 0;
unsigned long tAntes1 = 0;
unsigned long tAntes2 = 0;
unsigned long tAntes3 = 0;
unsigned long tAntes4 = 120000;// Timer 4 minutos estabilizacion sensores
long time_now = 0;
// change these settings to match your own setup (son de mi cuenta Thingspeak)
#define FEED "valor de feed"
#define APIKEY "valor de apikey"
// Data wire is plugged into pin 2 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices
// (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
// ethernet interface mac address, must be unique on the LAN
#define STATIC 1 // set to 1 to disable DHCP (adjust myip/gwip values below)
#if STATIC
// mac address
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
// ethernet interface ip address
static byte myip[] = { 192,168,1,32 };
// gateway ip address
static byte gwip[] = { 192,168,1,1 };
// mask address
static byte mymask[] = { 255,255,255,0 };
// dnsip address
static byte dnsip[] = { 212,166,210,81 };
#endif
char website[] PROGMEM = "api.thingspeak.com";
#define BUFFER_SIZE 500 //antes 400
byte Ethernet::buffer[BUFFER_SIZE];
BufferFiller bfill;
Stash stash;
void setup () {
lcd.begin(16, 2); // start the library
lcd.setCursor(0,0);
lcd.print("Version 1.09"); // print a simple message
delay(2000);
lcd.clear();
lcd.print("Starting...."); // print a simple message
lcd.setCursor(0,1);
lcd.print("Max/Min delay"); //Warning about 4 min delay in Max/Min
delay(2000);
// Start up the library
sensors.begin();
Serial.begin(38400);
Serial.println("Trying to get an IP...");
Serial.print("MAC: ");
for (byte i = 0; i < 6; ++i) {
Serial.print(mymac[i], HEX);
if (i < 5)
Serial.print(':');
}
Serial.println("\n[webClient]");
lcd.begin(16, 2);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Ethernet Start"); // print a simple message
delay(2000);
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
{
Serial.println( "Failed to access Ethernet controller");
lcd.begin(16, 2);
lcd.setCursor(0,0);
lcd.print("Ethernet Start");
lcd.setCursor(0,1);
lcd.print("Ethernet Error");
} else {
Serial.println( "Ethernet controller OK");
lcd.begin(16, 2);
lcd.setCursor(0,0);
lcd.print("Ethernet Start");
lcd.setCursor(0,1);
lcd.print("Ethernet OK");
}
delay(2000);
#if STATIC
Serial.println( "Getting static IP.");
if (!ether.staticSetup(myip, gwip)){
Serial.println( "could not get a static IP");
}
#else
Serial.println("Setting up DHCP");
if (!ether.dhcpSetup()){
Serial.println( "DHCP failed");
blinkLed(); // blink forever to indicate a problem
}
#endif
ether.printIp("IP: ", ether.myip);
ether.printIp("GW: ", ether.gwip);
ether.printIp("DNS: ", ether.dnsip);
ether.printIp("SRV: ", ether.hisip);
lcd.begin(16, 2);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Wait for DNS"); // print a simple message
if (!ether.dnsLookup(website)) {
Serial.println("DNS failed");
//lcd.begin(16, 2);
lcd.setCursor(0,1);
lcd.print("DNS Error");
//teston = 0;
} else {
Serial.println("DNS OK");
//lcd.begin(16, 2);
lcd.setCursor(0,1);
lcd.print("DNS OK");
}
delay(2000);
lcd.begin(16, 2);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("1 minute to"); //Inicio loop de publicacion en Thingspeak
lcd.setCursor(0,1);
lcd.print("Start Publish.."); //Inicio loop de publicacion en Thingspeak
delay(2000);
}
void loop () {
ether.packetLoop(ether.packetReceive());
long time_now = millis();
if ((long)(time_now - tAntes) > 30000) // regulador de tiempo medida datos y presentacion lcd
{
tAntes = time_now;
// call sensors.requestTemperatures() to issue a global temperature
// request to all devices on the bus
Serial.print(" Requesting temperatures...\n");
sensors.requestTemperatures(); // Send the command to get temperatures
Serial.println("DONE");
float temp01 = sensors.getTempCByIndex(0);// Why "byIndex"?
// You can have more than one IC on the same bus.
// 0 refers to the first IC on the wire
float temp02 = sensors.getTempCByIndex(1);
float temp03 = sensors.getTempCByIndex(2);
teston1 = teston/12;// Visualizacion tiempo ON en LCD limite 24 horas
// Comparador temperaturas para saber Max y Min
if (temp01<tempmin)
tempmin=temp01;
if (temp01>tempmax)
tempmax=temp01;
//Timer para permitir estabilizarse la temperatura en el lugar donde colocar la sonda, para evitar
// falsos maximos y minimos(notese que solo se ejecuta una vez)
if ((long)(tAntes4 - time_now) > 30000)
{
tempmin=temp01;
tempmax=tempmin;
}
//Presentador datos terminal serie
Serial.print("Sensor 1: ");
Serial.print(temp01);
Serial.print("Min Sensor1: ");
Serial.print(tempmin);
Serial.print("Max Sensor1: ");
Serial.print(tempmax);
Serial.print("Sensor 2: ");
Serial.print(temp02);
Serial.print("Sensor 3: ");
Serial.print(temp03);
Serial.print("Test ON: ");
Serial.print(teston1);
Serial.print("\n");
// FIN SERIE
//Escribe datos temperatura en el LCD
if ((long)(time_now - tAntes2) > 10000) // regulador de tiempo presentacion lcd
{
tAntes2 = time_now;
lcd.begin(16, 2);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("T.Sens2");
lcd.setCursor(10,0);
lcd.print(temp02);
lcd.setCursor(0,1);
lcd.print("T.Sens3");
lcd.setCursor(10,1);
lcd.print(temp03);
delay(4000);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("T.Ac.");
lcd.setCursor(5,0);
lcd.print(temp01);
lcd.setCursor(12,0);
lcd.print(teston1);
lcd.setCursor(0,1);
lcd.print("Min");
lcd.setCursor(3,1);
lcd.print(tempmin);
lcd.setCursor(8,1);
lcd.print("Max");
lcd.setCursor(11,1);
lcd.print(tempmax);
delay(4000);
}
// Reseteador temparaturas cada 24 horas (228 paquetes de 5 minutos)
if (teston > 288){
tempmax=temp01;
tempmin=temp01;
teston = 0;
}
//Envio de datos a Thingspeak
if ((long)(time_now - tAntes1) > 30000) // regulador de tiempo envio datos
{
tAntes1 = time_now;
// generate two fake values as payload - by using a separate stash,
// we can determine the size of the generated message ahead of time
// field1=(Field 1 Data)&field2=(Field 2 Data)&field3=(Field 3 Data)&field4=(Field 4 //Data)&field5=(Field 5 Data)&field6=(Field 6 Data)&field7=(Field 7 Data)&field8=(Field 8 //Data)&lat=(Latitude in Decimal Degrees)&long=(Longitude in Decimal Degrees)
//&elevation=(Elevation in meters)&status=(140 Character Message)
byte sd = stash.create();
stash.print("field1=");
stash.print(temp01);
stash.print("&field2=");
stash.print(temp02);
stash.print("&field3=");
stash.print(temp03);
stash.print("&field4=");
stash.print(tempmax);
stash.print("&field5=");
stash.print(tempmin);
stash.print("&field6=");
stash.print(teston1);
stash.save();
// generate the header with payload - note that the stash size is used,
// and that a "stash descriptor" is passed in as argument using "$H"
Stash::prepare(PSTR("POST /update HTTP/1.0" "\r\n"
"Host: $F" "\r\n"
"Connection: close" "\r\n"
"X-THINGSPEAKAPIKEY: $F" "\r\n"
"Content-Type: application/x-www-form-urlencoded" "\r\n"
"Content-Length: $D" "\r\n"
"\r\n"
"$H"),
website, PSTR(APIKEY), stash.size(), sd);
// send the packet - this also releases all stash buffers once done
ether.tcpSend();
}
// Testeador conexion etherner usando dnslookup
if ((long)(time_now - tAntes3) > 300000) // regulador de tiempo testeo 5 min.
{
tAntes3 = time_now;
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Wait for DNS");
if (!ether.dnsLookup(website)) {
Serial.println("DNS failed");
lcd.setCursor(0,1);
lcd.print("Error");
teston = 0;
} else {
lcd.setCursor(0,1);
lcd.print("OK");
teston++;//Indicador creciente testeo positivo
}
}
}
}
jueves, 23 de julio de 2020
martes, 28 de mayo de 2019
Tacometro con sensor TCTR5000
Esta entrada esta dedicada a los primeros pasos con el uso del sensor infrarojo TCTR5000 con Arduino. Este sensor es ampliamente usado para proyectos de robotica como seguidor/lector de lineas pintadas en el suelo. Consiste basicamente en un led emisor IR y un led receptor IR, conectados a una placa base con un potenciometro regulador del alcance de medicion, y un integrado transductor de la señal. Se alimenta con 5v y tiene una salida analogica A0 y una digital D0. El sistema funciona emitiendo una señal por el led emisor y viendo si esta reflejada por un objeto o no. En muestro proyecto aprovecharemos la capacidad de este sensor para "ver" la variación del reflejo producido por el movimiento de un ventilador con 6 aspas de 12cm y 12v, tipico de las fuentes de alimentacion de PC y que tiene mucho uso en refrigeración de PC´s.
Usaremos en este proyecto:
- Un Keypad shield de 6 botones como este:

- Un modulo sensor TCTR5000 como este:

- Un Arduino Uno y cables de conexion.
Debemos antes tener preparado el Keypad shield con pines de salida soldados en los agujeros libres que posee y que a veces (como en el dibujo) no estan presentes.
Las conexiones son:
GND y VCC del modulo sensor a GND y 5V del keypad shield, y D= del modulo a Pin 3 del keypad shield.
El sketch, al ejecutarse, nos muestra las rpm del ventilador al poner el sensor cerca de las aspas rotando del ventilador.
El sketch es este:
***************************************************************************
//Proyecto de tacometro (medidor de rpm) de un ventilador de 12cm de los que
//se usan para refrigerar las fuentes de alimentacion de un PC con las
//tipicas 1500 rpm de velocidad.
//El esquema de conexion usa el Keypad shield de 6 botones, con el LCD
//de 16x2 integrado en el shield, el modulo sensor infrarojo TCRT5000, se
//conecta en el shield a los pines 5v, GND y el pin D0 a Pin 3 del shield.
#include <LiquidCrystal.h>
int val;
int pind0 = 3;
long last=0;
int stat=HIGH;
int stat2;
int contar=0;
int sens=HIGH; // this value indicates the limit reading between dark and light,
// it has to be tested as it may change acording on the
// distance the leds are placed.
int nPalas = 6; // the number of blades of the propeller
int milisegundos=500; // the time it takes each reading
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // RS, E, D4, D5, D6, D7
void setup()
{
//Serial.begin(9600);
lcd.begin(16, 2);
lcd.clear();
pinMode(pind0,INPUT);
}
void loop()
{
val=digitalRead(pind0);
if(val!=sens)
stat=HIGH;
else
stat=LOW;
digitalWrite(pind0,stat); //as iR light is invisible for us, the led on pin D0
//indicate the state of the circuit.
if(stat2!=stat){ //counts when the state change, thats from (dark to light) or
//from (light to dark), remmember that IR light is invisible for us.
contar++;
stat2=stat;
}
if(millis()-last>=milisegundos){
int rps=((double)contar/nPalas)/2.0*1000.0/milisegundos;
int rpm=((double)contar/nPalas)/2.0*60000.0/(milisegundos);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("RPM = ");
lcd.print(rpm);
/*Serial.print("Contar - ");
Serial.println((contar/2.0));
Serial.print("RPS = ");
Serial.println(rps);
Serial.print("RPM = ");Serial.println(rpm);
Serial.print(" VAL ");Serial.println(val);*/
contar=0;
last=millis();
}
}
***********************************************************************
Consideraciones:
Este proyecto es parte de un conjunto de sensores integrados en un entorno Arduino, pensados para controlar diversos parametros del funcionamiento de un vehiculo. El proyecto consistirá finalmente en una red ethernet de varios Arduino funcionando conjuntamente recogiendo datos en diferentes "puestos" de control. Uno sera responsable de la conexión con el OBD de la ECU del vehiculo y suministrará datos disponibles OBDII de la ECU (rpm motor, velocidad, temperatura refrigerante, MAF, presion combustible,....), otro sistema estara en el bloque motor coleccionando datos de nivel de refrigerante, temperatura y presion del aceite, temperatura del vano motor, accionamiento de reles de emergencia para encendido de luces de emergencia, velocidad de giro del electroventilador, ... Otro actuara como sensor de proximidad y angulo muerto, de manera inteligente y predictiva.
Todo el conjunto procesará los datos que estarán disponibles en una red ethernet que los conectará y que eventualmente alimentará a una Raspberry Pi, que estará instalada en un hueco doble DIN del salpicadero del coche, con una pantalla tactil de 7 pulgadas. La Raspberry actuara como un autentico carputer, amen de servir como centro multimedia y GPS.
Usaremos en este proyecto:
- Un Keypad shield de 6 botones como este:

- Un modulo sensor TCTR5000 como este:
- Un Arduino Uno y cables de conexion.
Debemos antes tener preparado el Keypad shield con pines de salida soldados en los agujeros libres que posee y que a veces (como en el dibujo) no estan presentes.
Las conexiones son:
GND y VCC del modulo sensor a GND y 5V del keypad shield, y D= del modulo a Pin 3 del keypad shield.
El sketch, al ejecutarse, nos muestra las rpm del ventilador al poner el sensor cerca de las aspas rotando del ventilador.
El sketch es este:
***************************************************************************
//Proyecto de tacometro (medidor de rpm) de un ventilador de 12cm de los que
//se usan para refrigerar las fuentes de alimentacion de un PC con las
//tipicas 1500 rpm de velocidad.
//El esquema de conexion usa el Keypad shield de 6 botones, con el LCD
//de 16x2 integrado en el shield, el modulo sensor infrarojo TCRT5000, se
//conecta en el shield a los pines 5v, GND y el pin D0 a Pin 3 del shield.
#include <LiquidCrystal.h>
int val;
int pind0 = 3;
long last=0;
int stat=HIGH;
int stat2;
int contar=0;
int sens=HIGH; // this value indicates the limit reading between dark and light,
// it has to be tested as it may change acording on the
// distance the leds are placed.
int nPalas = 6; // the number of blades of the propeller
int milisegundos=500; // the time it takes each reading
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // RS, E, D4, D5, D6, D7
void setup()
{
//Serial.begin(9600);
lcd.begin(16, 2);
lcd.clear();
pinMode(pind0,INPUT);
}
void loop()
{
val=digitalRead(pind0);
if(val!=sens)
stat=HIGH;
else
stat=LOW;
digitalWrite(pind0,stat); //as iR light is invisible for us, the led on pin D0
//indicate the state of the circuit.
if(stat2!=stat){ //counts when the state change, thats from (dark to light) or
//from (light to dark), remmember that IR light is invisible for us.
contar++;
stat2=stat;
}
if(millis()-last>=milisegundos){
int rps=((double)contar/nPalas)/2.0*1000.0/milisegundos;
int rpm=((double)contar/nPalas)/2.0*60000.0/(milisegundos);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("RPM = ");
lcd.print(rpm);
/*Serial.print("Contar - ");
Serial.println((contar/2.0));
Serial.print("RPS = ");
Serial.println(rps);
Serial.print("RPM = ");Serial.println(rpm);
Serial.print(" VAL ");Serial.println(val);*/
contar=0;
last=millis();
}
}
***********************************************************************
Consideraciones:
Este proyecto es parte de un conjunto de sensores integrados en un entorno Arduino, pensados para controlar diversos parametros del funcionamiento de un vehiculo. El proyecto consistirá finalmente en una red ethernet de varios Arduino funcionando conjuntamente recogiendo datos en diferentes "puestos" de control. Uno sera responsable de la conexión con el OBD de la ECU del vehiculo y suministrará datos disponibles OBDII de la ECU (rpm motor, velocidad, temperatura refrigerante, MAF, presion combustible,....), otro sistema estara en el bloque motor coleccionando datos de nivel de refrigerante, temperatura y presion del aceite, temperatura del vano motor, accionamiento de reles de emergencia para encendido de luces de emergencia, velocidad de giro del electroventilador, ... Otro actuara como sensor de proximidad y angulo muerto, de manera inteligente y predictiva.
Todo el conjunto procesará los datos que estarán disponibles en una red ethernet que los conectará y que eventualmente alimentará a una Raspberry Pi, que estará instalada en un hueco doble DIN del salpicadero del coche, con una pantalla tactil de 7 pulgadas. La Raspberry actuara como un autentico carputer, amen de servir como centro multimedia y GPS.
viernes, 2 de septiembre de 2016
Bloqueador de llamadas usando un modulo Caller ID
Para mejorar el bloqueador de llamadas y hacerlo más compacto, a la vez que más sencillo de construir, me he decidido a comprar un módulo identificador de llamadas llamado Ferduino Caller ID, que puedes encontrar en Ebay. Se vende como un shield para aarduino con los componentes para montar, pero yo lo he montado para poderlo conectar con algunas líneas a mi shield bloqueador de llamadas con pantalla LCD que ya tenía diseñado. El Ferduino Caller ID lo teneis descrito aqui:
/* 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
}
}
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
}
}
jueves, 12 de mayo de 2016
Bloqueador de llamadas con conexion bluetooth
Tras ver que una conexión por cable con el modem de 56k era propensa a dar errores de comunicación y a fallos de recepción de los datos de CallerID, amen de que suponía la existencia de mucho cableado de conexión propenso a fallos, me plantee usar una conexión inalambrica por bluetooth entre el modem serie 56k y el arduino. Usar un modulo serie bluetooth en arduíno es sencillo, hay muchos tutoriales para ello. Pero un tutorial para convertir un modem 56k en un modem por bluetooth no es tan fácil de encontrar por internet. Para realizar todo esto he recurrido al empleo de dos módulos de comunicaciones bluetooth serie, uno como master tipo HC-05 conectado a arduino y otro como slave tipo HC-06 conectado al modem 56k. Los módulos son muy fáciles de configurar y tras establecer los parámetros de comunicaciones a 38400bps, el emparejamiento entre ellos es automático. La configuración del módulo HC-05 como master se hace mediante el uso de un modulo usb serie o incluso usando a arduino y un sketch específico para ello. Yo usé un modulo usb serie y el Hyperterminal de Windows. El HC-05 se coloca en modo Master con AT+ROLE=1 y en modo conexión con cualquier HC-06 presente con AT+CMODE=0, el cambiar el protocolo a 38400,0,0 se hace con AT+UART 38400,0,0 El HC-06 se coloca en modo 38400,0,0 con AT+BAUD6 . Tras esto, quitamos la alimentación para que vuelvan al modo conexión por bluetooth y tras volver a dar alimentación ambos módulos se conectan sin problemas. El módulo HC-05 se conecta a Arduino en la forma RX-TX y TX-RX. En su alimentación por parte de arduino en el shield que utilicé, he tenido la precaución de colocar un interruptor de alimentación de los 5v del módulo bluetooth, ya que con el módulo conectado a arduino y alimentado, la carga de los sketch da error de averdude, por interferencias en el RX/TX. Con lo que para cargar los sketch sólo tengo que poner el interruptor en apagado y listo. El módulo HC-06 se conecta al modem de 56k mediante el uso de un modulo serie y un cable nulo, igual que se describió en el sistema del discriminador inicial. La alimentación de 5v para el modulo serie y el HC-06 es fácil de obtener de cualquier punto de 5v del interior del modem de 56K.
También consideré el cambio de las pantallas LCD16x02 por unas Nokia LCD bastante mas curiosas, por la cantidad de lineas que presentan para poder presentar más datos. El integrar el módulo Nokia LCD 5110 es sencillo siguiendo el siguiente esquema:
Una vez conseguido esto, me he decidido también por colocar un buzzer que emita una señal de llamada para sustituir a los RING de los teléfonos, ya que es imposible evitar que al menos suenen dos veces antes de que el CallerID funcione. Así que he insertado código para que el sistema reconozca los RING recibidos, y haga sonar el buzzer como una llamada de teléfono, si el numero no está bloqueado, a partir del segundo RING. Los teléfonos deberían estar en mute o en ring muy bajo, para que no molestaran las llamadas bloqueadas. Realmente dichas llamadas se pueden bloquear para que no suenen haciendo que el modem coja la llamada entrante (hay una parte del sketch que contiene el código para hacerlo, en modo desactivado con slash, para activar si se desea), pero como en las pruebas usando el móvil vi que era factible el dejar las llamadas sin coger y a la vez impedir que el teléfono suene, pues me he decidido por esto último.
El sistema ya montado tiene el siguiente aspecto:
El resultado final del sketch 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. Ademas graba automáticamente los números que han llamado
y que posteriormente pueden seleccionarse con la botonadura para ser bloqueados. Al necesitar 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).
El hardware necesario es un Arduino Uno, un modem con CallerID (en mi caso US Robotics 56k o un Conceptronics
C55E de 56k), un modulo SD YL-30, una tarjeta SD, un modulo Serie HC05, un modulo LCD de 16x2 y
una botonadura tipo Keypad DIY de resistencias (una botonadura simple con tres resistencias de 3K en serie
conectando GND a Pin A0, p.e.).
Se usa un modulo HC05 master bluetooth para comunicarse con un modem bluetooth hc06 conectado al modem serie, que
a su vez está conectado a la linea de telefono.
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 hc05 a Arduino es : RX-TX(Pin digital 1) y TX-RX(Pin digital 0)
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
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 al Pin A1 - GND - 5v
*/
// LCD5110_NumberFonts
// Copyright (C)2015 Rinky-Dink Electronics, Henning Karlsen. All right reserved
// web: http://www.RinkyDinkElectronics.com/
//
// This program is a demo of the included number-fonts,
// and how to use them.
//
// This program requires a Nokia 5110 LCD module.
//
// It is assumed that the LCD module is connected to
// the following pins using a levelshifter to get the
// correct voltage to the module.
// CLK/ SCK - Pin 7
// MOSI - Pin 6
// DC - Pin 5
// RST - Pin 3
// CE/CS - Pin 4
//
#include <LCD5110_Basic.h>
LCD5110 myGLCD(7,6,5,3,4);
extern uint8_t SmallFont[];
extern uint8_t MediumNumbers[];
extern uint8_t BigNumbers[];
#include <SdFat.h>//CS en pin 10
SdFat sd;
SdFile myFile;
// 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
/// Guardamos en que entrada de arduino esta conectado el pin CS del modulo.
const int chipSelect = 10;
char nmbrstring[ ] = "NMBR";
char ringstring[ ] = "RING";
char numerodete[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 ringer = 2;// Contador de ring, los 2 primeros no se detectan
int pin = A1;//pin conexion buzzer
String stringThree;
byte Bin2;
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()
{
myGLCD.InitLCD();
//myGLCD.clrScr();
pinMode(A0, INPUT_PULLUP); // sets analog pin for input
//digitalWrite(pin, HIGH);
pinMode(pin, OUTPUT); // set a pin for buzzer output
myGLCD.setFont(SmallFont);
myGLCD.print("LCD Activado", 0, 0); // print a simple messag
delay (2000);
// Configuramos el puerto serie (esta version NO usa Serie Virtual)
Serial.begin(38400);
while (!Serial) {
; // Espera para conexion puerto serie, solo necesario para leonardo
}
myGLCD.clrScr();
myGLCD.print("Setup is Ready", 0, 0);
delay(2000);
//Iniciamos la SD
//Serial.print("Iniciando SD...");
//Serial.print("\n");
myGLCD.clrScr();
myGLCD.print("Iniciando SD...", 0, 0);
// 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))
{
//Serial.println("Error inicializar SD!");
myGLCD.print("Error SD...", 0, 20);
sd.initErrorHalt();
delay(2000);
myGLCD.clrScr();
myGLCD.print("PULSE RESET", 0, 40);
pinMode(10, INPUT);
delay(1000);
return;
}
myGLCD.print("SD ini...OK", 0, 20);
delay(2000);
//REcreando fichero RECIB.TXT
if (!myFile.open("RECIB.TXT", O_RDWR)) {
myGLCD.print("Error SD write", 0, 20);
delay(2000);
}
myFile.println("111111111");
delay(200);
myFile.close();// close the file:
myGLCD.clrScr();
myGLCD.print("RECIB.TXT ini", 0, 10);
delay(2000);
myGLCD.print("OK", 0, 30);
delay(2000);
myGLCD.clrScr();
myGLCD.print("Start Modem....", 0, 0);
// Iniciamos los comandos Hayes para configurar el modem
Serial.print("ATZ\r\n");
delay(4000);
myGLCD.print("4.", 0, 20);
Serial.print("AT+VCID=1\r\n");//Conceptronics CID ON
//Serial.print("AT#CID=1\r\n");//USR Robotics CID ON
delay(2000);
myGLCD.print("3.", 10, 20);
Serial.print("ATS7=5\r\n");//USR Robotics Answer Wait 7 seg
delay(2000);
myGLCD.print("2.", 20, 20);
Serial.print("ATS0=0\r\n");//USR Robotics Auto Answer OFF
delay(2000);
myGLCD.print("1.", 30, 20);
Serial.print("AT+FAE=1\r\n");//USR Robotics Adaptative Answer/Silent Answer
delay(2000);
myGLCD.print("OK", 40, 20);
delay(2000);
digitalWrite(pin, HIGH);
playNote(1,100);
digitalWrite(pin, LOW);
}
void loop()
{
static char buffer[20];
buttonselect();// Selector botones
myGLCD.setFont(SmallFont);
if (readline(Serial.read(), buffer, 80) > 0)
{
//Deteccion del numero llamante leido por puerto serie
char* numero1 = strchr(buffer, 'NMBR =');
char* prefinmbr = strtok(buffer, " =");
char* numero2 = strchr(numero1, ' ');
if(strcmp(prefinmbr, nmbrstring) == 0)//Detectamos la cadena NMBR que contiene el numero llamante
{
//Lector de numero
char* numerodete = numero2;//detecta numero con 1 espacio al inicio
String stringOne = numerodete;//convierte numero char a string
stringOne.trim();//elimina el espacio del inicio del número
myGLCD.clrScr();
myGLCD.print("Num.llamante:", 0, 0);
myGLCD.print("*********", 0, 20);
//myGLCD.print(charBuf, 0, 20);
stringOne.toCharArray(charBuf, 10);//convierte el numero string a char para strcmp
//ringer = 2;//Pone a 0 el contador de rings
myGLCD.print(stringOne, 0, 20);//Presenta en numero detectado
//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)) {
myGLCD.print("Error SD write", 0, 30);
}
myFile.println(stringOne);
delay (200);
myFile.close();// close the file:
llamadas++;// acumulado de numero de llamadas
myGLCD.print("Llamadas.....", 0, 40);
myGLCD.printNumI(llamadas, 60, 40);
myGLCD.print("WCOK", 60, 20);//Presenta el OK de grabacion numero detectado
//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;
// 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
{
myGLCD.clrScr();
myGLCD.print("Numero detec.:", 0, 0);
myGLCD.print(stringTwo, 0, 20); // Muestra el numero bloqueado
myGLCD.print("**BLOQUEADO**", 0, 30);//Presenta señal numero bloqueado
ringer = 20;//Impide que suene el buzzer
/* //Codigo activacion del modem para contestar y colgar
Serial.print("ATA\r\n");//Coge el tlf
delay(2000);
Serial.print("ATH1\r\n");//Cuelga el tlf
*/
delay (4000);
}// Fin deteccion numero bloqueado
}//Fin bucle lectura numeros bloqueados SD
}//Fin deteccion de llamada NMBR
//Deteccion de los RING para activar el buzzer
if(strcmp(buffer, ringstring) == 0)//Detectamos la cadena RING
{
/* Test cadena detectada
lcd.clear();
lcd.setCursor(0,0);
lcd.print(buffer);
lcd.print(ringer);
*///Fin test
ringer++;
//myGLCD.printNumI(ringer, 0, 35);//Print num rings
if(ringer > 3 && ringer < 15)//detector de rings para hacer sonar el buzzer
{
digitalWrite(pin, HIGH);
playNote(1,100);
playNote(1,200);
playNote(1,100);
playNote(1,100);
playNote(1,200);
playNote(1,100);
playNote(1,100);
playNote(1,200);
playNote(1,100);
digitalWrite(pin, LOW);
}
}
//Fin deteccion RING
}//Fin lectura buffer serie
//Timer Reponedor a 0 de rings
long time_now = millis();
if ((long)(time_now - tAntes6) > 80000)//Temporizador 80 seg para poner rings a 0
{
tAntes6 = time_now;
ringer = 2;
}
/*Test rings status
lcd.setCursor(0,15);
lcd.print(ringer);
*///Fin test
}// Fin LOOP
// Codigo de lectura de los telefonos bloqueados en la SD
String ReadFile(int Linea,char Ruta[]){
int Lin=0;
String Resultado;
byte Bin;
if (!myFile.open(Ruta, O_RDWR)) {
myGLCD.print("SD Read Error", 0, 0);
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;
}
/// AÑADIDO CONTROL BOTONADURA Y GRABADO NUMEROS BLOQUEADOS SD
void buttonselect()
{
lcd_key = read_LCD_buttons(); // read the buttons
switch (lcd_key) // depending on which button was pushed, we perform an action
{
case btn3:
{
myGLCD.clrScr();
//LcdCharacter(adc_key_in);
myGLCD.print("Numero Block", 0, 0);
bloquear();
delay(500);
break;
}
case btn2:
{
myGLCD.clrScr();
//gotoXY(0,1);
//LcdCharacter(adc_key_in);
myGLCD.print("Bloquear Numero?", 0, 0);
myGLCD.print("NO", 0, 40);
myGLCD.print("X", 30, 40);
myGLCD.print("SI", 60, 40);
delay(500);
break;
}
case btn1:
{
//gotoXY(7,0);
//myGLCD.print("Bloquear");
leer();
/*myGLCD.clrScr();
gotoXY(0,1);
LcdCharacter(adc_key_in);
myGLCD.print("SELECT");*/
break;
}
case btnNONE:
{
long time_now = millis();
if ((long)(time_now - tAntes) > 10000) // regulador de tiempo medida datos y presentacion lcd
{
myGLCD.clrScr();
myGLCD.print("Waiting call...", 0, 0);
myGLCD.print("Llamadas..", 0, 40);
myGLCD.printNumI(llamadas, 60, 40);
tAntes = time_now;
}
if ((long)(time_now - tAntes2) > 1000)//Blink de * para indicar funcionamiento normal
{
myGLCD.print("****************", 0, 10);
tAntes2 = time_now;
}
if ((long)(time_now - tAntes3) > 1500)
{
myGLCD.print("* * * * * * * * ", 0, 10);
tAntes3 = time_now;
}
//Reponedor a 0 de lectura llamadas si inactividad en botones
if ((long)(time_now - tAntes4) > 20000)
{
i2 = 0;
tAntes4 = time_now;
}
if ((long)(time_now - tAntes5) > 1800000) //RESETEO MODEM CADA 30 MINUTOS
{
modemreset();
tAntes5 = time_now;
ringer = 2;
}
break;
}
}
}
void leer()
{
char Ruta[10] = {'R', 'E', 'C', 'I', 'B', '.', 'T', 'X', 'T', '\0'};//establece nombre fichero tlfs bloqueados
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);
myGLCD.clrScr();
myGLCD.print("Numero Leido.....", 0, 0);
myGLCD.print(".................", 0, 10);
myGLCD.printNumI((llamadas + 5)- i2, 40, 10);
//gotoXY(0,1);
//myGLCD.print(" "); // Muestra el numero leido
myGLCD.print(charThree, 0, 30); // Muestra el numero leido
//myGLCD.print("..", 75, 0);
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))
{
i2 = 0;
llamadas = 0;
delay (1000);
myGLCD.clrScr();
myGLCD.print("Borrando las", 0, 0);
myGLCD.print("LLamadas...", 0, 10);
if (!myFile.open("RECIB.TXT", O_RDWR | O_CREAT)) {
myGLCD.clrScr();
myGLCD.print("Error SD write", 0, 10);
delay(2000);
myGLCD.print("PULSE RESET", 0, 20);
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)) {
myGLCD.print("Error SD write", 0, 10);
delay(2000);
myGLCD.clrScr();
myGLCD.print("PULSE RESET", 0, 20);
delay(2000);
}
myFile.println("111111111");
delay(200);
myFile.close();// close the file:
myGLCD.clrScr();
myGLCD.print("RECIB.TXT ini", 0, 0);
delay(2000);
myGLCD.print("OK", 0, 10);
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)){
myGLCD.print("Error SD write", 0, 0);
sd.initErrorHalt();
delay(2000);
myGLCD.print("PULSE RESET", 0, 10);
pinMode(10, INPUT);
delay(1000);
}
myFile.println(charThree);
delay(200);
myFile.close();
myGLCD.clrScr();
myGLCD.print("Numero bloqueado", 0, 0);
myGLCD.print("*********", 0, 20); // Limpia espacio numero
myGLCD.print(charThree, 0, 20); // Muestra el numero bloqueado
myGLCD.print("**BLOQUEADO**", 0, 30);
delay(2000);
}
//Sistema de lectura del puerto serie
int readline(int readch, char *buffer, int len)
{
static int pos = 0;
int rpos;
if (readch > 0) {
switch (readch) {
case '\n': // Ignore new-lines
break;
case '\r': // Return on CR
rpos = pos;
pos = 0; // Reset position index ready for next time
return rpos;
default:
if (pos < len-1) {
buffer[pos++] = readch;
buffer[pos] = 0;
}
}
}
// No end of line has been found, so return -1.
return -1;
}
// fin programa lectura puerto serie
// 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 < 200 && adc_key_in > 100) 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
// Reseteo modem
void modemreset()
{
myGLCD.clrScr();
myGLCD.print("Reset Modem....", 0, 0);
// Iniciamos los comandos Hayes para configurar el modem
Serial.print("ATZ\r\n");
delay(4000);
myGLCD.print("4.", 0, 20);
Serial.print("AT+VCID=1\r\n");//Conceptronics CID ON
//Serial.print("AT#CID=1\r\n");//USR Robotics CID ON
delay(2000);
myGLCD.print("3.", 10, 20);
Serial.print("ATS7=5\r\n");//USR Robotics Answer Wait 7 seg
delay(2000);
myGLCD.print("2.", 20, 20);
Serial.print("ATS0=0\r\n");//USR Robotics Auto Answer OFF
delay(2000);
myGLCD.print("1.", 30, 20);
Serial.print("AT+FAE=1\r\n");//USR Robotics Adaptative Answer/Silent Answer
delay(2000);
myGLCD.print("OK", 40, 20);
delay(2000);
}
// 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
}
}
El sistema ya montado tiene el siguiente aspecto:
El resultado final del sketch 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. Ademas graba automáticamente los números que han llamado
y que posteriormente pueden seleccionarse con la botonadura para ser bloqueados. Al necesitar 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).
El hardware necesario es un Arduino Uno, un modem con CallerID (en mi caso US Robotics 56k o un Conceptronics
C55E de 56k), un modulo SD YL-30, una tarjeta SD, un modulo Serie HC05, un modulo LCD de 16x2 y
una botonadura tipo Keypad DIY de resistencias (una botonadura simple con tres resistencias de 3K en serie
conectando GND a Pin A0, p.e.).
Se usa un modulo HC05 master bluetooth para comunicarse con un modem bluetooth hc06 conectado al modem serie, que
a su vez está conectado a la linea de telefono.
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 hc05 a Arduino es : RX-TX(Pin digital 1) y TX-RX(Pin digital 0)
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
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 al Pin A1 - GND - 5v
*/
// LCD5110_NumberFonts
// Copyright (C)2015 Rinky-Dink Electronics, Henning Karlsen. All right reserved
// web: http://www.RinkyDinkElectronics.com/
//
// This program is a demo of the included number-fonts,
// and how to use them.
//
// This program requires a Nokia 5110 LCD module.
//
// It is assumed that the LCD module is connected to
// the following pins using a levelshifter to get the
// correct voltage to the module.
// CLK/ SCK - Pin 7
// MOSI - Pin 6
// DC - Pin 5
// RST - Pin 3
// CE/CS - Pin 4
//
#include <LCD5110_Basic.h>
LCD5110 myGLCD(7,6,5,3,4);
extern uint8_t SmallFont[];
extern uint8_t MediumNumbers[];
extern uint8_t BigNumbers[];
#include <SdFat.h>//CS en pin 10
SdFat sd;
SdFile myFile;
// 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
/// Guardamos en que entrada de arduino esta conectado el pin CS del modulo.
const int chipSelect = 10;
char nmbrstring[ ] = "NMBR";
char ringstring[ ] = "RING";
char numerodete[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 ringer = 2;// Contador de ring, los 2 primeros no se detectan
int pin = A1;//pin conexion buzzer
String stringThree;
byte Bin2;
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()
{
myGLCD.InitLCD();
//myGLCD.clrScr();
pinMode(A0, INPUT_PULLUP); // sets analog pin for input
//digitalWrite(pin, HIGH);
pinMode(pin, OUTPUT); // set a pin for buzzer output
myGLCD.setFont(SmallFont);
myGLCD.print("LCD Activado", 0, 0); // print a simple messag
delay (2000);
// Configuramos el puerto serie (esta version NO usa Serie Virtual)
Serial.begin(38400);
while (!Serial) {
; // Espera para conexion puerto serie, solo necesario para leonardo
}
myGLCD.clrScr();
myGLCD.print("Setup is Ready", 0, 0);
delay(2000);
//Iniciamos la SD
//Serial.print("Iniciando SD...");
//Serial.print("\n");
myGLCD.clrScr();
myGLCD.print("Iniciando SD...", 0, 0);
// 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))
{
//Serial.println("Error inicializar SD!");
myGLCD.print("Error SD...", 0, 20);
sd.initErrorHalt();
delay(2000);
myGLCD.clrScr();
myGLCD.print("PULSE RESET", 0, 40);
pinMode(10, INPUT);
delay(1000);
return;
}
myGLCD.print("SD ini...OK", 0, 20);
delay(2000);
//REcreando fichero RECIB.TXT
if (!myFile.open("RECIB.TXT", O_RDWR)) {
myGLCD.print("Error SD write", 0, 20);
delay(2000);
}
myFile.println("111111111");
delay(200);
myFile.close();// close the file:
myGLCD.clrScr();
myGLCD.print("RECIB.TXT ini", 0, 10);
delay(2000);
myGLCD.print("OK", 0, 30);
delay(2000);
myGLCD.clrScr();
myGLCD.print("Start Modem....", 0, 0);
// Iniciamos los comandos Hayes para configurar el modem
Serial.print("ATZ\r\n");
delay(4000);
myGLCD.print("4.", 0, 20);
Serial.print("AT+VCID=1\r\n");//Conceptronics CID ON
//Serial.print("AT#CID=1\r\n");//USR Robotics CID ON
delay(2000);
myGLCD.print("3.", 10, 20);
Serial.print("ATS7=5\r\n");//USR Robotics Answer Wait 7 seg
delay(2000);
myGLCD.print("2.", 20, 20);
Serial.print("ATS0=0\r\n");//USR Robotics Auto Answer OFF
delay(2000);
myGLCD.print("1.", 30, 20);
Serial.print("AT+FAE=1\r\n");//USR Robotics Adaptative Answer/Silent Answer
delay(2000);
myGLCD.print("OK", 40, 20);
delay(2000);
digitalWrite(pin, HIGH);
playNote(1,100);
digitalWrite(pin, LOW);
}
void loop()
{
static char buffer[20];
buttonselect();// Selector botones
myGLCD.setFont(SmallFont);
if (readline(Serial.read(), buffer, 80) > 0)
{
//Deteccion del numero llamante leido por puerto serie
char* numero1 = strchr(buffer, 'NMBR =');
char* prefinmbr = strtok(buffer, " =");
char* numero2 = strchr(numero1, ' ');
if(strcmp(prefinmbr, nmbrstring) == 0)//Detectamos la cadena NMBR que contiene el numero llamante
{
//Lector de numero
char* numerodete = numero2;//detecta numero con 1 espacio al inicio
String stringOne = numerodete;//convierte numero char a string
stringOne.trim();//elimina el espacio del inicio del número
myGLCD.clrScr();
myGLCD.print("Num.llamante:", 0, 0);
myGLCD.print("*********", 0, 20);
//myGLCD.print(charBuf, 0, 20);
stringOne.toCharArray(charBuf, 10);//convierte el numero string a char para strcmp
//ringer = 2;//Pone a 0 el contador de rings
myGLCD.print(stringOne, 0, 20);//Presenta en numero detectado
//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)) {
myGLCD.print("Error SD write", 0, 30);
}
myFile.println(stringOne);
delay (200);
myFile.close();// close the file:
llamadas++;// acumulado de numero de llamadas
myGLCD.print("Llamadas.....", 0, 40);
myGLCD.printNumI(llamadas, 60, 40);
myGLCD.print("WCOK", 60, 20);//Presenta el OK de grabacion numero detectado
//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;
// 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
{
myGLCD.clrScr();
myGLCD.print("Numero detec.:", 0, 0);
myGLCD.print(stringTwo, 0, 20); // Muestra el numero bloqueado
myGLCD.print("**BLOQUEADO**", 0, 30);//Presenta señal numero bloqueado
ringer = 20;//Impide que suene el buzzer
/* //Codigo activacion del modem para contestar y colgar
Serial.print("ATA\r\n");//Coge el tlf
delay(2000);
Serial.print("ATH1\r\n");//Cuelga el tlf
*/
delay (4000);
}// Fin deteccion numero bloqueado
}//Fin bucle lectura numeros bloqueados SD
}//Fin deteccion de llamada NMBR
//Deteccion de los RING para activar el buzzer
if(strcmp(buffer, ringstring) == 0)//Detectamos la cadena RING
{
/* Test cadena detectada
lcd.clear();
lcd.setCursor(0,0);
lcd.print(buffer);
lcd.print(ringer);
*///Fin test
ringer++;
//myGLCD.printNumI(ringer, 0, 35);//Print num rings
if(ringer > 3 && ringer < 15)//detector de rings para hacer sonar el buzzer
{
digitalWrite(pin, HIGH);
playNote(1,100);
playNote(1,200);
playNote(1,100);
playNote(1,100);
playNote(1,200);
playNote(1,100);
playNote(1,100);
playNote(1,200);
playNote(1,100);
digitalWrite(pin, LOW);
}
}
//Fin deteccion RING
}//Fin lectura buffer serie
//Timer Reponedor a 0 de rings
long time_now = millis();
if ((long)(time_now - tAntes6) > 80000)//Temporizador 80 seg para poner rings a 0
{
tAntes6 = time_now;
ringer = 2;
}
/*Test rings status
lcd.setCursor(0,15);
lcd.print(ringer);
*///Fin test
}// Fin LOOP
// Codigo de lectura de los telefonos bloqueados en la SD
String ReadFile(int Linea,char Ruta[]){
int Lin=0;
String Resultado;
byte Bin;
if (!myFile.open(Ruta, O_RDWR)) {
myGLCD.print("SD Read Error", 0, 0);
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;
}
/// AÑADIDO CONTROL BOTONADURA Y GRABADO NUMEROS BLOQUEADOS SD
void buttonselect()
{
lcd_key = read_LCD_buttons(); // read the buttons
switch (lcd_key) // depending on which button was pushed, we perform an action
{
case btn3:
{
myGLCD.clrScr();
//LcdCharacter(adc_key_in);
myGLCD.print("Numero Block", 0, 0);
bloquear();
delay(500);
break;
}
case btn2:
{
myGLCD.clrScr();
//gotoXY(0,1);
//LcdCharacter(adc_key_in);
myGLCD.print("Bloquear Numero?", 0, 0);
myGLCD.print("NO", 0, 40);
myGLCD.print("X", 30, 40);
myGLCD.print("SI", 60, 40);
delay(500);
break;
}
case btn1:
{
//gotoXY(7,0);
//myGLCD.print("Bloquear");
leer();
/*myGLCD.clrScr();
gotoXY(0,1);
LcdCharacter(adc_key_in);
myGLCD.print("SELECT");*/
break;
}
case btnNONE:
{
long time_now = millis();
if ((long)(time_now - tAntes) > 10000) // regulador de tiempo medida datos y presentacion lcd
{
myGLCD.clrScr();
myGLCD.print("Waiting call...", 0, 0);
myGLCD.print("Llamadas..", 0, 40);
myGLCD.printNumI(llamadas, 60, 40);
tAntes = time_now;
}
if ((long)(time_now - tAntes2) > 1000)//Blink de * para indicar funcionamiento normal
{
myGLCD.print("****************", 0, 10);
tAntes2 = time_now;
}
if ((long)(time_now - tAntes3) > 1500)
{
myGLCD.print("* * * * * * * * ", 0, 10);
tAntes3 = time_now;
}
//Reponedor a 0 de lectura llamadas si inactividad en botones
if ((long)(time_now - tAntes4) > 20000)
{
i2 = 0;
tAntes4 = time_now;
}
if ((long)(time_now - tAntes5) > 1800000) //RESETEO MODEM CADA 30 MINUTOS
{
modemreset();
tAntes5 = time_now;
ringer = 2;
}
break;
}
}
}
void leer()
{
char Ruta[10] = {'R', 'E', 'C', 'I', 'B', '.', 'T', 'X', 'T', '\0'};//establece nombre fichero tlfs bloqueados
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);
myGLCD.clrScr();
myGLCD.print("Numero Leido.....", 0, 0);
myGLCD.print(".................", 0, 10);
myGLCD.printNumI((llamadas + 5)- i2, 40, 10);
//gotoXY(0,1);
//myGLCD.print(" "); // Muestra el numero leido
myGLCD.print(charThree, 0, 30); // Muestra el numero leido
//myGLCD.print("..", 75, 0);
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))
{
i2 = 0;
llamadas = 0;
delay (1000);
myGLCD.clrScr();
myGLCD.print("Borrando las", 0, 0);
myGLCD.print("LLamadas...", 0, 10);
if (!myFile.open("RECIB.TXT", O_RDWR | O_CREAT)) {
myGLCD.clrScr();
myGLCD.print("Error SD write", 0, 10);
delay(2000);
myGLCD.print("PULSE RESET", 0, 20);
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)) {
myGLCD.print("Error SD write", 0, 10);
delay(2000);
myGLCD.clrScr();
myGLCD.print("PULSE RESET", 0, 20);
delay(2000);
}
myFile.println("111111111");
delay(200);
myFile.close();// close the file:
myGLCD.clrScr();
myGLCD.print("RECIB.TXT ini", 0, 0);
delay(2000);
myGLCD.print("OK", 0, 10);
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)){
myGLCD.print("Error SD write", 0, 0);
sd.initErrorHalt();
delay(2000);
myGLCD.print("PULSE RESET", 0, 10);
pinMode(10, INPUT);
delay(1000);
}
myFile.println(charThree);
delay(200);
myFile.close();
myGLCD.clrScr();
myGLCD.print("Numero bloqueado", 0, 0);
myGLCD.print("*********", 0, 20); // Limpia espacio numero
myGLCD.print(charThree, 0, 20); // Muestra el numero bloqueado
myGLCD.print("**BLOQUEADO**", 0, 30);
delay(2000);
}
//Sistema de lectura del puerto serie
int readline(int readch, char *buffer, int len)
{
static int pos = 0;
int rpos;
if (readch > 0) {
switch (readch) {
case '\n': // Ignore new-lines
break;
case '\r': // Return on CR
rpos = pos;
pos = 0; // Reset position index ready for next time
return rpos;
default:
if (pos < len-1) {
buffer[pos++] = readch;
buffer[pos] = 0;
}
}
}
// No end of line has been found, so return -1.
return -1;
}
// fin programa lectura puerto serie
// 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 < 200 && adc_key_in > 100) 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
// Reseteo modem
void modemreset()
{
myGLCD.clrScr();
myGLCD.print("Reset Modem....", 0, 0);
// Iniciamos los comandos Hayes para configurar el modem
Serial.print("ATZ\r\n");
delay(4000);
myGLCD.print("4.", 0, 20);
Serial.print("AT+VCID=1\r\n");//Conceptronics CID ON
//Serial.print("AT#CID=1\r\n");//USR Robotics CID ON
delay(2000);
myGLCD.print("3.", 10, 20);
Serial.print("ATS7=5\r\n");//USR Robotics Answer Wait 7 seg
delay(2000);
myGLCD.print("2.", 20, 20);
Serial.print("ATS0=0\r\n");//USR Robotics Auto Answer OFF
delay(2000);
myGLCD.print("1.", 30, 20);
Serial.print("AT+FAE=1\r\n");//USR Robotics Adaptative Answer/Silent Answer
delay(2000);
myGLCD.print("OK", 40, 20);
delay(2000);
}
// 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
}
}
lunes, 18 de abril de 2016
QDI Platinix 2PE/800 overhaull
La placa QDI Platinix 2PE/800 es del tipo i845PE, soporta hasta 2GB de RAM en dos módulos de 1GB de DDR400 (DDR333 OC) y hasta FSB800 (en modo OC). El FSB maximo sin OC es de 166mhz, y las memorias van entonces a 333mhz, siendo el bus de 666mhz. El procesador máximo que soporta en un P4 Dual Core 3400mhz de FSB200 y multiplicador de 17x. No tiene soporte SATA. Nosotros vamos a intentar hacer lo siguiente:
- Poner el procesador a 3400mhz FSB200.
- Poner las memorias a 400mhz , como DDR400.
- Poner el Bus a 800mhz.
- Dar soporte a discos duros SATA bootables.
- Instalar Windows 7 32 bits.
La placa se configura en modo FSB 200 mediante jumpers del siguiente modo:

En la BIOS se puede seleccionar en la seccion QDI Innovation Features el modo AUTO, y ya arranca a FSB200.
Una vez hecho esto, las memorias estarán a FSB200, el BUS a 800mhz, y el procesador a FSB200, o sea a 3400mhz.
Para dar soporte a discos SATA necesitaremos añadir una controladora PCI SATA Bootable, una muy conveniente y barata es la SiI3114, con soporte de hasta 4 discos SATA. Nos dará 1,5gb/seg, o sea lo básico de SATA, pero suficiente.
La instalación de Windows 7 es de 32bits, ya que no tenemos posibilidad de aumentar la memoria a más de 2GB. La instalación es perfecta, salvo que no existen drivers para el controlador MPU-401 MIDI, lo cual es anecdótico.
La instalación del controlador de la tarjeta SATA se hace desde el CD de drivers, en la instalación de Windows 7, cuando este lo solicita. Volver a colocar el disco de instalación de Windows 7 y seguir.
Tras el arranque, vi que el sistema era inestable a 3400mhz, debido a que la placa no permite aumentar la CAS de las memorias en la Bios por encima de 2.5, p.e. a 3, aunque en el manual de la placa si lo menciona. Por tanto tenemos que reducir el FSB de 200 mhz a un valor aceptable.
El proceso seguido es el siguiente. Se configuran los jumpers de FSB de la placa para 200 mhz. Se selecciona en bios el FSB166/33. Con lo cual el arranque es con el procesador a 2830mhz y las memorias a DDR333. En Windows instalamos un programa controlador de mhz del PLL o chip de reloj de FSB de la placa, en nuestro caso es un chip Cypress CY28324PVC, que modifica el FSB en incrementos de 1mhz. El programa controlador de PLL elegido es el setfsb_2_2_134_98, ya que es el que nos permite usarlo en modo comando desde DOS en ventanas de windows o como accesos directos con los parámetros requeridos. Ejecutamos setfsb y elegimos el controlador de PLL CY28349BOC, que es el compatible con nuestro chip. Vamos a la pestaña CREATE y colocamos como nombre del PLL CY28324PVC y le damos a EXPORT. ya tenemos nuestro PLL creado con el nombre CY28324PVC. Cerramos el programa . Como comandos desde ventana DOS para establecer el FSB, realizaremos el siguiente (p.e para FSB166) archivo .bat:
C:\setfsb.exe -w1 -s166 -cg[CY28324PVC] -q
Los modificadores son:
-w es esperar 1 segundo.
-s SET FSB 166 mhz
-q es salir una vez realizado.
Estableciendo el comando SET a 188 de FSB el sistema parece estable haciendo un testeo con Stabilitytest.
El elegir setfsb en modo comandos es porque se pueden crear los archivos .bat que deseses para las frecuencias que quieras usar en ciertos momentos, y usar un launcher como el que tiene el Motherboard Monitor, o el Speedfan, para usarlos. Esto es, altos FSB para tareas a temperaturas de procesador bajas, y a temperaturas altas, usar FSB bajos.
Una cuestión más es que podemos usar el setfsb para hacer una emulación del comportamiento de los procesadores de los portátiles que varían su velocidad dependiendo de la carga necesaria de trabajo. Lo hacen para ahorrar bater´ñias, pero en nuestro caso lo usaríamos para mantener fresco el procesador en momentos de fuerte calor ambiental. El proceso es simple y se basa en al uso de la herramienta de windows XP y 7 llamada PERFMON.EXE. En su monitor de rendimiento crearemos una entrada de datos de "% de tiempo de procesador" para que la monitorice. En el item "Conjuntos de recopiladores de datos" crearemos una nueva entrada en el item "Definido por el usuario". Elegiremos el modo "Crear manualmente (avanzado)", damos a siguiente y elegimos "Alerta del controlador de rendimiento". Agregamos y elegimos Procesador - % de tiempo de procesador - Total - Agregar. En "Avisar cuando" ponemo el límite da carga de procesador que queramos, p.e. por encima de 50%. Damos a Propiedades y allí podemos elegir para Windows 7 una tarea creada en el Task Scheduler que ejecute un FSB que nossotros deseemos, o en Windows XP un archivo .bat. En la "programación" pondremos un inicio y en "Detener condición" pondremos una duración de unos pocos segundos para que se ejecute nuestro setfsb y reiniciar en unos minutos. Colocando varios conjuntos de recopiladores manuales de datos con diferentes grados de alerta de carga ya tenemos nuestro sistema funcionando con diferentes MHZ según la carga de CPU. Yo lo he puesto por encima de 50% a FSB188, y por debajo de 2% de carga a FSB166. Pero se podría poner en el Task Scheduler a FSB66 en idle, para refrigerar el procesador al máximo y bajar el consumo en Watios.
- Poner el procesador a 3400mhz FSB200.
- Poner las memorias a 400mhz , como DDR400.
- Poner el Bus a 800mhz.
- Dar soporte a discos duros SATA bootables.
- Instalar Windows 7 32 bits.
La placa se configura en modo FSB 200 mediante jumpers del siguiente modo:

En la BIOS se puede seleccionar en la seccion QDI Innovation Features el modo AUTO, y ya arranca a FSB200.
Una vez hecho esto, las memorias estarán a FSB200, el BUS a 800mhz, y el procesador a FSB200, o sea a 3400mhz.
Para dar soporte a discos SATA necesitaremos añadir una controladora PCI SATA Bootable, una muy conveniente y barata es la SiI3114, con soporte de hasta 4 discos SATA. Nos dará 1,5gb/seg, o sea lo básico de SATA, pero suficiente.
La instalación de Windows 7 es de 32bits, ya que no tenemos posibilidad de aumentar la memoria a más de 2GB. La instalación es perfecta, salvo que no existen drivers para el controlador MPU-401 MIDI, lo cual es anecdótico.
La instalación del controlador de la tarjeta SATA se hace desde el CD de drivers, en la instalación de Windows 7, cuando este lo solicita. Volver a colocar el disco de instalación de Windows 7 y seguir.
Tras el arranque, vi que el sistema era inestable a 3400mhz, debido a que la placa no permite aumentar la CAS de las memorias en la Bios por encima de 2.5, p.e. a 3, aunque en el manual de la placa si lo menciona. Por tanto tenemos que reducir el FSB de 200 mhz a un valor aceptable.
El proceso seguido es el siguiente. Se configuran los jumpers de FSB de la placa para 200 mhz. Se selecciona en bios el FSB166/33. Con lo cual el arranque es con el procesador a 2830mhz y las memorias a DDR333. En Windows instalamos un programa controlador de mhz del PLL o chip de reloj de FSB de la placa, en nuestro caso es un chip Cypress CY28324PVC, que modifica el FSB en incrementos de 1mhz. El programa controlador de PLL elegido es el setfsb_2_2_134_98, ya que es el que nos permite usarlo en modo comando desde DOS en ventanas de windows o como accesos directos con los parámetros requeridos. Ejecutamos setfsb y elegimos el controlador de PLL CY28349BOC, que es el compatible con nuestro chip. Vamos a la pestaña CREATE y colocamos como nombre del PLL CY28324PVC y le damos a EXPORT. ya tenemos nuestro PLL creado con el nombre CY28324PVC. Cerramos el programa . Como comandos desde ventana DOS para establecer el FSB, realizaremos el siguiente (p.e para FSB166) archivo .bat:
C:\setfsb.exe -w1 -s166 -cg[CY28324PVC] -q
Los modificadores son:
-w es esperar 1 segundo.
-s SET FSB 166 mhz
-q es salir una vez realizado.
Estableciendo el comando SET a 188 de FSB el sistema parece estable haciendo un testeo con Stabilitytest.
El elegir setfsb en modo comandos es porque se pueden crear los archivos .bat que deseses para las frecuencias que quieras usar en ciertos momentos, y usar un launcher como el que tiene el Motherboard Monitor, o el Speedfan, para usarlos. Esto es, altos FSB para tareas a temperaturas de procesador bajas, y a temperaturas altas, usar FSB bajos.
Una cuestión más es que podemos usar el setfsb para hacer una emulación del comportamiento de los procesadores de los portátiles que varían su velocidad dependiendo de la carga necesaria de trabajo. Lo hacen para ahorrar bater´ñias, pero en nuestro caso lo usaríamos para mantener fresco el procesador en momentos de fuerte calor ambiental. El proceso es simple y se basa en al uso de la herramienta de windows XP y 7 llamada PERFMON.EXE. En su monitor de rendimiento crearemos una entrada de datos de "% de tiempo de procesador" para que la monitorice. En el item "Conjuntos de recopiladores de datos" crearemos una nueva entrada en el item "Definido por el usuario". Elegiremos el modo "Crear manualmente (avanzado)", damos a siguiente y elegimos "Alerta del controlador de rendimiento". Agregamos y elegimos Procesador - % de tiempo de procesador - Total - Agregar. En "Avisar cuando" ponemo el límite da carga de procesador que queramos, p.e. por encima de 50%. Damos a Propiedades y allí podemos elegir para Windows 7 una tarea creada en el Task Scheduler que ejecute un FSB que nossotros deseemos, o en Windows XP un archivo .bat. En la "programación" pondremos un inicio y en "Detener condición" pondremos una duración de unos pocos segundos para que se ejecute nuestro setfsb y reiniciar en unos minutos. Colocando varios conjuntos de recopiladores manuales de datos con diferentes grados de alerta de carga ya tenemos nuestro sistema funcionando con diferentes MHZ según la carga de CPU. Yo lo he puesto por encima de 50% a FSB188, y por debajo de 2% de carga a FSB166. Pero se podría poner en el Task Scheduler a FSB66 en idle, para refrigerar el procesador al máximo y bajar el consumo en Watios.
viernes, 4 de diciembre de 2015
How to build an Analog UHF TV station
In tis entry I am going to explain how to use this little module:
This module is an UHF 200mw power transmitter. It has one video and one audio inputs. It is powered in a range from 3.3v to 5v. It has a litthe antenna cord.
The use of this module is pretty simple. You must to have a source of video and sound, i.e. from a the scart input/output of your TV or TDT. This can be easily obtained usind an Scart to RCA connector, that have a input/output switch in it, choose Output and go.
Yo need also a two line RCA male to male cable. To make the module more affordable to the connections, is better to solder this module to a PCB and attach to it two RCA female connectors, one power female connector, and an antenna female connector.
I used two in line diode to reduce voltage from an USB charger, that feeds the device.
The final project is in this youtube video, working:
https://www.youtube.com/watch?v=rLandibnaBI
martes, 23 de septiembre de 2014
Discriminador de llamadas telefónicas a líneas fijas
Hola, en esta nueva entrada voy a describir como crear un discriminador de llamadas telefónicas usando la capacidad de ciertos modems serie de hacer Caller ID o lo que es lo mismo, identificación de llamadas. Para ello usaremos un Arduino UNO R3 Atmega32, un modem serie U.S. Robotics 56K, un modulo serie, un cable serie modem nulo, un modulo SD YL-30 y un keypad shield LCD 16x2 (en la última versión del proyecto se usa un LCD 16x2 y una botonadura simple de 4 botones DIY). Como siempre el costo de los materiales es ridículo, si exceptuamos el módem, que es un cacharro que muchos tenemos en casa de la época del internet sin ADSL.
El sistema funciona del siguiente modo:
Al recibirse una llamada, el modem realiza un Caller ID y detecta el número llamante, para que se reciba esta información al menos deben recibirse dos RING, este es enviado al Arduino a través del cable modem nulo y el módulo serie. Arduino lee el número y lo compara con los números almacenados en un fichero de teléfonos bloqueados ya existente, si no lo encuentra entre los números del fichero, lo graba en un fichero de llamadas recibidas, si lo encuentra, le indica al modem que coja la llamada, evitando que nos fría a timbrazos. Luego también podremos leer el fichero de llamadas recibidas y bloquear los números que nos interesen, desde el propio Arduino, usando la botonadura del keypad y los números presentados en el LCD.
La conexiones a realizar entre los diferentes elementos y Arduino, son las siguientes:
- Modulo SD YL-30:
MOSI............11
MISO............12
SCK..............13
CS.................10
3,3v................3.3v
5v...................5v
GND..............GND
- Modulo Serie:
Es un módulo serie sencillo con entradas TX-RX y de voltaje, y una salida DB9 para poder conectarla al modem a través del cable serie.
Modulo: Arduino:
RX............................8
TX............................9
- Modulo Keypad shield LCD de 5 botones:
Conectaremos los pines del Keypad shield del modo siguiente:
Keypad: Arduino:
5v..........................................5v.
GND.....................................GND
4............................................4
5............................................5
6............................................6
7............................................7
8............................................2
9............................................3
A0.........................................A0
En el caso de usar un LCD 1602 bruto, hay que hacer una pequeña modificación para que sea usable en Arduino. Hay que soldarle una tira de 16 pines macho, y hay que soldar entre sí los pines 1 - 4 y 16 (GND) y entre sí los pines 2 y 15 (+5v.), así como unir los pines 1 y 3 con una resistencia de 3 K Ohm.
La correspondencia con Arduino es la siguiente:
LCD: Arduino:
1 ...................GND
2 ...................5v.
3.....................Unido a GND por resistencia 3 KOhm
4....................2
5....................GND
6.....................3
....
11.....................4
12.....................5
13.....................6
14.....................7
15.....................5v.
16 .....................GND
La botonadura DIY se hace de forma sencilla con cuatro botones y tres resistencias de 3 K Ohm. Como en la figura adjunta, pero uniendo un extremo al Pin analógico A0 y el otro a cualquier GND.
El cable serie de conexión entre el modulo serie y el modem se construye de la siguiente manera:
Se necesita un cable con tres polos para las líneas RX y TX, que deben cruzarse entre los dos conectores, y la linea de GND. En cada conector se deben unir entre si las patillas RTS-CTS (7 y 8) y las DTR-DSR (4 y 6). De esta manera el módem creerá que la negociación de datos que realiza es correcta y nos permitirá comunicarnos con el Arduino.
El sketch para hacer funcionar todo 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. Ademas graba automáticamente los números que han llamado
y que posteriormente pueden seleccionarse con la botonadura para ser bloqueados.
El hardware necesario es un Arduino Uno, un modem con CallerID (en mi caso US Robotics 56k), un modulo
SD YL-30, una tarjeta SD, un modulo Serie RS232, un cable serie modem nulo, un modulo LCD de 16x2 y
una botonadura tipo Keypad de resistencias (una botonadura simple con tres resistencias de 3K en serie
conectando GND a Pin A0, p.e.).
El cable serie modem nulo permite obviar el comportamiento del modem en respuesta a la lineas RTS-CTS,
DTR-DSR, las cuales se unen en los extremos de cada conector, cruzándose las lineas TX-RX y
uniendo las GND entre si.
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
*/
//Sample using LiquidCrystal library
#include <LiquidCrystal.h>
#include <SD.h> //CS en pin 10
// 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
// Guardamos en que entrada de arduino esta conectado el pin CS del modulo.
//const int chipSelect = 10;
char nmbrstring[ ] = "NMBR";
char numerodete[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 i2 = 0;
int llamadas = 0;// Contador de llamadas, debe ser 0. Otro valor es para pruebas.
File myFile; //fichero llamadas recibidas
String stringThree;
unsigned long tAntes = 0;
unsigned long tAntes2 = 0;
unsigned long tAntes3 = 0;
unsigned long tAntes4 = 0;
unsigned long tAntes5 = 0;
long time_now = 0;
void setup()
{
lcd.begin(16, 2); // start LCD library
pinMode(A0, INPUT_PULLUP); // sets analog pin for input
lcd.setCursor(0,0);
lcd.print("LCD Activado"); // print a simple messag
delay (2000);
// Configuramos el puerto serie (esta version NO usa Serie Virtual)
Serial.begin(9600);
while (!Serial) {
; // Espera para conexion puerto serie, solo necesario para leonardo
}
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Setup is Ready");
//Iniciamos la SD
//Serial.print("Iniciando SD...");
//Serial.print("\n");
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(10)) {
//Serial.println("Error inicializar SD!");
lcd.setCursor(0,1);
lcd.print("Error ini.SD!");
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
File Archivo1;
Archivo1 = SD.open("RECIB.TXT", FILE_WRITE);
if (Archivo1) {
Archivo1.println("111111111");
Archivo1.close();
lcd.clear();
lcd.setCursor(0,0);
lcd.print("RECIB.TXT ini");
delay(2000);
lcd.setCursor(0,1);
lcd.print("OK");
delay(2000);
} else {
lcd.setCursor(0,1);
lcd.print("Error SD write");
delay(2000);
}
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Start Modem....");
// Iniciamos los comandos Hayes para configurar el modem
Serial.print("ATZ\r\n");
delay(4000);
lcd.setCursor(0,1);
lcd.print("4.");
//mySerial.write("AT+VCID=1\r\n");//Conceptronics CID ON
Serial.print("AT#CID=1\r\n");//USR Robotics CID ON
delay(2000);
lcd.setCursor(2,1);
lcd.print("3.");
Serial.print("ATS7=5\r\n");//USR Robotics Answer Wait 7 seg
delay(2000);
lcd.setCursor(4,1);
lcd.print("2.");
Serial.print("ATS0=0\r\n");//USR Robotics Auto Answer OFF
delay(2000);
lcd.setCursor(6,1);
lcd.print("OK");
delay(2000);
}
void loop()
{
static char buffer[20];
buttonselect();// Selector botones
if (readline(Serial.read(), buffer, 80) > 0)
{
char* numero1 = strchr(buffer, 'NMBR =');
char* prefinmbr = strtok(buffer, " =");
char* numero2 = strchr(numero1, ' ');
if(strcmp(prefinmbr, nmbrstring) == 0)//Detectamos la cadena NMBR que contiene el numero llamante
{
//Lector de numero
char* numerodete = numero2;//detecta numero con 1 espacio al inicio
String stringOne = numerodete;//convierte numero char a string
stringOne.trim();//elimina el espacio del inicio del número
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Num.llamante:");
lcd.setCursor(0,1);
lcd.print(stringOne);
stringOne.toCharArray(charBuf, 10);//convierte el numero string a char para strcmp
lcd.setCursor(0,1);
lcd.print(charBuf);
//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.
myFile = SD.open("RECIB.TXT", FILE_WRITE);
// if the file opened okay, write to it:
if (myFile) {
myFile.println(stringOne);
myFile.close();// close the file:
llamadas++;// acumulado de numero de llamadas
lcd.setCursor(0,0);
lcd.print("Llamadas.....");
lcd.setCursor(13,0);
lcd.print(llamadas);
lcd.setCursor(12,1);
lcd.print("WCOK");
//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;
} else {
// if the file didn't open, print an error:
//Serial.println("error opening file");
lcd.setCursor(0,1);
lcd.print("error SD write");
}
// 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 detec.:");
lcd.setCursor(0,1);
lcd.print(charBuf); // Muestra el numero bloqueado
//Codigo contestar y colgar
Serial.print("ATA\r\n");//Coge el tlf
delay(2000);
Serial.print("ATH1\r\n");//Cuelga el tlf
delay (4000);
}// Fin deteccion numero bloqueado
}//Fin bucle lectura numeros bloqueados SD
}//Fin deteccion de llamada NMBR
}//Fin lectura buffer serie
}
// Codigo de lectura de los telefonos bloqueados en la SD
String ReadFile(int Linea,char Ruta[]){
int Lin=0;
String Resultado;
File myFile;
byte Bin;
myFile = SD.open(Ruta);;
if (myFile) {
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;
}
}
/// AÑADIDO 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,1);
//lcd.print(adc_key_in);
lcd.print("RIGHT ");
delay(500);
break;
}
case btn2:
{
/*lcd.clear();
lcd.setCursor(0,1);
lcd.print(adc_key_in);
lcd.print("DOWN ");*/
leer();
break;
}
case btn1:
{
//lcd.setCursor(7,0);
//lcd.print("Bloquear");
bloquear();
/*lcd.clear();
lcd.setCursor(0,1);
lcd.print(adc_key_in);
lcd.print("SELECT");*/
break;
}
case btnNONE:
{
long time_now = millis();
if ((long)(time_now - tAntes) > 10000) // regulador de tiempo medida datos y 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;
}
if ((long)(time_now - tAntes2) > 1000)
{
lcd.setCursor(15,0);
lcd.print("*");
tAntes2 = time_now;
}
if ((long)(time_now - tAntes3) > 1500)
{
lcd.setCursor(15,0);
lcd.print(" ");
tAntes3 = time_now;
}
//Reponedor a 0 de lectura llamadas si inactividad en botones
if ((long)(time_now - tAntes4) > 20000)
{
i2 = 0;
tAntes4 = time_now;
}
if ((long)(time_now - tAntes5) > 300000) //RESETEO MODEM CADA 5 MINUTOS
{
modemreset();
tAntes5 = time_now;
}
break;
}
}
}
void leer()
{
char Ruta[10] = {'R', 'E', 'C', 'I', 'B', '.', 'T', 'X', 'T', '\0'};//establece nombre fichero tlfs bloqueados
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(15,0);
lcd.print((llamadas + 5)- i2);
//lcd.setCursor(0,1);
//lcd.print(" "); // Muestra el numero leido
lcd.setCursor(0,1);
lcd.print(charThree); // Muestra el numero leido
lcd.setCursor(12,1);
lcd.print(".."); // Muestra el numero leido
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))
{
i2 = 0;
llamadas = 0;
delay (1000);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Borrando las");
lcd.setCursor(0,1);
lcd.print("LLamadas...");
myFile.close();
delay(2000);
//Borrando fichero RECIB.TXT
SD.remove("RECIB.TXT");
delay(2000);
myFile.close();
//REcreando fichero RECIB.TXT
File Archivo1;
Archivo1 = SD.open("RECIB.TXT", FILE_WRITE);
if (Archivo1) {
Archivo1.println("111111111");
delay(200);
Archivo1.close();
lcd.clear();
lcd.setCursor(0,0);
lcd.print("RECIB.TXT ini");
delay(2000);
lcd.setCursor(0,1);
lcd.print("OK");
delay(2000);
} else {
lcd.setCursor(0,1);
lcd.print("Error SD write");
delay(2000);
lcd.clear();
lcd.setCursor(0,1);
lcd.print("PULSE RESET");
delay(2000);
}
// fin recreo
}
}
//funcion para escribir el número leido de RECIB.TXT y grabarlo en
//el fichero de numeros bloqueados BLOQ.TXT
void bloquear()
{
myFile = SD.open("BLOQ.TXT", FILE_WRITE);
if (myFile){
myFile.println(charThree);
delay(200);
myFile.close();
} else {
lcd.setCursor(0,1);
lcd.print("error SD write");
}
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");
//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;
delay(2000);
}
//Sistema de lectura del puerto serie
int readline(int readch, char *buffer, int len)
{
static int pos = 0;
int rpos;
if (readch > 0) {
switch (readch) {
case '\n': // Ignore new-lines
break;
case '\r': // Return on CR
rpos = pos;
pos = 0; // Reset position index ready for next time
return rpos;
default:
if (pos < len-1) {
buffer[pos++] = readch;
buffer[pos] = 0;
}
}
}
// No end of line has been found, so return -1.
return -1;
}
// fin programa lectura puerto serie
// 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 < 200 && adc_key_in > 100) 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
// Reseteo modem
void modemreset()
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Reset Modem....");
// Iniciamos los comandos Hayes para configurar el modem
Serial.print("ATZ\r\n");
delay(4000);
lcd.setCursor(0,1);
lcd.print("4.");
//mySerial.write("AT+VCID=1\r\n");//Conceptronics CID ON
Serial.print("AT#CID=1\r\n");//USR Robotics CID ON
delay(2000);
lcd.setCursor(2,1);
lcd.print("3.");
Serial.print("ATS7=5\r\n");//USR Robotics Answer Wait 7 seg
delay(2000);
lcd.setCursor(4,1);
lcd.print("2.");
Serial.print("ATS0=0\r\n");//USR Robotics Auto Answer OFF
delay(2000);
lcd.setCursor(6,1);
lcd.print("OK");
delay(2000);
}
El sistema funciona del siguiente modo:
Al recibirse una llamada, el modem realiza un Caller ID y detecta el número llamante, para que se reciba esta información al menos deben recibirse dos RING, este es enviado al Arduino a través del cable modem nulo y el módulo serie. Arduino lee el número y lo compara con los números almacenados en un fichero de teléfonos bloqueados ya existente, si no lo encuentra entre los números del fichero, lo graba en un fichero de llamadas recibidas, si lo encuentra, le indica al modem que coja la llamada, evitando que nos fría a timbrazos. Luego también podremos leer el fichero de llamadas recibidas y bloquear los números que nos interesen, desde el propio Arduino, usando la botonadura del keypad y los números presentados en el LCD.
La conexiones a realizar entre los diferentes elementos y Arduino, son las siguientes:
- Modulo SD YL-30:
MOSI............11
MISO............12
SCK..............13
CS.................10
3,3v................3.3v
5v...................5v
GND..............GND
- Modulo Serie:
Es un módulo serie sencillo con entradas TX-RX y de voltaje, y una salida DB9 para poder conectarla al modem a través del cable serie.
Modulo: Arduino:
RX............................8
TX............................9
- Modulo Keypad shield LCD de 5 botones:
Conectaremos los pines del Keypad shield del modo siguiente:
Keypad: Arduino:
5v..........................................5v.
GND.....................................GND
4............................................4
5............................................5
6............................................6
7............................................7
8............................................2
9............................................3
A0.........................................A0
En el caso de usar un LCD 1602 bruto, hay que hacer una pequeña modificación para que sea usable en Arduino. Hay que soldarle una tira de 16 pines macho, y hay que soldar entre sí los pines 1 - 4 y 16 (GND) y entre sí los pines 2 y 15 (+5v.), así como unir los pines 1 y 3 con una resistencia de 3 K Ohm.
La correspondencia con Arduino es la siguiente:
LCD: Arduino:
1 ...................GND
2 ...................5v.
3.....................Unido a GND por resistencia 3 KOhm
4....................2
5....................GND
6.....................3
....
11.....................4
12.....................5
13.....................6
14.....................7
15.....................5v.
16 .....................GND
La botonadura DIY se hace de forma sencilla con cuatro botones y tres resistencias de 3 K Ohm. Como en la figura adjunta, pero uniendo un extremo al Pin analógico A0 y el otro a cualquier GND.
El cable serie de conexión entre el modulo serie y el modem se construye de la siguiente manera:
Se necesita un cable con tres polos para las líneas RX y TX, que deben cruzarse entre los dos conectores, y la linea de GND. En cada conector se deben unir entre si las patillas RTS-CTS (7 y 8) y las DTR-DSR (4 y 6). De esta manera el módem creerá que la negociación de datos que realiza es correcta y nos permitirá comunicarnos con el Arduino.
El sketch para hacer funcionar todo 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. Ademas graba automáticamente los números que han llamado
y que posteriormente pueden seleccionarse con la botonadura para ser bloqueados.
El hardware necesario es un Arduino Uno, un modem con CallerID (en mi caso US Robotics 56k), un modulo
SD YL-30, una tarjeta SD, un modulo Serie RS232, un cable serie modem nulo, un modulo LCD de 16x2 y
una botonadura tipo Keypad de resistencias (una botonadura simple con tres resistencias de 3K en serie
conectando GND a Pin A0, p.e.).
El cable serie modem nulo permite obviar el comportamiento del modem en respuesta a la lineas RTS-CTS,
DTR-DSR, las cuales se unen en los extremos de cada conector, cruzándose las lineas TX-RX y
uniendo las GND entre si.
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
*/
//Sample using LiquidCrystal library
#include <LiquidCrystal.h>
#include <SD.h> //CS en pin 10
// 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
// Guardamos en que entrada de arduino esta conectado el pin CS del modulo.
//const int chipSelect = 10;
char nmbrstring[ ] = "NMBR";
char numerodete[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 i2 = 0;
int llamadas = 0;// Contador de llamadas, debe ser 0. Otro valor es para pruebas.
File myFile; //fichero llamadas recibidas
String stringThree;
unsigned long tAntes = 0;
unsigned long tAntes2 = 0;
unsigned long tAntes3 = 0;
unsigned long tAntes4 = 0;
unsigned long tAntes5 = 0;
long time_now = 0;
void setup()
{
lcd.begin(16, 2); // start LCD library
pinMode(A0, INPUT_PULLUP); // sets analog pin for input
lcd.setCursor(0,0);
lcd.print("LCD Activado"); // print a simple messag
delay (2000);
// Configuramos el puerto serie (esta version NO usa Serie Virtual)
Serial.begin(9600);
while (!Serial) {
; // Espera para conexion puerto serie, solo necesario para leonardo
}
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Setup is Ready");
//Iniciamos la SD
//Serial.print("Iniciando SD...");
//Serial.print("\n");
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(10)) {
//Serial.println("Error inicializar SD!");
lcd.setCursor(0,1);
lcd.print("Error ini.SD!");
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
File Archivo1;
Archivo1 = SD.open("RECIB.TXT", FILE_WRITE);
if (Archivo1) {
Archivo1.println("111111111");
Archivo1.close();
lcd.clear();
lcd.setCursor(0,0);
lcd.print("RECIB.TXT ini");
delay(2000);
lcd.setCursor(0,1);
lcd.print("OK");
delay(2000);
} else {
lcd.setCursor(0,1);
lcd.print("Error SD write");
delay(2000);
}
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Start Modem....");
// Iniciamos los comandos Hayes para configurar el modem
Serial.print("ATZ\r\n");
delay(4000);
lcd.setCursor(0,1);
lcd.print("4.");
//mySerial.write("AT+VCID=1\r\n");//Conceptronics CID ON
Serial.print("AT#CID=1\r\n");//USR Robotics CID ON
delay(2000);
lcd.setCursor(2,1);
lcd.print("3.");
Serial.print("ATS7=5\r\n");//USR Robotics Answer Wait 7 seg
delay(2000);
lcd.setCursor(4,1);
lcd.print("2.");
Serial.print("ATS0=0\r\n");//USR Robotics Auto Answer OFF
delay(2000);
lcd.setCursor(6,1);
lcd.print("OK");
delay(2000);
}
void loop()
{
static char buffer[20];
buttonselect();// Selector botones
if (readline(Serial.read(), buffer, 80) > 0)
{
char* numero1 = strchr(buffer, 'NMBR =');
char* prefinmbr = strtok(buffer, " =");
char* numero2 = strchr(numero1, ' ');
if(strcmp(prefinmbr, nmbrstring) == 0)//Detectamos la cadena NMBR que contiene el numero llamante
{
//Lector de numero
char* numerodete = numero2;//detecta numero con 1 espacio al inicio
String stringOne = numerodete;//convierte numero char a string
stringOne.trim();//elimina el espacio del inicio del número
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Num.llamante:");
lcd.setCursor(0,1);
lcd.print(stringOne);
stringOne.toCharArray(charBuf, 10);//convierte el numero string a char para strcmp
lcd.setCursor(0,1);
lcd.print(charBuf);
//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.
myFile = SD.open("RECIB.TXT", FILE_WRITE);
// if the file opened okay, write to it:
if (myFile) {
myFile.println(stringOne);
myFile.close();// close the file:
llamadas++;// acumulado de numero de llamadas
lcd.setCursor(0,0);
lcd.print("Llamadas.....");
lcd.setCursor(13,0);
lcd.print(llamadas);
lcd.setCursor(12,1);
lcd.print("WCOK");
//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;
} else {
// if the file didn't open, print an error:
//Serial.println("error opening file");
lcd.setCursor(0,1);
lcd.print("error SD write");
}
// 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 detec.:");
lcd.setCursor(0,1);
lcd.print(charBuf); // Muestra el numero bloqueado
//Codigo contestar y colgar
Serial.print("ATA\r\n");//Coge el tlf
delay(2000);
Serial.print("ATH1\r\n");//Cuelga el tlf
delay (4000);
}// Fin deteccion numero bloqueado
}//Fin bucle lectura numeros bloqueados SD
}//Fin deteccion de llamada NMBR
}//Fin lectura buffer serie
}
// Codigo de lectura de los telefonos bloqueados en la SD
String ReadFile(int Linea,char Ruta[]){
int Lin=0;
String Resultado;
File myFile;
byte Bin;
myFile = SD.open(Ruta);;
if (myFile) {
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;
}
}
/// AÑADIDO 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,1);
//lcd.print(adc_key_in);
lcd.print("RIGHT ");
delay(500);
break;
}
case btn2:
{
/*lcd.clear();
lcd.setCursor(0,1);
lcd.print(adc_key_in);
lcd.print("DOWN ");*/
leer();
break;
}
case btn1:
{
//lcd.setCursor(7,0);
//lcd.print("Bloquear");
bloquear();
/*lcd.clear();
lcd.setCursor(0,1);
lcd.print(adc_key_in);
lcd.print("SELECT");*/
break;
}
case btnNONE:
{
long time_now = millis();
if ((long)(time_now - tAntes) > 10000) // regulador de tiempo medida datos y 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;
}
if ((long)(time_now - tAntes2) > 1000)
{
lcd.setCursor(15,0);
lcd.print("*");
tAntes2 = time_now;
}
if ((long)(time_now - tAntes3) > 1500)
{
lcd.setCursor(15,0);
lcd.print(" ");
tAntes3 = time_now;
}
//Reponedor a 0 de lectura llamadas si inactividad en botones
if ((long)(time_now - tAntes4) > 20000)
{
i2 = 0;
tAntes4 = time_now;
}
if ((long)(time_now - tAntes5) > 300000) //RESETEO MODEM CADA 5 MINUTOS
{
modemreset();
tAntes5 = time_now;
}
break;
}
}
}
void leer()
{
char Ruta[10] = {'R', 'E', 'C', 'I', 'B', '.', 'T', 'X', 'T', '\0'};//establece nombre fichero tlfs bloqueados
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(15,0);
lcd.print((llamadas + 5)- i2);
//lcd.setCursor(0,1);
//lcd.print(" "); // Muestra el numero leido
lcd.setCursor(0,1);
lcd.print(charThree); // Muestra el numero leido
lcd.setCursor(12,1);
lcd.print(".."); // Muestra el numero leido
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))
{
i2 = 0;
llamadas = 0;
delay (1000);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Borrando las");
lcd.setCursor(0,1);
lcd.print("LLamadas...");
myFile.close();
delay(2000);
//Borrando fichero RECIB.TXT
SD.remove("RECIB.TXT");
delay(2000);
myFile.close();
//REcreando fichero RECIB.TXT
File Archivo1;
Archivo1 = SD.open("RECIB.TXT", FILE_WRITE);
if (Archivo1) {
Archivo1.println("111111111");
delay(200);
Archivo1.close();
lcd.clear();
lcd.setCursor(0,0);
lcd.print("RECIB.TXT ini");
delay(2000);
lcd.setCursor(0,1);
lcd.print("OK");
delay(2000);
} else {
lcd.setCursor(0,1);
lcd.print("Error SD write");
delay(2000);
lcd.clear();
lcd.setCursor(0,1);
lcd.print("PULSE RESET");
delay(2000);
}
// fin recreo
}
}
//funcion para escribir el número leido de RECIB.TXT y grabarlo en
//el fichero de numeros bloqueados BLOQ.TXT
void bloquear()
{
myFile = SD.open("BLOQ.TXT", FILE_WRITE);
if (myFile){
myFile.println(charThree);
delay(200);
myFile.close();
} else {
lcd.setCursor(0,1);
lcd.print("error SD write");
}
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");
//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;
delay(2000);
}
//Sistema de lectura del puerto serie
int readline(int readch, char *buffer, int len)
{
static int pos = 0;
int rpos;
if (readch > 0) {
switch (readch) {
case '\n': // Ignore new-lines
break;
case '\r': // Return on CR
rpos = pos;
pos = 0; // Reset position index ready for next time
return rpos;
default:
if (pos < len-1) {
buffer[pos++] = readch;
buffer[pos] = 0;
}
}
}
// No end of line has been found, so return -1.
return -1;
}
// fin programa lectura puerto serie
// 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 < 200 && adc_key_in > 100) 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
// Reseteo modem
void modemreset()
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Reset Modem....");
// Iniciamos los comandos Hayes para configurar el modem
Serial.print("ATZ\r\n");
delay(4000);
lcd.setCursor(0,1);
lcd.print("4.");
//mySerial.write("AT+VCID=1\r\n");//Conceptronics CID ON
Serial.print("AT#CID=1\r\n");//USR Robotics CID ON
delay(2000);
lcd.setCursor(2,1);
lcd.print("3.");
Serial.print("ATS7=5\r\n");//USR Robotics Answer Wait 7 seg
delay(2000);
lcd.setCursor(4,1);
lcd.print("2.");
Serial.print("ATS0=0\r\n");//USR Robotics Auto Answer OFF
delay(2000);
lcd.setCursor(6,1);
lcd.print("OK");
delay(2000);
}
Suscribirse a:
Entradas (Atom)








