freeRam vous donne une photo à l'instant T
quand vous faites
String stx = String(millis() / 3600000.0, 2) + ";" + String(iEnrg, 2) + ";" + String(wConso, 3);
vous ne le voyez pas mais lors de la construction de cette String, de nombreuses petites String intermédiaires sont créées, étendues, copiées puis libérées.
➜ il commence par instancier une String pour stx. cette string est vide.
➜ il évalue la formule mathématique millis() / 3600000.0
et crée une String intermédiaire qui est la représentation décimale du nombre avec 2 chiffres après la virgule. appelons la S1
➜ il crée une String temporaire pour ";". appelons là S2
Maintenant il veut concaténer S1 et S2. Pour cela il regarde s'il y a la place dans S1 pour copier S2 au bout. Ce n'est pas le cas puisque S1 a été dimensionnée que pour le nombre. Donc le compilateur alloue un buffer temporaire assez grand pour S1 et S2, (appelons le S1.1) et copie S1 dedans, ajoute S2 à la fin et met le pointeur vers S1.1 à la place de S1, puis libère S1 et S2.
➜ ensuite il crée une String temporaire pour String(iEnrg, 2)
. appelons là S3
il faut maintenant rajouter S3 à la fin de S1.1
Pour cela il regarde s'il y a la place dans S1.1 pour copier S3 au bout. Ce n'est pas le cas puisque S1.1 a été dimensionnée au plus juste. Donc le compilateur alloue un buffer temporaire assez grand pour S1.1 et S3, (appelons le S1.2) et copie S1.1 dedans, ajoute S3 à la fin et met le pointeur vers S1.2 à la place de S1.1, puis libère S1.1 et S3.
la même chose recommence pour ";" et pour String(wConso, 3); avec chaque fois allocation d'une String, puis d'un buffer plus grand pour faire la copie et le déplacement des données... à la fin quand la String finale est construite, il l'affecte à stx.
Toutes ces allocations intermédiaires et toutes ces copies, vous ne les voyez pas si vous mettez un appel à freeRam() avant et après la construction de stx et si la mémoire est limitée, une ou plusieurs de ces opérations "invisibles" ne vont pas marcher mais l'arduino ne vous dira rien ni à la compilation et (sur AVR) ni à l'exécution. L'instruction ne sera juste pas exécutée complètement et vous aurez dans stx
quelque chose pas forcément complet.
si vous faites
Serial.print(millis()/3600000.0, 2); // 2 chiffres après la virgule
Serial.write(';'); // le séparateur
Serial.print(iEnrg, 2); // en flottant, 2 chiffres après la virgule
Serial.write(';'); // le séparateur
Serial.println(wConso, 3); // 3 chiffres après la virgule
il n'y a pas d'allocation dynamique du tout.