Dans ce tuto, on va apprendre à gérer un système distant à l'aide de messages SMS. L'avantage d'un tel système est la couverture du réseau GSM qui est quasi totale
Dans ce tuto, nous allons utiliser le module SIM900A, mais tout ce qu'on va dire est valable pour d'autre modules GSM comme le SIM800
voici quelques considérations concernant ce module
Avant toute chose, il faut vérifier si le module répond aux commandes AT. Pour ça, on va utiliser le programme AT1 qui envoie des commande AT à partir du moniteur série
/*
* Programme AT1 pour tester les commandes AT
* Port COMM physique {Rx(0), Tx(1)} <--> moniteur Série (9600 baud, CR+LF)
* Port COMM Software {Rx(11), Tx(12)} <--> moniteur Série (9600 baud, CR+LF)
_________________ ______________
| Arduino | | Moniteur |
| Rx(0) |<---------------| Série |
| Tx(1) |--------------->| 9600,CR+LF |
| | ---------------
| | _______________
| Rx(11)|<---------------|Tx Module |
| Tx(12)|--------------->|Rx GSM |
| | | |
| GND |----------------|GND |
| | ---------------
-----------------
*/
#include <SoftwareSerial.h>
SoftwareSerial Module(11,12); // (RX, TX)
void setup() {
Serial.begin(9600);
Module.begin(9600);
Serial.println("Tapez une commande AT est valider par ENTER");
}
void loop() {
if(Serial.available())Module.write(Serial.read());
if(Module.available())Serial.write(Module.read());
}
Maintenant que le module est testé, on va présenter quelques commandes AT dont on aura besoin dans ce tuto. Vous pouvez télécharger le fichier contenant toutes les commandes AT supportées par le module SIM900
Quand on envoie des commandes AT successives, Il faut attendre de recevoir la réponse d'une commande avant d'envoyer la commande suivante.
Cette restriction vient du fait que l'interface série du module SIM900 n'est vraiment full duplex. Si on envoie une commande alors que le module est entrain de répondre à la précédente, il n'est pas capable de lire la nouvelle commande qui sera ignorée
On peut procéder de deux façons pour un fonctionnement correct:
String str = Module.readString();
Module.readString();
La fonction proposée ici envoie une commande AT et affiche la réponse du module sur le moniteur série
La fonction prend juste le temps nécessaire pour attendre la réponse
void ATcom(String cmd) {
Module.println(cmd);
String receivedData = "";
unsigned long startTime = millis(); // Temps de départ pour le timeout
while (millis() - startTime < 1000) {
if (Module.available()) receivedData += char(Module.read());
if (receivedData.endsWith("OK\r\n") || receivedData.endsWith("ERROR\r\n"))break;
}
Serial.println(receivedData);
}
Exemple d'utilisation:
ATcom("ATE 1");
ATcom("AT+CMGF=1");
ATcom("AT+CNMI=2,2,0,1,0");
La variante ci-dessous présente une légère modification
String ATcom(String cmd, bool dsply) {
Module.println(cmd);
String receivedData = "";
unsigned long startTime = millis(); // Temps de départ pour le timeout
while (millis() - startTime < 1000) {
if (Module.available()) receivedData += char(Module.read());
if (receivedData.endsWith("OK\r\n") || receivedData.endsWith("ERROR\r\n"))break;
}
if (dsply)Serial.println(receivedData);
return receivedData;
}
Exemple d'utilisation:
ATcom("ATE 1", 0); // ne pas afficher la réponse
ATcom("AT+CMGF=1", 1); // afficher la réponse
String str = ATcom("AT+CNMI=2,2,0,1,0", 0); //retourne la réponse sans affichage
Vider le buffer de réception efficacement quelque soit le rythme d'arrivé des données peut s'avérer assez compliqué
J'utilise une des méthodes suivantes qui marchent bien dans la plupart des cas. La dernière méthode est la plus optimisée
Module.readString();
C'est une méthode simple et directe pour lire tout le contenu du buffer en une seule fois. Elle vide le
contenu actuel du buffer et tout ce qui arrive pendant la seconde qui suit (Timeout de la librairie). Peut
être inefficace si des données continuent d'arriver.
void clearInputBuffer() {
while (Module.available()) {
Module.read();
delay(100);
}
}
void clearInputBuffer() {
unsigned long topDepart = millis(); // Enregistre le temps de début
const unsigned long timeout = 500; // Durée max de l'operation
while (millis() - topDepart < timeout) {
while (Module.available()) {
Module.read();
}
delay(10); // Petit délai pour permettre de nouveaux caractères d'arriver
}
}
Cette révision du programme permet (comme la précédente) d'envoyer des commandes AT, en plus, si le module reçoit un SMS, il est affiché sur le moniteur série.
/*
* Programme AT2 pour tester les commandes AT
* Port COMM physique {Rx(0), Tx(1)} <--> moniteur Série (9600 baud, CR+LF)
* Port COMM Software {Rx(11), Tx(12)} <--> moniteur Série (9600 baud, CR+LF)
_________________ ______________
| Arduino | | Moniteur |
| Rx(0) |<---------------| Série |
| Tx(1) |--------------->| 9600,CR+LF |
| | ---------------
| | _______________
| Rx(11)|<---------------|Tx Module |
| Tx(12)|--------------->|Rx GSM |
| | | |
| GND |----------------|GND |
| | ---------------
-----------------
*/
#include <SoftwareSerial.h>
SoftwareSerial Module(11,12); // (RX, TX)
void setup() {
Serial.begin(9600);
Module.begin(9600);
Serial.println("Petite initialisation au départ");
Module.write(27); //mettre fin à une éventuelle commande inachevée
ATcom("AT&F"); // Config usine
ATcom("AT+CMGF=1"); // Mode texte
ATcom("AT+CNMI=2,2,0,1,0"); // Relayer messages reçus immédiatement
Serial.println("=====================================================");
Serial.println("Tapez une commande AT est valider par ENTER");
}
void loop() {
if(Serial.available())Module.write(Serial.read());
if(Module.available())Serial.write(Module.read());
}
void ATcom(String cmd) {
Module.println(cmd);
String receivedData = "";
unsigned long startTime = millis(); // Temps de départ pour le timeout
while (millis() - startTime < 1000) {
if (Module.available()) receivedData += char(Module.read());
if (receivedData.endsWith("OK\r\n") || receivedData.endsWith("ERROR\r\n"))break;
}
Serial.println(receivedData);
}
Voici quelques explications sur le code:
Pour envoyer un SMS d'une façon simple, il faut choisir le mode texte:
Ensuite, chaque fois que l'on désire envoyer un SMS, il faut suivre les étapes suivantes:
On va envoyer un SMS en tapant les commandes AT sur le moniteur Série. Pour cela, il faut utiliser le programme AT1 ou AT2
Pour remédier à ce petit désagrément, on rajoute une ligne au début la partie initialisation du programme pour afficher ce caractère et ensuite faire un couper/coller:
Serial.write(26);
Ou de preference:
Serial.println("Copier/Coller pour avoir ASCII(26) -->\x1A<--");
Voici une capture d'écran du moniteur série illustrant l'envoi d'un SMS:
/*
Envoi SMS, version basique
Port COMM physique {Rx(0), Tx(1)} <--> moniteur Série (9600 baud, CR+LF)
Port COMM Software {Rx(7), Tx(8)} <--> moniteur Série (9600 baud, CR+LF)
_________________ ______________
| Arduino | | Moniteur |
| Rx(0) |<---------------| Série |
| Tx(1) |--------------->| 9600,CR+LF |
| | ---------------
| | _______________
| Rx(11)|<---------------|Tx Module |
| Tx(12)|--------------->|Rx GSM |
| | | |
| GND |----------------|GND |
| | ---------------
-----------------
*/
#include <SoftwareSerial.h>
SoftwareSerial Module(11, 12); // (RX, TX)
void setup() {
Serial.begin(9600);
Module.begin(9600);
Serial.println("======= Initialisation =============");
Module.write(27); //mettre fin à une éventuelle commande inachevée
ATcom("AT&F", 1); // Config usine
ATcom("AT+CMGF=1", 1); // Mode texte
ATcom("ATE 0", 1); //pas d'écho
Serial.println("======= Envoi du message =============");
String str = ATcom("AT+CMGS=\"0667066947\"", 1);
if (str.endsWith("> ")) {
Module.print("Bonjour,\nCeci est un message de Test"); // max 160 octets
Module.write(26);
Serial.println("Bonjour,\nCeci est un message de Test"); // trace sur le moniteur série
delay(5000); //attendre la réponse après l'envoi du message
str = Module.readString(); // réponse
if (str.indexOf("+CMGS:") != -1)Serial.println("Message envoyé avec succès");
else {
Serial.println("Pas de réponse de confirmation");
Module.write(27);
}
} else {
Serial.println("Invité '>' non reçu");
Module.write(27);
}
Module.readString(); // nettoyer le buffer
}
void loop() {
if (Serial.available())Module.write(Serial.read());
if (Module.available())Serial.write(Module.read());
}
String ATcom(String cmd, bool dsply) {
Module.println(cmd);
String receivedData = "";
unsigned long startTime = millis(); // Temps de départ pour le timeout
while (millis() - startTime < 1000) {
if (Module.available()) receivedData += char(Module.read());
if (receivedData.endsWith("OK\r\n") || receivedData.endsWith("ERROR\r\n"))break;
}
if (dsply)Serial.print(receivedData);
return receivedData;
}
Dans cet exemple, on va essayer de coller à l'organigramme de la figure:
/*
Programme pour envoyer un SMS de test, version robuste
Port COMM physique {Rx(0), Tx(1)} <--> moniteur Série (9600 baud, CR+LF)
Port COMM Software {Rx(11), Tx(12)} <--> moniteur Série (9600 baud, CR+LF)
_________________ ______________
| Arduino | | Moniteur |
| Rx(0) |<---------------| Série |
| Tx(1) |--------------->| 9600,CR+LF |
| | ---------------
| | _______________
| Rx(11)|<---------------|Tx Module |
| Tx(12)|--------------->|Rx GSM |
| | | |
| GND |----------------|GND |
| | ---------------
-----------------
*/
#include <SoftwareSerial.h>
SoftwareSerial Module(11, 12); // (RX, TX)
void setup() {
Serial.begin(9600);
Module.begin(9600);
Module.write(27); //mettre fin à une éventuelle commande inachevée
Module.readString(); // vider le buffer
String str = "";
while (1) {
do{
Serial.println("Tester commande AT&F");
str = ATcom("AT&F" , 1);
}while(str.indexOf("OK") == -1); // recommencer si pas de réponse
if (isConnected())break; // module connecté au réseau
Serial.println("Redémarrage du module");
ATcom("AT+CFUN=1,1" , 1) ;
delay(10000); // laisser le module démarrer
}
ATcom("AT+CMGF=1" , 1); // mode text
ATcom("ATE 0" , 1); // l'echo peut saturer le buffer de réception
// =============== Envoyer SMS
Serial.println("Envoi SMS");
str = ATcom("AT+CMGS=\"0667066947\"" , 1);
if (str.endsWith("> ")) {
Module.print("Hello, \nCeci est un message de test");
Module.write(26);
if (waitFor("+CMGS:", 6000)) Serial.println("SMS envoyé avec succès");
else Serial.println("Echec finalisation SMS");
}else Serial.println("Invité '>' non reçu");
Module.write(27); // cas d'échec
Module.readString(); // nettoyer le buffer
}
void loop() {
}
String ATcom(String cmd, bool dsply) {
Module.println(cmd);
String receivedData = "";
unsigned long startTime = millis(); // Temps de départ pour le timeout
while (millis() - startTime < 1000) {
if (Module.available()) receivedData += char(Module.read());
if (receivedData.endsWith("OK\r\n") || receivedData.endsWith("ERROR\r\n"))break;
}
if (dsply)Serial.print(receivedData);
return receivedData;
}
bool isConnected() {
Serial.println("Verifier si le module est connecté");
delay(2000); // si le module vient d'être allumé
Module.readString(); // vider le buffer
Module.println("AT+CREG?");
if (waitFor("1", 5000)) {
Serial.println("Module Connecté");
Module.readString(); // vider le buffer
return true;
}
else {
Serial.println("Module Non Connecté");
return false;
}
}
bool waitFor(String STR, uint32_t Tms) {
String receivedData = "";
unsigned long startTime = millis(); // Temps de départ pour le timeout
while (millis() - startTime < Tms) {
if (Module.available()) {
char c = Module.read();
receivedData += c;
if (receivedData.endsWith(STR)) {
return true;
}
}
}
return false;
}
Dans cet exemple, dès que l'on reçoit quelque chose venant du module, on vérifie que c'est un SMS. Ensuite on isole et on affiche le numéro de l'expéditeur, la date et l'heure ainsi que le corp du message.
/*
Recevoir et afficher un SMS
Port COMM physique {Rx(0), Tx(1)} <--> moniteur Série (9600 baud, CR+LF)
Port COMM Software {Rx(11), Tx(12)} <--> moniteur Série (9600 baud, CR+LF)
_________________ ______________
| Arduino | | Moniteur |
| Rx(0) |<---------------| Série |
| Tx(1) |--------------->| 9600,CR+LF |
| | ---------------
| | _______________
| Rx(11)|<---------------|Tx Module |
| Tx(12)|--------------->|Rx GSM |
| | | |
| GND |----------------|GND |
| | ---------------
-----------------
*/
#include <SoftwareSerial.h>
SoftwareSerial Module(11, 12); // (RX, TX)
void setup() {
Serial.begin(9600);
Module.begin(9600);
Serial.println("======= Initialisation =====================");
Module.write(27); //mettre fin à une éventuelle commande inachevée
ATcom("AT&F"); // Config Usine
ATcom("AT+CMGF=1"); // mode Text
ATcom("AT+CNMI=2,2,0,1,0"); // Transferer messages reçus vers Arduino
Serial.println("J'attend un message\n\n");
}
void loop() {
if (Module.available() == 0)return; // on n'a rien reçu
// lire et afficher ce qui a été reçu
String sms = Module.readString();
Serial.println(sms);
// Vérifier si c'est un SMS
if (sms.indexOf("CMT") == -1)return; // ce n'est pas un SMS
// Isoler le numéro de téléphone
int n1 = sms.indexOf('"') + 1;
int n2 = sms.indexOf('"', n1);
String numtel = sms.substring(n1, n2); // numéro tel
Serial.print("Message de ");
Serial.println(numtel);
// isoler la date et heure
n1 = sms.lastIndexOf('"');
String date = sms.substring(n1 - 20, n1-12);
Serial.print("Reçu le ");
Serial.print(date);
String heure = sms.substring(n1 - 11, n1-3);
Serial.print(" à ");
Serial.println(heure);
// Isoler le corps du message
n2 = sms.indexOf("\r", n1 + 2);
Serial.println();
String msg = sms.substring(n1 + 3, n2);
Serial.println(msg);
Serial.println(F("\n\n====== J'attend un autre message ======"));
}
void ATcom(String cmd) {
Module.println(cmd);
String receivedData = "";
unsigned long startTime = millis(); // Temps de départ pour le timeout
while (millis() - startTime < 1000) {
if (Module.available()) receivedData += char(Module.read());
if (receivedData.endsWith("OK\r\n") || receivedData.endsWith("ERROR\r\n"))break;
}
Serial.println(receivedData);
}
Dans cet exemple, On va controller une LED à l'aide d'un message contenant les mots clé LEDON ou LEDOFF
/*
Recevoir et afficher un SMS
Port COMM physique {Rx(0), Tx(1)} <--> moniteur Série (9600 baud, CR+LF)
Port COMM Software {Rx(11), Tx(12)} <--> moniteur Série (9600 baud, CR+LF)
_________________ ______________
| Arduino | | Moniteur |
| Rx(0) |<---------------| Série |
| Tx(1) |--------------->| 9600,CR+LF |
| | ---------------
| | _______________
| Rx(11)|<---------------|Tx Module |
| Tx(12)|--------------->|Rx GSM |
| | | |
| GND |----------------|GND |
| | ---------------
-----------------
*/
#include <SoftwareSerial.h>
SoftwareSerial Module(11, 12); // (RX, TX)
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN,LOW);
Serial.begin(9600);
Module.begin(9600);
Serial.println("======= Initialisation =====================");
Module.write(27); //mettre fin à une éventuelle commande inachevée
ATcom("AT&F"); // Config Usine
ATcom("AT+CMGF=1"); // mode Text
ATcom("AT+CNMI=2,2,0,1,0"); // Transferer messages reçus vers Arduino
Serial.println("J'attend un message de commande \n\n");
}
void loop() {
if (Module.available() == 0)return; // on n'a rien reçu
// lire et afficher ce qui a été reçu
String sms = Module.readString();
Serial.println(sms);
// Vérifier si c'est un SMS
if (sms.indexOf("CMT") == -1)return; // ce n'est pas un SMS
if(sms.indexOf("LEDON") != -1)digitalWrite(LED_BUILTIN,HIGH);
else if(sms.indexOf("LEDOFF") != -1)digitalWrite(LED_BUILTIN,LOW);
Serial.println(F("\n\n====== J'attend un autre message ======"));
}
void ATcom(String cmd) {
Module.println(cmd);
String receivedData = "";
unsigned long startTime = millis(); // Temps de départ pour le timeout
while (millis() - startTime < 1000) {
if (Module.available()) receivedData += char(Module.read());
if (receivedData.endsWith("OK\r\n") || receivedData.endsWith("ERROR\r\n"))break;
}
Serial.println(receivedData);
}
Dans ce paragraphe on va contrôler une LED et un moteur CC
On va utiliser des SMS avec les mots clé
/*
Contrôler une LED et un Moteur CC
Port COMM physique {Rx(0), Tx(1)} <--> moniteur Série (9600 baud, CR+LF)
Port COMM Software {Rx(11), Tx(12)} <--> moniteur Série (9600 baud, CR+LF)
_________________ ______________
| Arduino | | Moniteur |
| Rx(0) |<---------------| Série |
| Tx(1) |--------------->| 9600,CR+LF |
| | ---------------
| | _______________
| Rx(11)|<---------------|Tx Module |
| Tx(12)|--------------->|Rx GSM |
| | | |
| GND |----------------|GND |
| | ---------------
-----------------
*/
#define ENA 10
#define IN1 9
#define IN2 8
#include <SoftwareSerial.h>
SoftwareSerial Module(11, 12); // (RX, TX)
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
TCCR1B = TCCR1B & B11111000 | B00000100; // f = 122.55 Hz, T = 8.16ms (D9, D10)
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(ENA, OUTPUT);
digitalWrite(ENA, 0); // roue libre
Serial.begin(9600);
Module.begin(9600);
Serial.println("======= Initialisation =====================");
Module.write(27); //mettre fin à une éventuelle commande inachevée
ATcom("AT&F"); // Config Usine
ATcom("AT+CMGF=1"); // mode Text
ATcom("AT+CNMI=2,2,0,1,0"); // Transferer messages reçus vers Arduino
Serial.println("J'attend un message de commande \n\n");
}
void loop() {
if (Module.available() == 0)return; // on n'a rien reçu
// lire et afficher ce qui a été reçu
String sms = Module.readString();
Serial.println(sms);
// Vérifier si c'est un SMS
if (sms.indexOf("CMT") == -1)return; // ce n'est pas un SMS
if (sms.indexOf("LEDON") != -1)digitalWrite(LED_BUILTIN, HIGH);
if (sms.indexOf("LEDOFF") != -1)digitalWrite(LED_BUILTIN, LOW);
int i1 = sms.indexOf("MOTOR(");
if(i1 != -1){
int i2 = sms.indexOf(",", i1 + 4); // 1ère virgule
int i3 = sms.indexOf(",", i2 + 1); // 2ème virgule
int i4 = sms.indexOf(")", i3 + 1); //
String sdir = sms.substring(i1 + 6, i2);
sdir.trim();
int dir = sdir.toInt();
String sduration = sms.substring(i2 + 1, i3);
sduration.trim();
uint32_t duration = sduration.toFloat() * 1000.0;
String spwm = sms.substring(i3 + 1, i4);
spwm.trim();
int pwm = spwm.toInt();
digitalWrite(IN1, dir);
digitalWrite(IN2, 1 - dir);
analogWrite(ENA, pwm);
Serial.println("En marche " + sdir + " " + sduration + " " + spwm);
if (duration != 0) {
delay(duration);
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
digitalWrite(ENA, 1);
Serial.println("STOP");
}
}
if (sms.indexOf("MOTORSTOP") != -1) {
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
digitalWrite(ENA, 1);
}
if (sms.indexOf("MOTORFREE") != -1)analogWrite(ENA, 0); // roue libre
}
void ATcom(String cmd) {
Module.println(cmd);
String receivedData = "";
unsigned long startTime = millis(); // Temps de départ pour le timeout
while (millis() - startTime < 1000) {
if (Module.available()) receivedData += char(Module.read());
if (receivedData.endsWith("OK\r\n") || receivedData.endsWith("ERROR\r\n"))break;
}
Serial.println(receivedData);
}
Dans cet exemple, on va envoyer un SMS (Request) pour demander une mesure. Le système effectue la mesure et retourne un SMS (Response) avec la mesure demandée
Considérons par exemple un cas de mesure de distance à l'aide d'un module à ultra-sons. On va voir que ça peut être très utile dans un cas pratique
Téléversez le programme ci-dessous et utilisez votre téléphone pour envoyer un SMS avec le mote clé mesure en majuscule ou en minuscule (mesure , MESURE, Mesure, ...)
/*
Mesure de distance par SMS
Port COMM physique {Rx(0), Tx(1)} <--> moniteur Série (9600 baud, CR+LF)
Port COMM Software {Rx(11), Tx(12)} <--> moniteur Série (9600 baud, CR+LF)
_________________ ______________
| Arduino | | Moniteur |
| Rx(0) |<---------------| Série |
| Tx(1) |--------------->| 9600,CR+LF |
| | ---------------
| | _______________
| Rx(11)|<---------------|Tx Module |
| Tx(12)|--------------->|Rx GSM |
| | | |
| GND |----------------|GND |
| | ---------------
-----------------
*/
#define trigPin 9
#define echoPin 8
#include <SoftwareSerial.h>
SoftwareSerial Module(11, 12); // (RX, TX)
void setup() {
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
digitalWrite(trigPin, LOW);
Serial.begin(9600);
Module.begin(9600);
Serial.println("======= Initialisation =====================");
Module.write(27); //mettre fin à une éventuelle commande inachevée
ATcom("AT&F" , 1); // Config Usine
ATcom("AT+CMGF=1" , 1); // mode Text
ATcom("AT+CNMI=2,2,0,1,0" , 1); // Transferer messages reçus vers Arduino
Serial.println("J'attend un message de commande \n\n");
}
void loop() {
if (Module.available() == 0)return; // on n'a rien reçu
// lire et afficher ce qui a été reçu
String sms = Module.readString();
sms.toUpperCase();
Serial.println(sms);
// Vérifier si c'est un SMS
if (sms.indexOf("CMT") == -1)return; // ce n'est pas un SMS
if (sms.indexOf("MESURE") == -1) return; // ce n'est pas une recquette
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
float Tus = pulseIn(echoPin, HIGH); // temps en µs
float Dcm = Tus * 0.0343 / 2; // distance en cm
// ========== envoyer réponse
ATcom("ATE 0" , 1);
String str = ATcom("AT+CMGS=\"0667066947\"" , 1);
if (str.endsWith("> ")) {
Module.print("La distance est: " + String(Dcm) + " Cm");
Module.write(26);
if (waitFor("+CMGS:", 6000)) Serial.println("SMS envoyé avec succès");
else Serial.println("Echec finalisation SMS");
} else Serial.println("Invité '>' non reçu");
Module.write(27); // cas d'échec
Module.readString(); // nettoyer le buffer
}
String ATcom(String cmd, bool dsply) {
Module.println(cmd);
String receivedData = "";
unsigned long startTime = millis(); // Temps de départ pour le timeout
while (millis() - startTime < 1000) {
if (Module.available()) receivedData += char(Module.read());
if (receivedData.endsWith("OK\r\n") || receivedData.endsWith("ERROR\r\n"))break;
}
if (dsply)Serial.println(receivedData);
return receivedData;
}
bool waitFor(String STR, uint32_t Tms) {
String receivedData = "";
unsigned long startTime = millis(); // Temps de départ pour le timeout
while (millis() - startTime < Tms) {
if (Module.available()) {
char c = Module.read();
receivedData += c;
if (receivedData.endsWith(STR)) {
return true;
}
}
}
return false;
}
Dans l'exemple ci-dessous, les points importants sont:
Module.println("AT+CSCS=\"UCS2\"");
Module.println("AT+CSMP=17,167,0,8");
/*
Envoi SMS avec caractères accentués codage UCS2
Port COMM physique {Rx(0), Tx(1)} <--> moniteur Série (9600 baud, CR+LF)
Port COMM Software {Rx(7), Tx(8)} <--> moniteur Série (9600 baud, CR+LF)
_________________ ______________
| Arduino | | Moniteur |
| Rx(0) |<---------------| Série |
| Tx(1) |--------------->| 9600,CR+LF |
| | ---------------
| | _______________
| Rx(11)|<---------------|Tx Module |
| Tx(12)|--------------->|Rx GSM |
| | | |
| GND |----------------|GND |
| | ---------------
-----------------
*/
#include <SoftwareSerial.h>
SoftwareSerial Module(11, 12); // (RX, TX)
void setup() {
Serial.begin(9600);
Module.begin(9600);
Serial.println("======= Initialisation =============");
Module.write(27); //mettre fin à une éventuelle commande inachevée
Module.readString(); // vider le buffer d'entrée
ATcom("ATE 1"); // juste pendant la phase d'initialisation
ATcom("AT+CMGF=1");
ATcom("AT+CSCS=\"UCS2\"");
ATcom("AT+CSMP=17,167,0,8");
ATcom("AT+CNMI=2,2,0,1,0");
ATcom("ATE 0");
Serial.println("======= Envoi message accentué =============");
String numtelucs2 = ucs2(L"0667066947"); // ne pas oublier le L
Module.println("AT+CMGS=\"" + numtelucs2 + "\"");
String str = Module.readString();
Serial.print(str);
if (str.endsWith("> ")) {
Module.print(ucs2(L"ABCéèêàçǵ€")); // ne pas oublier le L
Module.write(26);
delay(5000); //attendre la réponse après l'envoi du message
str = Module.readString(); // réponse
if (str.indexOf("+CMGS:") != -1)Serial.println("\nMessage envoyé avec succès");
else {
Serial.println("\nPas de réponse de confirmation");
Module.write(27);
}
} else {
Serial.println("Invité '>' non reçu");
Module.write(27);
}
Module.readString(); // nettoyer le buffer
}
void loop() {
if (Serial.available())Module.write(Serial.read());
if (Module.available())Serial.write(Module.read());
}
void ATcom(String cmd) {
Module.println(cmd);
String receivedData = "";
unsigned long startTime = millis(); // Temps de départ pour le timeout
while (millis() - startTime < 1000) {
if (Module.available()) receivedData += char(Module.read());
if (receivedData.endsWith("OK\r\n") || receivedData.endsWith("ERROR\r\n"))break;
}
Serial.println(receivedData);
}
String ucs2(wchar_t *wstr) {
String str,s;
for (byte i = 0; wstr[i] != L'\0'; i++) {
s = String(wstr[i],HEX);
while (s.length() < 4) s = "0" + s;
str += s;
}
return str;
}
/*
Recevoir et afficher un SMS avec le codage UCS2
Port COMM physique {Rx(0), Tx(1)} <--> moniteur Série (9600 baud, CR+LF)
Port COMM Software {Rx(11), Tx(12)} <--> moniteur Série (9600 baud, CR+LF)
_________________ ______________
| Arduino | | Moniteur |
| Rx(0) |<---------------| Série |
| Tx(1) |--------------->| 9600,CR+LF |
| | ---------------
| | _______________
| Rx(11)|<---------------|Tx Module |
| Tx(12)|--------------->|Rx GSM |
| | | |
| GND |----------------|GND |
| | ---------------
-----------------
*/
#include <SoftwareSerial.h>
SoftwareSerial Module(11, 12); // (RX, TX)
void setup() {
Serial.begin(9600);
Module.begin(9600);
Module.write(27); //mettre fin à une éventuelle commande inachevée
Module.readString(); // vider le buffer d'entrée
ATcom("ATE 1"); // juste pendant la phase d'initialisation
ATcom("AT+CMGF=1");
ATcom("AT+CSCS=\"UCS2\"");
ATcom("AT+CSMP=17,167,0,8");
ATcom("AT+CNMI=2,2,0,1,0");
ATcom("ATE 0");
Serial.println(F("\nJ'attend un message\n\n"));
}
void loop() {
if (Module.available() == 0)return; // on n'a rien reçu
String sms = Module.readString(); //Ce qu'on a reçu
Serial.println(sms);
int n1 = sms.indexOf("CMT");
if (n1 == -1)return; // ce n'est pas un SMS
// Isoler le numéro de téléphone
n1 = sms.indexOf('"') + 1;
int n2 = sms.indexOf('"', n1);
String numtel = sms.substring(n1, n2); // numéro tel
Serial.print("Message de ");
if (isUCS2(numtel)) {
Serial.println(UcsstrToUtfstr(numtel));
} else {
Serial.println(numtel);
}
// isoler la date et heure
n1 = sms.lastIndexOf('"');
String date = sms.substring(n1 - 20, n1 - 12);
Serial.print("Reçu le ");
Serial.print(date);
String heure = sms.substring(n1 - 11, n1 - 3);
Serial.print(" à ");
Serial.println(heure);
// Isoler le corps du message
n2 = sms.indexOf("\r", n1 + 2);
String msgBdy = sms.substring(n1 + 3, n2);
Serial.println();
if (isUCS2(msgBdy)) {
Serial.println(UcsstrToUtfstr(msgBdy));
} else {
Serial.println(msgBdy);
}
Serial.println(F("\n\n====== J'attend un autre message ======"));
}
void ATcom(String cmd) {
Module.println(cmd);
String receivedData = "";
unsigned long startTime = millis(); // Temps de départ pour le timeout
while (millis() - startTime < 1000) {
if (Module.available()) receivedData += char(Module.read());
if (receivedData.endsWith("OK\r\n") || receivedData.endsWith("ERROR\r\n"))break;
}
Serial.println(receivedData);
}
bool isUCS2(String str) {
if (str.length() % 4 != 0) {
return false;
}
for (int i = 0; i < str.length(); i++) {
if (!isxdigit(str[i])) {
return false;
}
}
return true;
}
uint32_t unicode2utf8(uint16_t U) {
uint8_t BT0;
uint16_t BT1;
uint32_t BT2;
if (U < 0x80)return (U);
else if (U < 0x800) {
BT0 = 0x80 | (U & 0x003F);
BT1 = 0xC0 | (U >> 6);
return (BT1 << 8) | BT0;
} else {
BT0 = 0x80 | (U & 0x003F);
BT1 = 0x80 | ( (U >> 6) & 0x003F );
BT2 = 0xE0 | ( (U >> 12) );
return (BT2 << 16) | (BT1 << 8) | BT0;
}
}
String UcsstrToUtfstr(const String ucs2) {
uint8_t n = ucs2.length();
String utf8 = "";
for (uint8_t i = 0; i < n ; i += 4) {
String onechar = ucs2.substring(i, i + 4);
const char* onechart = onechar.c_str();
uint16_t CP = strtoul(onechart, NULL, 16);
uint32_t U8 = unicode2utf8(CP);
if (U8 > 0xFFFF)utf8 += char(U8 >> 16);
if (U8 > 0xFF)utf8 += char(U8 >> 8);
utf8 += char(U8);
}
return utf8;
}