Partage
  • Partager sur Facebook
  • Partager sur Twitter

problème String avec Serial.readString()

    5 juin 2020 à 22:33:02

    à tous bonjour,

    je fais un essai de transmission Bluetooth avec des HC05.
    je souhaite que le SLAVE envoie une commande vers le MASTER, pour allumer ou éteindre une LED.
    au début, ça fonctionne avec des 'char' quand je tape :

    pour l'ARDUINO qui supporte le SLAVE


    void loop() { if(digitalRead(BOUTON) == LOW) { Serial.print('1'); } if(digitalRead(BOUTON) == HIGH) { Serial.print('0'); } }


    pour l'ARDUINO qui supporte le MASTER


    void loop()
    {
        char texte;
           
        if(Serial.available() > 0)
        {
            texte = Serial.read();
       
            if(texte == '1')
            {
              digitalWrite(LED_pin, HIGH);
            }
                 
            if(texte == '0')
            {
              digitalWrite(LED_pin, LOW);
            }
        }       
    }

    mais si j'essaie avec des "string", avec les codes suivants, rien ne ce passe :


    pour l'ARDUINO qui supporte le SLAVE


    void loop()
    {
        if(digitalRead(BOUTON) == LOW)
        {
          Serial.print("ON");
        }
               
           if(digitalRead(BOUTON) == HIGH)
        {
          Serial.print("OFF");
        }
    }

    pour l'ARDUINO qui supporte le MASTER

    void loop()
    {
        String texte;
           
        if(Serial.available() > 0)
        {
            texte = Serial.readString();
       
            if(texte == "ON")
            {
              digitalWrite(LED_pin, HIGH);
            }
                 
            if(texte == "OFF")
            {
              digitalWrite(LED_pin, LOW);
            }
        }       
    }
    • Partager sur Facebook
    • Partager sur Twitter
      6 juin 2020 à 18:23:35

      Le problème, c'est que ton master émet l'état en permanence.

      Avec des caractères, tu vas te retrouver avec quelque chose dans ce style :

      111111111111111100000000011111111111111111111110000000

      Vu que tu lis caractères par caractères dès qu'il y en a un de disponible, cela fonctionne correctement.

      Par contre, avec des strings, tu vas te retrouver avec quelque chose dans ce style :

      ONONONONONONONONONONONONONONOFFOFFOFFOFFOFFONONONONONONON

      Mais la fonction readString ne peut pas deviner quand s'arrêter de lire la string.

      Dans l'exemple précédant, où commencerait chaque commande ? Pas évidant à dire non ? (est-ce "ON" ? ou "NON" ? ou "ONONON" ?)

      D'ailleurs, c'est écrit dans la doc : cette fonction s'arrête de lire après un timeout qui est de 1 seconde par défaut.

      Vu que le master émet en permanence, la fonction readString ne s'arrête jamais.

      Une solution simple serait de mettre un delay de 1500ms après chaque write dans le master, pour n'envoyer des données que toutes les 1.5s et donc laisser le temps à readString d'atteindre le timeout.

      Mais cela rendra ton programme beaucoup moins réactif.

      Une autre solution consiste à utiliser un caractère délimiteur (un saut de ligne par exemple) et de lire les données jusqu'à ce délimiteur.

      ////////// MASTER //////////
      
      void loop()
      {
          if(digitalRead(BOUTON) == LOW)
          {
            Serial.print("ON\n");
          }
          if(digitalRead(BOUTON) == HIGH)
          {
            Serial.print("OFF\n");
          }
      }
      
      ////////// SLAVE //////////
      
      string texte; // Variable globale, c'est important !
      
      void loop()
      {
      	if(Serial.available() > 0)
      	{
      		char c = Serial.read();
      		if ( c == '\n' ) {
      			if(texte == "ON") {
      				digitalWrite(LED_pin, HIGH);
      			}
      			if(texte == "OFF") {
      				digitalWrite(LED_pin, LOW);
      			}
      			texte = "";
      		} else {
      			texte += c;
      		}
      	}
      }





      -
      Edité par lorrio 6 juin 2020 à 18:25:38

      • Partager sur Facebook
      • Partager sur Twitter
        7 juin 2020 à 18:57:53

        effectivement ça marche mieux comme ça.

        d'autant plus que j'ai mis une émission uniquement au changement d'état des boutons.

        merci.

        • Partager sur Facebook
        • Partager sur Twitter
          7 juin 2020 à 20:07:56

          Émettre uniquement au changement d'état, c'est bien mais risqué si il n'y a pas d’acquittement.

          Si la transmission radio est perturbée au moment de l'envoie, le récepteur ne recevra pas le message et ne prendra donc pas en compte le changement.

          Émettre à interval régulier permet de s'affranchir de ce problème.

          Et le top du top pour s'assurer de la transmission tout en évitant de spammer les ondes radio, c'est de mettre en place un système d’acquittement.

          Lorsque le destinataire reçoit un message, il renvoie un acquittement (du genre "OK") à l'émetteur, ce qui permet de lui indiquer que le message a bien été reçu.

          Si l'émetteur ne reçoit pas l’acquittement, il en déduit que le message a été perdu et peut donc prendre l'initiative de le renvoyer un peu plus tard.

          • Partager sur Facebook
          • Partager sur Twitter
            17 août 2021 à 22:35:45

            lorrio a écrit:

            ////////// MASTER //////////
            
            void loop()
            {
                if(digitalRead(BOUTON) == LOW)
                {
                  Serial.print("ON\n");
                }
                if(digitalRead(BOUTON) == HIGH)
                {
                  Serial.print("OFF\n");
                }
            }
            
            ////////// SLAVE //////////
            
            string texte; // Variable globale, c'est important !
            
            void loop()
            {
            	if(Serial.available() > 0)
            	{
            		char c = Serial.read();
            		if ( c == '\n' ) {
            			if(texte == "ON") {
            				digitalWrite(LED_pin, HIGH);
            			}
            			if(texte == "OFF") {
            				digitalWrite(LED_pin, LOW);
            			}
            			texte = "";
            		} else {
            			texte += c;
            		}
            	}
            }





            -
            Edité par lorrio 6 juin 2020 à 18:25:38

            salut,

            désoler de déterrer le post mais j'essaye d'utiliser ton code si dessus pour transmettre des variables par un minimum de SMS via mon tel et a terme une appli mobile a un shield SIM900.

            la syntaxe d'envoi du SMS que je souhaite mettre en place est la suivante :

            tab01\n100\n150\n200\n

            le premier String découper correspond au tableau dans lequel je souhaite enregistré les variable, du coup a la réception de données depuis mon SIM900 ton code me fait rentré dans une boucle while dans laquelle j'ai essayer de réimplanter le même code pour qu'il boucle et remplisse le tableau.

            j'arrive donc bien a rentré dans ma boucle while 

            je ne comprend pas pourquoi mais pour que l'index zéro de mon tableau prenne la valeur de la première variable (100 ici) il m'as fallut rajouter un second saut de ligne après tab01 (tab01\n\n100\n150\n200\n

            pour que seul l'index zéro de mon tableau soit rempli avec la première variable il faut que la ligne de code  "texte = "";" soit placer dans la boucle for dessous la ligne "tab01[i] = texte;", si elle est mise juste après en dehors de la boucle for tout mon tableau ce rempli avec la valeur de la première variable

            aurais-tu une idée de ce qui peut provoquer ça.?

            en te remerciant si tu veux bien y jeter un œil car ça fais plusieurs heure que je tourne autour sans réellement comprendre a quel moment et comment ton code récupère le bout de string suivant...

            void loop()
            {
            
              // tab01\n\n150\n180\n200\n
            
              //sms qui arrive a rentré dans la condition if (texte == "tab01")
              //a enregistré la première variable mais ne veut pas enregistrer les autres même si présente sur le port serie.
              //si dans la boucle for j'enlève la ligne texte = ""; et que je la met juste après cette boucle le tableau ce rempli avec la valeur de la première variable (150 ici)
            
              if (SIM900.available() > 0)
              {
                char c = SIM900.read();
                if ( c == '\n' )
                {
                  if (texte == "tab01")
                  {
                    digitalWrite(pompe, HIGH);
            
                    // boucle while pour remplir le tableau
            
                    while (SIM900.available () > 0 )
                    {
                      if (SIM900.available() > 0)
                      {
                        char c = SIM900.read();
                        if ( c == '\n' )
                        {
                          for (int i = 0; i < 5; i++)     //enregistrement de 3 variables dans le tableau
                          {
                            tab01[i] = texte;
                            
                          }
                          texte = "";
                        }
                        else
                        {
                          texte += c;
                        }
                      }
                    }
            
                  }
            
                  texte = "";
                }
                else
                {
                  texte += c;
                }
              }
            
            
            
            
              Serial.print ("case 1 = ");
              Serial.println(tab01 [0]);
              Serial.print ("case 2 = ");
              Serial.println(tab01 [1]);
              Serial.print ("case 3 = ");
              Serial.println(tab01 [2]);
              Serial.print ("case 4 = ");
              Serial.println(tab01 [3]);
              Serial.print ("case 5 = ");
              Serial.println(tab01 [4]);
            
            
            }



            édit....

            en faisant d'autre tests je m'aperçois que si mes variables comporte un seul chiffre c'est la troisième variable qui va remplir le tableau, si 2 chiffres c'est la deuxième variable et a partir de 3 chiffres c'est la première variable qui sera appliquer au tableau....

            a ni rien comprendre....
                  



            -
            Edité par SebastienDuffrene 18 août 2021 à 0:41:32

            • Partager sur Facebook
            • Partager sur Twitter
              22 août 2021 à 11:30:08

              Le Serial est asynchrone, ce qui signifie que les caractères arrivent un par un à une vitesse plus ou moins aléatoire suivant la charge de travail du Sim900.

              Par exemple, il se peut très bien que le SIM900 t'envoie d'abord un premier bloque du genre "tab01\n\n1" suivi d'un second bloc "50\n180\n200\n".

              Si tu mets une boucle while (SIM900.available () > 0 ), rien ne te garantie qu'elle va s'exécuter sur tout le contenu reçu.

              Comme dis plus haut, si le SIM900 envoie envoie en 2 blocs, alors ta boucle while va s'arrêter.

              La seule solution, c'est de faire un bout de code qui traite les caractères un par un à chaque fois qu'il y en a un de reçu :

              - si c'est un caractère autre que \n, on l'ajoute à la chaine en cour de réception

              - si c'est un \n, on l'ajoute au tableau et on incrément l'index pour la prochaine réception.

              Exemple:

              string tab01[5]; // Variable globale contenant le tableau de réception
              string texte;    // Variable globale contenant la chaine en cours de réception
              int tabidx = 0;  // Variable globale contenant l'index d'enregistrement dans le tableau
               
              void loop()
              {
              
                  // Si un caractère est dispo
                  if(Serial.available() > 0)
                  {
                      
                      // On le lit
                      char c = Serial.read();
                      
                      // Si ce n'est pas un \n, on l'ajoute à la chaine en cours de réception
                      if ( c != '\n' ) {
                          
                          texte += c;
                      
                      // Et si c'est un \n, on enregistre la chaine dans le tableau
                      } else {
                          
                          // Enregistrement dans le tableau
                          tab[tabidx] = texte;
                          
                          // Effacement de la chaine en cours, pour en recommencer une nouvelle vierge
                          texte= "";
                          
                          // Incrémentation index (pour que la prochaine chaine soit engistrée au prochain index du tableau quand le \n sera reçu)
                          tabidx++;
                          
                      }
                      
                  }
                  
                  // Et si tout est reçu, on affiche
                  if (tabidx == 5) {
                      Serial.print ("case 1 = ");
                      Serial.println(tab01 [0]);
                      Serial.print ("case 2 = ");
                      Serial.println(tab01 [1]);
                      Serial.print ("case 3 = ");
                      Serial.println(tab01 [2]);
                      Serial.print ("case 4 = ");
                      Serial.println(tab01 [3]);
                      Serial.print ("case 5 = ");
                      Serial.println(tab01 [4]);
                      
                      // Et retour à 0 pour recommencer à remplir le tableau
                      tabidx = 0;
                      
                  }
                  
              }



              • Partager sur Facebook
              • Partager sur Twitter

              problème String avec Serial.readString()

              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
              • Editeur
              • Markdown