Lecture d'une réponse sur le port série

Bonjour,

Je bute sur un problème que je n'arrive pas à résoude.
J'utilise une carte Arduino Uno avec le shield GSM de Seeduino.

J'envoi une commande AT+CREG? qui me retourne la réponse suivante :

AT+CREG?

+CREG: 2,1,"160E","66E1"

OK

Après chaque ligne, on a les caractères CR et LF.
Je met cette réponse dans un tableau de char, mais je n'arrive pas à lire les caractères après la position 7, c'est à dire qu'après le premier ? je n'arrive pas à accéder à la valeur.

Voici le code qui se trouve dans loop :

  if(Serial.available())
  {
    char string[50] = {}; // Chaine recu par AT+CREG?
    char byteRead;  // Caractère lu dans la liaison série GPRS
    
    GPRS.print("AT+CREG?");
    delay(100);

    int availableBytes = GPRS.available();
    for(int i=0; i<availableBytes; i++)
    {
      string[i] = GPRS.read();
    }
    
    Serial.println(char(string[7]));
    delay(10000);
  }

Dans ce cas Serial.println(char(string[7])) me retourne bien la valeur "?", mais après 7, je n'ai rien qui s'affiche alors que le tableau fait plus de 30 caractères.
Je pense qu'il s'agit d'un problème lié aux caractères CR et LF, mais je ne trouve pas de solution.

scrat27:
après 7, je n'ai rien qui s'affiche alors que le tableau fait plus de 30 caractères.

Et ça ça te parle pas..... ?

Serial.println(char(string[7]));

C'est ton programme de réception avec cette boucle for le problème.
Ta boucle de lecture n'attend pas d'avoir reçu l'intégralité du message pour se terminer.
En fait, tu ne lis que les caractères qui on été envoyés pendant le delais de 100ms que tu as mis après l'envoi de la demande.
Il faudrait faire une boucle un peu plus intelligente. Qui lise la réponse jusqu'à la réception de la fin de ligne (CR+LF).
Dans le genre:

pointeur = 0
do{
     attente d'un caractère
     lecture caractère
     mise en buffer du caractère à la position pointeur
     pointeur+1
}while (caractère reçu!=CR); // CR ou LF le dernier envoyé
ajout du \0 dans le buffer à la position pointeur

Merci pour vos réponses.

Jean-François:
Et ça ça te parle pas..... ?

C'est à dire ? je ne comprend pas ?

Pour ce qui est de la bloucle, la réponse renvoyée par le module SIM900 se présente sur 3 lignes, on a donc plusieurs fois la séquence CR LF, du coup la solution proposée ne me permettrait de récupérer que la première ligne.

Je me demande si ce serait pas intéressant d'utiliser une boucle while avec en condition : GPRS.available()
De cette manière tant qu'il exite des données à lire, la boucle continue de mettre dans le buffer et la lecture ne se limite pas aux données envoyées pendant les 100ms.

Qu'en pensez vous ? cela pourait il fonctionner ?

Pourquoi vouloir réinventer la roue ? Il suffit de suivre le code dispo sur le wiki :GPRS Shield V2.0 | Seeed Studio Wiki

Ensuite on ne sait pas sur quel série tu tournes : hardware ou software ?
Ensuite tu fais une lecture complétement asynchrone :

GPRS.print("AT+CREG?");
    delay(100);

    int availableBytes = GPRS.available();
    for(int i=0; i<availableBytes; i++)
    {
      string[i] = GPRS.read();
    }

je pense que tu dois être en série hardware, car si tu es en software et que ça marche c'est un énorme coup de bol ! On travaille plutôt de cette manière (à supposer qu'on est en série hard):

GPRS.print("AT+CREG?");
while(GPRS.available()==0);
 delay(20);
int i=0;
char Buffer[50]={NULL};
while(GPRS.available()) Buffer[i++]=GPRS.read();

Effectivement, comme j'utilise une Arduino Uno et que le port série Hardware me sert au débug, j'utilise un port série Software pour communiquer avec la carte GSM.

Puis je utiliser le code fourni en exemple ?

Oui celui du wiki utilise la même configuration que toi

scrat27:
Pour ce qui est de la boucle, la réponse renvoyée par le module SIM900 se présente sur 3 lignes, on a donc plusieurs fois la séquence CR LF, du coup la solution proposée ne me permettrait de récupérer que la première ligne.

Je me demande si ce serait pas intéressant d'utiliser une boucle while avec en condition : GPRS.available()

Il faut bien comprendre un truc les caractères arrivent un par un à leur rythme. Si tu lis les caractères dès qu'available() est différent de zéro, tu vas lire un caractère et sortir de la boucle..
available() c'est bien mais il faut gérer un hors temps pour s'arrêter lorsqu'il n'y a plus de données. Ce hors temps doit être estimé en disant si je n'ai pas reçu de caractère au bout de xxxms alors on considère qu'on a atteint la fin d'un message. Si tu mets un temps trop court dès fois tu en rates si tu mets un temps trop long tu perds du temps à attendre.

Maintenant, le plus simple si tu veux le message complet c'est tout simplement d'attendre le OK qui termine le message.

Effectivement il doit y avoir un problème de temporisation car quant j'utilise le code

  GPRS.print("AT+CREG?");
  delay(100);

while(GPRS.available()==0);
 delay(20);
int i=0;
char Buffer[50]={NULL};
while(GPRS.available()) Buffer[i++]=GPRS.read();

Je ne peut récupérer que les données avant les CR LF

Pour ce qui est de la détection du OK, comment puis je m'y prendre étant donné que la lecture se fait caractère par caractère ?

Oui c'est normal, je supposais que tu utilisais le port série hard pour communiquer avec le shield, ce qui n'était pas le cas. Il faut comprendre une chose : le port série hard est ainsi nommé car il dispose d'un buffer (mémoire tampon) qui lui permet de recevoir des données (et d'en émettre) quoique fasse l'Atmega. Donc dans ce cas la le timing n'est pas vraiment un problème. En revanche en soft, l'Atmega doit être "à l'écoute" pour réceptionner, donc si tu poses un delay() après GPRS.available() tu "n'écoutes pas" et tu perds des données. Étudie le code du wiki, il prend justement en compte ce fait

B@tto:
Oui c'est normal, je supposais que tu utilisais le port série hard pour communiquer avec le shield, ce qui n'était pas le cas. Il faut comprendre une chose : le port série hard est ainsi nommé car il dispose d'un buffer (mémoire tampon) qui lui permet de recevoir des données (et d'en émettre) quoique fasse l'Atmega. Donc dans ce cas la le timing n'est pas vraiment un problème. En revanche en soft, l'Atmega doit être "à l'écoute" pour réceptionner, donc si tu poses un delay() après GPRS.available() tu "n'écoutes pas" et tu perds des données. Étudie le code du wiki, il prend justement en compte ce fait

La librairie softwareSerial gère un buffer de réception. De ce coté là pas de problème. C'est juste le code de scrat27 qui pose problème.

Si la version qui lit jusqu'au CR+LF fonctionne ce n'est quand même pas très difficile de la généraliser pour lire des messages sur plusieurs lignes. Si tu sais lire une ligne tu sais en lire 2, 5, 10, ....

fdufnews:
La librairie softwareSerial gère un buffer de réception. De ce coté là pas de problème. C'est juste le code de scrat27 qui pose problème.

C'était même le cas lorsque c'était NewSoftSerial ?