[Fatto] Accendere led con sms. Sim900 shield senza librerie sim900.h

Ciao ragazzi, era da un paio di giorni che stavo lavorando su questo piccola parte di codice e volevo condividerla su questo forum spettacolare in modo da aiutare e non far perdere tanto tempo agli smanettoni principianti come me in futuro.

Innanzi tutto dico a tutti che un pò di giorni fa ho acquistato una GSM/GPRS shield di questo tipo:
http://www.geeetech.com/wiki/index.php/Arduino_GPRS_Shield
All’inizio è stato abbastanza traumatico capire come funzionasse, ma dopo aver rivisto un pò di volte il codice mi sono reso conto che era davvero semplice.
Quello che volevo fare, come progetto basilare era semplicemente accendere un led attraverso un comando mandato tramite sms del tipo “accendi”.
Ho iniziato a girare un pò il web e dopo ore e ore di ricerche non ho trovato nulla. Tutti consigliavano di utilizzare la libreria sim900.h, ma non sono contento delle cose precotte, inoltre non mi pareva il caso installare un’intera libreria per poter leggere semplicemente un sms.
Così dopo svariati milioni di sms inviati alla mia shield, e dopo ore a capire come funzionasse questa scheda, sono riuscito nell’impresa.
Posto il codice in modo tale che sia utile a qualcuno in futuro :slight_smile:

#define led 13

#include <SoftwareSerial.h>

SoftwareSerial sim900(7,8);
char istruzioni_sim[100];

void setup(){
  Serial.begin(19200);
  sim900.begin(19200);
  pinMode(led, OUTPUT); 
  delay(500);
}

void loop(){
  leggi_da_sim900(); 
}

void leggi_da_sim900(){  
  boolean ricevuto_sms = false;
  int i = 0;
  int numero_sms = 0;

  while(sim900.available() >0){
    char carattere = sim900.read();
    istruzioni_sim[i] = carattere;

    if(strcmp(istruzioni_sim, "\r\n+CMTI: \"SM\",")==0){   //vuol dire che ho ricevuto dalla shield la funzione di un nuovo sms
      carattere = sim900.read() -'0';                      //il carattere dopo la virgola è un numero; rappresenta l'ultimo sms
      numero_sms = carattere;  
      istruzioni_sim[i+1] = carattere;                      //salvo ugualmente il numero nel vettore istruzioni_sim
      ricevuto_sms = true;                                  //mi servirà per leggere l'sms solo quando lo ricevo
    }
    i++;
    delay(5);
  }

  if(ricevuto_sms == true){                                 //a questo punto vuol dire che ho ricevuto un sms
    while(i>0){
      istruzioni_sim[i] = NULL;                             //posso svuotare il vettore
      i--; 
    }
    leggi_sms(numero_sms);                                  //passo alla funzione leggi_sms il valore dell'ultimo sms da leggere
    i=0;
    ricevuto_sms = false;
  }
}


void leggi_sms(int ultimo_sms){
  String sms;                                            //ho utilizzato una variabile string perchè non sapevo quanto dovesse essere lungo un sms
  int inizio_sms = 0;
  int count = 0;
  sim900.print("AT+CMGR=");                              //invio alla shield, la richiesta di lettura di sms
  sim900.println(ultimo_sms);                            //attenzione al println
  delay(200);

  while(sim900.available() >0){
    char carattere = sim900.read();                      //inizio a leggere l'sms
    if(carattere == '\"'){
      inizio_sms = count;                                //questa funzione si occupa di vedere dove inizia il testo dell'sms visto che la strnga ricevuta è del tipo ABC"\r\nTESTOSMS\r\n\r\n\r\nOK
    }
    sms += carattere;
    count++;
    delay(5);
  }

  sms.toLowerCase();                                                 //rendo tutto minuscolo
  
  //Serial.print(sms.substring((inizio_sms+3), (count-8)));         //questo perchè la stringa è composta come segue: ABC"\r\nBLA\r\n\r\n\r\nOK, comunque se abiliti questo Serial.print viene visualizzato il corpo dell'sms
  if(sms.substring((inizio_sms+3), (count-8)) == "accendi"){        //la parola accendi, è la mia parola chiave, può essere comunque cambiata per eseuire diverse azioni
    digitalWrite(led, HIGH);
  }
  else if(sms.substring((inizio_sms+3), (count-8)) == "spegni"){
    digitalWrite(led, LOW);
  }
  sms="";
  sim900.print("AT+CMGD=");                                          //invio alla shield la richiesta di eliminare l'ultimo_sms
  sim900.println(ultimo_sms);
  delay(100);
}

Se ci sono problemi o consigli per migliorarlo scrivete pure!

Volevo solo chiedervi perchè la variabile

char istruzioni_sim[100];

deve essere dichiarata in modo globale. Se la dichiaro all'interno della funzione leggi_da_sim900() non funziona, ovvero:

void leggi_da_sim900(){ 
char istruzioni_sim[100];
.
.
.
if(strcmp(istruzioni_sim, "\r\n+CMTI: \"SM\",")==0){   //vuol dire che ho ricevuto dalla shield la funzione di un nuovo sms
      carattere = sim900.read() -'0';                      //il carattere dopo la virgola è un numero; rappresenta l'ultimo sms
      numero_sms = carattere;  
      istruzioni_sim[i+1] = carattere;                      //salvo ugualmente il numero nel vettore istruzioni_sim
      ricevuto_sms = true;                                  //mi servirà per leggere l'sms solo quando lo ricevo
    }
.
.
.
}

L'if che ho scritto non funziona...come mai?Non viene eseguita la funzione strcmp

Perché strcmp vuole 2 stringhe di char mentre tu gli passi un array, forse non hai messo il terminatore "\0" in fondo a quell'array e la stringa non è riconosciuta come tale.

Mmmm... Però il modo in cui riempo il vettore di char è lo stesso, sia se la variabile è dichiarata globale, sia che è dichiarata nella funzione. Quindi se mancasse il carattere di fine stringa, non dovrebbe funzionare in nessun modo no?

sono disperato... ho lo stesso shield gprs della geeetech con sim900 ma non riesco a farlo funzionare con nessuno sketch... nemmeno con questo :frowning: L'sms che mandi contiene "acceso" e si dovrebbe accendere il led 13 vero? Uso arduino duemilanove con atmega 328... I jumpers sono impostati su sw, xduino o gprs?

Anche tu commetti lo stesso errore di un tuo collega: il comando AT deve essere terminato da un e non da , perciò non puoi usare il println

Riguardo alla questione della dichiarazione globale della stringa istruzioni è consigliabile farlo perché non sempre le routine chiamate dispongono di molta memoria SRAM: meglio allocare lo spazio all’inizio del programma,

Salve, io ho un problema.
Anche io ho una Shield con un Sim.900
e sto cercando come te di programmare senza librerie sim900.h

il mio problema è che: Riesco a ricevere gli SMS e me li salva in una memoria

come: +CMTI: “SM”,6 dove 6 è la memoria

poi cerco di richiamarlo con

mySerial.print( “AT+CMGR=” );
mySerial.println( SmsStorePos );

ma la Sim.900 non da segno di vita

avete dei consigli per me?

Grazie Mille

Ho provato sia con
#include <SoftwareSerial.h>
SoftwareSerial mySerial(7, 8);

che

#include <SoftwareSerial.h>
SoftwareSerial mySerial(0, 1);

Ho cmq provato a scaricare il tuo programma sull mio arduino e non mi funziona...