Bonjour, nouveau sur le site. Une petite question bète pour commencer

D'abord bonjour à tout le forum. Je commence à me passionner pour arduino. Le premier problème auquel je me confronte est que sur une communication sérielle entre un ardunio uno qui fait une Serial.println() toutes les secondes d'un nombre incrémenté de même (donc 1, 2, 3, etc) j'ai un résultat parfait sur l'IDE arduino et sa sortie sérielle. Mais quand je fais le même exercice avec un programme développé sur QT j'ai des Line Feed (LF ou 0x0A) qui apparaissent de manière aléatoire. Et ce sur une vitesse de 9600 bauds. Lorsque je passe en 57600 bauds il n'y a plus de problème. Quelle est l'explication à ce phénomène ?

Bonjour et bienvenue,

Merci de prendre quelques minutes pour lire les bonnes pratiques du forum francophone et les appliquer.

Merci de donner un peu plus f'informations.
Le code utilisé, par exemple.

Quand vous faites un println ça rajoute un retour chariot et une nouvelle ligne à la fin automatiquement (CR LF ou "\r\n")

Ouais ben désolé, j'ai lu toutes les "bonnes pratiques" j'ai fouillé dans les forums pour trouver une piste à mes questions.....
Là, quand je fais un println(texteX) ça envoie un LN sur la voie série. Donc, à la réception sur le moniteur série de l'IDE arduino j'ai : texte1LNtexte2LN.....
ce qui donne à l'écran
texte1
texte2
texte3
.....etc
Et ce avec une communication en 9600 bauds
Je fais le même exercice avec une application développée en QT et dans ce cas j'ai des LF qui apparaissent de manière aléatoire et ce avec une vitesse de 9600 bauds.
texte1
texte2

texte3
texte4
texte5
texte6

texte7
Or, avec une vitesse de 57600bauds je n'ai pas ce problème sur mon application QT.
Application QT qui utilise les librairies qextserialport
Voilivoilou. J'espère avoir été assez clair

Vous voulez dire que c’est une application qui reçoit les données de l’Arduino?

Comme dit précédemment println envoie CR set LF.

Sinon ce que l’on vous demande pour vous aider c’est de Poster les codes et détailler le matériel et sa connexion

Oui, c'est bien une application QT qui écoute sur le port série

        port = new QextSerialPort();
        port->setPortName(ui->cbPort->currentText());
        port->setBaudRate(getBaudRateFromString(ui->cbSpeed->currentText()));
        port->setParity(PAR_NONE);// parité
        port->setStopBits(STOP_1);// nombre de bits de stop
        port->setDataBits(DATA_8);// nombre de bits de données
        port->setFlowControl(FLOW_OFF);// pas de contrôle de flux
        port->open(QextSerialPort::ReadWrite);
        ui->pbConnect->setText("Deconnecter");
        // on fait la connexion pour pouvoir obtenir les évènements
        connect(port,SIGNAL(readyRead()), this, SLOT(readData()));
        connect(ui->teEmit,SIGNAL(textChanged()),this,SLOT(sendData()));
        if(port->isOpen())
        {
            ui->lMessage->setText("connecté");
        }
        else
        {
            ui->lMessage->setText("erreur de connexion");
        }

et le slot de lecture readData()

void MainWindow::readData()
{
    QByteArray array = port->readAll();
    ui->teRecept->insertPlainText(array);
}

Le code de l'arduino est très simple

int i = 0;
void setup() 
{
  // put your setup code here, to run once:

  Serial.begin(9600);
  Serial.println("coucou");
}

void loop() 
{
  // put your main code here, to run repeatedly:
  Serial.println(i);
  if (i < 1000)
  {
    i++;
  }
  delay(1000);
}

Voilà.
Donc, en 9600 bauds la réception sur le moniteur série de l'IDE arduino affiche bien
1
2
3
4
et ainsi de suite et sans "trous" entre deux nombres
Sur mon application Qt il y a des "trous" soit des LF supplémentaires de manière aléatoire
1
2

3
4

5
6
7
8
9

10 etc.....
et je dis bien que ce sont des LF uniquement (vérifié sur un éditeur hexadécimal)
Pour info je bosse sur Debian11 et avec un arduino uno rev3
Or ce problème n'arrive pas avec une vitesse de 57600 bauds
Autre test réalisé avec un arduino nano : le problème ne se pose pas.
Autre info, j'ai deux câbles différents pour le uno et le nano. Le premier mesure 1.8m et l'autre 50cm.
Voilà, j'espère avoir été exhaustif.

il ne faut pas utiliser readAll(). comme dit la doc

This function has no way of reporting errors; returning an empty QByteArray can mean either that no data was currently available for reading, or that an error occurred. This function also has no way of indicating that more data may have been available and couldn't be read.

il faut prendre la même approche asynchrone qu'on prendrait sur un Arduino. Vous lisez les caractères quand ils arrivent et vous les imprimer.

par exemple vous pourriez dire si un octet est dispo (avec bytesAvailable()) alors le lire cet octet (avec read et une demande de 1 octet) et l'imprimer.

Comme votre arduino émet le passage à la ligne, votre appli QT émet aussi le passage à la ligne.

peut-être un truc comme cela (tapé ici, ça fait une éternité que je n'ai pas utilisé Qt) avec une petite classe

#include <QCoreApplication>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QObject>

class LecteurPortSerie : public QObject
{
    Q_OBJECT

  public:
    LecteurPortSerie(QSerialPort *portSerie) : portSerie(portSerie) {}

  public slots:
    void gestionReception()  {
      QByteArray donnees;
      while (portSerie->bytesAvailable() > 0)  {
        donnees.append(portSerie->read(1));
      }
      qDebug() << "Données reçues :" << donnees;
    }

  private:
    QSerialPort *portSerie;
};

int main(int argc, char *argv[]) {
  QCoreApplication a(argc, argv);

  QSerialPort portSerie;
  portSerie.setPortName("COM1"); // Remplacez par le nom de votre port série câblé en dur pour le test
  portSerie.setBaudRate(QSerialPort::Baud9600); // 9600 bauds
  portSerie.setDataBits(QSerialPort::Data8); // 8N1 est le défaut pour Arduino
  portSerie.setParity(QSerialPort::NoParity);
  portSerie.setStopBits(QSerialPort::OneStop);

  if (portSerie.open(QIODevice::ReadWrite))  {
    LecteurPortSerie lecteur(&portSerie);
    QObject::connect(&portSerie, &QSerialPort::readyRead, &lecteur, &LecteurPortSerie::gestionReception);
    qDebug() << "Port série ouvert avec succès.";
    return a.exec();
  } else {
    qDebug() << "Impossible d'ouvrir le port série.";
    return 1;
  }
}

Merci pour votre réponse.
Alors,

  1. j'ai modifié le slot readData comme ceci
void MainWindow::readData()
{
    QByteArray donnees;
    while (port->bytesAvailable() > 0)
    {
        donnees.append(port->read(1));
    }
    ui->teRecept->insertPlainText(donnees);
}

et ce avec la bibliothèque QtExtSerialPort
2. J'ai modifié tout le code en utilisant la bibliothèque QtSerialPort

void MainWindow::on_pbConnect_clicked()
{
    if (ui->pbConnect->isChecked())
    {
        port->setPortName(ui->cbPort->currentText());
        port->setBaudRate(getBaudRateFromString(ui->cbSpeed->currentText()));
        port->setDataBits(QSerialPort::Data8); // 8N1 est le défaut pour Arduino
        port->setParity(QSerialPort::NoParity);
        port->setStopBits(QSerialPort::OneStop);
        if (port->open(QSerialPort::ReadWrite))
        {
            ui->pbConnect->setText("Deconnecter");
            // on fait la connexion pour pouvoir obtenir les évènements
            connect(port,SIGNAL(readyRead()), this, SLOT(readData()));
            connect(ui->teEmit,SIGNAL(textChanged()),this,SLOT(sendData()));
            ui->lMessage->setText("connecté");
        }
        else
        {
            ui->lMessage->setText("erreur de connexion");
        }
    }
}

en passant sur les déclarations de setBaudrate et du slot de réception qui sont les mêmes.....
Et j'ai toujours ces maudits Line Feed qui apparaissent de manière aléatoire...
Je me permets de douter de la qualité de mon câble usb acheté pour 4€ au PasClerc......
Pis désolé, je ne réponds pas vite, mais c'est que j'ai encore des oignons a récolter avant la pluie.....

En fait, plus la vitesse en bauds est rapide moins les LF réfractaire apparaissent.
Peut-être n'est-ce que le simple fait d'une mise à jour pas parfaite du QTextEdit dans QT...
Ou de ce maudit câble usb ?
Je teste encore avec le Nano et un petit câble usb.

Bon, ben avec le Nano et son petit câble usb, il n'y a aucun problème. Donc, soit l'arduino uno merde, soit le câble que j'utilise absorbe des perturbations.
Mais comment se fait-ce que sur le moniteur série de l'IDE arduino tout se passe comme il faut.... ?
Bon, badaboum, tout ce titouin pour un problème physique ? peut-être. Mais si ça peut être utile comme expérience, ben tant mieux.
Bonne soirée

Faites une lecture jusqu’à avoir reçu le ’\n’

Ouaip, une bonne solution, mais j'aimerais bien savoir quelle est la cause. Vais trouver un autre câble... Suis teigneux

je serai tenté d’explorer

  • le fait qu’il y a un timeout sur l’entrée série avec un buffer vide et vous faites donc une impression d’un message vide
  • la possibilité que la réception s’arrête au \r et que le message suivant soit le \n

Testez la longueur de la chaîne avant d’imprimer et si c’est 0 ça prêche pour le timeout at exemple. Si la chaîne n’est pas vide, Testez aussi si le premier caractère n’est pas un chiffre - c’est serait aussi une bonne indication.

Parce qu’il affiche les caractères des qu’ils arrivent, pas de buffering pour affichage ultérieur

Ok, mais je ne comprends toujours pas pourquoi avec un arduino Nano, tout se passe très bien. Pas de "trous".
Bon j'ai modifié ma fonction de lecture comme suit

void MainWindow::readData()
{
    QByteArray donnees;
    while (port->bytesAvailable() > 0)
    {
        donnees.append(port->read(1));
    }
    if (donnees.length()>0)
    {
        if (donnees[0] >= '0' && donnees[0] <= '9')
        {
            ui->teRecept->insertPlainText(donnees);
        }
        else
        {
            QString str = "premier char = ";
            int i = char(donnees[0]);
            str += QString::number(i);
            
            ui->teRecept->insertPlainText(str);
        }
        
    }
    else
    {
        ui->teRecept->setText("données vides");
    }
}

Et là j'ai plein de CR et de LF en premier caractère de mes données. C'est encore pire qu'avant.

Testez aussi si le premier caractère n’est pas un chiffre - c’est serait aussi une bonne indication.

Une indication qui indiquerait quoi ?

Autre indication, si je lis de cette manière

void MainWindow::readData()
{
    while (port->bytesAvailable() > 0)
    {
        ui->teRecept->insertPlainText(port->read(1));
    }
}

j'obtiens systématiquements et régulièrement deux LF consécutifs entre chaque nombre :
1

2

3

4 etc....

l'arduino envoie \r et \n quand vous faites un println()
je suppose que chacun d'entre eux crée un passage à la ligne

essayez de zapper le '\r'

void MainWindow::readData() {
    char caractereRecu;
    while (port->bytesAvailable() > 0) {
        port->getChar(&caractereRecu);                            // Lire un octet du port
        if (caractereRecu != '\r') {                              // Vérifie si le caractère reçu n'est pas '\r'
            ui->teRecept->insertPlainText(QChar(caractereRecu));
        }
    }
}

Yep ! Nickel !
J'avais essayé un truc comme ceci

void MainWindow::readData()
{
    QByteArray qba;
    while (port->bytesAvailable() > 0)
    {
        qba += port->read(1);
    }
    if ((qba.length() > 0) && (qba[0] != '\r'))
    {
        ui->teRecept->insertPlainText(qba);
    }
}

et ça me donnait ceci
12

3

4

5

67

8

9
En tous cas, merci beaucoup !!!
A la prochaine

vous pourriez aussi ne pas émettre le \r :wink:

au lieu de faire

  Serial.println(i);

qui envoie le nombre suivi de \r et \n, faites

  Serial.print(i);
  Serial.write('\n'); // on n'envoie qu'un line feed

Effectivement. Ca marche aussi avec

Serial.print('\n');

Et encore merci