Módulo GSM SIM800L - Aplicações com Arduino

Módulo GSM SIM800L

Neste tutorial, iremos testar as principais aplicações do módulo GSM SIM800L diretamente com os comandos AT pela UART , assim, podemos fazer o mesmo código para diversos microcontroladores como PIC, ESP8266/32, ARM, AVR, etc, mudando apenas os métodos de utilização da UART de MCU para MCU, já que os comandos AT serão sempre iguais. Para esse tutorial usaremos o Arduino Mega como controlador.

Módulo GSM SIM800L
Figura 1 - Módulo GSM SIM800L

[toc]

kit robotica educacional com Arduino ESP ou Microbit

O que vamos aprender?

As principais aplicações deste módulo são:

  • SMS (receber e enviar).
  • Obter horário da rede, similar ao NTP ou RTC.
  • Obter localização por triangulação da rede.
  • Conexões TCP/UDP (inclusive SSL/TLS).
  • Ligações com entrada e saída de áudio.

Neste tutorial, Aprenderemos os 3 primeiros itens separadamente encontrados na lista apresentada.


Mãos a obra - Testando algumas funções do SIM800L

Componentes necessários

Montando o projeto

Atenção: esse módulo pode utilizar muita corrente de sua fonte em picos de transmissão (até 2A), então não alimente-o diretamente pelo Arduino. Recomenda-se utilizar uma fonte externa de 3,4V a 4,3V de no mínimo 2A. Caso não tenha uma fonte com tanta corrente, você pode adicionar alguns capacitores de alto valor capacitivo para ajudar nos picos de transmissão. Se a fonte não for suficiente para alimentá-lo, ele irá reiniciar aleatoriamente durante as transmissões.

 

Esquematico no Frittzing Arudino Mega e Módulo GSM SIM800L
Figura 2 - Esquematico no Frittzing

Projeto 1 - Enviando e recebendo SMS

Programando o Arduino

void setup()
{
  Serial2.begin(115200);
  pinMode(13, OUTPUT);//LED
  pinMode(8, OUTPUT);//Pino de reset do GSM

  //reinicia o GSM
  digitalWrite(8, 0);
  delay(2000);
  digitalWrite(8, 1);
  delay(7000);

  if (gsmWrite("AT", "OK") == "FAIL")
  {
    return;//Se o GSM nao responder, retorna a funcao (trava o mcu)
  }

  delay(5000);//Espera o termino da inicializacao do GSM
  SMSsnd("014998202683", "Arduino ON, lendo mensagens...");//Envia a mensagem pro numero. Atencao: precisa do DDD!

  
}

void loop()
{
  SMSrd();//Verifica se há novas mensagens para serem lidas a cada 10seg
  delay(10000);
}


String gsmWrite(String snd, String rcv)//Funcao que envia dados pro GSM e espera a resposta de ate 30seg
{
  Serial2.println(snd);

  if (rcv.indexOf("+CMGS") > -1)
  {
    delay(150);
    Serial2.write(0x1A);
  }

  for (uint16_t i = 0; i < 1200; i++)
  {
    delay(25);
    if (Serial2.available())
    {
      delay(50);
      String a = Serial2.readString();


      if (a.indexOf(rcv) > -1 || rcv.length() == 0)
      {
        return a;
      }
    }
  }

  return "FAIL";
}

void SMSsnd(String nm, String msg)//Funcao que envia o SMS
{
  String snd = "AT+CMGS=\"";  snd += nm;  snd += "\"";

  gsmWrite("AT+CMGF=1", "OK");
  gsmWrite("AT+CSMP=17,255,0,0", "OK");
  gsmWrite(snd, ">");
  gsmWrite(msg, "+CMGS:");
}

void SMSrd()//Funcao que le se ha SMS nao lido
{
  String c = "";
  gsmWrite("AT+CMGF=1", "OK");
  c = gsmWrite("AT+CMGL=\"REC UNREAD\"", "");

  if (c.indexOf("+CMGL:") > -1)
  {
    if    (c.indexOf("ON") > -1)//ON
    {
      digitalWrite(13, 1);//se o SMS conter o texto ON, liga o LED
    }
    else if (c.indexOf("OFF") > -1)//OFF
    {
      digitalWrite(13, 0);//se o SMS conter o texto OFF, desliga o LED
    }

    gsmWrite("AT+CMGD=1,1", "OK");//apaga todas mensagens (SIM card ha pouca memoria)
  }
}

Colocando para funcionar

Depois de ligar nosso projeto na alimentação, vamos logo receber uma mensagem indicando que o sistema está ativo, mostrando que o envio de SMS funcionou perfeitamente. Também foi adicionada a leitura de SMS, de modo que, quando um SMS é enviado com a mensagem "ON" ou "OFF",  o LED no pino 13 seja ligado ou desligado.

Mensagem recebida do Módulo GSM SIM800L
Figura 3 - Mensagem recebida do Módulo GSM SIM800L

Projeto 2 - Obtendo horário através da rede

Programando o Arduino

void setup()
{
  Serial.begin(115200);
  Serial2.begin(115200);//Inicia a Serial do GSM
  pinMode(8, OUTPUT);//Pino de reset do GSM

  //Reinicia o GSM
  digitalWrite(8, 0);
  delay(2000);
  digitalWrite(8, 1);
  delay(7000);

  String rcv = gsmWrite("AT", "*PSUTTZ:");//Espera o GSM obter o horario da rede
  if (rcv.indexOf("FAIL") > -1)
  {
    gsmWrite("AT+CLTS=1;&W", "OK");//Se nao responder, pode ser configuracao do seu GSM, entao vamos ativar a obtencao automatica de horario pela rede
    setup();//retorna ao inicio
  }

  delay(5000);
  

  
}

void loop()
{
  Serial.println(gsmTIME());//Mostra a data e horario no Serial Monitor
  delay(5000);
}


String gsmWrite(String snd, String rcv)//Funcao que envia dados ao GSM e espera a resposta
{
  Serial2.println(snd);

  if (rcv.indexOf("+CMGS") > -1)
  {
    delay(150);
    Serial2.write(0x1A);
  }

  for (uint16_t i = 0; i < 1200; i++)
  {
    delay(25);
    if (Serial2.available())
    {
      delay(50);
      String a = Serial2.readString();


      if (a.indexOf(rcv) > -1 || rcv.length() == 0)
      {
        return a;
      }
    }
  }

  return "FAIL";
}

String gsmTIME()//Funcao que retorna a data e horario
{
  String c = gsmWrite("AT+CCLK?", "+CCLK:");

  int16_t a = c.indexOf("\"") + 1;
  int16_t b = c.indexOf("\"", a);
  return c.substring(a, b);
}

Colocando para funcionar

Abrindo o Serial Monitor, podemos observar a data e o horário retornado pelo módulo GSM, lembrando que a data está no padrão (ano/mês/dia). O ultimo valor do horário corresponde ao fuso horário*4, logo, para obter nosso fuso horário, basta dividir "-12" por 4  e chegamos em -3 (fuso horário de brasília).

Data e hora do módulo GSM SIM800L
Figura 4 - Data e hora do módulo GSM SIM800L

Projeto 3 - Obtendo localização através da rede

Programando o Arduino

void setup()
{
  Serial.begin(115200);
  Serial2.begin(115200);
  pinMode(8, OUTPUT);//Pino de reset do GSM

  //Reseta o GSM
  digitalWrite(8, 0);
  delay(2000);
  digitalWrite(8, 1);
  delay(7000);

  if (gsmWrite("AT", "OK") == "FAIL")
  {
    return;
  }

  delay(5000);
  
  if (gsmWrite("AT+SAPBR=1,1", "OK") == "FAIL")//Ativa a rede pra localizacao
  {
    return;
  }
  else
  {
    String rcv = gsmWrite("AT+CIPGSMLOC=1,1", "+CIPGSMLOC:");//Pergunta a localizacao ao GSM
    int a = rcv.indexOf(":") + 2;
    int b = rcv.indexOf(",", a);
    if (rcv.substring(a, b) == "0")
    {
      a = rcv.indexOf(",", b) + 1;
      b = rcv.indexOf(",", a) + 1;
      b = rcv.indexOf(",", b);
      Serial.println(rcv.substring(a, b));//Mostra a localizacao no Serial monitor
    }
  }
}

void loop()
{
  
}


String gsmWrite(String snd, String rcv)//Funcao que envia dados ao GSM e espera a resposta
{
  Serial2.println(snd);

  if (rcv.indexOf("+CMGS") > -1)
  {
    delay(150);
    Serial2.write(0x1A);
  }

  for (uint16_t i = 0; i < 1200; i++)
  {
    delay(25);
    if (Serial2.available())
    {
      delay(50);
      String a = Serial2.readString();


      if (a.indexOf(rcv) > -1 || rcv.length() == 0)
      {
        return a;
      }
    }
  }

  return "FAIL";
}

Colocando para funcionar

As coordenadas que o módulo GSM retorna é longitude e latitude respectivamente.

Coordenadas lidas pelo Módulo GSM SIM800L
Figura 5 - Coordenadas lidas pelo Módulo GSM SIM800L

Entendendo a fundo

Software

Para utilização do módulo GSM foram usados os comandos "AT" do Datasheet, este pode ser encontrado logo abaixo em nossa seção de referências. Existem incontáveis comandos para as mais diversas aplicações e se você pretende utilizar o módulo GSM, aconselhamos que estude o Datasheet e conheça os comandos necessários para seu projeto.

A comunicação entre o Microcontrolador e o módulo GSM é feita através da porta Serial (UART) à 115200b/s neste caso, mas pode ser alterada. A cada comando enviado, normalmente, retorna-se uma resposta, então sempre que enviamos um comando, precisamos esperar a resposta para saber se os dados enviados foram realmente enviados. Para isso, foi criada uma função básica cuja função é escrever o dado no módulo GSM e esperar o retorno da resposta em um tempo limite de 30 segundos. Tome cuidado que alguns comandos podem demorar até 85 segundos para retornar resposta e caso isso aconteça, o código irá falhar por timeout. Para arrumar isso, aumente o timeout da função de leitura.

-Função gsmWrite(String snd, String rcv)

gsmWrite("AT", "OK");

A função criada para envio de dados do módulo GSM é uma boa maneira de utilizar o mesmo em diversos tipos de códigos, entretanto, como normalmente após a escrita de algum comando nós esperamos uma resposta, isto pode deixar nosso código lento e travando, já que alguns comandos demoram até 85 segundos!

Essa função basicamente escreve o comando (primeiro argumento da função, "snd") AT na porta Serial e posteriormente espera a resposta do mesmo (segundo argumento da função, "rcv"). Caso o módulo GSM não retorne a reposta esperada em 30 segundos que definimos no loop FOR() da função, retorna-se a mensagem "FAIL".

 -Comandos AT

O módulo GSM SIM800L funciona com os comandos AT e a maioria deles retorna alguma mensagem de confirmação ou erro, vamos ver como alguns deles funcionam!

AT+CCLK

Figura 6 - AT+CCLK

Quando requisitado "AT+CCLK?" do SIM800L, retorna-se "+CCLK: <time>" e ao fim, "OK". Também pode-se retornar erros como mostrado na imagem.

AT+CMGL

Figura 7 - AT+CMGL

A leitura de SMS do nosso projeto foi dedicada apenas às mensagens não lidas, por isso utilizamos "AT+CMGL="REC UNREAD"", mas você pode trocar para qualquer uma das opções acima que se encaixar melhor ao seu projeto.


Conclusões finais

As utilidades para o módulo GSM são inúmeras e isto nos permite ter uma gama de aplicações muito grande em um mesmo projeto, já que conta com diversas features, desde SMS até conexões TCP e etc. Apesar de alguns comandos demorarem bastante por causa da latência da rede telefônica, ainda podemos usufruir bem deste incrível módulo. O SIM800L faz muito mais do que mostrado aqui, entretanto estamos mostrando apenas o básico para norteá-los.

Referencias


Comunicação Wireless UDP com ESP (Parte 1)

Comunicação Wireless UDP com ESP

Neste material, iremos aprender a fazer uma comunicação Wireless UDP entre dois ESP8266 para transmissão de informações. O grande diferencial do ESP é sua comunicação Wireless com suporte a WiFi, então nada mais justo que aprender a usar isto. Lembrando que este código também funciona para o ESP32.

 

[toc]

Protocolo UDP

O protocolo UDP, da camada de transporte, nos permite de forma rápida e descomplicada, o envio de informações através da rede. A simplicidade de usar o UDP é compensada ao fato de não ser uma comunicação orientada à conexão, como por exemplo o TCP, logo, não há garantia que os pacotes sejam recebidos de forma ordenada ou se quer sejam recebidos. Usa-lo para aplicações simples é recomendado, já que não são dados críticos; a perda de pacotes (improvável, porém possa acontecer) não é tão prejudicial ao sistema. Iremos transmitir de um Cliente para um Host.

Esta comunicação simples pode ser feita para transmitir dados até um banco de dados em um computador ou informações para outros Micro controladores. As aplicações são as mais diversas e variadas possíveis, novamente, o limite é sua imaginação.

Lembre-se, serão dois ESP8266, um cliente e outro host. Os dois códigos estarão logo abaixo!

Veja como é rápido o processo de envio e recebimento dos dados. O cliente pisca quando envia o pacote e o host  pisca após receber o pacote, é tão rápido que os dois parecem piscar juntos:

 


Mãos à obra

Componentes necessários

 

Hardware

Acenderemos o LED_BUILTIN do NodeMCU para indicar a transmissão de dados. Este LED OnBoard, está conectado ao pino D4 do NodeMCU.

Código do projeto

Cliente

#include <ESP8266WiFi.h>//Biblioteca do WiFi.
#include <WiFiUdp.h>//Biblioteca do UDP.

WiFiUDP udp;//Cria um objeto da classe UDP.
long x;//Variavel para ser enviada.

void setup()
{
   pinMode(D4, OUTPUT);//Habilita o LED onboard como saida.
   digitalWrite(D4, 1);//Desliga o LED.

   WiFi.mode(WIFI_STA);//Define o ESP8266 como Station.
}

void loop()
{
   connect();//Sub-rotina para conectar-se ao host.

   send();//Sub-rotina para enviar os dados ao host.

   delay(500);//Aguarda meio segundo.
}

void connect()//Sub-rotina para verificar a conexao com o host.
{
   if (WiFi.status() != WL_CONNECTED)//Caso nao esteja conectado ao host, ira se conectar.
   {
      WiFi.begin("NodeMCU", "");//Conecta à rede do host.
      delay(2000);//Espera ate que a conexao seja feita.
   }
}

void send()//Sub-rotina para enviar dados ao host.
{
   if (WiFi.status() == WL_CONNECTED)//Só ira enviar dados se estiver conectado.
   {
      x = random(0, 1000);//Gera um numero aleatorio entre 0 e 1000.
      udp.beginPacket("192.168.4.1", 555);//Inicializa o pacote de transmissao ao IP e PORTA.
      udp.println(x);//Adiciona-se o valor ao pacote.
      udp.endPacket();//Finaliza o pacote e envia.

      digitalWrite(D4, 0);//-
      delay(5);//-
      digitalWrite(D4, 1);//Pisca o led rapidamente apos enviar.
   }
   else//Caso nao esteja com uma conexao estabelicida ao host, piscara lentamente.
   {
      digitalWrite(D4, 0);
      delay(250);
      digitalWrite(D4, 1);
   }
}

 

Host

#include <ESP8266WiFi.h>//Biblioteca do WiFi.
#include <WiFiUdp.h>//Biblioteca do UDP.

WiFiUDP udp;//Cria um objeto da classe UDP.

String req;//String que armazena os dados recebidos pela rede.

void setup()
{
   pinMode(D4, OUTPUT);//Habilita o LED onboard como saida.
   digitalWrite(D4, 1);//Desliga o LED.

   Serial.begin(115200);//Habilita a comunicaçao serial para a string recebida ser lida no Serial monitor.

   WiFi.mode(WIFI_AP);//Define o ESP8266 como Acess Point.
   WiFi.softAP("NodeMCU", "");//Cria um WiFi de nome "NodeMCU" e sem senha.
   delay(2000);//Aguarda 2 segundos para completar a criaçao do wifi.

   udp.begin(555);//Inicializa a recepçao de dados UDP na porta 555
}

void loop()
{
   listen();//Sub-rotina para verificar a existencia de pacotes UDP.
}

void listen()//Sub-rotina que verifica se há pacotes UDP's para serem lidos.
{
   if (udp.parsePacket() > 0)//Se houver pacotes para serem lidos
   {
       req = "";//Reseta a string para receber uma nova informaçao
       while (udp.available() > 0)//Enquanto houver dados para serem lidos
       {
           char z = udp.read();//Adiciona o byte lido em uma char
           req += z;//Adiciona o char à string
       }

       //Após todos os dados serem lidos, a String estara pronta.

       Serial.println(req);//Printa a string recebida no Serial monitor.

       digitalWrite(D4, 0);//-
       delay(5);//-
       digitalWrite(D4, 1);//Pisca o LED rapidamente apos receber a string.
    }
}

 

Entendendo a fundo

Software

Recomendamos que vocês a leiam esta referência sobre WiFi, praticamente todos comandos disponíveis estão explicados AQUI.

Cliente

 

-Enviando dados para o destino

udp.beginPacket("192.168.4.1", 555);//Inicializa o pacote de transmissao ao IP e PORTA.
udp.println(x);//Adiciona-se o valor ao pacote.
udp.endPacket();//Finaliza o pacote e envia.

Nesta parte, usamos 3 funções do UDP, entre elas estão:

-Função WiFiUDP::beginPacket()

udp.beginPacket("192.168.4.1", 555);

Estamos enviando o pacote para o IP "192.168.4.1" que é o IP padrão do host no ESP8266, na porta 555.

 

-Função WiFiUDP::println()

udp.println(x);

Adicionamos o valor da variável X ao pacote.

 

-Função WiFiUDP::endPacket()

udp.endPacket();

Por ultimo, fechamos o pacote para finalmente ser enviado ao destino.

 

Para melhor entendimento, veja esta figura:

 

  • Vermelho = beginPacket();
  • Verde = print();
  • Azul = endPacket();

 


Host

 

-Função WiFiUDP::parsePacket()

udp.parsePacket();

Esta função faz a verificação de novos dados no buffer. Se houver dados novos para serem lidos, a função irá retornar um numero maior que zero.


Desafio

O desafio agora é você fazer uma mensagem de retorno para quem enviou uma mensagem ao host, por exemplo, quando o cliente 1 enviar dados ao host, o host responda "OK". Também faça um Print do IP de quem foi recebido o dado. Na referencia do WiFi (citado acima), há os comandos necessários!

 

Finalizando

Com a possibilidade de comunicação entre dispositivos pelo WiFi ou Wireless Ponto-a-Ponto, podemos fazer projetos muito legais e redes de dispositivos para se comunicarem. Não se esqueça de ver a parte 2 do material, sobre TCP! Dúvidas? Sugestões? Críticas? Comente abaixo!