Pb enregistrement Float sur EEPROM I2C (Résolu)

bonsoir,

en train d'essayer d'enregistrer sur une EEPROM I2C différentes variables, y arrives maintenant sans problèmes pour les bytes et les int, mais gros problème pour stocker et récupérer les floats,
bien compris qu'il fallait les découper en 4 octets pour ensuite les traiter séparément à l'enregistrement et opération inverse à la lecture, mais là coince complet, pas doué en C, à la limite de mes compétences sur les conversions de type et surtout vois plus rien, qcq heures que suis dessus.... :frowning:

j'ai donc fait un petit bout de prg qui stocke un ensemble de float en EEPROM au niveau du setup, puis le Loop relis le tout et l'affiche sur un LCD,
mais je me prends dans le nez un msg d'erreur du type "invalid opérands or types 'float' and 'int' to 'binary' operator " à la ligne suivante située dans le setup :
i2c_eeprom_write_byte(AdrBaseEeprom++, (Varfloat >> 24) & 0xFF); // écriture MSB
(bien peur de mélanger un peu le tout et m'y perdre)
si un sachant aux idées claires avais la bonté de jeter un coup d'oeil sur ce soucis, et me remettre sur la piste, serais juste top ! :wink:
merci par avance
et bien sur le code en question
```
*#include <Wire.h> //I2C library
#include <LiquidCrystal_I2C.h>

#define ad_ROM_1_I2C 0x50
LiquidCrystal_I2C lcd(0x24,20,4);

// variables a sauvegarder dans l'EEPROM
float Varfloat[] = {123.4,234.5,345.6,567.8,678.9};

// routine d'ecriture de byte individuel dans l'EEPROM
// lui passer adresse, donnee
void i2c_eeprom_write_byte(unsigned int eeaddress, byte data )
{
 Wire.beginTransmission(ad_ROM_1_I2C);
 Wire.write((int)(eeaddress >> 8)); // envoi du MSB de l'adresse
 Wire.write((int)(eeaddress & 0xFF)); // envoi du LSB de l'adresse
 Wire.write(data); //écriture de l'octet
 Wire.endTransmission();
 delay(5);// les écritures consécutives trop rapide mettent leur fiabilité en vrac (marche a partir de 3ms)    
}

// routine de lecture de byte individuel dans l'EEPROM
// lui passer adresse, elle rend le byte correspondant
byte i2c_eeprom_read_byte(unsigned int eeaddress )
{
 byte rdata = 0xFF;
 Wire.beginTransmission(ad_ROM_1_I2C);
 Wire.write((int)(eeaddress >> 8)); // envoi du MSB de l'adresse
 Wire.write((int)(eeaddress & 0xFF)); // envoi du LSB de l'adresse
 Wire.endTransmission();
 Wire.requestFrom(ad_ROM_1_I2C,1);
 if (Wire.available()) rdata = Wire.read(); //lecture de l'octet adressé
 return rdata;
}

void setup()
{
 Wire.begin();  // Init port I2C
 lcd.init();    // initialisation du lcd
 lcd.backlight();
 Serial.begin(9600);

unsigned int AdrBaseEeprom =0; //adresse de l'EEPROM démarre à 0  
 for (int i=0; i<(sizeof(Varfloat) / sizeof(float)); i++) // boucle de balayage de la table
 {    
   float temp = Varfloat[i];
   i2c_eeprom_write_byte(AdrBaseEeprom++, (Varfloat[i] >> 24) & 0xFF); // écriture MSB ---------ligne a Pb, aussi vrai pour les suivantes...
   i2c_eeprom_write_byte(AdrBaseEeprom++, (Varfloat1[i] >> 16) & 0xFF); // écriture MSB-1
   i2c_eeprom_write_byte(AdrBaseEeprom++, (Varfloat[i] >> 8) & 0xFF); // écriture MSB-2
   i2c_eeprom_write_byte(AdrBaseEeprom++, Varfloat[i] & 0xFF); // écriture LSB
   writeFloat(AdrBaseEeprom,AI_C1[i]);
 }
}

void loop()
{
 //Lecture de l'EEPROM
 unsigned int AdrBaseEeprom =0; //adresse de l'EEPROM démarre à 0
 for (int i=0; i<(sizeof(Varfloat) / sizeof(float)); i++) // boucle de balayage de la table
 {
   byte a = i2c_eeprom_read_byte(AdrBaseEeprom++); // chrgt MSB
   byte b = i2c_eeprom_read_byte(AdrBaseEeprom++); // chrgt MSB-1
   byte c = i2c_eeprom_read_byte(AdrBaseEeprom++); // chrgt MSB-2
   byte d = i2c_eeprom_read_byte(AdrBaseEeprom++); // chrgt LSB
   unsigned int ret =  (unsigned int)((a << 24) | (b << 16) | (c << 8) | (d << 0));
   float calcul = (((float)&ret));

// sert a rien, a part verifier de visu que ce qui est écrit correspond aux valeurs qu'on a ecrit
   lcd.clear();
   lcd.setCursor(0,0);
   lcd.print("Valeur lue EEPROM ");
   lcd.setCursor(0,1);
   lcd.print(calcul);  // affiche variable reconstituée
   lcd.setCursor(0,2);
   lcd.print("Valeur Tblx ");
   lcd.setCursor(0,3);
   lcd.print(Varfloat[i]);// affiche variable de base    
   delay(1000);
 }  
}*
```

un peu modifié mon code pour y voir plus clair, mais pas ça....

toujours le même message d'insulte là où l'ai commenté dans le code, soit je passe mon float en unsigned int et je peux le découper en 4, le charger en mémoire, le récupérer mais perd bien sur les décimales,

soit j'essai de découper directement le float et erreur de compilation :frowning:
comprends pas, vous met a 2° version au cas où...

merci d'avance et bonne nuit, là dodo..

#include <Wire.h> //I2C library
#include <LiquidCrystal_I2C.h>
#define ad_ROM_1_I2C 0x50
LiquidCrystal_I2C lcd(0x20,20,4);

// variables a sauvegarder dans l'EEPROM
float Varfloat[] = {123.4 , 234.5 , 345.6 , 567.8, 678.9};

// routine d'ecriture de byte individuel dans l'EEPROM
// lui passer adresse, donnee
void i2c_eeprom_write_byte(unsigned int eeaddress, byte data ) 
{
  Wire.beginTransmission(ad_ROM_1_I2C);
  Wire.write((int)(eeaddress >> 8)); // envoi du MSB de l'adresse
  Wire.write((int)(eeaddress & 0xFF)); // envoi du LSB de l'adresse
  Wire.write(data); //écriture de l'octet
  Wire.endTransmission();
  delay(5);// les écritures consécutives trop rapide mettent leur fiabilité en vrac (marche a partir de 3ms)    
}

// routine de lecture de byte individuel dans l'EEPROM
// lui passer adresse, elle rend le byte correspondant
byte i2c_eeprom_read_byte(unsigned int eeaddress ) 
{
  byte rdata = 0xFF;
  Wire.beginTransmission(ad_ROM_1_I2C);
  Wire.write((int)(eeaddress >> 8)); // envoi du MSB de l'adresse
  Wire.write((int)(eeaddress & 0xFF)); // envoi du LSB de l'adresse
  Wire.endTransmission();
  Wire.requestFrom(ad_ROM_1_I2C,1);
  if (Wire.available()) rdata = Wire.read(); //lecture de l'octet adressé
  return rdata;
}

void setup() 
{
  Wire.begin();  // Init port I2C
  lcd.init();    // initialisation du lcd 
  lcd.backlight();
  Serial.begin(9600);

  unsigned int AdrBaseEeprom =0; //adresse de l'EEPROM démarre à 0  
  for (int i=0; i<(sizeof(Varfloat) / sizeof(float)); i++) // boucle de balayage de la table
  {     
    
//***********************************************************************
//*****************     PROBLEME     ************************************
// compile pas si float temp = Varfloat[i];
// marche si unsigned int temp = Varfloat[i] mais perd les décimales, 
//logique pour un entier
//***********************************************************************
    unsigned int temp = Varfloat[i];
//    float temp = Varfloat[i];    

    i2c_eeprom_write_byte(AdrBaseEeprom++, (temp >> 24) & 0xFF); // écriture MSB 
    i2c_eeprom_write_byte(AdrBaseEeprom++, (temp >> 16) & 0xFF); // écriture MSB-1
    i2c_eeprom_write_byte(AdrBaseEeprom++, (temp >> 8) & 0xFF); // écriture MSB-2
    i2c_eeprom_write_byte(AdrBaseEeprom++, temp & 0xFF); // écriture LSB
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Ecriture de : ");
    lcd.setCursor(14,0);
    lcd.print(temp);
    lcd.setCursor(0,1);
    lcd.print("a l'adresse : ");
    lcd.setCursor(14,1);
    lcd.print(AdrBaseEeprom-1);
    delay(300);   
  }
}

void loop() 
{
  //Lecture de l'EEPROM 
  unsigned int AdrBaseEeprom =0; //adresse de l'EEPROM démarre à 0
  for (int i=0; i<(sizeof(Varfloat) / sizeof(float)); i++) // boucle de balayage de la table
  {
    byte a = i2c_eeprom_read_byte(AdrBaseEeprom++); // chrgt MSB
    byte b = i2c_eeprom_read_byte(AdrBaseEeprom++); // chrgt MSB-1
    byte c = i2c_eeprom_read_byte(AdrBaseEeprom++); // chrgt MSB-2
    byte d = i2c_eeprom_read_byte(AdrBaseEeprom++); // chrgt LSB
    float calcul =  (unsigned int)((a << 24) | (b << 16) | (c << 8) | (d << 0));

    // sert a rien, a part verifier de visu que ce qui est écrit correspond aux valeurs qu'on a ecrit
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("verif liste / EEPROM");
    lcd.setCursor(0,1);
    lcd.print("Nb total octets : ");     
    lcd.setCursor(16,1);
    lcd.print(sizeof(Varfloat));  
    lcd.setCursor(0,2);
    lcd.print("Elmt num : ");
    lcd.setCursor(12,2);
    lcd.print(i);
    lcd.setCursor(0,3);
    lcd.print(Varfloat[i]);    
    lcd.setCursor(12,3);
    lcd.print(calcul);    
    delay(500);
  }   
}

L'opération de décalage est une opération binaire. Elle ne fonctionne pas sur des flottants.
Pour récupérer les 4 octets utilisés pour coder un flottant il y a 2 méthodes:
Soit utiliser un pointeur de byte pour aller lire les 4 octets en mémoire

  float maVariable;
  byte *ptr;
  
  ptr = (byte *)&maVariable;
  for(byte i=0;i<4;i++){
      byte octet = *(ptr+i);
   // là tu utilises octet pour faire ce que tu veux
  }
}

Soit utiliser une union

  float maVariable;
  union {
    float f;
    byte b[4];
  }convert;
  
  convert.f=maVariable;
  for(byte i=0;i<4;i++){
      byte octet = convert.b[i];
   // là tu utilises octet pour faire ce que tu veux
  }

Yeap, tu est génial , et ce forum tout autant !!!

tip-top, me suis de nouveau cassé la tête pour arriver à reconstruire le float mais fonctionne enfin !

Pour être franc, pas tout compris, une partie de la nuit et la matinée passée sur cette fichue opération, vraiment là qu'on constate ses limites, mais vais pouvoir l'intégrer dans mon projet.
( faut vraiment que j'arrive à comprendre ces pointeurs, unions et autres, mais là pas le courage !)

et pour ceux à qui ça pourrais être utile, je met un code qui marche là-dessous :

merci à toi,
tout de bon :wink:

#include <Wire.h> //I2C library
#include <LiquidCrystal_I2C.h>
#define ad_ROM_1_I2C 0x50
LiquidCrystal_I2C lcd(0x20,20,4);

// variables a sauvegarder dans l'EEPROM
float Varfloat[] = {123.4 , 234.5 , 345.6 , 567.8, 678.9};
float calcul; //variable reconstituée à a lecture

void setup() 
{
  Wire.begin();  // Init port I2C
  lcd.init();    // initialisation du lcd 
  lcd.backlight();
  Serial.begin(9600);

  unsigned int AdrBaseEeprom =0; //adresse de l'EEPROM démarre à 0  
  for (int i=0; i<(sizeof(Varfloat) / sizeof(float)); i++) // boucle de balayage de la table
  { 
    byte *ptr;
    ptr = (byte *)&Varfloat[i];
    for(byte j=0;j<4;j++)
    {
      byte octet = *(ptr+j);
      i2c_eeprom_write_byte(AdrBaseEeprom++,octet);
    }    
    // sert a rien, juste à voir de visu ce qui se passe...
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Ecriture de : ");
    lcd.setCursor(14,0);
    lcd.print(Varfloat[i]);
    lcd.setCursor(0,1);
    lcd.print("a l'adresse : ");
    lcd.setCursor(14,1);
    lcd.print(AdrBaseEeprom-1);
    delay(300);  
  }
}

void loop() 
{
  //Lecture de l'EEPROM 
  unsigned int AdrBaseEeprom =0; //adresse de l'EEPROM démarre à 0
    union u_tag 
  {
    byte b[4];
    float fval;
  } u;
  
  for (int i=0; i<(sizeof(Varfloat) / sizeof(float)); i++) // boucle de balayage de la table
  {
    u.b[0] = i2c_eeprom_read_byte(AdrBaseEeprom++); // chrgt LSB
    u.b[1] = i2c_eeprom_read_byte(AdrBaseEeprom++); // chrgt LSB+1
    u.b[2] = i2c_eeprom_read_byte(AdrBaseEeprom++); // chrgt LSB+2
    u.b[3] = i2c_eeprom_read_byte(AdrBaseEeprom++); // chrgt MSB
    calcul = u.fval;

    // sert a rien, a part verifier de visu que ce qui est écrit correspond aux valeurs qu'on a ecrit
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("verif liste / EEPROM");
    lcd.setCursor(0,1);
    lcd.print("Nb total octets : ");     
    lcd.setCursor(16,1);
    lcd.print(sizeof(Varfloat));  
    lcd.setCursor(0,2);
    lcd.print("Elmt num : ");
    lcd.setCursor(12,2);
    lcd.print(i);
    lcd.setCursor(0,3);
    lcd.print(Varfloat[i]);    
    lcd.setCursor(12,3);
    lcd.print(calcul);    
    delay(1000);
  }   
}

// routine d'écriture de byte individuel dans l'EEPROM
// lui passer adresse, donnée, elle enregistre
void i2c_eeprom_write_byte(unsigned int eeaddress, byte data ) 
{
  Wire.beginTransmission(ad_ROM_1_I2C);
  Wire.write((int)(eeaddress >> 8)); // envoi du MSB de l'adresse
  Wire.write((int)(eeaddress & 0xFF)); // envoi du LSB de l'adresse
  Wire.write(data); //écriture de l'octet
  Wire.endTransmission();
  delay(5);// les écritures consécutives trop rapide mettent leur fiabilité en vrac (marche a partir de 3ms)    
}

// routine de lecture de byte individuel dans l'EEPROM
// lui passer adresse, elle rend le byte correspondant
byte i2c_eeprom_read_byte(unsigned int eeaddress ) 
{
  byte rdata = 0xFF;
  Wire.beginTransmission(ad_ROM_1_I2C);
  Wire.write((int)(eeaddress >> 8)); // envoi du MSB de l'adresse
  Wire.write((int)(eeaddress & 0xFF)); // envoi du LSB de l'adresse
  Wire.endTransmission();
  Wire.requestFrom(ad_ROM_1_I2C,1);
  if (Wire.available()) rdata = Wire.read(); //lecture de l'octet adressé
  return rdata;
}

Bonjour,
Pour les pointeurs, tu peux jeter un œil ici : Les pointeurs et tableaux - Tutoriels et cours - Arduino Forum.
@+

Super,

merci à toi, soigneusement rangé le répertoire tuto à lire...
et en plus, m'as l'air bien pédagogique ! :slight_smile: