IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Arduino Discussion :

Formatage de nombre


Sujet :

Arduino

  1. #1
    Membre habitué
    Homme Profil pro
    Webmaster
    Inscrit en
    Mai 2011
    Messages
    258
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France

    Informations professionnelles :
    Activité : Webmaster
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2011
    Messages : 258
    Points : 151
    Points
    151
    Par défaut Formatage de nombre
    Bonsoir,
    J'utilise un Arduino Uno avec des capteur analogiques.
    Je lis des valeurs avec analogRead() et c'est ok.
    Cependant, j'utilise un shield Wifi pour communiquer avec un Raspberry.
    Et là, les choses se gâtent .
    Il faut un nombre d'octets fixe dans l'entête http ( "content-lenght") à transmettre au Raspberry.
    Il faut donc que je formate mes valeurs de mesures afin qu'elles aient toujours la même longueur en bytes.
    Ainsi la valeur 345 sur trois octets ne pose pas de problèmes, mais la valeur 12 doit être convertie en 012 afin
    de conserver un nombre fixe d'octets à transmettre.
    En C, j'utilisai sprintf, mais aucune trace de cette instruction pour l'Arduino.
    Comment faire ?

  2. #2
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 685
    Points : 5 328
    Points
    5 328
    Par défaut
    Citation Envoyé par frederic13870 Voir le message
    Il faut un nombre d'octets fixe dans l'entête http ( "content-lenght") à transmettre au Raspberry.
    Il faut donc que je formate mes valeurs de mesures afin qu'elles aient toujours la même longueur en bytes.
    Ainsi la valeur 345 sur trois octets ne pose pas de problèmes, mais la valeur 12 doit être convertie en 012 afin
    de conserver un nombre fixe d'octets à transmettre.
    En C, j'utilisai sprintf, mais aucune trace de cette instruction pour l'Arduino.
    Comment faire ?
    Sprintf existe mais sans le %f - Vous pouvez générer un buffer et calculer sa longueur aussi pour le content-length (attention c’est th à la fin, pas ht)

    Si vous utilisez Ajax par exemple et pouvez interpréter les données avant affichage, vous pouvez envoyer les valeurs en binaire (représentation ascii) ainsi une valeur qui tient sur 4 octets par exemple sera écrite «0xDEADBEEF» ce qui fait un nombre de caractères toujours connu (bien sûr une petite valeur sera avec des 0 «0x00000BAD»)

    Vous pouvez aussi ne pas mettre le content-length et juste clore la connexion à la fin de l’envoi
    Il faut préciser dans le header en HTTP/1.1
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    client.println("Connection: close");
    Plus de détail dans la section 4.4 du protocole

  3. #3
    Membre habitué
    Homme Profil pro
    Webmaster
    Inscrit en
    Mai 2011
    Messages
    258
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France

    Informations professionnelles :
    Activité : Webmaster
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2011
    Messages : 258
    Points : 151
    Points
    151
    Par défaut J'ai trouvé une bricole
    Voilà le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
                String zero = "0";
                int sensor value_1;
                int sensorPin_1 =A0;
                String new_value;
                int i,l,to_add;
     
                sensorValue_1 = analogRead(sensorPin_1);
                 delay(100);
     
                value =  String (sensorValue_1,DEC);
                l = value.length();
                to_add = 5 - l;
                for (i=0;i<=5;i++) new_value = zero; 
                new_value += value;
                wiflyUart.print(new_value);
                delay(1000);
                wiflyUart.print(",");
                delay (1000);
    J'obtiens ainsi la même longueur pour mes variables, quelle que soit la valeur de la mesure.
    Je déplore que sprintf ne marche que pour les integers et pas pour les floats, car mes variables sont soit des floats soit des integers.
    Mais bon, avec le C , on arrive toujours à se débrouiller.
    Merci pour l'aide et bon Dimanche.

  4. #4
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 685
    Points : 5 328
    Points
    5 328
    Par défaut
    Citation Envoyé par frederic13870 Voir le message
    Voilà le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ...
    for (i=0;i<=5;i++) new_value = zero;
    --> euh, ça c'est louche. Vous mettez 5 fois de suite new_value à "0"...

    lancez ce code d'exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    const byte sensorPin = A0; // analogRead  donne une valeur entre 0 et 1023
     
    void setup()
    {
      Serial.begin(115200);
      Serial.println(F("---------------    (15 positions)"));
    }
     
    void loop()
    {
      char buffer[30];
      // nombre entier
      long nombreEntier = (analogRead(A0) - 512) * 10000;
      sprintf(buffer, "% 15d", nombreEntier );
      Serial.println(buffer);
     
      // float
      double nombreDecimal = (nombreEntier * 3.25) / random(7,55);
      dtostrf(nombreDecimal, 15, 3, buffer);
      Serial.println(buffer);
      delay(1000);
    }

    (on essaye d'éviter la classe String sur les petits micro-contrôleurs pour éviter des risques de morcellement de la mémoire. On préfère les cStrings)

  5. #5
    Membre habitué
    Homme Profil pro
    Webmaster
    Inscrit en
    Mai 2011
    Messages
    258
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France

    Informations professionnelles :
    Activité : Webmaster
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2011
    Messages : 258
    Points : 151
    Points
    151
    Par défaut Heu, c'était pas le bon sketch
    Voilà celui-qui marche
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
                String zero="0";
                int sensorValue_1;
                int i,l,to_add;
                String new_value;
     
                // lecture valeur dans sensorValue_1
     
                value =  String (sensorValue_1,DEC);
                l = value.length();
                to_add = 3 - l;
                for (i=0;i<=to_add;i++) new_value += zero; 
                new_value += value;
                wiflyUart.print(new_value);
                delay(1000);
                new_value="";
    Ainsi , toutes mes valeurs font quatre octets.

    on essaye d'éviter la classe String sur les petits micro-contrôleurs pour éviter des risques de morcellement de la mémoire. On préfère les cStrings
    Ah bon ? j ' ignorais cela.

    A la lecture de ton code, celui-ci est bien plus robuste et bien plus "pro".

    Je vais l' intégrer dans mon projet.

    Ta remarque me met en garde, car j'ai encore la gestion de l ' alimentation à coder et je suis à plus de 70 % d' utilisation des ressources mémoires.

    Merci encore et bon W.E.

  6. #6
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 685
    Points : 5 328
    Points
    5 328
    Par défaut
    Si vous réussissez à vous débarrasser de la classe String vous verrez que vous économiserez de la mémoire flash et (suivant ce que vous faites) de la RAM.

    Notez que sprintf() est aussi super coûteux en que pour un int/long il vaut mieux utiliser itoa() ou ltoa()

  7. #7
    Rédacteur

    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Novembre 2006
    Messages
    503
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Transports

    Informations forums :
    Inscription : Novembre 2006
    Messages : 503
    Points : 1 332
    Points
    1 332
    Par défaut
    Citation Envoyé par frederic13870 Voir le message
    Ta remarque me met en garde, car j'ai encore la gestion de l ' alimentation à coder et je suis à plus de 70 % d' utilisation des ressources mémoires.
    C'est clair qu'il faut éviter d'écrire trop de code sur ces bécanes (Arduino, ESP) ou d'utiliser des fonctions ou librairies inutiles.

    Envoyer un nombre avec trop peu de zéros devant, des espaces, voir d'autres caractères, ce n'est pas un souci pour un Raspberry Pi et un bon programmeur.
    Un Raspberry Pi a beaucoup plus de ressources et il suffit de choisir le bon langage ou serveur Web sur ce nano-ordinateur.

    Je l'ai déjà dit à plusieurs occasions et les modérateurs devraient intervenir:

    Citation Envoyé par frederic13870 Voir le message
    J'utilise un Arduino Uno avec des capteur analogiques.
    Je lis des valeurs avec analogRead() et c'est ok.
    Ce n'est pas 100% clair ce que veut faire frederic13870.
    Il y a trop d'interprétations possibles.
    Pour moi, il collecte des données sur l'Arduino et les envoient sur le Pi.

    Citation Envoyé par Jay M Voir le message
    Si vous utilisez Ajax par exemple et pouvez interpréter les données avant affichage, vous pouvez envoyer les valeurs en binaire (représentation ascii) ainsi une valeur qui tient sur 4 octets par exemple sera écrite «0xDEADBEEF» ce qui fait un nombre de caractères toujours connu (bien sûr une petite valeur sera avec des 0 «0x00000BAD»)
    A mon avis c'est hors contexte.
    J'ai l'impression que Jay M pense que c'est le Pi qui va faire une requête pour demander des données à l'Arduino.
    C'est peut-être le cas, mais frederic13870 ne le dit pas.

    Il faudrait donner plus de détails du projet dans le premier message de la discussion. Une ou deux lignes suffiront, voire les logiciels ou technologies utilisées, voire les souhaits.

    Ensuite les lecteurs pourront répondre à la fois aux questions liées au code, voire à des alternatives de design.

    Donc on ne peut rien dire de plus pour l'instant.
    Cordialement

  8. #8
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 685
    Points : 5 328
    Points
    5 328
    Par défaut
    Pour moi la question était très précise et le contexte de qui demande quoi pas nécessaire.
    Il faut donc que je formate mes valeurs de mesures afin qu'elles aient toujours la même longueur en bytes.
    --> il voulait donc savoir (pour application à un content-length connu) comment générer ses nombres avec du padding.

    Citation Envoyé par boijea Voir le message
    A mon avis c'est hors contexte.
    J'ai l'impression que Jay M pense que c'est le Pi qui va faire une requête pour demander des données à l'Arduino.
    C'est peut-être le cas, mais frederic13870 ne le dit pas.
    là c'est vous qui interprétez ce que j'ai écrit.

    Pour préciser:

    A/ J'ai un exemple de fonctions C (et donc des cStrings) pour répondre à sa question et générer des nombres avec du padding (des espaces)

    B/ Je n'ai fait qu'émettre un avis technique sur plusieurs alternative a l'envoi d'un content-length statique que son "donc" semblait pour lui être incontournable :
    • 1. ne pas envoyer le content-length, il n'est pas obligatoire si on termine la connexion ensuite
    • 2. envoyer les données sous forme "binaire" (la représentation hexadécimale d'un nombre flottant sur 32 bit prenant toujours 10 caractères par exemple en l'écrivant "0xAABBCCDD".
    • 3. comme cela n'est bien sûr pas génial s'il s'agit d'afficher une page web pour un humain de l'autre côté, c'est là que AJAX peut rentrer en ligne de compte, on émet l'info en binaire mais elle est convertie par la partie demandeuse en Javascript par exemple.

  9. #9
    Modérateur

    Avatar de Vincent PETIT
    Homme Profil pro
    Consultant en Systèmes Embarqués
    Inscrit en
    Avril 2002
    Messages
    3 185
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant en Systèmes Embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2002
    Messages : 3 185
    Points : 11 551
    Points
    11 551
    Par défaut
    Salut
    Citation Envoyé par frederic13870 Voir le message
    Il faut un nombre d'octets fixe dans l'entête http ( "content-lenght") à transmettre au Raspberry.
    Qui définit le nombre d'octets fixes ? C'est toi ?
    La science ne nous apprend rien : c'est l'expérience qui nous apprend quelque chose.
    Richard Feynman

  10. #10
    Modérateur

    Avatar de Vincent PETIT
    Homme Profil pro
    Consultant en Systèmes Embarqués
    Inscrit en
    Avril 2002
    Messages
    3 185
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant en Systèmes Embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2002
    Messages : 3 185
    Points : 11 551
    Points
    11 551
    Par défaut
    Citation Envoyé par Jay M
    Si vous utilisez Ajax par exemple et pouvez interpréter les données avant affichage, vous pouvez envoyer les valeurs en binaire (représentation ascii) ainsi une valeur qui tient sur 4 octets par exemple sera écrite «0xDEADBEEF» ce qui fait un nombre de caractères toujours connu (bien sûr une petite valeur sera avec des 0 «0x00000BAD»)
    +1 mais la représentation ASCII n'est même pas utile.

    Lorsque on est face à ce genre de problème (anormalement complexe, tordu, tiré par les cheveux) qui doit répondre à quelque chose qui paraît simple ; figer la longueur du corps de la requête, il faut tout de suite appliquer le Rasoir d'Ockham aussi appelé principe de simplicité.

    Ici on dois trouver un moyen pour que les mesures aient toujours la même longueur (en byte) pour les envoyer. Et ça tombe bien car l'ADC de ton Arduino UNO est un ADC 10 bits et peu importe la mesure, jamais ça ne dépassera 10 bits.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     octet MSB   octet LSB
    [xxxx xx00] [0000 0000]   // valeur minimum mesurable par l'ADC
     
    [xxxx xx11] [1111 1111]   // valeur maximum mesurable par l'ADC
    Il n'y a besoin que de 2 octets pour envoyer toutes les valeurs possibles. En allant un peu plus loin sans complexifier les choses, on peut ajouter un 3ème octet pour identifier le capteur, dans le cas où il y en a plusieurs.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    [NUM_ADC] [MSB_ADC] [LSB_ADC]   // 3 octets (24 bits), rien de plus
    Exemple le système qui reçoit la requête lit : 0x03 0x01 0x02 alors il sait que le capteur numéro 3 vient d'envoyer la valeur 0000 0001 0000 0010.

    Et pour ce qui concerne l'interprétation de : 0000 0001 0000 0010 on peut laisser le serveur en faire ce qu'il veut, comme dit par Jay M. Imaginons qu'on puisse faire du C côté serveur, si il faut l'afficher pour l'utilisateur alors on fera simplement :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    	double valeur = (double)((MSB_ADC << 8) + LSB_ADC)/5;
     
    	printf("valeur %f\n", valeur);



    ps : @Jay M, exacte faire la conversion en type float dans le Arduino complexifie inutilement le problème.
    La science ne nous apprend rien : c'est l'expérience qui nous apprend quelque chose.
    Richard Feynman

  11. #11
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 685
    Points : 5 328
    Points
    5 328
    Par défaut
    Oui 2,3 ou 4 octets c’est la même chose, mais si vous voulez générer un simple page web lisible qui dit

    «*il fait 18,25°C dans la chambre

    C’est pas top de pondre de l’hexa

    C’est là où @boija a raison, ce serait bien de savoir quel est le vrai besoin pour choisir la bonne solution

    Pour le nombre d’octets, le challenge habituel sur un petit arduino c’est qu’il faut mettre le content-length dans l’en tête, donc au début de ce que vous générez et si vous enchaînez ensuite des client.print() pour envoyer le contenu HTML sans avoir préparé un gros buffer (parce que vous n’avez pas assez de mémoire) alors c’est la zone pour savoir combien d’octets déclarer dans l’entete. L’idée de Frédéric était de faire du remplissage de manière à avoir toujours le même nombre d’octets, la majorité de la page web est connue, juste les valeurs vont changer

    Donc en mettant un espace (représenté ici par _) devant il écrirait

    «*il fait _9,25°C dans la chambre

    Et ce serait le même nombre d’octets


    Mais le plus simple c’est de ne pas s’ennuyer avec content-length du tout...

  12. #12
    Membre habitué
    Homme Profil pro
    Webmaster
    Inscrit en
    Mai 2011
    Messages
    258
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France

    Informations professionnelles :
    Activité : Webmaster
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2011
    Messages : 258
    Points : 151
    Points
    151
    Par défaut Pour la petite histoire
    L'Arduino Uno lit des mesures, analogiques et digitales.
    Je communique avec lui par une liaison wifi, protocole http 1/1.
    L'arduino ne possédant pas Apache, il faut émuler le fonctionnement d'un serveur pour les réponses au GET du navigateur soit cohérentes.
    J'utilise un shield Arduino Wifly EZY avec une puce RN 171.
    Il m'a été été spécifié que dans l'entête à retourner au navigateur, je dois écrire la longueur en byte de la "page".
    C'est pour cela que je cherche un format fixe.
    J'ai beaucoup appris avec ce projet et vous remercie tous pour l'aide apportée.

  13. #13
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 685
    Points : 5 328
    Points
    5 328
    Par défaut
    Citation Envoyé par frederic13870 Voir le message
    Je communique avec lui par une liaison wifi, protocole http 1/1
    ...
    Il m'a été été spécifié que dans l'entête à retourner au navigateur, je dois écrire la longueur en byte de la "page".
    La norme dit
    For compatibility with HTTP/1.0 applications, HTTP/1.1 requests containing a message-body MUST include a valid Content-Length header field unless the server is known to be HTTP/1.1 compliant.
    Donc c’est mieux en effet, mais pas obligatoire.

    D’un point de vue pratique vous pourriez aussi transformer chacune des valeurs dans un petit buffer avec les fonctions itoa() ou dtostrf() avant De générer la page et avec un strlen() vous pourriez connaître la longueur en octet de chacune des petites variables

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [XSL-FO] formatage de nombre
    Par qouify dans le forum XSL/XSLT/XPATH
    Réponses: 3
    Dernier message: 16/05/2006, 14h58
  2. [PHP-JS] Formatage de nombre
    Par goldorax113 dans le forum Langage
    Réponses: 5
    Dernier message: 08/05/2006, 12h50
  3. formatage de nombre
    Par Phiz dans le forum Collection et Stream
    Réponses: 7
    Dernier message: 29/03/2006, 19h17
  4. Formatage de nombres dans une page JSP
    Par Addouna dans le forum Général JavaScript
    Réponses: 9
    Dernier message: 10/03/2006, 14h01
  5. Formatage des nombres à l'affichage
    Par nbutin dans le forum SQL Procédural
    Réponses: 3
    Dernier message: 13/07/2004, 11h54

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo