(deleted)
De mémoire, il me semble que le support des float n'est pas implémenté la chaine de compilation pour ces petits processeurs.
[EDIT]: je n'ai pas été clair. Le support des flottants n'est pas implémenté dans sprintf
Bonjour, Monsieur EtauLimeur:
en attendant mieux, j'ai éssayé ça sur PC (j'ai coupé le float en 2, formatté sa partie entière, puis sa partie fractionnaire (multipliée par 100, sans se préoccupper des erreurs d'arrondi)
; je n'ai pas retiré le caractère de fin de ligne, qui peut être mis dans le format.
int mday = 11, mon=3,year=2019, hour=12, minute=55, sec =44;
float tot_litrage =18.75;
int iLitrage= int(tot_litrage); //
int fLitrage= int (100.0 * (tot_litrage- iLitrage));
sprintf(buffer2, "%02d/%02d/%02d-%02d/%02d/%02d*%06d.%02dLF%c",
mday, mon, year, hour, minute, sec, iLitrage, fLitrage, 0x0A );
printf("%s\n", buffer2);
}
Ca donne ça:
11/03/2019-12/55/44*000018.75LF
fdufnews:
De mémoire, il me semble que le support des float n'est pas implémenté la chaine de compilation pour ces petits processeurs.
Si: je sais que c'est gourmand -quelques ko; peut être 10% - , mais des librairies gérant des senseurs divers et variés (DHT ) devraient être réécrites.
Et la librairie mathématique d'avr a un ensemble de fonctions gérant l'élévation du soleil , et sa position, et la durée du jour (en float) qui fait envie... aux possesseurs de PC (elles sont ennuyeuses à trouver, sinon)
Bonjour,
Comme le dit fdufnews %f n'est pas implémenté dans sprintf pour les processeurs avr. Il faut utiliser dtosrtf()
Mais les floats existent -c'est donc un support incomplet, mais bien pratique:
il suffit donc de les convertir en partie entière et fractionnaire, après avoir fait toutes les multiplications et divisions sans s'ennuyer avec les débordements....
(deleted)
Dans le format, une chaine c'est %s et non %c
il faut que litre fasse 10 caractères car il faut compter le \0 qui marque la fin de la chaine.
LF est le retour ligne (la variable c == 10)?
et dire que je m'étais décarcassé pour l'écrire explicitement....
(deleted)
Différentes remarques:
des lors "%02d" ne devrait pas me donner "2019" ?! (ou je retourne me coucher ?)
%02d
—> le d c’est pour « Entier décimal signé », largeur minmum 2, remplissage avec des 0 si nécessaire pour atteindre la largeur minimum.
En pratique L’argument width est un entier décimal non négatif qui contrôle le nombre minimal de caractères qui sont générés. Si le nombre de caractères dans la valeur de sortie est inférieur à la longueur spécifiée, des espaces sont ajoutés à gauche ou à droite des valeurs, selon que l’indicateur d’alignement à gauche (-) est spécifié ou non, jusqu’à ce que la largeur minimale soit atteinte. Si width est préfixé par 0, des zéros non significatifs sont ajoutés aux conversions en entiers ou en nombres à virgule flottante jusqu’à ce que la largeur minimale soit atteinte, sauf en cas de conversion en valeur infinie ou NaN.
La spécification de largeur ne provoque jamais la troncature d’une valeur. Si le nombre de caractères dans la valeur de sortie est supérieur à la largeur spécifiée, ou si width n’est pas spécifié, tous les caractères de la valeur sont générés, conformément à la spécification precision.
====
Pour le support des float, ça rajoute énormément de besoin en flash et c’est ce qui a conduit à l’éliminer en effet. Il y a moyen de le rajouter si vous en avez vraiment besoin par un flag à la compilation, c’est même assez simple de rajouter un menu qui permet de l’activer en éditant boards.txt (jamais testé parceque je pense que c’est une mauvaise idée et solution de facilité, vaut mieux se demander comment s’en passer)
En pratique sur un petit micro contrôleur avec peu de ram, on se pose toujours la question « ai-je vraiment besoin de construire ce buffer, que vais-je en faire ? »... si c’est pour transmettre quelque part, il n’y a aucune raison valable généralement, il suffit d’envoyer les différents éléments les uns après les autres, les communications sont série de toutes façon généralement, donc tout part bit par bit.
De plus balancer un gros buffer de plus de 64 octets d’un coup dans print pour Serial rend la fonction print bloquante jusqu’à ce qu’il n’en reste plus que 64 à transmettre... ça peut créer des soucis de timing dans votre application
Quand on affiche des float il faut aussi se demander si les chiffres après la virgule que l’on montre sont nécessaires et pertinents. Un capteur de température donne-t-il une précision au centième de degrès ? Un module de mesure de distance par ultrason donne-t-il une précision au centième de mm ? Etc
Enfin si vous avez vraiment besoin de traiter des float sur un micro-processeur 8 bits sans unité de calcul décimaux (c’est lent donc) et avoir une représentation ASCII , la librairie AVR vous propose la fonction dtostrf().
Tout d'abord, mon calcul de la partie entière et fractionnaire est sous optimal (18.7499 sera affiché 18.74 ...)
Une meilleure / moins mauvaise façon de faire serait:
int litrageEntier, litrageFrac,litrageX100; // on peut aller jusqu'à 600 l: c'esr beaucoup
litragex100 = int (litrage*100.0 +0.5); // litrage est > 0, sauf si on stère de l'antimaiière
litrageFrac = litrageX100 % 100;
litrageEntier = litrageX100 / 100;
et après, l'affichage d'entiers se fait comme avant; On perd 2 octets de RAM par rapport à mon écriture précédente, et on gagne ... 4 octets par rapport à l'écriture dans une chaîne temporaire (peut être sous dimensionnée).
Les gains ou pertes de l'usage de floats sont les suivants :
on n'a pas à s'ennuyer avec les bornes des résultats, définitifs ou intermédiaires (chasser des over/underflows peut prendre des jours: le gain avec des floats conduisait, il y a 30 ans, à acheter des cartes RAMs supplémentaires -leur prix était hénaurme, mais moins que les maigres salaires: aujourdh'hui, les prix des processurs+RAM+perifs sont négligeables, le temps passé à chasser les débordements restant constant ...)
Les floats (à un recadrage près) font leurs calculs sur 24 bits, plus vite que les .u.int32_t (moins que les ints d'arduino, cependant)... Ce n'est pas si lent...
La bibliothèque d'affichage complète mange 4K de flash: ce n'est pas énorme sur un 328 (13%), sauf s'il est plein ... et ça fait 1.6% d'un 2560 (quand il est plein à 80%, je doute que le support complet des floats soit
le poste à regarder avec suspicion). Pour les autres processeurs, arm-s- (coûtent un bras) et espifs (pas chers; vont concurrencer les avr-s-), la gloutonnerie en flash et en temps est encore plus négligeable (certes, les petits ruisseaux font les grandes rizières, et accumuler des dépenses négligeables n'est pas sain).
En plus, les fabricants ou distributeurs de capteurs font tous les calculs en floats (les capteurs sortent trop vite et ne sont pas vendables pour les bricoleurs sans bibliothèque Arduino: ils en font une, fiable quoique peu élégante...).
Il y a des cas où l'affichage avec enormémént de décimales est fort utile: je pense aux baromètres, dont la mesure absolue est soumise à des dérives, mais dont les variations -si à l'abri de courants d'air- donnent une indication de la variation d'altitude : le centième de Pa correspond à 10 cm (résolution de ce mode, implicant, au moins au débuggage, d'afficher 8 chiffres... Ce n'est donc pas si ridicule que ça d'afficher 4 chiffres, dans une phase de mise au point.
je pense aux baromètres, dont la mesure absolue est soumise à des dérives, mais dont les variations -si à l'abri de courants d'air- donnent une indication de la variation d'altitude : le centième de Pa correspond à 10 cm (résolution de ce mode, implicant, au moins au débuggage, d'afficher 8 chiffres... Ce n'est donc pas si ridicule que ça d'afficher 4 chiffres, dans une phase de mise au point.
je ne suis pas d'accord... on peut penser que ça donne une indication mais bien souvent on se leurre et on est dans le bruit statistique qui ne sera pas opérationnel en prod...
Pour reprendre la pression, un BMP180 par exemple va mesurer entre 300 et 1100hPa avec 0.02hPa de bruit en "advanced resolution mode" et une accuracy relative de ±0.12hPa donc sur ce capteur vous êtes très loin de ±0.01 hPa
(en mesure absolue il propose -1±1 hPa et effectivement 10m correspondent à 1.2hPa de changement au niveau de la mer)
(un BMP280 est à ±0.12 hPa, soit ±1 m)
et je ne parle pas de l'impact de l'alimentation, variation de t° etc...
De plus la précision d'un float sur un UNO ou similaire est assez mauvaise puisse codage sur 4 octets. le calcul de la pression sur un BMP180 doit tenir compte d'une équation assez complexe prenant en compte des paramètres stockés en EEPROM
c3 = 160.0 * pow(2,-15) * AC3;
c4 = pow(10,-3) * pow(2,-15) * AC4;
b1 = pow(160,2) * pow(2,-30) * VB1;
c5 = (pow(2,-15) / 160) * AC5;
c6 = AC6;
mc = (pow(2,11) / pow(160,2)) * MC;
md = MD / 160.0;
x0 = AC1;
x1 = 160.0 * pow(2,-13) * AC2;
x2 = pow(160,2) * pow(2,-25) * VB2;
y0 = c4 * pow(2,15);
y1 = c4 * c3;
y2 = c4 * b1;
p0 = (3791.0 - 8.0) / 1600.0;
p1 = 1.0 - 7357.0 * pow(2,-20);
p2 = 3038.0 * 100.0 * pow(2,-36);
et ensuite vous faites un
pu = (data[0] * 256.0) + data[1] + (data[2]/256.0);
s = T - 25.0;
x = (x2 * pow(s,2)) + (x1 * s) + x0;
y = (y2 * pow(s,2)) + (y1 * s) + y0;
z = (pu - x) / y;
pour enfin obtenir un P = (p2 * pow(z,2)) + (p1 * z) + p0;
dans tous ces stockages de variables intermédiaire vous accumulez des imprécisions car vous serez précis en gros qu'à 6 chiffres après la virgule
bref - à part cas particulier je ne suis pas convaincu du grand interêt de pousser trop loin la confiance dans ce qu'on obtient...
Je n'ai jamais su ce que voulait dire "mesure absolue"," mesure relative" et bruit:
pour moi, un bruit est blanc et non correlé ; s'il est gaussien, on peut vérifier ce que raconte le constructeur (hors courants d'air...) par le calcul de la moyenne de l'écart (en valeur absolue) entre une mesure et la mesure précédente.
float erreur = 0.0, mesurepre = -99.0; // les mesures sont positives; n'existent pas au début
int ier=0
while (ier < 256) {
float mesure = mesurer();
if (mesurepre> 0) { ier++; erreur = erreur + abs(mesurepre - mesure);}
mesurepre= mesure;
}
erreur = (erreur +128.0) / 256.0; // éventuellement, diviser par sqrt(2*pi; cf wikipedia + demi-normale)
NB : on peut faire la même chose avec un calcul en entiers sur un tout petit contrôleur.... mais il faut contrôler les overflows...
De mémoire, le bruit identifié par ce calcul était cohérent avec ce qu'affirme le constructeur.
Si les deux autres sources d'erreur sont à variation très lente,
ceci est mon interprétation, peut être optimiste ou indulgente
le capteur est qualifié pour
positionner un étage de parking -sans GPS- ou d'ascenseur (un étage fait 3-4 m; le bruit correspond à 10cm -20 cm sur une variation-, et a donc moins d'une chance sur 1000 d'être de 1 mètre). Ce qui est revendiqué par Bosch (équipementier automobile)...
" la précision d'un float sur un UNO ou similaire est assez mauvaise puisse codage sur 4 octets."
3 octets + exposant.. calcul sur 24 bits (
ce que fait la simple precision en Fortran depuis des décennies (le siècle/millénaire dernier);
et certains logiciels -Splus- offrent le choix entre la simple précision et la double, son pendant libre R n'offrant "que " la double précision : ceci indiquerait que ce choix a une valeur commerciale et n'est pas si mauvais que ça (évite d'ouvrir un PC et d'y mettre une barrette de RAM...)).
Ce que je dis c'est que pour que votre seconde décimale soit représentative (précision de l’afficheur) il ne faut pas que l'incertitude soit de l’ordre de 0,1 sinon le dernier digit de l’affichage n’a plus aucune signification (on ne peut pas donner un résultat plus précis que son incertitude).
hors c'est souvent le cas en pratique
Dans une phase de debuggage, cela ne me choque absoluement pas de mettre des décimales extra-numéraiires, voire complétement ridicules; dans une phase finale (passage sur un proc plus petit : les arduini mega sont idéaux pour debugguer, avec des printf -c'est le seul moyen facilement accessible et reproductible, sauf la contemplation de son code -avec les yeux de Chimène-); utilisation de petits afficheurs au lieu de la jonction série : on n'aura pas toujours un PC/RPi+grand écran sous la main-, ces affichages, superflus, gourmands voire inutiles peuvent évidemment disparaître)....
J'avais préféré respecter la demande initiale (avec, au début, la possibilité de maltraiter la dernière décimale qui n'a pas forcément de sens, de toutes façons) qui peut avoir un sens -ça dépend de son capteur, et éventuellent de l'autre boîte noire, la bibliothéque du constructeur)
moi je reviens à mon point de départ qui est : A quoi va servir ce gros buffer... si c'est pour faire un "print()" ça ne sert à rien... et print sait très bien imprimer un float...
Ca peut servir sur des petits écrans (et certaines bibliothèques: certaines ne savent gérer "que " des chaînes de caractères -mais ne font que ça- , imposant de convertir explicitement en null terminated strings (je doute qu'il puisse mettre 30 chars sur une seule petite ligne, cependant , ou alors il faut une grosse loupe...)
les librairies qui ne savent gérer que les "chaînes" sont à mettre à la poubelle ou améliorer
c'est pas compliqué de rajouter l'infrastructure de Print - et vous pouvez faire toujours des petits buffers avec chaque élément indépendant
" qui ne savent gérer que les "chaînes" sont à mettre à la poubelle ou améliorer "
ou à tester très vite... à garder si elles consomment peu de place.
(le cas le plus flagrant est de faire un miniterminal serie ).
Quant aux améliorations: que se passera-t-il si leur auteur fait des maintenances logicielles et que ces maintenances sont prises en compte par le gestionnaire de librairies d'arduino?
Même si les amélirorations ne sont pas compliquées, elles sont un peu chronophages, soumises à bugs ... voire à destruction via un gestionnaire de librairies...