lundi 12 avril 2021

ARDUINO : le moniteur série


 

 ARDUINO : le moniteur série

 

Le moniteur série est un outil indispensable au développement d'un logiciel sur ARDUINO. Beaucoup de débutants ignorent même son existence, ce qui est bien dommage.

1. Mise en œuvre

On peut lancer cet outil à partir du menu "Outils / Moniteur série", après avoir branché une carte, en ayant choisi au préalable le port correspondant à la carte branchée, à l'aide du menu "Outils / port".

Voici un petit sketch qui affiche des informations simples :

void setup() {
  Serial.begin(115200);
  Serial.println("Test ARDUINO");
}

void loop() {
  for (int i = 0 ; i < 10 ; i++) {
    Serial.print("compteur : ");
    Serial.println(i);
    delay(1000);
  }
  delay(10000);
}

Ce sketch, si on le lance avec le moniteur série ouvert affichera les informations suivantes :

On voit tout de suite quel est l'intérêt d'un pareil outil, qui servira principalement à mettre au point son logiciel et vérifier que tout se passe bien.

On peut ainsi suivre le déroulement de l'exécution de son logiciel, afficher des variables, des textes, etc.

En bas de la fenêtre, un menu permet de sélectionner la vitesse de transmission, ici 115200 baud, conformément à ce qui est écrit dans le code :

  Serial.begin(115200);

Par pitié ne choisissez pas de vitesse inférieure, 9600 baud par exemple, comme on le voit beaucoup trop souvent. Cette vitesse appartient au passé.

L'autre menu permet de choisir le caractère de fin lorsque l'on entre une chaîne de caractères dans la zone de texte sous le titre (Aucun, NL, CR, les deux).

2. print() ou println()

Ces deux méthodes sont presque identiques, mis à part que println() affiche un caractère '\n', ou NEWLINE, à la fin de la ligne. Autrement dit le prochain affichage se fera sur la ligne suivante.

Ces deux méthodes acceptent un argument de type int, long, char, char [], float, etc.

Quelques petits détails :

Afficher un nombre flottant :

  float f = 123.456;
  Serial.println(f, 3);  // permet d'afficher 3 décimales (2 par défaut)

Afficher un nombre en hexadécimal :

  int x = 123;
  Serial.println(x, HEX);

3 autres options existent : OCT (octal), DEC (décimal), BIN (binaire).

3. Serial.printf() sur ESP8266 et ESP32

La méthode printf() de l'objet Serial n'est pas disponible sur les plateformes ARDUINO, mais elle est présente sur ESP8266 et ESP32.

  for (int i = 0 ; i < 10 ; i++) {
    Serial.print("compteur : ");
    Serial.println(i);
  }

Avec Serial.printf() ces deux lignes pourront être remplacées par une seule :

  for (int i = 0 ; i < 10 ; i++) {
    Serial.printf("compteur : %d\n", i);
  }

La chaîne "%d" est ce que l'on appelle une chaîne de formatage, et le programme va remplacer cette chaîne par la valeur de l'argument suivant, dans notre cas une variable entière nommée i.

printf() n'ajoute pas de caractère de fin de ligne. Il faut l'ajouter : \n

Différents formats sont possibles :

  • %d : afficher un entier
  • %l : afficher un entier long
  • %u : afficher un entier non signé
  • %lu : afficher un entier long non signé
  • %c : afficher un caractère
  • %s : afficher une chaîne de caractères

Afficher plusieurs variables est possible :

  for (int i = 0 ; i < 10 ; i++) {
    int j = i * 10;
    char s[] = "blabla";
    Serial.printf("compteurs : %s %d %d\n", s, i, j);
  }

Je vous renvoie à la documentation :

https://www.cplusplus.com/reference/cstdio/printf/

4. printf() sur ARDUINO

Pour ceux qui viennent du monde C standard, il existe éventuellement une possibilité d'utiliser printf() sur ARDUINO, et là je parle de la fonction C standard printf(), pas de la méthode Serial.printf().

printf() est disponible sur ARDUINO, mais elle n'affiche rien sur la sortie standard, car celle-ci n'est pas redirigée vers un port série précis. La sortie standard existe bien mais il faut lui affecter un flux. On procède comme ceci :

static FILE uartout = {0} ;

static int console_putchar (char c, FILE *stream)
{
  if (c == '\n') Serial.write('\r');
  Serial.write(c);
  return 0;
}

void setup(void)
{
  Serial.begin(115200);
  Serial.println("printf() sur ARDUINO");
  fdev_setup_stream (&uartout, console_putchar, NULL, _FDEV_SETUP_WRITE);
  stdout = &uartout;
}

// Ensuite les fonctions standard C putchar(), printf() et puts() sont parfaitement utilisables :

void loop() {
  for (int i = 0 ; i < 10 ; i++) {
    printf("compteur : %d\n", i);
    delay(1000);
  }
  delay(10000);
}

printf() n'ajoute pas de caractère de fin de ligne. Il faut l'ajouter : \n

Les appels à delay() sont bien entendu facultatifs.

5. sprintf(), snprintf()

Ces fonctions sont disponibles sur ARDUINO. Elles réalisent la même opération que printf(), mais dans une chaîne de caractères, que l'on peut ensuite afficher :

  for (int i = 0 ; i < 10 ; i++) {
    char s[15];
    sprintf(s, "compteur : %d", i);
    Serial.println(s);
  }
 
Pour plus de sécurité il est préférable d'utiliser snprintf() :

  for (int i = 0 ; i < 10 ; i++) {
    char s[15];
    snprintf(s, 15, "compteur : %d", i);
    Serial.println(s);
  }

On évitera ainsi les débordements si la chaîne s est trop courte pour contenir le résultat.

6. dtostrf()

Pourquoi utiliser dtostrf() ?

Toujours pour une question de mémoire disponible, le fonction sprintf() n'accepte pas les chaîne de formatage du type flottant : %f

  float f = 1.234;
  char s[10];
  dtostrf(f, 5, 3, s);
  Serial.print("valeur : ");
  Serial.println(s); 

Ses paramètres sont les suivants :

char *dtostrf(double val, signed char width, unsigned char prec, char *s)

val : la valeur flottante

width : la longueur totale, y compris le point

prec : le nombre de décimales

s : la chaîne de caractères destinataire (de longueur suffisante)

Si le nombre de caractères à afficher est supérieur au nombre de chiffres réel, la fonction complète avec des blancs à gauche (width peut être négatif pour que les blancs soient ajoutés à droite).

Il faut bien dimensionner la chaîne fstr en fonction du paramètre width car la fonction ne vérifie pas le débordement. fstr doit être dimensionné au minimum à width + 1, car il ne faut pas oublier qu'une chaîne de caractère C se termine toujours par un caractère nul.

Un petit exemple avec printf() et dtostrf() :

void loop()
{
  float f = 6789.12345;
  char fstr[12];
  
  for (int i = 0 ; i < 10 ; i++) {
    printf("%lu result: i=%d f=\"%s\"\n", millis(), i, dtostrf(f, -10, 4, fstr));
  }   delay(10000); }

7. Plusieurs instances

Lorsque plusieurs cartes ARDUINO sont branchées sur un PC, et que l'on désire afficher les informations de ces différentes cartes, ouvrir une nouvelle fenêtre IDE ne suffit pas, car on ne pourra ouvrir qu'un seul moniteur série. Il faut lancer deux instances de l'IDE, en double-cliquant sur chaque fichier .ino.

8. alternatives

Le moniteur série de l'IDE ARDUINO n'est qu'un terminal comme il en existe des dizaines.

Sous Windows, on peut utiliser également teraterm, coolterm, et bien d'autres.

Sous Linux, minicom, picocom, etc.

9. Reset

A chaque fois que l'on lance le moniteur série, ou un autre terminal, la carte ARDUINO est redémarrée. Ceci est dû au simple fait que la ligne DTR est reliée à la broche RESET de l'ARDUINO, à travers un condensateur. Or la ligne DTR bascule à l'ouverture de la ligne série, ce qui provoque donc un RESET. C'est un moindre mal, mais il vaut mieux le savoir.

Sur une PRO MINI, par exemple, si l'on veut éviter cet inconvénient, il suffit de ne pas brancher le fil DTR du convertisseur USB, mais seulement RX, TX et GND. 

10. Utiliser le traceur série pour afficher des graphes

Dans le menu outils on trouve également le Traceur Série, qui permet d'afficher des graphes.

Un petit exemple :

void setup() {
  Serial.begin(115200);
  Serial.println("A1 A2");
}

void loop() {
  for (int i = 0 ; i < 10 ; i++) {
    float a1 = random(1000,2000)/100.0;
    float a2 = random(1000,2000)/100.0;
    a2 += 20;        // offset
    Serial.print(a1);
    Serial.print(",");
    Serial.println(a2);
    delay(500);
  }
  delay(1000);
}


Un tutoriel assez complet ici :

https://www.redohm.fr/2020/01/arduino-traceur-serie/ 

Cet outil est assez pauvre en fonctionnalités. Personnellement je préfère de très loin MatPlotLib, une librairie PYTHON.

Quelques exemples ici :

https://riton-duino.blogspot.com/2019/08/un-logger-analogique-et-digital.html

https://riton-duino.blogspot.com/2018/07/banc-de-mesure-de-consommation.html 

11. Utiliser le moniteur série pour entrer des commandes

La zone de texte sous le titre peut servir à envoyer des chaînes de caractères qui pourront être lues par le sketch, à l'aide de diverses méthodes (read(), readBytesUntil(), parseInt(), etc.).

Je vous renvoie à cet article :

https://riton-duino.blogspot.com/2019/12/commander-un-arduino-par-la-ligne-serie_21.html

12. Conclusion

Le moniteur série est un outil que l'on devrait mettre en œuvre systématiquement au démarrage de l'écriture d'un code. On ne peut en tirer que des bénéfices, surtout en phase de mise au point d'un programme.


Cordialement

Henri


4 commentaires:

  1. Bonjour, merci pour cet article intéressant sur le moniteur série. J'aimerais aller un peu plus bas niveau dans le codage des fonctions de la bibliotheque Serial de Arduino. Pourriez vous m'indiquer ou je peux trouver le code source de la librairie Serial d'Arduino. Merci

    RépondreSupprimer
    Réponses
    1. Dans le répertoire packages/arduino/hardware/avr/1.6.207/cores/arduino/abi.cpp du répertoire Arduino15
      1.6.207 dépend de la version IDE
      Arduino15 est situé ici : C:\Users\{username}\AppData\Local\Arduino15 ou C:\Users\{username}\Documents\ArduinoData\packages
      Sous Linux: ~/.arduino15

      Supprimer
  2. moniteur serie ouvert comment resoudre le broleme

    RépondreSupprimer