EEPROM programme débutant

Bonjour à tous,

Voici mon problème:

#include <EEPROM.h>
void setup() {
  Serial.begin(9600);
  union data {
    float f;
    int i;
  } convert;

  float f = 1.23;  // 00000001 .  00001011
  convert.f = f;

  EEPROM.write(0, highByte(convert.i)); //00000001
  EEPROM.write(1, lowByte(convert.i));  //00001011

  //----------------------------------

  byte high = EEPROM.read(0);
  byte low = EEPROM.read(1);

  convert.i = (high << 8) + low;
  f = convert.f;

  Serial.println(convert.i);
  Serial.println();
  Serial.println(f);

}

void loop() {
  // put your main code here, to run repeatedly:

}

J’ai pour résultat :

1- convert.i : 28836 incorrect

2- f : 1.23 correct

Merci pour votre attention

JPD

Faire une union entre un float et un int n'a aucun sens. Un float d'autre part a une taille de 32bits.
Si tu nous parlais plutôt de ce que tu veux exactement faire ?

L'entier n'est pas initialisé, comment peux-tu savoir s'il est incorrect ?

Il s'agit d'une union. Les deux variables membres se recouvrent (partiellement car elles n'ont pas la même taille).

“Faire une union entre un float et un int n’a aucun sens. Un float d’autre part a une taille de 32bits.”

Faux: ça veut dire qu’on reserve la place la plus grande pour un float et un int , soit 4 octets.
(c’est le sosie de EQUIVALENCE en Fortran, qui était souvent interdit, car source de désordre - même si ça faisait un sens pour un compilateur ou un lecteur très soigneux et que ça continue de faire un sens, tout en restant abominable)

gère proprement, à mon sens, les écritures et lectures en EEPROM (sans avoir à se soucier de la taille, calculée par sizeof

#define EEPROM_write(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) EEPROM.write(address+i, pp[i]);}
#define EEPROM_read(address, p)  {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) pp[i]=EEPROM.read(address+i);}

(l’utilisateur n’a pas à se soucier de la nature de ce qu’il veut stocker, qui est forcé à un tableau d’octets)

(partiellement car elles n’ont pas la même taille)
Ceci a un sens pour les arduino basés sur avr (le int a 16 bits); les arduini basés sur arm ou esp ont ils des “int” de 16 bits?

Par ailleurs, si on veut écrire en EEPROM deux nombres, et les récupérer, il faut veiller à ce que le dernier ne squatte pas l’adresse de l’autre (seul le dernier écrit sera recupérable, sinon; est ce souhaitable)
Pour écrire un entier puis un réel, j’écrirais (non testé)

#include <EEPROM.h>


#define EEPROM_write(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) EEPROM.write(address+i, pp[i]);}
#define EEPROM_read(address, p)  {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) pp[i]=EEPROM.read(address+i);}

void setup() {
  Serial.begin(115200);
  int a = 12345, aLu=-1; 
  float b=56.78, bLu=-9.0;
  int addr_a=0;
  int addr_b;
  addr_b= addr_a + sizeof(a); // évite chevauchement
  EEPROM_write(addr_a, a);
  EEPROM_write(addr_b, b);
  
  EEPROM_read(addr_a, aLu);
  EEPROM_read(addr_b, b_lu);
Serial.println(aLu);
Serial.println(bLu);
}
void loop{}

Comme le dit hbachetti on de peut pas interpréter un bout d’un float comme un entier.
Il suffit de voir la structure d’un float pour se rendre compte que ça n’a aucun sens.

Dans le monde ARDUINO l'int est codé sur 2 octets, le float sur 4 octets.
Chercher à faire l'union d'un int est d'un float, deux entités radicalement différentes, ne rime à rien.

  float f;
  EEPROM.put(0, 1.23);
  EEPROM.get(0, f);
  Serial.println(f);

Cela donne bien le résultat attendu, sans gymnastique inutile.

EEPROM::put() et EEPROM::get() sont deux fonctions template qui tiennent compte du type de la variable passée en paramètre.

Merci.

J'ai pris ça dans le livre qui venait avec la carte Mega 2506:

https://www.amazon.ca/s?k=simon+monk&i=stripbooks&gclid=Cj0KCQjwrrXtBRCKARIsAMbU6bENn93wl-3GPJCsvsY-JJrDliuVMRTdhRyRm-t3w2o0Z54kdDEEJ-UaAsYgEALw_wcB&hvadid=230010979844&hvdev=c&hvlocphy=9000462&hvnetw=g&hvpos=1t1&hvqmt=e&hvrand=10190334108039086848&hvtargid=kwd-301245660225&hydadcr=3284_10310740&tag=googcana-20&ref=pd_sl_q3kscnve9_e

" The following union defenition allows both a float and an int to refer to the same two bytes of memory: code" p 119

jpd

"Chercher à faire l'union d'un int est d'un float, deux entités radicalement différentes, ne rime à rien."

Ca rime à chercher à économiser 2 (cas des avr) ou 4 octets, avec un risque enorme de confusion (c'était utilisé, quoique interdit, dans les années 80 pour recouvrir, disons un tableau d'entiers par un tableau de reels, en pariant qu'ils ne seraient jamais utilisés simultanément: le gain de place permettait de faire fonctionner des logiciels interessants -ils rimaient à quelque chose pour les utilisateurs qui n'étaient pas poetes!- sur de très petits calculateurs, même pour l'époque, au prix d'enormes problèmes de maintenance).