Convertir un entier en chaine de caratère

Bonjour à tous,

Pour utiliser un afficheur LCD, j'ai besoin de convertir un entier en chaine de caractère et là, je dois avouer que je suis complètement largué :cry:

Pour fixer le décor, je ne connais rien en C ...

Bref, en partant de ce post : http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1259832451, j'ai écrit ça :

#include <stdio.h>

void setup()
{
 Serial.begin(9600);
}

void loop()
{
  char tampon[25];
  float ma_valeur=34567.567;

  sprintf(tampon,"la valeur est %f8.2",ma_valeur);
  Serial.print(tampon);
  delay(2000);
}

... et le résultat est ( roullement de tambour ) : "la valeur est ?f8.2" :-[

Où est l'erreur ? L'instruction sprintf est elle adaptée ?

Merci d'avance pour vos tuyaux.
A+

sprintf(tampon,"la valeur est %f8.2",ma_valeur);

la syntaxe correcte du printf, ou sprintf, est %8.2f (et pas %f8.2)

churchill

Bonjour Churchill,

Merci pour l'info, je testerais dès ce soir.

A+

Bon, finalement, j'ai pas résisté à tester tout de suite ...

Ca marche pas :cry: .

Ca affiche : "la valeur est "
Ca réserve bien la place pour completer la chaine mais c'est tout.
J'ai agrandi tampon à 40, sans résultat.
J'ai changé le type de variable des fois que mais sans amélioration.

Je ne sais pas si c'est normal mais je n'ai pas la librairie Stdio dans le repertoire d'Arduino ( versio 0018 ) : Faut-il la rajouter ?

Si vous avez des suggestions, n'hésitez pas ...

Merci d'avance.

Salut,

essaye en mettant juste '%f' :

sprintf(tampon,"la valeur est %f",ma_valeur);

Bonjour,

J'ai un problème aussi avec ça.
J'ai un Arduino Duemilanove.
Selon les codes que j'ai vue sur internet la fonction sprintf prend en charge les variables float avec ce symbole %f.
On dirait que c'est pas tout les Arduinos qui peuvent faire fonctionner la fonction sprintf correctement?
Car la correction de churchill et de flaith est correcte.

Avec ce code ça me donne: la valeur est ?

#include <Stdio.h>

void loop()
{
}

void setup()
{
  Serial.begin(9600);
  
  char tampon[25];
  float ma_valeur=34567.567;

  sprintf(tampon, "la valeur est %f", ma_valeur);
  Serial.print(tampon);
  delay(2000);
}

J'ai trouver ce lien qui en parle un peut de ce problème: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1200716061

Cette solution aide un peu!
Avec ce code ça me donne: la valeur est 3.14

#include <Stdio.h>

void loop()
{
}

void setup()
{
  Serial.begin(9600);
  
  char tampon[32];
  float temp = 3.14;
  int temp1 = (temp - (int)temp) * 100;                    // temp1 = (3.14 - 3) * 100 = 14
  sprintf(tampon,"la valeur est %0d.%d", (int)temp, temp1);      // %d pour les variables décimale.    (int)temp = 3 et temp1 = 14
  Serial.println(tampon);
  delay(2000);
}

Mais si je met:

float temp = 34567.567; // Ce nombre est trop grand?

Avec ce code j'ai une erreur car ça me donne: la valeur est 32767.32767

C'est bizarre qu'il y ai autant de problème avec les float et l'Arduino pour la conversion de float à chaine de character.
Quelqu'un a t-il une explication?
Est ce un problème au nivaux le la programmation des fusibles de l'ATmega328 de l'Arduino?

Merci

Peut-être est-ce du à la non intégration par l'arduino de la librairie gérant le printf. Je n'en ai aucune idée et je ne peux le vérifier parce que je suis au boulot là. Mais j'avais eu ce souci en programmant un atmega tout seul avec éclipse. Il fallait spécifiquement indiquer au linker d'utiliser la librairie pour printf. Ce n'est pas fait par défaut parce que je crois que c'est très gourmand en mémoire.
Voir : http://winavr.scienceprog.com/avr-gcc-tutorial/using-sprintf--function-for-float-numbers-in-avr-gcc.html

Peut-être un problème similaire ?
churchill

Re bonjour,

Bon, ça y est, mon problème est règlé.
En fait, je n'avais pas besoin de float, juste d'un entier et dans ce cas, ça fonctionne :smiley:

... par contre, le cas du float reste un mystère

J'ai fait pas mal de recherche sur le net aujourd'hui ( au boulot , chuuuut ) et j'ai trouvé des trucs interessants comme les fonctions ITOA --> voir là : c - Arduino String Formatting Issue - Stack Overflow et là Arduino Playground - LCD

Je ne sais pas ce que cela vaut mais si ça peut aider quelqu'un.

J'ai lu aussi ( je ne sais plus où ) que la fonction sprintf fait appel à une librairie qui consomme pas mal de ressources mais vu mon niveau, "j'ai pas tout comprendu" :wink:

A+

Bonjour,

Oui Bidouille la fonction itoa() est aussi une bonne solution pour convertir un entier en chaine de character.

int nombre = 37;
char chaine_nombre[5];

itoa(nombre, chaine_nombre, 10);  // convertir l'entier 37 en chaine de character "37" en base 10 (en décimale).

J'ai trouvé ça pour les float.
Par défaut les float sont pas supporter par la fonction sprintf.

Les symbole accepté par défaut que j'ai testé sont:
%o = pour les variable octal. (int, long. ect...)
%d = pour les variable décimale. (int, long. ect...)
%x = pour les variable hexadecimal minuscule. (int, long. ect...)
%X = pour les variable hexadecimal majuscule. (int, long. ect...)
%c = pour les variable ASCII. (char)
%s = pour les variable chaine de character. (char tampon[25])

Les symbole NON accepté par défaut que j'ai testé sont:
%b = pour les variable binaire. (int, long. ect...)
%f = pour les variable à virgule flottante. (float, double)
%e = pour les variable traité comme une notation scientifique (e.g. 1.2e+2). (float, double)

http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html

The following conversion flags are supported:

    * % Matches a literal % character. This is not a conversion.
    * d Matches an optionally signed decimal integer; the next pointer must be a pointer to int.
    * i Matches an optionally signed integer; the next pointer must be a pointer to int. The integer is read in base 16 if it begins with 0x or 0X, in base 8 if it begins with 0, and in base 10 otherwise. Only characters that correspond to the base are used.
    * o Matches an octal integer; the next pointer must be a pointer to unsigned int.
    * u Matches an optionally signed decimal integer; the next pointer must be a pointer to unsigned int.
    * x Matches an optionally signed hexadecimal integer; the next pointer must be a pointer to unsigned int.
    * f Matches an optionally signed floating-point number; the next pointer must be a pointer to float.
    * e, g, F, E, G Equivalent to f.
    * s Matches a sequence of non-white-space characters; the next pointer must be a pointer to char, and the array must be large enough to accept all the sequence and the terminating NUL character. The input string stops at white space or at the maximum field width, whichever occurs first.
    * c Matches a sequence of width count characters (default 1); the next pointer must be a pointer to char, and there must be enough room for all the characters (no terminating NUL is added). The usual skip of leading white space is suppressed. To skip white space first, use an explicit space in the format.
    * [ Matches a nonempty sequence of characters from the specified set of accepted characters; the next pointer must be a pointer to char, and there must be enough room for all the characters in the string, plus a terminating NUL character. The usual skip of leading white space is suppressed. The string is to be made up of characters in (or not in) a particular set; the set is defined by the characters between the open bracket [ character and a close bracket ] character. The set excludes those characters if the first character after the open bracket is a circumflex ^. To include a close bracket in the set, make it the first character after the open bracket or the circumflex; any other position will end the set. The hyphen character - is also special; when placed between two other characters, it adds all intervening characters to the set. To include a hyphen, make it the last character before the final close bracket. For instance, [^]0-9-] means the set of everything except close bracket, zero through nine, and hyphen. The string ends with the appearance of a character not in the (or, with a circumflex, in) set or when the field width runs out. Note that usage of this conversion enlarges the stack expense.
    * p Matches a pointer value (as printed by p in printf()); the next pointer must be a pointer to void.
    * n Nothing is expected; instead, the number of characters consumed thus far from the input is stored through the next pointer, which must be a pointer to int. This is not a conversion, although it can be suppressed with the * flag.

These functions return the number of input items assigned, which can be fewer than provided for, or even zero, in the event of a matching failure. Zero indicates that, while there was input available, no conversions were assigned; typically this is due to an invalid input character, such as an alphabetic character for a d conversion. The value EOF is returned if an input failure occurs before any conversion such as an end-of-file occurs. If an error or end-of-file occurs after conversion has begun, the number of conversions which were successfully completed is returned.

By default, all the conversions described above are available except the floating-point conversions and the width is limited to 255 characters. The float-point conversion will be available in the extended version provided by the library libscanf_flt.a. Also in this case the width is not limited (exactly, it is limited to 65535 characters). To link a program against the extended version, use the following compiler flags in the link stage:

-Wl,-u,vfscanf -lscanf_flt -lm

A third version is available for environments that are tight on space. In addition to the restrictions of the standard one, this version implements no %[ specification. This version is provided in the library libscanf_min.a, and can be requested using the following options in the link stage:

-Wl,-u,vfscanf -lscanf_min -lm

Je pense qu'il faut faire quelque chose dans AVR Studio pour que les float soit supportées.
arduino-0018\hardware\tools\avr

Mais je sais pas où écrire cette ligne de code pour faire la modification entre les 2 librairies libprintf_flt.a et libprintf_min.a.

Quelqu'un à t-il la connaissance des MakeFile avec AVR Studio?
J'aurais besoin d'aide pour être capable de faire la modification pour mon Arduino.

Merci

@demss

float temp = 34567.567; // Ce nombre est trop grand?

Avec ce code j'ai une erreur car ça me donne: la valeur est 32767.32767

C'est bizarre qu'il y ai autant de problème avec les float et l'Arduino pour la conversion de float à chaine de character.
Quelqu'un a t-il une explication?
Est ce un problème au nivaux le la programmation des fusibles de l'ATmega328 de l'Arduino?

Merci

Les valeur entières non signées ne dépassent pas 32767 (-32767...32767), essaye avec un "long" ou "unsigned int" :wink:

Merci flaith j'avais oublier que pour l'Arduino une variable int = 16 bits!

Avec des variable long j'ai toujours une erreur ça me donne: la valeur est -30969.0

#include <Stdio.h>

void loop()
{
}

void setup()
{
  Serial.begin(9600);
  
  char tampon[32];
  float temp = 34567.567;
  long temp1 = (temp - (long)temp) * 100;
  sprintf(tampon,"la valeur est %0d.%d", (long)temp, temp1);
  Serial.println(tampon);
  delay(2000);
}

Et avec des variable unsigned int j'ai toujours une erreur ça me donne: la valeur est -30969.56

Ici avec des variable unsigned int et une variable float = 30968.567 ça va mieux ça me donne: la valeur est 30968.566

#include <Stdio.h>

void loop()
{
}

void setup()
{
  Serial.begin(9600);
  
  char tampon[32];
  float temp = 30968.567;
  unsigned int temp1 = (temp - (unsigned int)temp) * 1000;
  sprintf(tampon,"la valeur est %0d.%d", (unsigned int)temp, temp1);
  Serial.println(tampon);
  delay(2000);
}

Les Variable float sont réputé pour être non exacte alors .566 au lieu de .567 c'est surement satisfaisant pour des float.

Est ce que les variable float on une limite de 30969 pourtant ce sont des variables 32 bits selon la doc?
http://arduino.cc/en/Reference/Float
Quand je programme avec Visual C++ pour un processeur PC les variable float sont aussi = 32 bits et j'ai pas la limite de 30969.

Merci

et en indiquant que c'est un un long que tu utilises dans ton '%d' :
sprintf(tampon,"la valeur est %0ld.%d", (long)temp, temp1); :smiley:

Merci flaith maintenant ça fonctionne! :smiley:

Voici le code fonctionnel et voici ce qu'il donne: la valeur est 34567.56

#include <Stdio.h>

void loop()
{
}

void setup()
{
  Serial.begin(9600);
  
  char tampon[32];
  float temp = 34567.567;
  long temp1 = (temp - (long)temp) * 100;                     // * 100 pour 2 chiffre après la virgule. pour 3 chiffre "* 1000"...
  sprintf(tampon,"la valeur est %0ld.%0ld", (long)temp, temp1); 
  Serial.println(tampon);
  delay(2000);
}

Attention: on rajoute un L minuscule après le zéro pour dire que c'est une variable long 32 bits.
À ne pas confondre, le L minuscule et le chiffre 1 ce ressemble beaucoup.

Merci

Merci à toi demss pour avoir trouvé la solution à ce problème.

J'ai trouver une méthode très simple pour afficher une variable float lol.

float var = 45.6;
Serial.print(var);

Mais cette méthode par défaut affiche seulement 2 chiffre après la virgule.
Le dernier chiffre est arrondie à l'entier suppérieur.
Je trouve que c'est bien car après le deuxième chiffres après la virgule la variable float devient imprécise pour l'Arduino.

Pour ceux que ça peut intéresser voici le résultat de mes testes:

float t_Float = 34567.5622;
int t_Int = 3470;
int t_Int_Bin = B1001110;  // Variable Binaire
long t_Int_Hex = 0x5AF7;  // Variable Hexadecimale
long t_Long = 3456789;
char t_Char = 'A';
char t_chaine[32] = "Salut";

char tampon[32];


void loop()
{
}

void setup()
{
  Serial.begin(9600);
  delay(500);
  
  Serial.println("Afficher les variable en utilisant seulement la fonction Serial.print():");
  Serial.print("La variable float = ");
  Serial.println(t_Float, 4);                  // Ici seulment 2 chiffre après la virgule vont être affiché si on met pas le 4. Le dernier chiffre est arrondie à l'entier suppérieur.
  Serial.print("La variable int = ");
  Serial.println(t_Int);
  Serial.print("La variable Binaire = ");
  Serial.println(t_Int_Bin, BIN);
  Serial.print("La variable Hexadecimal = ");
  Serial.println(t_Int_Hex, HEX);
  Serial.print("La variable long = ");
  Serial.println(t_Long);
  Serial.print("La variable char = ");
  Serial.println(t_Char);
  Serial.print("La variable char[32] = ");
  Serial.println(t_chaine);
  Serial.println("");

  Serial.println("Afficher les variable en utilisant les fonction sprintf() et Serial.print():");
  long temp1 = (t_Float - (long)t_Float) * 10000;                     // * 100 pour 2 chiffre après la virgule. pour 3 chiffre "* 1000"...
  sprintf(tampon,"La variable float = %0ld.%0ld", (long)t_Float, temp1);
  Serial.println(tampon);
  sprintf(tampon,"La variable int = %d", t_Int);
  Serial.println(tampon);
  sprintf(tampon,"La variable Hexadecimal = %0lX", t_Int_Hex);
  Serial.println(tampon);
  sprintf(tampon,"La variable long = %0ld", t_Long);
  Serial.println(tampon);
  sprintf(tampon,"La variable char = %c", t_Char);
  Serial.println(tampon);
  sprintf(tampon,"La variable char[32] = %s", t_chaine);
  Serial.println(tampon);

  delay(2000);
}

Et le résultat:

Afficher les variable en utilisant seulement la fonction Serial.print():
La variable float = 34567.5625
La variable int = 3470
La variable Binaire = 1001110
La variable Hexadecimal = 5AF7
La variable long = 3456789
La variable char = A
La variable char[32] = Salut

Afficher les variable en utilisant les fonction sprintf() et Serial.print():
La variable float = 34567.5625
La variable int = 3470
La variable Hexadecimal = 5AF7
La variable long = 3456789
La variable char = A
La variable char[32] = Salut

Pour l'affichage LCD la fonction lcd.print() ressemble beaucoup à la fonction pour l'affichage Serial Serial.print().
Alors je pense qu'on a pas besoin de faire de conversion de variable numérique en variable chaine de character pour afficher nos variable.
Tous le travaille de conversion à déjà été fait par les concepteur de c'est 2 librairies.