On utilise le moniteur série pour mettre au point le code Arduino, mais il est possible de faire bien d’autres choses. Nous allons découvrir dans cet article les principales méthodes pour imprimer (envoyer) des chaînes de caractères sur le port série. print et println pour envoyer du texte simple. La fonction printf pour convertir, formater et combiner plusieurs variables dans une même chaîne de caractère. sprintf et snprintf pour stocker le résultats dans une variable.
Accès rapide aux fonctions
print ou println printf options de printf sprintf ou snprintf (ESP32 / ESP8266 uniquement) write Macro F
Sommaire
- 1 Comment ouvrir le port série dans du code C++ Arduino ?
- 2 Imprimer du texte sur le port série avec print ou println
- 3 Comment combiner plusieurs variables avec print ou println
- 4 Combiner et formater plusieurs variables dans une chaîne avec printf
- 5 Macro F
- 6 Stocker le résultat d’une chaîne formatée avec sprintf ou snprintf dans une variable (uniquement pour ESP32 et ESP8266)
- 7 Imprimer le contenu d’un buffer de bytes avec write()
- 8 Téléverser le code Arduino des exemples
- 9 Mises à jour
Comment ouvrir le port série dans du code C++ Arduino ?
Avant de pouvoir envoyer des messages sur le port série, il est nécessaire d’initialiser la communication avec la commande Serial.begin(vitesse). Cette méthode prend comme paramètre la vitesse du port série en bauds.
Par défaut, elle est fixée à 9600 bauds.
Vous pouvez opter pour l’une de ces vitesses 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, ou 115200.
La plupart des cartes de développement actuelles supportent sans aucun problème la vitesse de 115200 bauds.
Serial.begin(115200);
Imprimer du texte sur le port série avec print ou println
La fonction print() est la fonction de base. Elle permet d’envoyer (imprimer) un caractère ou une chaine de caractères sans aucun formatage particulier.
Les caractères sont envoyés sur le port série les uns à la suite des autres.
Exemple | Résultat sur le moniteur série |
Serial.print("A"); Serial.print("B"); Serial.print("C"); |
ABC |
Pour renvoyer le curseur à la ligne (comme sur un traitement de texte), il existe plusieurs solutions :
- Utiliser la méthode println()
- Ajouter \n à la fin de la chaîne publiée
- Combiner les deux
Exemple | Résultat obtenu sur le moniteur série |
Serial.print("Une demo "); Serial.print("avec "); Serial.println("un retour à la ligne "); |
Une demo avec un retour à la ligne |
Equivalent | |
Serial.print("Une demi avec \n"); Serial.print("un retour à la ligne"); |
Une demo avec un retour à la ligne |
Comment combiner plusieurs variables avec print ou println
Comme dans la plupart des autres langages (Javascript, PHP..), le C++ autorise de combiner des chaînes à l’aide de l’opérateur +. Il faudra au préalable convertir la donnée en chaîne à l’aide de la fonction String().
Voici un exemple qui combine dans une même chaîne de caractère une variable de type entier, une variable de type float (nombre décimal) et un booléen.
int INT_VAR = 32;
float FLOAT_VAR = 32.23;
bool BOOL_VAR = true;
Serial.println("Un chaine qui combine un entier " + String(INT_VAR) + ", un décimal " + String(FLOAT_VAR) + " est un bool " + String(BOOL_VAR));
Combiner et formater plusieurs variables dans une chaîne avec printf
La méthode printf est un format de sortie standard du C++. Espressif a implémenté la méthode printf dans la classe Serial du framework Arduino-ESP32 et ESP8266. Ce n’est pas le cas avec le framework Arduino.
Comment utiliser printf sur Arduino avec PrintEx
Si vous tentez de compiler du code développé pour ESP32 ou ESP8266 sur un Arduino, vous obtiendrez une erreur de compilation si vous écrivez Serial.printf(). C’est tout simplement parce que la méthode n’a pas été développée pour le framework Arduino.
On trouve des exemples de code un peu partout sur internet pour faire cela, mais le plus facile est d’utiliser la librairie PrintEx de Christopher Andrews. Son fonctionnement est presque aussi complet que l’implémentation faite par Espressif pour l’ESP32 et ESP8266.
Sur PlatformIO, ajouter l’option suivante à votre fichier platformio.ini. Sur l’IDE Arduino, ajouter la librairie depuis le gestionnaire comme d’habitude
lib_deps =
chris--a/PrintEx @ ^1.2.0
Ensuite, déclarer PrintEx au début de votre programme
#include
Enfin, il suffit d’étendre (ajouter les fonctions) à la classe Print du framework Arduino
setup()
{
Serial.begin(155200);
PrintEx serial = Serial;
serial.printf("Hello");
}
Et maintenant on peut utiliser la fonction comme ceci
serial.printf("la pression atmosphérique est de %u hPa", pressure);
Comment utiliser printf() du framework ESP32, ESP8266 ou PrintEx
La méthode printf() permet à la fois de formater une ou plusieurs données et ensuite les combiner dans une même chaîne avant de l’envoyer sur le port série. Pour cela, il suffit de spécifier la position dans la chaîne à l’aide du caractère %.
printf("la pression atmosphérique est de %u hPa", pressure);
L’argument %specifier sera ensuite remplacé par la valeur mise en forme correspondante.
Pour formater comme on le souhaite la chaine de sortie, il est possible d’ajouter des options supplémentaires. Les options sont détaillés dans les paragraphes suivants.
%[flags][width][.precision][length]specifier
Voici un exemple qui permet de formater un nombre décimal avec un seul chiffre significatif. L’arrondi est automatique.
%.1f
On peut combiner autant de variables qu’on le souhaite. Il faudra simplement passer les variables dans le même ordre que dans la chaîne de sortie.
Attention, avec PrintEx ajouter serial. devant printf
Specifier disponibles pour convertir en chaîne
Pour pouvoir combiner des variables de natures différentes dans la chaîne de sortie, il faut indiquer à la commande printf le type de chaque données
En gras les specifiers non supportés par PrintEx
Specifier | Type de données C++ Arduino | Description | Exemple |
---|---|---|---|
d ou i | Int
Byte Word Long (préférable d’utiliser unsigned Int) |
Entier décimal signé | 392 |
u | Entier décimal non signé | 7235 | |
o | Octal non signé | 610 | |
x | unsigned long
unsigned int |
Entier hexadécimal non signé (minuscule) | 7fa |
X | Entier hexadécimal non signé (majuscule) | 7FA | |
f ou F | float
double |
Virgule flottante décimale, minuscule | 392.65 |
e | Notation scientifique exposant en minuscule | 3.9265e+2 | |
E | Notation scientifique exposant en majuscule | 3.9265E+2 | |
g | Utilisez la représentation la plus courte : %e ou %f | 392.65 | |
G | Utilisez la représentation la plus courte : %E ou %F | 392.65 | |
c | char | Caractère | a |
s | char [] | Chaîne de caractères | exemple |
n | – | Rien n’est imprimé | |
% | – | Un % suivi d’un autre caractère % écrira un seul % | % |
Option Flag (drapeau)
Le flag permet d’ajouter des caractères avant la valeur :
- Forcer l’ajout d’un signe (+ ou -)
- Insérer un espace
- Remplir avec des zéros
- Remplir avec 0x pour les nombres hexadécimaux
flag | Description |
---|---|
– | Justifiez à gauche dans la largeur de champ donnée. Par défaut, la justification est à droite de la valeur (voir l’option largeur) |
+ | Force à faire précéder le résultat d’un signe plus ou moins ( + ou – ) même pour les nombres positifs. Par défaut, seuls les nombres négatifs sont précédés du signe – |
(space) | Si aucun signe ne doit être écrit, un espace est inséré avant la valeur |
# | Utilisée avec les specifiers o, x ou X, la valeur est précédée de 0 , 0x ou 0X respectivement pour les valeurs différentes de zéro. Utilisé avec a, A, e, E, f, F, g ou G, la chaîne de sortie doit contenir un point décimal même si aucun chiffre ne suit. Par défaut, si aucun chiffre ne suit, aucun point décimal n’est écrit |
0 | Remplit à gauche le nombre avec des zéros (0) au lieu d’espaces lorsque le remplissage est spécifié (voir l’option largeur) |
Option width (largeur)
Spécifie (ou pas) le nombre de caractères à imprimer
with | Description |
---|---|
(nombre) | Nombre minimum de caractères à imprimer. Si la valeur à imprimer est inférieure à ce nombre, le résultat est complété par des espaces vides. La valeur n’est pas tronquée même si le résultat est plus grand |
* | La largeur n’est pas spécifiée dans la chaîne de formatage, mais sous la forme d’un argument de valeur entière supplémentaire précédant l’argument à mettre en forme |
Option Precision (précision)
Permet de définir la précision des nombres décimaux (le nombre de chiffres significatifs à imprimer) ou le nombre maximal de caractères si c’est une chaine.
.precision | Description |
---|---|
.nombre |
|
.* | La précision n’est pas spécifiée dans la chaîne de format , mais sous la forme d’un argument de valeur entière supplémentaire précédant l’argument à mettre en forme. |
Options de conversion tirées de cet article.
Macro F
La macro F() qui permet de déplacer la chaîne dans la mémoire Flash afin d’éviter que la RAM du micro-contrôleur soit saturée si de nombreux messages sont envoyés sur le port série par exemple.
Stocker le résultat d’une chaîne formatée avec sprintf ou snprintf dans une variable (uniquement pour ESP32 et ESP8266)
La méthode sprintf() permet de stocker le résultat de la conversion dans une variable de type char[].
La commande sprintf() nécessite d’initialiser la variable de sortie avec une taille au moins égale à la longueur de la chaîne. C’est tout simplement le nombre de caractères de la chaîne de sortie.
char output_sprintf[6];
sprintf(output_sprintf, "%.1f°C", temp);
printf("Valeur formatée enregistrée dans la variable output %s \n", output_sprintf);
Pour combiner plusieurs variables dans une même chaîne, il faudra utiliser la fonction snprintf() qui s’écrit de manière similaire
char output_snprintf[60];
snprintf(output_snprintf, sizeof(output_snprintf), "La température est de %.1f°C, l'humidité est de %.1f%% \n", temp, hum);
printf("output_snprintf = %s \n", output_snprintf);
Imprimer le contenu d’un buffer de bytes avec write()
On peut être amené à utiliser un tableau de bytes. Ce tableau pourra par exemple contenir le code numérique de chaque caractère d’une String (chaîne de caractères).
Pour imprimer sur le port série un tableau de byte, les fonctions print(), println() ne fonctionnent pas car elles attendent une variable de type char, char[] ou String.
Pour imprimer le contenu d’un buffer avec la fonction write(), il suffit de parcourir ce dernier à l’aide d’une boucle for().
String stringtocopy = "Arduino";
// mesure la longueur de la chaine
int buffer_size = stringtocopy.length();
printf("Buffer size: %u\n", buffer_size);
// Cree un buffer ayant la meme taille que la chaine
byte buffer[buffer_size];
// Copie le contenu de la chaine a l'aide de la fonction getBytes
// Attention, il faut ajouter 1 a la taille de la chaine pour ne pas avoir de caractere NULL
stringtocopy.getBytes(buffer, buffer_size + 1);
Serial.println("Print buffer with write function");
// On imprime un a un chaque cellule du buffer a l aide d une boucle for
for (int i = 0; i < buffer_size; i++) {
Serial.write(buffer[i]);
}
Téléverser le code Arduino des exemples
Créer un nouveau croquis sur l’IDE Arduino ou PlatformIO et téléverser le code pour tester tous les exemples présentés précédemment.
Le code détecte automatiquement s’il fonctionne sur un Arduino (plateforme AVR). Le code a été testé sur Arduino Uno et ESP32.
#include "Arduino.h"
#include
#define SERIAL_SPEED 115200
void setup() {
Serial.begin(SERIAL_SPEED);
PrintEx serial = Serial; //Wrap the Serial object in a PrintEx interface.
Serial.println("\n=== print et println ====");
Serial.print("A");
Serial.print("B");
Serial.print("C");
Serial.println("\n=======");
Serial.println("Une demo avec ");
Serial.print("un retour à la ligne ");
Serial.println("\n---- Ou -----");
Serial.print("Une demo avec \n");
Serial.print("un retour à la ligne");
Serial.println("\n=== Concatenation avec println ====");
int INT_VAR = 32;
float FLOAT_VAR = 32.23;
bool BOOL_VAR = true;
Serial.println("Un chaine qui combine un entier " + String(INT_VAR) + ", un décimal " + String(FLOAT_VAR) + " est un bool " + String(BOOL_VAR));
Serial.println("\n=== printf ====");
unsigned int x = 0x999b989;
byte b = 120;
word w = 63450;
signed long l = 2147483646; // signed long -2,147,483,648 to 2,147,483,647
char c = 65; // A
char s[] = "une chaîne de caractères";
float f = 99.57;
double fdbl = 99.5769;
#ifdef __AVR__
serial.printf("Hexa %x %X \n", x, x);
serial.printf("Byte %u \n", b);
serial.printf("Word %u \n", w);
serial.printf("Long %lu \n", l);
serial.printf("Caractère %c \n", c);
serial.printf("%s \n", s);
serial.printf("Variable float %f | %.2f \n", f, f);
serial.printf("Variable double %f | %.2f \n", fdbl, fdbl);
#else
printf("Hexa %x %X \n", x, x);
printf("Byte %u \n", b);
printf("Word %u \n", w);
printf("Long %u \n", l);
printf("Caractère %c \n", c);
printf("%s \n", s);
printf("Variable float %f | %.2f \n", f, f);
printf("Variable double %f | %.2f \n", fdbl, fdbl);
#endif
Serial.println("\n=== FAKE BME280 ====");
double temp = 18.68;
double hum = 67.98;
#ifdef __AVR__
serial.printf("La température est de %.2f°C, l'humidité est de %.1f%% \n", temp, hum);
#else
printf("La température est de %.1f°C, l'humidité est de %.1f%% \n", temp, hum);
#endif
#ifdef __AVR__
//printf("output_sprintf = %s \n", output_sprintf);
serial.printf("La température est de %.1f°C, l'humidité est de %.1f%% \n", temp, hum);
#else
char output_sprintf[6];
sprintf(output_sprintf, "%.1f°C", temp);
printf("output_sprintf = %s \n", output_sprintf);
#endif
#ifdef __AVR__
#else
char output_snprintf[60];
snprintf(output_snprintf, sizeof(output_snprintf), "La température est de %.1f°C, l'humidité est de %.1f%% \n", temp, hum);
printf("output_snprintf = %s \n", output_snprintf);
#endif
Serial.println("\n=== write() buffer to Serial ====");
String stringtocopy = "Arduino";
int buffer_size = stringtocopy.length();
#ifdef __AVR__
serial.printf("Buffer size: %u\n", buffer_size);
#else
printf("Buffer size: %u\n", buffer_size);
#endif
byte buffer[buffer_size];
stringtocopy.getBytes(buffer, buffer_size + 1);
Serial.println("Print buffer with write() function");
for (int i = 0; i < buffer_size; i++) {
Serial.write(buffer[i]);
}
}
void loop() {
}
[env:uno]
platform = atmelavr
board = uno
framework = arduino
monitor_speed = 115200
lib_deps =
chris--a/PrintEx @ ^1.2.0
[env:lolin_d32]
platform = espressif32
board = lolin_d32
framework = arduino
monitor_speed = 115200
Ouvrez le moniteur série pour visualiser le fonctionnement des fonctions. Journal d’exécution récupéré sur un ESP32.
=== print et println ====
ABC
=======
Une demo avec
un retour à la ligne
---- Ou -----
Une demo avec
un retour à la ligne
=== Concatenation avec println ====
Un chaine qui combine un entier 32, un décimal 32.23 est un bool 1
=== printf ====
Hexa 999b989 999B989
Byte 120
Word 63450
Long 2147483647
Caractère A
une chaîne de caractères
Variable float 99.570000 | 99.57
Variable double 99.576900 | 99.58
=== FAKE BME280 ====
La température est de 18.7°C, l'humidité est de 68.0%
=== Write buffer to Serial ====
Buffer size: 7
Print buffer with write function
Arduino
Mises à jour
10/12/2020 Modification de printf. La méthode printf est exposée dans la classe Serial uniquement dans le framework Arduino-ESP32. Merci à Jean pour m’avoir signalé l’erreur.
16/11/2020 Ajout de la macro F
2/10/2020 Publication de l’article
Avez-vous aimé cet article ?
[Total: 2 Moyenne: 5]