bclose

ENVIAR Y RECIBIR LLAMADAS Y SMS

Optimizando el funcionamiento del módulo GPRS SIM900

Objetivos

 

 

    • Optimizar la programación del GPRS.
    • Dotarlo de mayor autonomía.
    • Crear una función para enviar los comandos AT
    • Agrupar el envío y la recepción de llamadas y SMS en un sólo programa.
 

Material requerido.

 

  Tienda España Tienda Mexico
Vista principal de un arduino uno Arduino UNO Arduino UNO
Vista principal Shield GPRS Shield GPRS

 

OPTIMIZAR EL PROGRAMA

 

En las sesiones anteriores dedicadas al GRPS hemos visto cómo conectarlo correctamente y los comandos AT necesarios para enviar y recibir llamadas y SMS de una forma bastante sencilla. Sin embargo, para el que se haya fijado, aunque los comandos AT se envían correctamente y el módulo cumple la función que buscamos, hay algunas cosillas que se pueden mejorar.

Y es que al parecer la librería SoftwareSerial no se lleva del todo bien con el módulo GPRS y los comandos AT; y al enviar simplemente estos comandos con función SIM900.println(); algunas respuestas se quedan en el limbo.

A esto podríamos añadir que, siendo el GPRS un módulo orientado hacia proyectos autónomos y sin supervisión, no tendremos acceso al monitor serie (hasta ahora lo hemos supervisado desde ahí), no estaremos seguros de que las cosas estén yendo bien y estemos realmente conectados a la red móvil.

Y por último, podría ser que durante el periodo que tengamos funcionando nuestro proyecto perdiera la alimentación del Arduino o del GPRS, o se desconectase de la red móvil por alguna razón. Así que también vamos a implementar una serie de funciones para que sea capaz de reiniciarse y configurarse de forma autónoma, y de que se asegure que estemos conectados a la red antes de enviar llamadas o SMS.

Para poder reiniciarlo de esta forma y dotarle de autonomía es imprescindible haber realizado la soldadura que habilita el encendido por software del módulo GPRS mediante un pulso en el pin 9, y conectarlo al pin 9 de Arduino que usaremos para ello (ya hablamos de esto en las sesiones anteriores).

activar tarjeta software

 

FUNCIÓN PARA ENVIAR LOS COMANDOS AT

 

Al parecer el error al recibir algunas respuestas de los comandos AT por el monitor serie se debe a que enviamos el comando siguiente antes de recibir la respuesta, y los “delays” no parecen solucionarlo, sino todo lo contrario (como casi siempre).

Por lo tanto crearemos una función enviarAT con los siguientes objetivos:

 
  • Enviar el comando AT.
  • Esperar una respuesta del SIM900.
  • Comprobar que la respuesta es correcta.
  • Mostrar por el monitor serie la respuesta recibida. 

La programación de la función queda de la siguiente forma:

int enviarAT(String ATcommand, char* resp_correcta, unsigned int tiempo)
{

  int x = 0;
  bool correcto = 0;
  char respuesta[100];
  unsigned long anterior;

  memset(respuesta, '\0', 100); // Inicializa el string
  delay(100);
  while ( SIM900.available() > 0) SIM900.read(); // Limpia el buffer de entrada
  SIM900.println(ATcommand); // Envia el comando AT
  x = 0;
  anterior = millis();
  // Espera una respuesta
  do {
    // si hay datos el buffer de entrada del UART lee y comprueba la respuesta
    if (SIM900.available() != 0)
    {
        respuesta[x] = SIM900.read();
        x++;
      // Comprueba si la respuesta es correcta
      if (strstr(respuesta, resp_correcta) != NULL)
      {
        correcto = 1;
      }
    }
  }
  // Espera hasta tener una respuesta
  while ((correcto == 0) && ((millis() - anterior) < tiempo));
  Serial.println(respuesta);

  return correcto;
}

Está función la usaremos siempre que enviemos un comando AT, y si queremos verificar la respuesta, simplemente la incluiremos dentro de un if que verifique que nos el módulo nos haya devuelto la respuesta que buscamos.

Esta estructura condicional la usaremos para verificar que realmente estemos conectados a la red móvil, aunque podríamos usarlo en todos los comandos AT para que, en caso de que algo falle, nos saque un mensaje por pantalla indicándonos dónde está el error.  Realmente no totalmente necesario ya que leyendo el monitor serie se puede ver dónde falla con sólo  mirar las respuestas a los comandos AT.

 

ENCENDER EL MÓDULO POR SOFTWARE

 

Ya hemos hablado anteriormente acerca de cómo encender y apagar el módulo sin tener que presionar el pulsador del GPRS, enviando un pulso de un segundo desde Arduino al pin 9 de la tarjeta. Sin embargo, imaginad que enviamos las instrucciones para encenderlo y resulta que ya estaba encendido. Lo que haríamos sería apagarlo.

Así que vamos a crear también una función para encender el módulo pero comprobando antes que no está encendido ya. Es muy sencillo, si enviamos el comando “AT”  y nos devuelve OK es que estaba encendido. Si no devuelve nada tendremos que enviar el pulso para encenderlo:

Contenido solo disponible para suscriptores. ¡Accede al contenido!

Con este programa creemos que ya podréis afrontar vuestros proyectos con mayores garantías de éxito, otorgándoles un cierto nivel de autonomía y confianza. La estructura de tipo switch() que hemos creado nos da la posibilidad de incluir de forma muy sencilla otros casos en los que sean las lecturas de ciertos sensores las que activen las llamadas o los SMS, e incluso podrías incluir en estos últimos el valor de las lecturas dentro del texto del SMS en el caso que sea necesario.

 

Resumen de la sesión

 

En esta sesión hemos aprendido varias cosas importantes:

 
    • A enviar correctamente los comandos AT y asegurarnos de recibir la respuesta del módulo GPRS.
    • A verificar la respuesta cuando lo creamos necesario.
    • Asegurarnos de que estamos correctamente conectado a la red móvil.
    • A encender y reiniciar el módulo por software.
    • Hemos creado un programa para recibir y enviar llamadas y SMS, al que hemos dotado de capacidad de trabajar de forma autónoma con ciertas garantías de éxito.
 
 
 

LikeUsOnFacebook_Icon

 

Para porder realizar consultas a nuestros expertos, tienes que ser suscriptor. Suscribiendote nos ayudas a mantener este proyecto en marcha.

¡ Quiero Suscribirme !

Si ya eres premium y no puedes comentar haz login. Hacer login

(96) Comments

  • Avatar for Ivan Uriarte
    • Ivan Uriarte

    Hola, supongo que has seguido el tutorial en el que explicabamos como reconocer los números de teléfono. SI es así, hay una parte del mismo en el que recorremos el array de la agenda para buscar ese texto en el sms. int pos = mensaje.indexOf(agenda[i]);

    Lo que tienes que hacer, si te he entendido bien, es guardar en ese momento el contenido de agenda[i] en una variable, y así tendrías el número que ha activade el relé. Con eso compones el mensaje que quieras enviar.

    Un saludo.

  • Avatar for Ivan Uriarte
    • Dracemidx

    Hola buenas a todos:
    Estoy intentando crear un proyecto de activación de un relé a través de una llamada telefónica dentro de una agenda telefónica de números agregados anteriormente.
    Una vez activado o desactivado el relé, que realice un aviso por SMS a cada numero de la agenda telefónica.
    Logré crear una parte del código y me envía los SMS con un mensaje que defino en el programa pero quiero agregar el numero que activó el rele en el SMS.
    Ej: En la agenda de telefono, tengo el numero +56YYYY, ese numero llamó y debido a que estaba autorizado, activó el relé, se envía un SMS a los numero de la agenda con el siguiente formato («+56YYYY accionó el rele») pero no consigo obtener la variable que analiza, compara y mantiene ese numero «+56YYYY» en memoria.

    Intenté hacer Serial.print(mensaje) a este proyecto pero me indica los comandos AT enviados y no aparece en la cadena de texto el número que realizó la llamada.

    Gracias por su ayuda.

  • Avatar for Ivan Uriarte
    • Ivan Uriarte

    Hola Josep, yo no conozco ningún comando AT para mandar llamadas a varios números. o más sencillo es que hagas un bucle for donde recorras un array con los núeros a los que quieras llamar y vayas haciendo las llamadas. Un saludo.

  • Avatar for Ivan Uriarte
    • Josep

    Hola muy buenas , como puedo hacer que cuando se me dispara la alarma me mande la llamada a mas de un numero de telefono.
    Muchas gracias.

  • Avatar for Ivan Uriarte
    • Miguel Dieppa

    Solucionado!, tenia problemas de RAM, recomiendo el uso de Serial.print(F());, no sabia este metodo para optimizar el codigo!
    Aquí explican bien como funciona y que hace.
    https://aprendiendoarduino.wordpress.com/tag/progmem/

  • Avatar for Ivan Uriarte
    • Miguel Dieppa

    Hola Buenas, Amigo le he dado la vuelta a su tu código muchas veces ya aun no tengo buenos resultados, ya estoy frustrado de internar y no tener éxito.

    He intentado rehacer tu código de enviar_sms con string, igual como una pregunta anterior pero no se respondió, quiero hacer mensaje_sms(String Telefono, String Mensaje), pero aun no tengo éxito, coloco mi codigo a ver si me puedes ayudar.

    Gracias!

    void mensaje_sms(String Numero, String Texto)
    {
    wdt_reset();
    if (Numero != NULL && Texto != NULL) {

    if (enviarAT(«AT+CREG?», «+CREG: 0,1», 1000) == 1) //comprueba la conexion a la red
    {

    Serial.print(«Enviando SMS…a «);
    Serial.println(Numero);

    enviarAT(«AT+CMGF=1\r», «OK», 2000); //Comando AT para mandar un SMS
    //sprintf(aux_str, comando, strlen(Texto)); //Numero al que vamos a enviar el mensaje no lo uso

    // printf(«AT+CMGS=\»%s\»»,AT, Numero); //Numero al que vamos a enviar el mensaje no lo uso

    //Serial.print(«Numero: «);
    // Serial.println(numero);

    String comando = «AT+CMGS=\»»;

    Numero.concat(‘\»‘);

    comando.concat(Numero);

    wdt_reset();
    delay(2000);
    wdt_reset();

    Texto.concat((char)26);

    Serial.print(«comando: «);
    Serial.println(comando);

    //Serial.print(«Numero: «);
    // Serial.println(Numero);

    Serial.print(«Texto: «);
    Serial.println(Texto);

    //Texto del mensaje
    if (enviarAT(comando, ‘>’, 10000) == 1)
    {

    if ( enviarAT(Texto, «OK», 10000) == 1) {
    Serial.println(«SMS enviado»);
    }

    } else {
    Serial.println(«SMS NO enviado»);
    }

    } else {
    reiniciar();
    iniciar();

    }

    } else {
    Serial.println(«Error: No hay numero o no hay texto para el mensaje»);
    }

    }

  • Avatar for Ivan Uriarte
    • Ivan Uriarte

    Hola Victor, es que en AT+CPIN tienes que meter el pin de tu tarjeta SIM. te esta dando error porque no es ese.

  • Avatar for Ivan Uriarte
    • Victor Vega

    Holaa, buenas noches, disculpa tengo el problema de que en el Monitor Serial me aparece como sigue…
    Iniciando…
    AT
    OK
    AT+CPIN=»1234″
    ERROR

    Conectando a la red…

    Y no hace absolutamente nada. Necesito de tu ayuda por favor.

  • Avatar for Ivan Uriarte

    Hola de nuevo Ivan, gracias por contestar. Sigo dándole vueltas al código y quería ver si me aclaras un par de cosillas de la funcion mensaje_sms…
    1. sprintf: he visto que es una función para convertir números a cadenas tipo string. Entiendo que aux_str es donde se almacena el string (que en realidad es un puntero), pero no entiendo porqué los otros dos paramentos. El 2º, en la función es el formato, y se pone el comando AT para indicar el nº de telefono,; en el 3º se pone la longitud del SMS…No veo la relación entre el nº de telefono y la longitud del mensaje.
    2. Se manda la funcion enviarAt «aux_str» y en la siguiente linea «sms». ¿Como entiende eso la funcion enviarAT? Quiero decir, eso no son comandos AT, como ejecuta esto el modulo?

    sprintf(aux_str, «AT+CMGS=\»XXXXXXXXX\»», strlen(sms)); //Numero al que vamos a enviar el mensaje
    //Texto del mensaje
    if (enviarAT(aux_str, «>», 10000) == 1)
    {
    enviarAT(sms, «OK», 10000);
    }

  • Avatar for Ivan Uriarte
    • Ivan Uriarte

    Eso ,es. EL comando lo que hace es esperar hasta que el GPRS ha cogido la red. Hasta que no le llega la respuesta que necesitamos no pasa a la siguiente línea.

  • Avatar for Ivan Uriarte
    • OMoreno

    Hola muy buenas, tengo un duda del código, a ver si me la podéis aclarar.
    En la funcion void iniciar() , ¿este while que hace o para que sirve? porque si enviarAT devuelve un cero es que el comando AT no se ha ejecutado correctamente, o eso entiendo yo…
    Y por otro lado, en esta llamada a la funcion enviarAT, el «+CREG: 0,1» ¿que significa, de donde sale?

    while ( enviarAT(«AT+CREG?», «+CREG: 0,1», 1000) == 0 )
    {
    }

    Gacias!!

  • Avatar for Ivan Uriarte

    Hola! Estimados, estoy trabajando el un proyecto… y quería consultarles si es posible modificar la hora de un módulo RTC enviando un SMS con el cambio de hora al Arduino … Saludos!

  • Avatar for Ivan Uriarte
    • Ivan Uriarte

    https://www.prometec.net/gprs-controlar-led/ Echa un ojo aquí. Tendrías que buscar de alguna forma el teléfono después de encontrar el NO CARRIER. Teniendo el teléfono sólo tienes que realizar la llamada en vez de encender el LED. Un saludo.

  • Avatar for Ivan Uriarte
    • Ivan Uriarte

    Hola Julian, he descargado el programa y funciona bien. Si estás haciendo copia y pega te recomiendo que lo descargues con el enlace que hay al final de la página, para asegurarnos que no tengas ningún error.

  • Avatar for Ivan Uriarte

    Hola buenas noches

    podrían ayudarme por favor para que al recibir una llamada se conteste automaticamente
    como podría hacer tal cosa?? he dado vueltas y no encuentro la solución

  • Avatar for Ivan Uriarte
    • Julian

    Estoy trabajando en un sistema con Arduino UNO y SIM900, el inconveniente que tengo es que no envía todos los SMS, encontré este artículo que me parece muy bueno para poder investigar la falla, pero al intentar compilar me me da varios errores como los que detallo a continuación, me podrías ayudar.
    Muchas Gracias
    H:\Arduino\Envio_y_recepcion_de_llamadas_y_SMS-1\Envio_y_recepcion_de_llamadas_y_SMS\Envio_y_recepcion_de_llamadas_y_SMS.ino:161:31: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]

    enviarAT(«ATH», «OK», 1000); // Cuelga la llamada

    ^

    H:\Arduino\Envio_y_recepcion_de_llamadas_y_SMS-1\Envio_y_recepcion_de_llamadas_y_SMS\Envio_y_recepcion_de_llamadas_y_SMS.ino:161:31: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]

Para porder realizar consultas a nuestros expertos, tienes que ser suscriptor. Suscribiendote nos ayudas a mantener este proyecto en marcha.

¡ Quiero Suscribirme !

Si ya eres premium y no puedes comentar haz login. Hacer login