BTS Mesure BTS Mesure
Présentation2014CapteursModulationTyponsArduinoDémodulationApp InventorCourbesVidéos
 
PrésentationSimulationGSMGPSSDCapteursFinal

Présentation

Pour optimiser nos chances de retrouver le ballon sonde nous allons inclure un module GSM compatible avec Arduino le SIM800L.

Ce module nous enverra par SMS les coordonnées GPS du ballon sonde.

Pour le câblage nous allons utiliser 5 pattes :
  • 5V : alimentation,  le module consomme des pics de courant allant jusqu'à 2 Ampères. Il faut donc une alimentation externe (pour nous cela sera les piles) assistée d'un condensateur de 1000 µF placé entre Vin et GND.
  • GND : la masse
  • SIM_TXD relié à RX1 de notre carte MEGA (Serial1)
  • SIM_RXD relié à TX1 de notre carte MEGA (Serial1)
  • RST : reset. Lorsque cette patte est reliée à rien (haute impédance) le module fonctionne. Par contre si on relie cette patte à la masse, le module s'éteint (consommation réduite : c'est important pour nos piles). De plus lorsque l'on remet RST en haute impédance, le reset s'effectue et peut corriger d'éventuels bugs...



Les commandes AT

Pour programmer ce module et envoyer des SMS nous allons utiliser les commandes AT suivantes :

AT+CMGF=1 <CR>  : permet d’activer le mode texte pour l’envoi du SMS. Cette commande renvoie le code OK en cas de réussite. Le temps d’attente maximal est de 1 secondes.

AT+CMGS=\"+336xxxxxxxx\"<CR>Ceci est le texte du SMS<CTRL-Z>

  • <CR> = code ASCII 13 contenu dans println
  • <CTRL-Z> = code ASCII 26, signale la fin du message.

 

  • La première étape consiste en l’envoi du numéro de téléphone du destinataire suivi d'un retour charriot <CR>. La variable numéro représente le numéro de téléphone pris avec l’indicatif téléphonique (+33 pour un numéro de téléphone français).  Après quelques ms, le SIM800 répond par une invite > à poursuivre par le contenu du message.
  • Le programme envoie ensuite le corps du message au module SIM800 (attendre au moins 200 ms avant d'envoyer le corps du message).
  •  La saisie du texte se termine par un CTR+Z. Pour ce faire le programme envoie simplement la valeur 0x1A au module GSM. En effet 0x1A = 1*161+10 = 26 est le code ASCII de CTR+Z.  
  • Le module SIM800L  renvoi un code d’erreur à l’utilisateur si le module GSM ne donne pas de réponse pendant plus de 20 secondes après l’envoi du message.

Ci-contre le programme minimaliste : il envoi le SMS sans vérifier les réponses du SIM800L. On utilisera ce sous programme dans notre programme ballon sonde



void SMS() {
  Sgsm.println("AT+CMGF=1"); // SMS en mode texte 
  delay(50);
  Sgsm.print("AT+CMGS=\""); Sgsm.print(numero); Sgsm.println("\"");
  delay(200);    // Il est indispensable de faire une pause entre le numéro et le corps du message
  Sgsm.print("Ceci est le message SMS à envoyer.");
  Sgsm.write(26); // Caractère de fin 26 <Ctrl-Z>
  Sgsm.println(); 
}


Notre sous programme SMS()

Ce sous programme est appelé par une boucle cadencée à 2s (représentée par la variable n).

Nous profitons de cette cadence pour éviter la fonction delay et ralentir le programme principal. Ainsi l'exécution de ce sous programme ne requiert que quelques ms.

Pour économiser les piles, nous mettons en service le module durant 30s puis hors service durant 90s. Nous envoyons un SMS toutes les 120s.

Au delà de 9000 m (présence du réseau improbable), nous mettons hors service le module grâce à la patte RST mise à GND.



/* 1) Zone 1 : les déclarations */

// 1.b) Les Constantes et #define 
#define Sgsm Serial2
#define numero "+336xxxxxxxx"    // Mettre ici le numéro que l'on souhaite appeler

// 1.c) Les variables globales
int RST=2;                    // Pour éteindre la carte GSM SIM800L

/* 2) Zone 2 : Initialisation (le setup) */
void setup() {
   Sgsm.begin(9600);
   }
   
 /* 3) Zone 3 : le Programme Principal */
void loop() {
  SMS();  
}  
   
/* 4) Zone 4 : les sous programmes (ou fonctions) */
void SMS() {
  int sms = n%60;              // Pour envoyer un SMS tout les 2*60 = 120s
  if (Alti>9000){              // Si Altitude >9000 m on éteint le GSM
      pinMode(RST,OUTPUT);
      digitalWrite(RST,LOW);
      return;}
  if (sms==1) {
      pinMode(RST,INPUT);      // On allume le GSM en mettant RST en haute impédance, attendre au moins 6s pour se connecter au réseau
      return;}
  if (sms==10) Sgsm.println("AT+CMGF=1");                             // Au bout de 20s sous tension on envoie le SMS
  if (sms==11) {                                                      // Composition n° au bout de 22s
      Sgsm.print("AT+CMGS=\""); Sgsm.print(numero); Sgsm.println("\"");
      }
  if (sms==12) {                                                   // Il est préférable d'attendre (ici 2s) avant d'envoyer le corps du message
      Sgsm.print("Temps = "); Sgsm.print(2*n);Sgsm.print(" s");
      Sgsm.print(" : https://maps.google.fr/maps?q="); Sgsm.print(N,5); Sgsm.print(","); Sgsm.print(E,5);
      Sgsm.print(" Alti=");Sgsm.print(Alti);Sgsm.print(" m");
      Sgsm.print(" P= ");Sgsm.print(int(Pext));Sgsm.print(" hPa");
      Sgsm.print(" T= ");Sgsm.print(Text,1);Sgsm.print(" C");
      Sgsm.write(26); // Caractère de fin 26 <Ctrl-Z>
      Sgsm.println(""); 
      }
  if (sms==15) {               // Puis au bout de 30s on éteint le GSM
      pinMode(RST,OUTPUT);
      digitalWrite(RST,LOW); } 
}


Allumer et éteindre une LED par SMS

Pour mieux comprendre comment communique un SIM800 avec un Arduino voici un programme qui permet à  un Arduino de recevoir un ordre par SMS : led on ou led off.

Ce programme analyse le message reçu, récupère le numéro du téléphone à l'origine du SMS et renvoie un SMS de confirmation de l'ordre au téléphone.



/* Allumer une LED par SMS
Pour allumer la LED envoyer led on
pour éteindre la LED envoyer led off
*/

/* 1) Zone 1 : les déclarations */
// 1.a) Les bibliothèques et création d'objets

//#include <SoftwareSerial.h>
//int Txd = 6, Rxd = 7; // SIM800
//SoftwareSerial gsm(Txd, Rxd); // RX, TX : il faut relier Rx de l'Arduino au Tx du SIM800
#define gsm Serial1     // Si utilisation MEGA


// 1.c) Les variables globales
int led =13;
String reponse, numeroSMS, SMS;
unsigned long t0;

/* 2) Zone 2 : Initialisation (le setup) */
void setup() {
  pinMode(led,OUTPUT);
  Serial.begin(9600);
  gsm.begin(9600);
  delay(2000);
  Serial.println("Initialisation...");
  gsm.println("AT");
  while (!message("OK",1000,0)) gsm.println("AT");
  gsm.println("AT+CNUM");            // Affiche n° de la carte SIM utilisée
  message("OK",20000,1);
  Serial.print ("Qualite reseau : ");
  gsm.println("AT+CSQ");            // Qualité du réseau, pb si CSQ = 0
  message("OK",10000,1);
  gsm.println("AT+CMGF=1");         // Mode Texte
  message("OK",1000,0);
  gsm.println("AT+CMGD=1,4"); // effacer les SMS en mémoire dans la carte SIM
  message("OK",2000,0);      // car on lit toujours le message N°1 de la carte SIM...
}

/* 3) Zone 3 : le Programme Principal */
void loop() {
  if (message("+CMTI:",20000,0)) LireSMS();   // Si nouveau SMS disponible SIM800 envoie +CMTI:
}

/* 4) Zone 4 : les sous programmes (ou fonctions) */

void LireSMS(){
  gsm.println("AT+CMGF=1");  // Mode Texte
  message("OK",1000,0);
  gsm.println("AT+CMGR=1");  // Lit le premier message disponible sur la carte SIM
  message("OK",2000,1);
  // Récupérer N° de telephone emetteur pour lui répondre
  int test=reponse.indexOf("+33");
  numeroSMS = reponse.substring(test,test+12);
  Serial.println("SMS recu depuis : " + numeroSMS);
  
 // Analyse du message reçu 
  if (reponse.indexOf("led on")>0) {
     SMS = "Ordre recu : Allumer LED !";
     digitalWrite(led,1);}
   else {
       if (reponse.indexOf("led off")>0){
       SMS = "Ordre recu : Eteindre LED !";
       digitalWrite(led,0);}
       else SMS = "Ordre non compris !";}
       
  gsm.println("AT+CMGD=1,4"); // effacer les SMS de la Carte SIM
  message("OK",1000,0);
  Serial.println(SMS);
  Serial.println("");
  
  // Envoyer la confirmation de l'ordre par SMS 
  Serial.println("Envoi message confirmation"); 
  gsm.println("AT+CMGS=\""+ numeroSMS +"\"");
  message(">",1000,0);
  gsm.println(SMS);
  gsm.write(26); // Caractère de fin 26 <Ctrl-Z>
  gsm.println(""); 
  message("+CMGS:",10000,1);  }
      
/* Sous Programme message(attente, timeout, affiche)
Après avoir envoyé une instruction AT au module SIM800,celui-ci répond. 
message("OK", 1000,1) :
  Vérifie que la réponse contient le terme "OK" (attente)
  Il attend au maximum 1000ms (timeout) la réponse
  Affiche (affiche=1) la réponse et le temps mis pour l'obtenir
  ou n'affiche pas (affiche=0) sauf si la réponse attendue n'est pas correcte
  renvoie vrai si le message contient OK en moins de 1000 ms
*/
boolean message(String attente, unsigned int timeout, boolean affiche) {
  t0 = millis();
  reponse="";
  while (millis() - t0 < timeout) {
    while(gsm.available()) reponse.concat(char(gsm.read()));
    if (reponse.indexOf(attente)>0){        // Lit encore 100 ms le port série  
      delay (100);                          // pour être sur de ne rien louper...
       while(gsm.available()) reponse.concat(char(gsm.read()));
        break;}}
  if (affiche || reponse.indexOf(attente)==-1 ) {      
    Serial.print("Attente = "+ attente +" "+ reponse.indexOf(attente)+" duree ");
    Serial.print(millis()-t0); Serial.println(" ms");
    Serial.println(reponse);}
  
  if (reponse.indexOf(attente)>0) return true;
  else return false;
}


Envoyer des mesures et recevoir des consignes par internet

Nous pouvons utiliser aussi notre module SIM800L pour envoyer des données sur internet grâce aux fonctions GPRS (General Packet Radio Service , protocole réseau, 2G+)


/* Envoyer les mesures d'un DHT22 par GPRS
Nous allons envoyer des données (température et humidité mesurée par le DHT22) par l'URL
http://tpil.projet.perso.sfr.fr/DHT22/communique2.php?t=19.2&h=51
Cette adresse envoie t=19,2°C et H = 51%

le script communique2.php traite cette adresse afin d'écrire une réponse de confirmation qui contient aussi 
une consigne haute et une consigne basse pour simuler un système de chauffage...

Pour changer les consignes par internet :
http://tpil.projet.perso.sfr.fr/DHT22/capteur.php

http://tpil.projet.perso.sfr.fr/DHT22/

*/

/* 1) Zone 1 : les déclarations */
// 1.a) Les bibliothèques et création d'objets

//#include <SoftwareSerial.h>
//int Txd = 6, Rxd = 7; // SIM800
int Reset =8;
//SoftwareSerial gsm(Txd, Rxd); // RX, TX : il faut relier Rx de l'Arduino au Tx du SIM800
#define gsm Serial1     // Si utilisation MEGA
#define SERIAL_BUFFER_SIZE 256  // augmenter la taile du buffer serie

#include "DHT.h"
#define DHTPIN 11          // la sortie du DHT22 est reliée à D11 de notre Arduino
#define DHTTYPE DHT22      // DHT 22
DHT dht(DHTPIN, DHTTYPE);  // Création de l'objet dht

// 1.c) Les variables globales
String reponse,Chs,Cbs,heure;
unsigned long t0;
int test,hum,Ch,Cb;
float temp;


/* 2) Zone 2 : Initialisation (le setup) */
void setup() {
  pinMode(Reset,INPUT);
  pinMode(12,OUTPUT);
  pinMode(13,OUTPUT);
  digitalWrite(12,0);
  digitalWrite(13,1);
  Serial.begin(9600);
  gsm.begin(9600);
  gsm.begin(9600);
  dht.begin();
  delay(2000);
  Serial.println("Initialisation...");
  gsm.println("AT");
  while (!message("OK",1000,0)) gsm.println("AT");
  gsm.println("AT+CNUM");
  message("OK",1000,1);
  setupGPRS();

}

/* 3) Zone 3 : le Programme Principal */
void loop() {

  Serial.print ("Qualite reseau (Pb si < 10) : ");
  gsm.println("AT+CSQ");            // Qualité du réseau
  if (message("OK",1000,0)){
    test=reponse.indexOf("+CSQ:");
    Serial.println(reponse.substring(test,test+10));}
    
  hum = dht.readHumidity();
  temp = dht.readTemperature();
  if (isnan(temp) || isnan(hum)|| hum==0){temp=22.5;hum=45;} // Si pas de capteur
  Requete();                       // envoi de la requete
  delay(10000);
}

/* 4) Zone 4 : les sous programmes (ou fonctions) */

void setupGPRS() { //Réglage mode GPRS et protocole IP
  Serial.print( "Setup");
  gsm.println("AT+HTTPTERM");
  message("OK",2000,0);
  // Serial.print("Protocole IP : ");
  gsm.println("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"");
  message("OK",10000,0);
  gsm.println("AT+SAPBR=3,1,\"APN\",\"free\"");
  message("OK",10000,0);
//  Serial.println("Suppression de la fonction echo : ");
//  gsm.println("ATE0");
//  message("OK",2000);
  gsm.println("AT+SAPBR=1,1");
  message("OK",2000,0);
  gsm.println("AT+CGATT=1");
  message("OK",2000,0);
}

void Requete() { // HTTP GET 
  gsm.println("AT+HTTPINIT");
  message("OK",2000,0);
  Serial.println("Parametre URL: ");
    gsm.print("AT+HTTPPARA=\"URL\",\"http://tpil.projet.perso.sfr.fr/DHT22/communique2.php?t=");
  gsm.print(temp,1);
  gsm.print("&h=");gsm.print(hum);gsm.println("\"");
  message("OK",5000,1);
  Serial.print("Mode GET : ");
  gsm.println("AT+HTTPACTION=0");
  if (message("+HTTPACTION: 0,200",20000,0)){
    Serial.println(" Message envoye !");
    gsm.println("AT+HTTPREAD");
    message("/html",10000,5);
    test=reponse.indexOf("<p>");
    heure=reponse.substring(test+3,test+11);
    test=reponse.indexOf("Ch=");
    Ch=reponse.substring(test+3,test+6).toInt();
    test=reponse.indexOf("Cb=");
    Cb=reponse.substring(test+3,test+6).toInt();
    Serial.println("Heure de confirmation : " + heure);
    Serial.print("Consignes lues : ");
    Serial.println("Ch = "+ String(Ch) + "\tCb = "+String(Cb));
    Serial.println();
    // Serial.print( "Fin HTTP : ");
    gsm.println("AT+HTTPTERM");
    message("OK",2000,0);  
  }
  else reset();
}
 
boolean message(String attente, unsigned int timeout, boolean affiche) {
  t0 = millis();
  reponse="";
  while (millis() - t0 < timeout) {
    while(gsm.available()) reponse.concat(char(gsm.read()));
    if (reponse.indexOf(attente)>0){
      delay (100);
       while(gsm.available()) reponse.concat(char(gsm.read()));
        break;}}
  if (affiche || reponse.indexOf(attente)==-1 ) {      
    Serial.print("Attente = "+ attente +" "+ reponse.indexOf(attente)+" duree ");
    Serial.print(millis()-t0); Serial.println(" ms");
    Serial.println(reponse);}
  
  if (reponse.indexOf(attente)>0) return true;
  else return false;
}


void reset() {
  
  pinMode(Reset,OUTPUT);
  digitalWrite(Reset,LOW);
  Serial.println ("Remise a Zero");
  delay(5000);
  pinMode (Reset,INPUT);
  Serial.println("Reset logiciel !");
  Serial.flush();                      // Pour afficher le messsage avant le reset
  asm volatile ("  jmp 0");            // Reset de la carte Arduino
//  delay(6000);
//  gsm.println("AT");
//  while (!message("OK",1000,0)) gsm.println("AT");
//  setupGPRS();
  }