Go Down

Topic: printf (Read 1 time) previous topic - next topic

hbachetti

Nov 18, 2018, 10:33 am Last Edit: Nov 18, 2018, 05:14 pm by hbachetti
Dans le monde ARDUINO, lorsque l'on veut afficher un texte suivi de la valeur d'une variable on écrit :

Code: [Select]

    Serial.print("i=");
    Serial.println(i);

En C traditionnel on écrirait plutôt ceci :

Code: [Select]

    printf("i=%d\n", i);

La fonction printf existe pourtant dans la librairie C, mais elle n'écrit ... nulle part !

Voici la solution : http://playground.arduino.cc/Main/Printf
Paragraphe : Hooking up printf() on AVR

Code: [Select]


static FILE uartout = {0} ;

static int uart_putchar (char c, FILE *stream)
{
  Serial.write(c) ;
  return 0 ;
}

void setup() {
  Serial.begin(115200);
  fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);
  stdout = &uartout ;
}

void loop()
{
  const char *s = "result:";

  for (int i = 0 ; i < 10 ; i++) {
    printf("%s i=%d\n", s, i);
  }
  delay(1000);
}


avec Serial.print
Le croquis utilise 1816 octets (5%) de l'espace de stockage de programmes. Le maximum est de 30720 octets.
Les variables globales utilisent 194 octets (9%) de mémoire dynamique, ce qui laisse 1854 octets pour les variables locales. Le maximum est de 2048 octets.

avec printf
Le croquis utilise 3154 octets (10%) de l'espace de stockage de programmes. Le maximum est de 30720 octets.
Les variables globales utilisent 214 octets (10%) de mémoire dynamique, ce qui laisse 1834 octets pour les variables locales. Le maximum est de 2048 octets.

Ce petit confort vous coûtera 1.3K de mémoire programme (4%).

@+

Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

lesept

Oui, mais comment l'utilise t-on ? Peux-tu donner le même exemple que pour sprintf ? Et un ou deux autres avec des float, des char, etc...
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

hbachetti


C'est exactement la même utilisation que sprintf.

%c : caractère
%s : chaîne de caractère
%d : entier
%l : long
%lu : unsigned long
etc.

ATTENTION : Comme pour sprintf, PAS DE FLOAT. Ceci est une limitation de la librairie C.

J'ai modifié l'exemple :

Code: [Select]

void loop()
{
  const char *s = "result:";

  for (int i = 0 ; i < 10 ; i++) {
    printf("%lu %s i=%d\n", millis(), s, i);
  }
  delay(1000);
}


ATTENTION: comme printf travaille sur un stream, la sortie n'est visible qu'après affichage d'un '\n'.

@+
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

hbachetti

Ici un exemple avec un float.
La variable est convertie dans une chaîne avec dtostrf() puis affichée avec printf().

Code: [Select]

char * dtostrf(
double __val,
signed char __width,
unsigned char __prec,
char * __s)


val : la valeur à convertir
width : le nombre de caractères minimum à afficher y compris le '.' décimal.
prec : nombre de chiffres après la virgule

Code: [Select]

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


Si le nombre de caractères à afficher est supérieur au nombre de chiffres réel, la fonction complète avec des blancs (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  :smiley-confuse:

Je sais, ce n'est pas génial mais c'est mieux que rien.

@+
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

lesept

Ah, si : c'est génial !
A force d'essayer on finit par réussir... Donc, plus ça rate, plus on a de chances que ça marche (proverbe Sharduinok).

kamill

#5
Nov 18, 2018, 04:57 pm Last Edit: Nov 18, 2018, 04:58 pm by kamill
Bonjour,

Vraiment très intéressant.
Par contre le lien dans ton premier post ne fonctionne pas.

hbachetti

Merci kamill

C'est corrigé.

@+
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

bricoleau

Très intéressant

Je pense qu'il y a moyen de combiner ça avec l'approche que j'ai suivie ici, qui a l'avantage de s'interfacer nativement avec la méthode print telle que fournie par l'IDE.

Au final on doit par exemple pourvoir arriver à Serial.print(toto("%s i=%d\n", s, i));

et même Serial.print(toto(F("%s i=%d\n"), s, i)); pour laisser la chaîne de formatage en flash.

Cela fonctionnerait nativement pour les print et println, dans toutes les classes dérivées de print.h (Serial, LCD, Client, etc.)

Faut juste trouver un nom adéquat pour "toto", court et parlant et pas en conflit avec un nom qui existerait déjà dans l'écosystème. Peut-être juste "f" ?
Tutoriels arduino : http://forum.arduino.cc/index.php?topic=398112.0

bricofoy

#8
Nov 19, 2018, 02:01 pm Last Edit: Nov 19, 2018, 02:01 pm by bricofoy
f en effet je ne l'ai jamais vu pour le moment. ou pf (pour "print formaté" :) )
-tu savais que si tu passe le CD de windows à l'envers, tu entends une chanson satanique ?
-non, mais il y a pire : à l'endroit, ça l'installe !

hbachetti


Bien sûr, une simple fonction qui fait un snprintf() dans un buffer statique et le retourne.
En étant peu gourmand au niveau taille du buffer bien sûr.

@+
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

bricoleau

waaaaa ça fonctionne  ;D

Et sans buffer statique alloué en RAM en permanence !

Cela donne ça
Code: [Select]
#include "printf_c.h"

void setup() {
  Serial.begin(115200);
 
  const char *s = "result:";
  for (int i = 0 ; i < 10 ; i++) {
    Serial.println(f("%s i=%d", s, i));
  }
}

void loop() {}


Alleluia les gars !
On a un printf intégré aux méthodes print() et println() dans toutes les classes qui les utilisent !


Je publie ça demain en version beta
Tutoriels arduino : http://forum.arduino.cc/index.php?topic=398112.0

bricofoy

-tu savais que si tu passe le CD de windows à l'envers, tu entends une chanson satanique ?
-non, mais il y a pire : à l'endroit, ça l'installe !

ard_newbie


Pour info, printf() est déjà utilisable avec le compilateur de la DUE.

Go Up