IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Arduino Discussion :

Défaut de transmission série avec Windows 10


Sujet :

Arduino

  1. #1
    Candidat au Club
    Homme Profil pro
    Amateur d'informatique
    Inscrit en
    Novembre 2014
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Amateur d'informatique

    Informations forums :
    Inscription : Novembre 2014
    Messages : 6
    Points : 2
    Points
    2
    Par défaut Défaut de transmission série avec Windows 10
    Bonjour à tous,

    J’ai récemment changé d’ordinateur et je rencontre un problème que je ne parviens pas à régler.

    J’ai développé il y a quelques années une application Arduino (UNO R3) pour le contrôle d’une matrice de LED RGB à partir d’un ordinateur. Cette application envoie le motif d’éclairage comme une trame d’octet.

    Jusqu’à présent, j’utilisais un ordinateur équipé de Windows 7 (64 bit, version 1.6.8 de l’IDE) et je n’ai rencontré aucun problème. J’ai remplacé l’ordinateur par un autre plus récent équipé de Windows 10 et cela ne fonctionne plus correctement.

    Le téléchargement se déroule bien, la communication bi-directionnelle entre l’ordinateur et l’Arduino est fonctionnelle mais dès que j’envoie une trame un peu longue (au maximum 180 octets), elle n’est pas transférée entièrement.

    Cela semble dépendre de la vitesse de transfert : à 57600 baud, le problème apparaît pour une trame de 65 octets, pour une vitesse plus lente, la longueur de la trame est un peu plus longue mais encore insuffisante. De même, si je réduis le délai imposé ici à 1200 µs, quelques octets supplémentaires sont transmis mais c'est insuffisant.

    J’ai testé plusieurs versions d’IDE (1.6.2, 1.6.8, 1.8.12) sans résultats.

    J’ai testé sur d’autres PC en Windows 7 et Windows 10 et le problème n’apparait que quand je télécharge le firmware avec Windows 10.

    Si je télécharge le firmware avec Windows 7 mais que l’utilise l’application avec Windows 10, cela fonctionne très bien.

    J’ai le même défaut avec des Arduinos officiels et des clones.

    Auriez-vous déjà rencontré ce problème (je n'ai rien trouvé de semblable sur Internet) ? Je place le code Arduino en fin de message.

    Par avance merci.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //----------------------------------------------------------------------:
    //   ---         Réception des octets envoyés par le PC           ---   :
    //----------------------------------------------------------------------:
    unsigned char In[NPIX * 3 + 4];      // Tableau de réception des paramètres.
    unsigned int  LgMsg;                 // Longueur du message reçu.
     
        unsigned int i = 0;              // Compteur de boucle.
     
        while (Serial.available())
        {
          In[i++] = Serial.read();
          delayMicroseconds(1200);
        }
        LgMsg = i - 1;        // Longueur du message = nombre d'octets recus.
     
    Serial.println(LgMsg);

  2. #2
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    Bonjour

    il n'est jamais bon d'essayer de deviner le tempo d'une communication asynchrone
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        while (Serial.available())
        {
          In[i++] = Serial.read();
          delayMicroseconds(1200);
        }
    --> vous allez sans doute vider le buffer de réception avant d'avoir tout reçu

    comment se fait l'envoi de l'information? avez vous un marqueur de début et de fin de trame?

  3. #3
    Candidat au Club
    Homme Profil pro
    Amateur d'informatique
    Inscrit en
    Novembre 2014
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Amateur d'informatique

    Informations forums :
    Inscription : Novembre 2014
    Messages : 6
    Points : 2
    Points
    2
    Par défaut
    Bonjour,

    Merci pour ce premier retour.

    Marqueur de début de trame : plus ou moins. Le début de la trame débute par 98, 99 ou 100.

    Marqueur de fin de trame : caractère de fin de ligne (code ASCII 10).

  4. #4
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    Citation Envoyé par Big Mama Voir le message
    Marqueur de fin de trame : caractère de fin de ligne (code ASCII 10).
    OK donc au lieu de faire un while() qui attend la fin du buffer, faites un while qui attend la fin de ligne et il n'y a pas besoin du delay()

    il faut s'assurer bien sûr de ne pas déborder du tableau prévu donc tester l'indice et décider de ce que vous faites des caractères en trop si la ligne est trop longue (laisser tomber cette ligne et attendre la prochaine ou les ignorer par exemple)

  5. #5
    Candidat au Club
    Homme Profil pro
    Amateur d'informatique
    Inscrit en
    Novembre 2014
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Amateur d'informatique

    Informations forums :
    Inscription : Novembre 2014
    Messages : 6
    Points : 2
    Points
    2
    Par défaut
    Merci Jay M,

    C'est une piste que je voulais tenter, en particulier en utilisant "Serial.readBytesUntil" ou "Serial.readStringUntil". Je vais tester çà car le délai ajouté initialement, ce n'est pas très propre et ne m'a jamais satisfait, mais cela fonctionnait.

    Ce que je ne comprends pas, c'est pourquoi ce firmware fonctionne mal quand il est compilé et téléchargé sous Windows 10. Pour information, si je génère le binaire compilé sous Windows 7 puis télécharge ce binaire ".HEX" avec Windows 10 et un programme maison, cela fonctionne parfaitement. C'est comme si la compilation générait un binaire différent selon qu'on la réalise avec Windows 7 ou Windows 10.

    Je ferai aussi un test avec linux.

  6. #6
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    Je suis sur Mac et Linux donc je ne peux pas vous dire pourquoi Windows se comporte bizarrement, tout ce que je pourrais dire c’est que je ne suis pas surpris

    Blague à part, le driver série qui s’occupe des envois n’est sans doute pas le même et votre ordinateur a aussi avec le nouveau système une performance différente. Vous aviez mis un délai qui devait être adéquat pour votre ancien environnement mais c’était de toutes façons un bug en attente. La voie série doit être lue quand les octets arrivent et si le buffer est vide ça ne veut pas forcément dire que le message est terminé, juste qu’un octet n’est pas encore arrivé.

    Je vous déconseille fortement les fonctions readByte or readString etc car elles incluent un timeout et vous ne saurez pas si ce que vous obtenez est du au time out ou à la vraie fin de communication.

    Pour votre cas c’est super simple, utilisez read pour remplir le buffer jusqu’au caractère nouvelle ligne et codez cela en asynchrone pour ne pas rester dans l’attente : une fonction qui retourne vrai par exemple quand un nouveau message est arrivé et dans la loop vous mettez juste
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    void loop() {
      if (nouveauMessage()) {
        // gérer ici le message 
      } else {
        // Pas de nouvelle commande
      }
    }

  7. #7
    Candidat au Club
    Homme Profil pro
    Amateur d'informatique
    Inscrit en
    Novembre 2014
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Amateur d'informatique

    Informations forums :
    Inscription : Novembre 2014
    Messages : 6
    Points : 2
    Points
    2
    Par défaut
    Bug en attente : tout à fait vrai. J'ai prévu de corriger cela avec un transfert plus robuste (code de début de ligne, longueur de la trame, checksum en fin de trame et code de fin de trame) et puis le temps à passé. Mais "les bugs finissent toujours par vous rattraper" (proverbe chinois ancestral).

    J'ai eu des soucis avec readByte et je vais donc faire simplement comme vous le suggérez.

    A suivre donc ...

  8. #8
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    j'ai en tête un simple truc comme cela

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    const byte tailleMax = 10;  // à adapter à votre besoin
    char message[tailleMax + 1]; // +1 pour rajouter un caractère nul à la fin
     
    bool nouveauMessage() {
      static byte indice = 0;
      bool messageDisponible = false;
      int r = Serial.read();
      if (r != -1) { // -1 veut dire que l'on a rien à lire
        if (r == '\n') { // marqueur de fin
          message[indice] = '\0';         // on marque la fin
          indice = 0;                     // on se prépare pour la prochaine fois
          messageDisponible = true;
        } else {
          if (indice < tailleMax) {       // on ignore les caractères en trop
            message[indice++] = (char) r; // on stocke
          } else {
            // ici éventuellement gestion de commande trop longue
          }
        }
      }
      return messageDisponible;
    }
     
    void setup() {
      Serial.begin(115200);
    }
     
    void loop() {
      if (nouveauMessage()) {
        // gérer ici le message
        Serial.print(F("Message :")); Serial.println(message);
      } else {
        // Pas de nouvelle commande
        // ...
      }
     
    }
    si vous faites tourner ce code et ouvrez le moniteur série à 115200 bauds, le 10 premiers caractères de la ligne que vous taperez et validez (si vous avez bien mis NL comme caractère de validation) vont s'afficher dans le moniteur

    Avantage = code non bloquant

  9. #9
    Candidat au Club
    Homme Profil pro
    Amateur d'informatique
    Inscrit en
    Novembre 2014
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Amateur d'informatique

    Informations forums :
    Inscription : Novembre 2014
    Messages : 6
    Points : 2
    Points
    2
    Par défaut
    Rebonjour,

    Très intéressant. Je vais regarder çà quand j'aurai un moment.

    Je progresse de mon côté sur une piste qui ressemble et qui s'inspire de vos conseils précédents. En particulier, je contrôle que les caractères reçus on des codes ASCII compris entre 32 (espace) et 122 (z).

    Cela fonctionne parfaitement avec le terminal de l'IDE (après quelques déboires et erreurs, évidemment). Je dois tester cela avec mon programme mais je progresse par sous-étapes pour éviter de mettre le bazar dans ce qui fonctionne.

    Dès que j'aurais un solution qui fonctionne, je l'expliquerais ici.

  10. #10
    Candidat au Club
    Homme Profil pro
    Amateur d'informatique
    Inscrit en
    Novembre 2014
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Amateur d'informatique

    Informations forums :
    Inscription : Novembre 2014
    Messages : 6
    Points : 2
    Points
    2
    Par défaut
    Bonjour,

    J'ai résolu mon problème en suivant les conseils de Jay M et un excellent tutoriel qui explique bien les contraintes liés à la transmission asynchrone et propose une solution très proche de celle de Jay M et qui fonctionne parfaitement.

    Ce tutoriel est accessible par le lien : https://forum.arduino.cc/t/ecouter-l...hrone/480990/4

    Merci donc à Jay M pour m'avoir indiqué la bonne direction.

  11. #11
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    super - avec ce genre d'approche vous êtes tranquille (du moins tant que la loop() ne bloque pas trop longtemps sinon il y a le risque que le buffer d'entrée (64 octets) soit saturé et que vous perdiez des octets)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Communication des [ports série] avec [Delphi] 7 sous Windows
    Par mizouz dans le forum API, COM et SDKs
    Réponses: 4
    Dernier message: 05/05/2013, 08h29
  2. Problème avec le port série sous Windows XP
    Par didou2dek dans le forum Composants VCL
    Réponses: 6
    Dernier message: 02/09/2003, 19h50
  3. QueryString avec window.Open ??
    Par christine dans le forum ASP
    Réponses: 4
    Dernier message: 29/08/2003, 09h27
  4. Réponses: 4
    Dernier message: 23/07/2003, 13h07
  5. ADSI avec windows 2000
    Par alex2205 dans le forum Windows Serveur
    Réponses: 2
    Dernier message: 25/03/2003, 16h59

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo