Cet article fait office de tutoriel. Vous apprendrez à envoyer et recevoir des SMS avec le SIM900. Par ailleurs vous trouverez sur cette page l’ensemble de mes tutoriels dédiés à Arduino. Jetez-y un coup d’oeil. Bonne lecture !

Voici la suite logique de mon précédent article dédié au module SIM900 de SIMCom (lire: Arduino – Prise en main du module SIM900). Ce module GSM simple d’emploi est très utilisé par les amateurs de cartes Arduino. Dans cette série d’articles je vous propose de découvrir quelques unes des fonctionnalités offertes par le SIM900 et de comprendre leur mise en oeuvre. Nous apprendrons aujourd’hui à envoyer et recevoir des SMS au format ASCII.

Je vous rappelle que j’utilise le shield GSM GPRSbee pour mes expérimentations. Néanmoins les programmes suivant fonctionneront avec n’importe quel shield GSM pour peu que celui-ci soit muni du module SIM900 ! Notre premier programme consistera donc en l’envoi d’un SMS au format ASCII …

Toutefois je conçois actuellement mon propre shield GSM dans le cadre d’un projet étudiant. Je publierais certainement un article sur le sujet. En attendant je vous propose de découvrir un premier prototype de circuit imprimé réalisé avec Eagle.

SIM900_ICARE_Upsilon_Audio

La conception du circuit imprimé avance bien … Je conçois ce circuit dans le cadre de mon projet ICARE.

Petit rappel à propos des SMS

J’aimerais vous rappeler quelques caractéristiques techniques du SMS (Short Message Service). La taille d’un SMS est de 1120 bits ce qui représente 160 caractères codés sur 7 bits ou encore 70 caractères si ceux-ci sont codés sur 16 bits. Les caractères sont bien évidemment codés sur 7 bits par défaut. Néanmoins certains caractères spéciaux nécessitent un codage sur 16 bits. Nous utiliserons un codage 7 bits pour nos différents exemples. Nos messages ne devront donc pas dépasser la taille limite de 160 caractères !

Par ailleurs il existe différents types de SMS. Il existe même 4 classes pour être plus précis. Les SMS que vous envoyés avec votre téléphone sont des messages de classe 1. Cela signifie que ces messages sont enregistrés dans la mémoire du téléphone par défaut. Si cette mémoire est pleine les messages sont enregistrés dans la carte SIM. C’est ce type de message qui nous intéresse dans le cadre de cet article. Nous nous intéresserons aux autres classes de SMS dans un prochain article. Nous parlerons notamment des fameux flash SMS ! Un peu de patience ! Je suis sur le coup …

Envoyer un SMS

Rappelez-vous. Pour communiquer avec le module GSM nous devons utiliser les commandes AT. Pour cela nous disposons d’une documentation très complète qui répertorie toutes les commandes AT compatibles avec le SIM900. Ce qui représente quand même 240 pages ! Vous pouvez vous procurez ce document en suivant ce lien. Pour envoyer un SMS nous avons seulement besoin de deux commandes AT ! Nous rajouterons seulement une commande pour déverrouiller la carte SIM. Voici le programme Arduino.

//SIM900 - Envoyer des SMS
//Par Pierre Pelé
//http://upsilonaudio.com/
//Décembre 2013

int8_t answer;
int onModulePin= 2; // Il s'agit du port DTR (ou PWR) du module SIM900.
char aux_string[30];
// Inscrivez ici le numéro de téléphone pour l'envoie du SMS.
char phone_number[]="+33600000000";
void setup()
{

    pinMode(onModulePin, OUTPUT);
    Serial.begin(115200);
    Serial2.begin(115200);    
        
    Serial.println("------------------------------------------------------");
    Serial.println("----Upsilon Audio - Envoyer un SMS avec le SIM900-----");
    Serial.println("------------------------------------------------------");
    Serial.println("");
    Serial.println("Initialisation en cours ...");
    power_on();
    
    delay(3000);
    
    // Cette commande active la carte SIM.
    //Supprimez cette ligne si vous n'avez pas de code PIN.
    sendATcommand("AT+CPIN=****", "OK", 2000);
    
    delay(3000);
    
    Serial.println("Connexion au reseau en cours ...");

    while( (sendATcommand("AT+CREG?", "+CREG: 0,1", 500) || 
            sendATcommand("AT+CREG?", "+CREG: 0,5", 500)) == 0 );

    Serial.println("Mode SMS en cours d'activation ...");
    // Activation du mode texte pour les SMS.
    sendATcommand("AT+CMGF=1", "OK", 1000);
    Serial.println("Envoi du SMS en cours ...");
    
    sprintf(aux_string,"AT+CMGS=\"%s\"", phone_number);
    // Envoi du numéro de téléphone au module GSM.
    answer = sendATcommand(aux_string, ">", 2000);
    if (answer == 1)
    {
        // Insérez ici le coprs du message.
        Serial2.println("Ceci est un SMS !");
        Serial2.write(0x1A);
        answer = sendATcommand("", "OK", 20000);
        if (answer == 1)
        {
            Serial.println("Message envoye !");    
        }
        else
        {
            Serial.print("Erreur !");
        }
    }
    else
    {
        Serial.print("Erreur !");
        Serial.println(answer, DEC);
    }

}


void loop() // Il n'y a aucune commandes dans la fonction loop.
{
}

// Définition des différentes fonctions.

void power_on(){

    uint8_t answer=0;
    
    // Cette commande vérifie si le module GSM est en marche.
    answer = sendATcommand("AT", "OK", 2000);
    if (answer == 0)
    {
        // Mise en marche du module GSM
        digitalWrite(onModulePin,HIGH);
        delay(3000);
        digitalWrite(onModulePin,LOW);
    
        // Envoie d'une commande AT toutes les deux secondes et attente d'une réponse.
        while(answer == 0){
            answer = sendATcommand("AT", "OK", 2000);    
        }
    }
    
}

// Cette fonction permet d'envoyer des commandes AT au module GSM.
int8_t sendATcommand(char* ATcommand, char* expected_answer, unsigned int timeout){

    uint8_t x=0,  answer=0;
    char response[100];
    unsigned long previous;

    // Initialisation de la chaine de caractère (string).
    memset(response, '\0', 100);
    
    delay(100);
    
    // Initialisation du tampon d'entrée (input buffer).
    while( Serial2.available() > 0) Serial2.read();
    
    // Envoi des commandes AT
    Serial2.println(ATcommand);


    x = 0;
    previous = millis();

    // Cette boucle attend la réponse du module GSM.
    
    do{
// Cette commande vérifie s'il y a des données disponibles dans le tampon.
//Ces données sont comparées avec la réponse attendue.
        if(Serial2.available() != 0){    
            response[x] = Serial2.read();
            x++;
            // Comparaison des données
            if (strstr(response, expected_answer) != NULL)    
            {
                answer = 1;
            }
        }
    // Attente d'une réponse.
    }while((answer == 0) && ((millis() - previous) < timeout));    

    //Serial.println(response); //Cette ligne permet de debuguer le programme en cas de problème !
    return answer;
}

Vous pouvez télécharger ce programme en suivant ce lien (4 Ko).

Ce programme ne fait appel à aucune bibliothèque particulière (si ce n’est la bibliothèque standad). On définit toutes les fonctions que l’on utilise. La fonction power_on permet simplement d’allumer le module GSM si celui-ci est en veille tandis que la fonction sendATcommand permet d’envoyer des commandes AT au SIM900. Cette dernière fonction attend trois argument. Le premier argument est la commande AT à envoyer au SIM900. Le deuxième argument constitue la réponse attendue et le dernier argument représente le temps d’attente maximal. Cette fonction retourne la valeur 1 si la commande AT a correctement été exécutée par le module GSM et la valeur 0 le cas échéant. En d’autres termes la fonction renvoie la valeur 0 si le SIM900 n’a pas envoyé le code de retour attendu au terme d’un laps de temps défini par l’utilisateur. N’hésitez pas à posez vos questions dans les commentaires si vous souhaitez en savoir plus sur le fonctionnement exact de ce programme. Vous remarquerez que j’ai largement commenté le programme.

J’ai utilisé une carte Arduino Méga pour réaliser ce programme. Pour rappel cette carte dispose de quatre ports séries ! Le port Serial est utilisé pour communiquer avec l’ordinateur et afficher les réponses dans le moniteur série tandis que le port Serial2 est utilisé pour communiquer avec le module SIM900 et envoyer les commandes AT. Si vous ne disposez pas d’une carte Arduino Méga vous pouvez créer un port série de manière logiciel en utilisant la bibliothèque newSoftSerial.

Ce programme fait donc appel à trois commandes AT. Voici ces commandes dans leur ordre d’apparition dans le programme.

sendATcommand(« AT+CPIN=**** », « OK », 2000);
Activation de la carte SIM

La commande AT+CPIN permet de déverrouiller la carte SIM. Vous devez remplacer les astérisques par votre code PIN. Supprimez simplement cette ligne si voter carte SIM ne possède pas de code PIN. Cette commande renvoi le code OK en cas de réussite. Le temps d’attente maximal est de 2 secondes. Je vous recommande pour vos expérimentations de supprimer le code PIN. En effet celui-ci peut-être source de problèmes si vous faites des RESET à répétition. J’en ai fais l’expérience !

sendATcommand(« AT+CMGF=1 », « OK », 1000);
Activation du mode texte pour l'envoi de SMS

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

sprintf(aux_string, »AT+CMGS= »%s » », phone_number);
answer = sendATcommand(aux_string, « > », 2000);
Envoi du SMS

La commande AT+CMGS permet d’envoyer un SMS. La première étape consiste en l’envoi du numéro de téléphone du destinataire. La variable phone_number 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). Le programme envoie ensuite le corps du message au module SIM900. La saisie du texte se termine par un CTR+Z. Pour ce faire le programme envoi simplement la valeur 0x1A au module GSM. En effet 0x1A est le code ASCII de CTR+Z.  Le programme 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 au SIM900. Voilà !

Ce programme peut paraître compliqué en première approche. Mais il n’en est rien ! Car envoyer un SMS en seulement trois commandes c’est absolument magique ! Bon. Il y a un peu plus que trois lignes de code dans ce programme. Je vous l’accorde. Mais on ne fait que s’assurer du bon déroulement du programme.

Recevoir un SMS

Nous souhaitons désormais recevoir un SMS à l’aide du SIM900. Pour cela on va modifier le programme précédent en modifiant simplement la fonction setup (). La prochaine étape consistera en un programme capable d’exécuter certaines actions en fonction des SMS qu’il reçoit ! Autrement dit on sera capable de commander notre carte Arduino simplement en lui envoyant un SMS. Ce qui n’est absolument pas sécurisé ! Mais pas moins intéressant. Voici le programme Arduino permettant de recevoir un SMS. Le SMS reçu s’affiche dans le moniteur série.

//SIM900 - Recevoir des SMS
//Par Pierre Pelé
//http://upsilonaudio.com/
//Décembre 2013

int8_t answer;
int x;
int onModulePin= 2; // Il s'agit du port DTR (ou PWR) du module SIM900.
char SMS[200];

void setup(){

    pinMode(onModulePin, OUTPUT);
    Serial.begin(115200);
    Serial2.begin(115200);  

    Serial.println("------------------------------------------------------");
    Serial.println("---Upsilon Audio - Recevoir un SMS avec le SIM900-----");
    Serial.println("------------------------------------------------------");
    Serial.println("");
    Serial.println("Initialisation en cours ...");
    power_on();
    
    delay(3000);
    
    // Cette commande active la carte SIM.
    //Supprimez cette ligne si vous n'avez pas de code PIN.
    sendATcommand("AT+CPIN=****", "OK", 2000);
    
    delay(3000);
    
    Serial.println("Mode SMS en cours d'activation ...");
    // Activation du mode texte pour les SMS.
    sendATcommand("AT+CMGF=1", "OK", 1000);
    // Sélection de la mémoire.
    sendATcommand("AT+CPMS=\"SM\",\"SM\",\"SM\"", "OK", 1000);
    // Lecture du premier SMS disponible.
    answer = sendATcommand("AT+CMGR=1", "+CMGR:", 2000);
    if (answer == 1)
    {
        answer = 0;
        while(Serial2.available() == 0);
        // Cette boucle récupère les données du SMS
        do{
// Si des données sont disponibles dans le tampon de la liaison série
// Le programme récupère ces données et les compares au code retour de la compmande AT
            if(Serial2.available() > 0){    
                SMS[x] = Serial2.read();
                x++;
                // Le module GSM a t'il envoyé le code de retour "OK" ?
                if (strstr(SMS, "OK") != NULL)    
                {
                    answer = 1;
                }
            }
        }while(answer == 0); // Attente du code de retour.
        
        SMS[x] = '\0';
        
        Serial.println("Voici le SMS:");
        Serial.println("");
        Serial.print(SMS);
        Serial.println("");    
        
    }
    else
    {
        Serial.print("Erreur: ");
        Serial.println(answer, DEC);
    }


}


void loop() // Il n'y a aucune commandes dans la fonction loop.
{
}

// Définition des différentes fonctions.

void power_on(){

    uint8_t answer=0;
    
    // Cette commande vérifie si le module GSM est en marche.
    answer = sendATcommand("AT", "OK", 2000);
    if (answer == 0)
    {
        // Mise en marche du module GSM
        digitalWrite(onModulePin,HIGH);
        delay(3000);
        digitalWrite(onModulePin,LOW);
    
        // Envoie d'une commande AT toutes les deux secondes et attente d'une réponse.
        while(answer == 0){
            answer = sendATcommand("AT", "OK", 2000);    
        }
    }
    
}

// Cette fonction permet d'envoyer des commandes AT au module GSM.
int8_t sendATcommand(char* ATcommand, char* expected_answer, unsigned int timeout){

    uint8_t x=0,  answer=0;
    char response[100];
    unsigned long previous;

    // Initialisation de la chaine de caractère (string).
    memset(response, '\0', 100);
    
    delay(100);
    
    // Initialisation du tampon d'entrée (input buffer).
    while( Serial2.available() > 0) Serial2.read();
    
    // Envoi des commandes AT
    Serial2.println(ATcommand);


    x = 0;
    previous = millis();

    // Cette boucle attend la réponse du module GSM.
    
    do{
// Cette commande vérifie s'il y a des données disponibles dans le tampon.
//Ces données sont comparées avec la réponse attendue.
        if(Serial2.available() != 0){    
            response[x] = Serial2.read();
            x++;
            // Comparaison des données
            if (strstr(response, expected_answer) != NULL)    
            {
                answer = 1;
            }
        }
    // Attente d'une réponse.
    }while((answer == 0) && ((millis() - previous) < timeout));    

    //Serial.println(response); //Cette ligne permet de debuguer le programme en cas de problème !
    return answer;
}

Vous pouvez télécharger ce dernier programme en suivant ce lien (4 Ko).

Le fonctionnement de ce programme est assez similaire à celui du programme précédent. Si ce n’est qu’au lieu d’envoyer un SMS on reçoit des caractères du SIM900 pour former un message complet. De même que précédemment n’hésitez pas à poster vos questions dans les commentaires !

Voici dans le détail les nouvelles commandes AT qui apparaissent dans ce programme.

sendATcommand(« AT+CPMS= »SM », »SM », »SM » », « OK », 1000);
Sélection de la mémoire

La commande AT+CPMS= »SM », »SM », »SM » permet de sélectionner la mémoire SM (SIM Message storage). La réponse attendue est OK. Le temps d’attente maximal est de 1 seconde.

answer = sendATcommand(« AT+CMGR=1 », « +CMGR: », 2000);
Lecture du premier SMS disponible

La commande AT+CMGR=1 permet de lire le premier SMS disponible. Le temps d’attente maximal est de 2 seconde. Le programme stocke tous les caractères reçus dans la variable SMS qui est déclarée en début de programme. La fin du message est détectée par l’envoi par le SIM900 du code de retour OK. Puis la chaîne de caractères se termine par le caractère  comme c’est la règle en langage C. Néanmoins si le message reçu contient le mot OK alors le SMS sera tronqué. Voilà !

Dans un prochain article nous verrons comment commander une carte Arduino par SMS. Je publierais également un petit article expliquant comment envoyer un flash SMS (SMS de classe 0). Ces SMS s’affichent directement sur l’écran du terminal mobile. Le nom de l’expéditeur est rarement affiché ! De quoi faire quelques blagues à vos amis … J’ai bien dit vos amis !

Vous avez aimé ce tutoriel ? N’hésitez pas à laisser quelques commentaires ! Vous pouvez également me suivre sur Twitter.

Pierre Pelé