décomposition d'une chaine en variables uint8_t

Bonjour à tous, je suis toujours débutant et je suis toujours en train de faire ma domotique volets
j'ai développé la télécommande, et elle envoie à chaque récepteur les commandes sous la forme d'une chaine
donc coté emetteur

 char transmissionVolets[50];
...

void setup()
{
...
}

void loop()
{
compositionMessage();
transmission433mhz();
...
}

void compositionMessage()

{
  sprintf(transmissionVolets,"$,%d,%d,%2d,%2d,%2d,%2d,%2d,%d,%2d,%2d,%d*%2d\n",
          emetteur,destinataire,heureCourante,minCourante,secCourante,hUp,minUp,autoUp,hDown,minDown,autoDown,checksum);
          }

jusque là ça va.
à la réception, je voudrais maintenant éclater cette chaine et récupérer les variables j'ai mis des séparateurs virgule, je peux mettre autre chose s'il faut c'est pas un problème...
pouvez vous m'aider s'il vous plait
merci beaucoup

Bonsoir,

La fonction correspondant à sprintf est sscanf. Regardez bien sa syntaxe (similaire à celle de sprintf) et n'oubliez pas de passer les adresses de vos variables en mettant une "&" devant leur nom.

Bonne bidouille

MicroQuettas

merci MicroQuettas
après quelques erreurs de ma part, j'ai reussi avec sscanf, et oui ca marche !
je t'ai mis ton 1er karma ;o))
juste un truc qui membete : en uint8_t avec %d ca marche pas, en int ca marche mais ca comsomme plus de memoire

void compositionMessage()
{
  int e,d,hC,mC,sC,hU,mU,aU,hD,mD,aD=0;
  char *p;
  sprintf(transmissionVolets,"$,%d,%d,%2d,%2d,%2d,%2d,%2d,%d,%2d,%2d,%d*",
          emetteur,destinataire,heureCourante,minCourante,secCourante,hUp,minUp,autoUp,hDown,minDown,autoDown);
          for (p=transmissionVolets; *p; p++) // calcule le checksum sans tenir compte des 6 premiers caracteres
 //Serial.println(p);//juste pour comprendre
  checksum^=(byte) *p;
 sprintf(p,"%02X",checksum); // ajoute le checksum et le code de fin
 //Serial.println(transmissionVolets);
 sscanf(transmissionVolets,"$,%d,%d,%2d,%2d,%2d,%2d,%2d,%d,%2d,%2d,%d*",&e,&d,&hC,&mC, &sC,&hU,&mU,&aU,&hD,&mD,&aD);
 Serial.print("les variables sont :");
 Serial.println(e);
 Serial.println(d);
 Serial.println(hC);
 Serial.println(mC);
 Serial.println(sC);
 Serial.println(hU);
 Serial.println(mU);
 Serial.println(aU);
 Serial.println(hD);
 Serial.println(mD);
 Serial.println(aD);

          }

quelqu'un aurait il une idée simple pour que ca marche en uint8_t ?
merci

Bonjour,

scanf attend des “int” pour un “%d”, cf

Par ailleurs, scanf et printf sont très puissantes, mais très gourmandes en mémoire. Vous risquez d’être vite coincé si vous utilisez un AVR328 (Uno et similaires).

Ceci dit, on peut optimiser le code pour utiliser moins de mémoire.
Je reviens vers vous demain car aujourd’hui j’ai la famille.

Bonne bidouille

MicroQuettas

merci MicroQuettas, bon dimanche et à demain,
:frowning: eh oui, je sais, et le pire, c'est que je n'utilise pas l'avr328 mais le 168 (arduino mini pro 168 5v 16) qui a 1ko de sram...
d'où ma question...
déjà pour gagner de la mémoire, je transformerai mes heures et minutes en int hmn (hmn =(h*60+mn) comme ca ca me fera 2 octets au lieu de 2+2.
et pour mes états booleens, je mettrai un char (a pour auto et m pour manuel) et j'utiliserai %c au lieu de %d...
qu'en pensez vous ? c'est bon ?
merci

MicroQuettas:
Bonsoir,

La fonction correspondant à sprintf est sscanf. Regardez bien sa syntaxe (similaire à celle de sprintf) et n’oubliez pas de passer les adresses de vos variables en mettant une “&” devant leur nom.

Bonne bidouille

MicroQuettas

vaut mieux éviter ces 2 fonctions, elles “bouffent” énormément de mémoire.

Il faut leur préférer des fonctions de bases come strtok(), atoi(), atol(), etc… (cf stdlib.h et string.h)

Voici un exemple qui montre bien la différence (en utilisant votre code)

char transmissionVolets[] = "$,10,20,30,40,50,60,70,80,90,95,99*";

void compositionMessage()
{
  int e, d, hC, mC, sC, hU, mU, aU, hD, mD, aD = 0;
  int n = sscanf(transmissionVolets, "$,%d,%d,%2d,%2d,%2d,%2d,%2d,%d,%2d,%2d,%d*", &e, &d, &hC, &mC, &sC, &hU, &mU, &aU, &hD, &mD, &aD);
  if (n == 11) {
    Serial.println("les variables sont :");
    Serial.println(e);
    Serial.println(d);
    Serial.println(hC);
    Serial.println(mC);
    Serial.println(sC);
    Serial.println(hU);
    Serial.println(mU);
    Serial.println(aU);
    Serial.println(hD);
    Serial.println(mD);
    Serial.println(aD);
  }
}

void setup() {
  Serial.begin(115200);
  compositionMessage();
}

void loop() {}

la console affiche bien la bonne analyse des données

[sub][color=blue]les variables sont :
10
20
30
40
50
60
70
80
90
95
99
[/color][/sub]

et si on regarde la taille du programme on voit:

[color=purple]Sketch uses [b][color=red]4128 bytes[/color][/b] (1%) of program storage space. Maximum is 253952 bytes.
Global variables use [b][color=red]288 bytes[/color][/b] (3%) of dynamic memory, leaving 7904 bytes for local variables. Maximum is 8192 bytes.[/color]

(j’ai compilé sur un MEGA)

maintenant si vous utilisez le code suivant

char transmissionVolets[] = "$,10,20,30,40,50,60,70,80,90,95,99*";
const char * virgule = ",";

union { // http://en.cppreference.com/w/cpp/language/union
  byte val[11];
  struct {
    byte emetteur, destinataire, heureCourante, minCourante, secCourante, hUp, minUp, autoUp, hDown, minDown, autoDown;
  } data;
} valeurs;

void compositionMessage()
{
  char *p;
  byte i;
  p = strtok(transmissionVolets, virgule); // http://en.cppreference.com/w/cpp/string/byte/strtok

  if ((p != NULL) && (*p == '

où on est un peu “smart” :slight_smile: en utilisant une union et une struct ce qui permet d’utiliser une boucle pour remplir les valeurs mais aussi d’accéder aux variables par leur petit nom.

La sortie sur la console donne aussi

[sub][color=blue]les variables sont :
10
20
30
40
50
60
70
80
90
95
99
[/color][/sub]

mais quand on regarde les informations de compilation

[color=purple]Sketch uses [b][color=green]2352 bytes[/color][/b] (0%) of program storage space. Maximum is 253952 bytes.
Global variables use [b][color=green]259 bytes[/color][/b] (3%) of dynamic memory, leaving 7933 bytes for local variables. Maximum is 8192 bytes.[/color]

On voit qu’on a gagné quelques octets en pouvant utiliser les bytes au lieu des int et surtout beaucoup de mémoire programme (on passe de 4128 à 2352 octets soit une économie de 1776 octets - le prix de la fonction sscanf())

Pour ce qui est du sprintf(), ma recommendation serait de ne pas construire la chaîne de cette façon. Généralement il n’y a pas besoin d’avoir une chaîne complète pour l’envoyer d’un coup, vous pouvez envoyer bout par bout et faire une succession de print/write plutôt qu’un seul gros print/write. ça vous économise en plus le buffer en RAM pour construire le gros message qui ne sert à rien (sauf si vous voulez vraiment calculer un checksum)

si vous avez besoin du gros message, par exemple pour calculer simplement un checksum (mais autant l’envoyer aussi alors) dans ce cas utiliser les fonctions itoa() et strcat() pour fabriquer le buffer plutôt que sprintf();

)) {
    i = 0;
    do {
      p = strtok(NULL, virgule);
      valeurs.val[i++] = atoi(p); // http://en.cppreference.com/w/cpp/string/byte/atoi
    } while (p && (i < sizeof(valeurs)));

if (i == sizeof(valeurs)) {
      Serial.println(“les variables sont :”);
      Serial.println(valeurs.data.emetteur);
      Serial.println(valeurs.data.destinataire);
      Serial.println(valeurs.data.heureCourante);
      Serial.println(valeurs.data.minCourante);
      Serial.println(valeurs.data.secCourante);
      Serial.println(valeurs.data.hUp);
      Serial.println(valeurs.data.minUp);
      Serial.println(valeurs.data.autoUp);
      Serial.println(valeurs.data.hDown);
      Serial.println(valeurs.data.minDown);
      Serial.println(valeurs.data.autoDown);
    }
  }
}

void setup() {
  Serial.begin(115200);
  compositionMessage();
}

void loop() {}


où on est un peu "smart" :) en utilisant une union et une struct ce qui permet d'utiliser une boucle pour remplir les valeurs mais aussi d'accéder aux variables par leur petit nom. 

La sortie sur la console donne aussi 

§DISCOURSE_HOISTED_CODE_4§


mais quand on regarde les informations de compilation 

§DISCOURSE_HOISTED_CODE_5§


On voit qu'on a gagné quelques octets en pouvant utiliser les bytes au lieu des int et surtout beaucoup de mémoire programme (on passe de **4128** à **2352** octets soit une économie de 1776 octets - le prix de la fonction sscanf())

Pour ce qui est du sprintf(), ma recommendation serait de ne pas construire la chaîne de cette façon. Généralement il n'y a pas besoin d'avoir une chaîne complète pour l'envoyer d'un coup, vous pouvez envoyer bout par bout et faire une succession de print/write plutôt qu'un seul gros print/write. ça vous économise en plus le buffer en RAM pour construire le gros message qui ne sert à rien (sauf si vous voulez vraiment calculer un checksum) 

si vous avez besoin du gros message, par exemple pour calculer simplement un checksum (mais autant l'envoyer aussi alors) dans ce cas utiliser les fonctions itoa() et strcat() pour fabriquer le buffer plutôt que sprintf();

Bonjour J-M-L

en lisant ton exemple, je suis allé lire les explications sur les unions ici : http://en.cppreference.com/w/cpp/language/union

et je bute sérieusement sur ce point :

The union is only as big as necessary to hold its largest data member. The other data members are allocated in the same bytes as part of that largest member.

qui est encore plus obscur dans l'exemple suivant :

union S
{
    std::int32_t n;     // occupies 4 bytes
    std::uint16_t s[2]; // occupies 4 bytes
    std::uint8_t c;     // occupies 1 byte
};                      // the whole union occupies 4 bytes

Comment est-il physiquement possible que deux variables de chacune 4octets et une de 1 une fois réunies dans une union n'occupent que 4 octets ? Où est stockées l'info qui devrait être dans les octets "manquants" ?

EDIT : Ok c'est bon, je crois que j'ai compris. C'est subtil ta méthode pour remplir une struct depuis une boucle... j'en reste comme deux ronds de flan. Moisi, le flan.
C'est quand je vois des techniques comme ça, qui semblent t'être naturelles vu la fréquence avec laquelle tu ponds des exemples de ce genre, que je me dis que je suis trop vieux pour programmer correctement/efficacement ...

je suis plus vieux que vous sans doute :slight_smile:

réponse à la question - tout n'est pas stocké, ce n'est pas une [

struct

](Data structures - C++ Tutorials). Une union justement c'est pour dire "je n'aurais pas toujours besoin de toutes les données à la fois donc je mets le tout dans un gros paquet et je me crée des petits noms sympas pour y accéder"

--> dans mon cas

union { // http://en.cppreference.com/w/cpp/language/union
  byte val[11];
  struct {
    byte emetteur, destinataire, heureCourante, minCourante, secCourante, hUp, minUp, autoUp, hDown, minDown, autoDown;
  } data;
} valeurs;

J'ai deux éléments dans mon union, le premier c'est le tableau de 11 octets et dans le second élément (organisé en structure parce qu'on peut donner des petits noms) il se trouve que j'ai aussi 11 éléments d'un octet. donc l'union va réserver 11 octets et vous pouvez lire le contenu soit par le tableau, soit en passant par la structure. c'est une technique classique pour avoir une vison des octets ou de variables de types plus complexes. par exemple si vous récupérez octets après octets sur un liaison série des variables genre float ou double, vous les rangez en utilisant le tableau, ce qui permet de travailler en octets, puis vous les accédez en utilisant les autres variables.

il faut faire attention car le standard ne garantit pas que les éléments sont organisés dans l'ordre. Le compilateur peut arbitrairement décider de mélanger les choses pour optimiser les accès, donc il faut vérifier au moins une fois que c'est arrangé dans le bon ordre. (sans optimisation agressive, le compilo fait souvent ce qui semble logique et conserve votre ordre)

c'est à peu près ce que j'avais compris (yes !), merci pour l'explication détaillée, c'est toujours plus clair quand c'est bien écrit :slight_smile:

merci J-M-L,
vous dites que sprintf et sscanf sont consommateurs de memoire et qu’il faut les éviter,
pour lire le message et extraire les variable je vais utiliser votre methode, mais pour le composer sur le l’émetteur j’avais écrit :

#include <stdio.h>
uint8_t emetteur = 0,destinataire=1,heureCourante=8,minCourante=30,secCourante=0,hUp=8,minUp=0,autoUp=1,hDown=19,minDown=15,autoDown=1,checksum=10;
float Mes;
 char transmissionVolets[50];
 //strcpy(transmissionVolets,"$");=================> JE REMPLACE PAR SNPRINTF
// la chaine devra etre "$emetteur,destinataire,heureCourante,minCourante,secCourante,hUp,minUp,autoUp,hDown,minDown,autoDown,*checksum"

// donc nombre car = "&1,1,2,2,2,2,2,1,2,2,1*2\n=33
void setup()
{
  Serial.begin(9600);
 Mes = 0;
 
}

void loop()
{
 Serial.print(transmissionVolets);
 compositionMessage();
 Serial.print(" devient ");
 Mes += 0.02;
 Serial.println(transmissionVolets);
 String MaLigne = LigneMesure("Temperature = %s %s", Mes, "C");
 Serial.println(MaLigne);
 delay(200);
}
void compositionMessage()
{
  int e,d,hC,mC,sC,hU,mU,aU,hD,mD,aD=0;
  char *p;
  sprintf(transmissionVolets,"$,%d,%d,%2d,%2d,%2d,%2d,%2d,%d,%2d,%2d,%d*",
          emetteur,destinataire,heureCourante,minCourante,secCourante,hUp,minUp,autoUp,hDown,minDown,autoDown);
          for (p=transmissionVolets; *p; p++) // calcule le checksum sans tenir compte des 6 premiers caracteres
 //Serial.println(p);//juste pour comprendre
  checksum^=(byte) *p;
 sprintf(p,"%02X",checksum); // ajoute le checksum et le code de fin
 //Serial.println(transmissionVolets);
 sscanf(transmissionVolets,"$,%d,%d,%2d,%2d,%2d,%2d,%2d,%d,%2d,%2d,%d*",&e,&d,&hC,&mC, &sC,&hU,&mU,&aU,&hD,&mD,&aD);
 Serial.print("les variables sont :");
 Serial.println(e);//
 Serial.println(d);
 Serial.println(hC);
 Serial.println(mC);
 Serial.println(sC);
 Serial.println(hU);
 Serial.println(mU);
 Serial.println(aU);
 Serial.println(hD);
 Serial.println(mD);
 Serial.println(aD);

          }
   
String LigneMesure(char *Type, float Mesure, char *Unite)
{
char Mes[6] = { '\0' };
char buffer[25] = {'\0'};
dtostrf(Mesure,5,2,Mes);
snprintf(buffer,25, Type, Mes, Unite);
return buffer;
}

(mon code est brouillon car j’utilise des exemples que je trouve et que je modifie, donc qui contiennent encore les données initiales…)

sprintf, pour le débutant que je suis a l’avantage d’etre facile à comprendre, mais s’il est déconseillé, par quoi dois je le remplacer sachant que :

  • pour des raisons de simplicité et de compréhension/debuggage de mon programme, je préfère effectivement, lorsque je fais une mise à jour des recepteurs toujours envoyer le meme message, donc comprenant toutes les variables.
  • je tiens à vérifier à chaque envoi l’intégrité de l’émission/réception, d’ou la nécessité d’utiliser le checksum (enfin d’après ce que j’ai compris suite aux différent échanges que j’ai eu sur ce forum entre autre)
    NB : pour l’instant pour l’émission j’utilise un uno avec lcd keypad et pour la réception des mini pro 168 en 5 volts 16 bits. et pour la transmission des emetteurs et des recepteurs low-cost chinois
    merci
    merci

comme vous voulez le checksum il vous faut la chaîne de caractère, mais ça pourrait être fait en petits morceaux

je ne suis pas sur mon ordi alors je tape ça direct - y'a peut-être des fautes mais c'est pour expliquer le principe de construire la trame petit à petit ainsi que le checksum

char petitBuffer[10];
byte v1 = 22;
byte v2 = 13
char *p;

byte checksum = 0;

Serial.print(F("$,"));
checksum^='

Bien sûr si vous avez compris mon approche avec l’union contenant un tableau et une structure, celà peut être écrit pour toutes les variables à l’aide d’une simple boucle qui parcourt le tableau, un peu comme je l’ai fait pour l’analyse, plutôt que de faire ça « à la main » pour toutes les variables

;
checksum^=',';

itoa(v1, petitBuffer,10);  // itoa - C++ Reference
for (p= petitBuffer; *p; p++) checksum^=(byte) *p;
Serial.print(petitBuffer);

Serial.print(F(","));
checksum^=',';

itoa(v2, petitBuffer,10);  // itoa - C++ Reference
for (p= petitBuffer; *p; p++) checksum^=(byte) *p;
Serial.print(petitBuffer);

// continuez pour toutes les variables....

Serial.print(F(""));
checksum^='
';

Serial.print(checksum);


Bien sûr si vous avez compris mon approche avec l’union contenant un tableau et une structure, celà peut être écrit pour toutes les variables à l’aide d’une simple boucle qui parcourt le tableau, un peu comme je l’ai fait pour l’analyse, plutôt que de faire ça « à la main » pour toutes les variables

encore une astuce impressionnante :slight_smile: merci beaucoup, je suis ce topic avec attention même si je n'ai pas cette problématique, ça donne des idées :slight_smile:

bonjour à tous,
merci à J-M-L pour son aide, mais il faut que je me rende à l'évidence, tout ceci est trop complexe pour moi, copier un code, ca je sais faire mais n'importe qui sait faire, mais dès que je veux adapter ca ne marche plus ! j'ai fait 50 essais aujourd'hui et rien ne veut...
juste pour aider la communauté sur les unions, j'ai fait des recherches et j'ai touvé ca. et effectivement cel explique qu'on écrit toujours en partant du premier bit de l'adresse, donc on ecrase et ne prend pas plus que la plus grosse des variables...
pour ce qui est de mes développements, je crois qu'il faudra que je m'en tienne à la prog basique en C que je maitrisais il y a une dizaine d'années (je suis un vieux retraité qui veux faire de la prog pour garder les neurones actifs, mais les neurones ne sont plus aussi vaillants qu'à l'origine ... >:(

Bonsoir LuckyMaxou,

Je me permets de revenir pour vous dire de ne surtout pas vous décourager !

Les optimisations et les "astuces" vous avez tout le temps de les apprendre... quand vous en aurez besoin... D'ici là, faites à votre idée. Inspirez vous de choses qui marchent et que vous comprenez !
Peu importe si c'est lourd et pas optimisé, c'est votre projet et progressivement vous ferez mieux !

Sachez aussi que les astuces et les syntaxes compliquées ne sont pas forcément de bonnes choses. Elles tournent à la prouesse intellectuelle pour leur auteur, mais il est facile d'écrire un code auquel personne d'autre ne comprend rien. Et souvent, même l'auteur peine à s'y retrouver quand il doit y revenir quelques mois après...

C'est beaucoup plus dur de faire quelque chose de simple, clair, que tout le monde comprend et dont on peut s'inspirer.

Alors ne vous découragez pas et persévérez, à votre idée.

Bonne bidouille

MicroQuettas

MicroQuettas:
Bonsoir LuckyMaxou,

Je me permets de revenir pour vous dire de ne surtout pas vous décourager !

Les optimisations et les "astuces" vous avez tout le temps de les apprendre... quand vous en aurez besoin... D'ici là, faites à votre idée. Inspirez vous de choses qui marchent et que vous comprenez !
Peu importe si c'est lourd et pas optimisé, c'est votre projet et progressivement vous ferez mieux !

Sachez aussi que les astuces et les syntaxes compliquées ne sont pas forcément de bonnes choses. Elles tournent à la prouesse intellectuelle pour leur auteur, mais il est facile d'écrire un code auquel personne d'autre ne comprend rien. Et souvent, même l'auteur peine à s'y retrouver quand il doit y revenir quelques mois après...

C'est beaucoup plus dur de faire quelque chose de simple, clair, que tout le monde comprend et dont on peut s'inspirer.

Alors ne vous découragez pas et persévérez, à votre idée.

Bonne bidouille

MicroQuettas

100% d'accord avec la partie de ne jamais se décourager !!

Ma réponse (qui n'est pas si compliquée que cela faut pas exagérer - approche très classique de ce genre de challenge) n'avait été motivée que parce que LuckyMaxou avait écrit

:frowning: eh oui, je sais, et le pire, c'est que je n'utilise pas l'avr328 mais le 168 (arduino mini pro 168 5v 16) qui a 1ko de sram...
d'où ma question...

Les optimisations et les "astuces" sont parfois nécessaire tout de suite, si le programme ne rentre pas dans le processeur choisi

Effectivement si la mémoire n'est pas un soucis, utilisez sprintf et sscanf() ça sert à rien de laisser de la mémoire inutilisée :slight_smile: - ou alors prenez un arduino un peu plus costaud et revenez sur ce genre d’approche à base de pointeurs plus tard

Bonjour à tous,
merci J-M-L et merci microquettas
d'abord je voudrais insister sur le fait que mon post ne voulais engager aucune polémique et parlait juste de MES limites et malheureusement je coince parfois sur des solutions simples autant que sur des solutions compliquées. j'ai surtout besoin qu'on m'explique bien (codes très documentés et exemples aboutis même s'il ne correspondent pas à mon exemple exactement, car je cherche 2 choses :

  • la première c'est APPRENDRE
    et la seconde c'est faire ma domotique.
    c'est vrai que j'ai toujours eu des soucis avec les pointeurs, même en langage C...
    Bref... quand J-M-L que je remercie encore écrit :
Ma réponse (qui n'est pas si compliquée que cela faut pas exagérer - approche très classique de ce genre de challenge) n'avait été motivée que parce que LuckyMaxou avait écrit 

Quote
:( eh oui, je sais, et le pire, c'est que je n'utilise pas l'avr328 mais le 168 (arduino mini pro 168 5v 16) qui a 1ko de sram...
d'où ma question...
Les optimisations et les "astuces" sont parfois nécessaire tout de suite, si le programme ne rentre pas dans le processeur choisi

Ma question du jour serait justement :
Exactement jusqu'à quel pourcentage à la compilation peut-on aller sur la mémoire prog et la sram sans craindre des bugs pendant l'exécution ?
merci

ha. vaste interrogation, ça ressemble à celle que je me posais dans ce fil où tu trouvera peut être des éléments de réponse.

MicroQuettas:
Sachez aussi que les astuces et les syntaxes compliquées ne sont pas forcément de bonnes choses. Elles tournent à la prouesse intellectuelle pour leur auteur, mais il est facile d’écrire un code auquel personne d’autre ne comprend rien. Et souvent, même l’auteur peine à s’y retrouver quand il doit y revenir quelques mois après…

C’est beaucoup plus dur de faire quelque chose de simple, clair, que tout le monde comprend et dont on peut s’inspirer.

Bonjour MicroQuettas,

Entièrement d’accord. Une des principales qualité d’un soft est qu’il soit facilement compréhensible et maintenable.

luckymaxou:
Bonjour à tous,
merci J-M-L et merci microquettas
d’abord je voudrais insister sur le fait que mon post ne voulais engager aucune polémique

pas de soucis - on écrit ici entre gens de bonne compagnie et on peut sereinement exprimer son point de vue. le débat est sain et pour certaines questions il n’y a pas de solution unique.

luckymaxou:
Ma question du jour serait justement :
Exactement jusqu’à quel pourcentage à la compilation peut-on aller sur la mémoire prog et la sram sans craindre des bugs pendant l’exécution ?
merci

Votre challenge principal (d’où ma réponse un peu avancée) était le suivant selon ce que vous avez écrit:

  • vous avez des contraintes de places mémoire.

Il y a deux types de mémoire à ménager la SRAM (qui sert pour stocker tout ce qui est volatile) et la mémoire flash qui sert à stocker votre programme et éventuellement des données statiques (qui n’est pas effacée quand vous éteignez votre arduino)

le problème que vous souleviez fait que l’usage de sprintf() ou sscanf() (comme on l’a vu plus haut) augmente de plusieurs kilo-octets la mémoire programme car ce sont des fonctions complexes, donc gourmandes pour stocker le code.

De plus pour faire appel à ces fonctions il vous faire appel à ces fonctions il faut passer en paramètre une chaîne de formatage qui elle même va prendre de la RAM.

Enfin, comme vous l’avez vu, un %d travaille en entier, soit sur 2 ou 4 octets suivant les arduinos, et vous n’avez besoin que d’1 octet pour représenter vos informations, donc vous gaspillez de la RAM pour rien.

La réponse à votre question ci dessus cependant n’est pas simple. En gros, si tout rentre en mémoire FLASH alors vous n’avez pas à vous soucier d’optimiser cette partie là, ça ne vous apporte rien de laisser de la mémoire programme vide… votre code n’est pas à risque. Pour ce qui concerne la RAM (ou SRAM) là il faut être judicieux. Il y a ce que vous dit le compilateur à la compilation → c’est ce qu’il voit que vous allouer de manière statique en RAM. et ensuite il y a ce que vous allez utiliser lorsque le program tourne. il peut s’agir d’allocation dans le TAS ou dans la PILE (cf les débats ci dessus ou le lien de bricofoy où on a évoqué ce sujet)

Utiliser le TAS de manière non contrôlée sur un petit micro-processeur est dangereux, vous risquez de morceler la mémoire ce qui peut conduire à des bugs si vous ne testez pas le retour de tentative d’allocation de mémoire. si vous utilisez la PILE alors il faut regarder ce que consomment les fonctions et les appels les plus profonds (une fonction appelle une fonction qui appelle une fonction → tout cela rajoute les variables locales et deux trois autres trucs sur la pile) et voir si ça rentre dans votre SRAM. Si oui, vous êtes bon et pas la peine de travailler sur l’optimisation, si non alors il faut plonger un peu plus les mains dans le moteur et les octets, c’est ce que je vous proposais plus haut