Partage
  • Partager sur Facebook
  • Partager sur Twitter

Fonctionnement Serial.available() et Serial.read()

Arduino

    23 mai 2019 à 21:10:45

    Bonjour, d'abord merci de prêter attention à ce message, et un petit peu de contexte. Je cherche à communiquer entre Arduino et Python, mais je n'ai pas trouvé de manière simple de le faire. Dans quel sens : Python vers Arduino. Communiquer quoi : des chaînes de caractères. Problème : lesdites chaînes de caractères.

    En fait, j'ai réussi à transmettre des "bytes" (donc des caractères si j'ai bien compris), mais je ne peux pas envoyer une chaîne de caractères entières directement me semble-t-il. Pour être plus précis, il me semble que Serial.read() ne lise qu'un caractère à la fois et ne puisse se charger d'une chaîne complète. En effet, d'après quelques tests avec le moniteur série, il apparaît qu'un Serial.println() puisse lui se charger sans problème d'une chaîne de caractères. (Ce Serial.println() me sert à vérifier l'état de mes variables, par exemple la variable qui est censée recevoir la chaîne complète).

    Mon idée était de vérifier combien de caractères avaient été passé (avec le Serial.available()), de lire ces caractères (avec une boucle for comportant un Serial.read()), puis de les renvoyer sur le moniteur série (avec le Serial.println()) pour vérifier que j'en avais bien reçu l'intégralité (*code plus bas). Or cette méthode ne marche pas, et je pense que cela vient de mon manque de connaissances sur les fonctions Serial.available() et Serial.read(). Si quelqu'un pouvait m'éclairer sur ce sujet, la documentation d'Arduino n'aide pas vraiment à en comprendre le fonctionnement. 

    En plus de ce problème de méconnaissance, il me semble également que le Serial.println() influencerait le Serial.available() suivant non ? (Cela induirait une boucle quelque peu désagréable).

    * Code :

    int serial_past = 0;
    
    void setup(){
      Serial.begin(9600);
    }
    
    String read_data(int a){          
      char userInput;
      String chaine = "";
      for(int i = 0; i<a; i++){
        userInput = Serial.read();
        chaine = String(chaine+userInput);
      }
    }
    
    void return_data(String a){
      Serial.println(a);
    }
    
    void loop(){
      String input;
      Serial.println(Serial.available());
      Serial.println(serial_past);
      if(Serial.available()>serial_past){
        input = read_data(Serial.available()-serial_past);
        return_data(input);
        serial_past = Serial.available();
      }
    }

    Merci à tous ceux qui ont pris le temps de jeter un œil à ce message !  

    • Partager sur Facebook
    • Partager sur Twitter
      24 mai 2019 à 1:09:56

      Serial.available() donne le nombre de caractère disponible dans le buffer, ce n'est pas le nombre total de caractère, tu n'as pas besoin de serial_past.

      while (Serial.available() > 0) {
        chaine += char(Serial.read());
      }
      
      • Partager sur Facebook
      • Partager sur Twitter
        24 mai 2019 à 19:10:31

        Merci de ta réponse ! 

        J'ai toutefois un problème, je n'arrive pas à la mettre en oeuvre :-°

        Par exemple, si je fais le code suivant, quand j'envoie "Test" dans le moniteur série, il est renvoyé "T" puis "e" puis "s" puis "t" (une lettre par ligne) mais je ne comprends pas pourquoi !

        Code : 

        String chaine;
        
        void setup(){
          Serial.begin(9600);
        }
        
        void loop(){
          while(Serial.available()>0){
            chaine += char(Serial.read());
          }
          if(chaine != ""){
            Serial.println(chaine);
            chaine = "";
          }
        }

        Mon incompréhension vient du fait que je pensais que le while() tournait jusqu'à ce que tous les caractères entrés soient passés (donc que l'on récupère tous les caractères), sans sortir de la boucle avant la fin. Or si j'ai les différentes lettres qui s'affichent, c'est donc que la boucle n'est activée que caractère par caractère.

        Merci des possibles réponses !

        EDIT : J'ai finalement essayé de rajouter un delay() de 2ms dans le while(), ce qui permet d'attendre un peu pour revérifier le buffer. ET CA MARCHE ! Toutefois je voudrais savoir si il y a d'autres méthodes sans delay() ou non.

        Code EDIT :

        String chaine;
        
        void setup(){
          Serial.begin(9600);
        }
        
        void loop(){
          while(Serial.available()>0){
            chaine += char(Serial.read());
            delay(2);
          }
          if(chaine != ""){
            Serial.println(chaine);
            chaine = "";
          }
        }

        Voilà !

        -
        Edité par PèlegrinGrégoire 24 mai 2019 à 19:23:25

        • Partager sur Facebook
        • Partager sur Twitter
          24 mai 2019 à 20:07:15

          Utiliser un délai, n'est pas viable. Il te faut définir un protocole pour savoir le nombre d'octet envoyé. SI tu n'as que des chaînes, c'est simple, les premiers octets indiquent la taille, les autres sont les caractères.

          Quelque chose dans ce goût-là:

          enum class ProtocolState {
            Size,
            Data,
          };
          ProtocolState state = ProtocolState::Size;
          unsigned len;
          
          void setup(){
            Serial.begin(9600);
          }
          
          void loop(){
            switch (state) {
              case ProtocolState::Size:
                if (Serial.available() > 1) {
                  // lecture sur 2 octets
                  len = Serial.read() << 8;
                  len |= Serial.read();
                }
                state = ProtocolState::Data;
                break;
              case ProtocolState::Data:
                if (Serial.available() >= len) {
                  String chaine;
                  for (unsigned i = 0; i < len; ++i) {
                    chaine += char(Serial.read());
                  }
                  Serial.println(chaine);
                  state = ProtocolState::Size;
                }
                break;
            }
          }

          (Pas testé)

          • Partager sur Facebook
          • Partager sur Twitter
            1 juin 2019 à 15:50:48

            Houla, effectivement, il faudrait faire ça ! 

            Après, j'ai réussi à le faire également avec un serialEvent()

            • Partager sur Facebook
            • Partager sur Twitter

            Fonctionnement Serial.available() et Serial.read()

            × 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