Belső EEPROM használata

Amikor először használtam az ATmega chip belső eeprom-ját, nem néztem meg alaposan az eeprom kezelésére rendelkezésre álló könyvtárat. Azt hittem, csak byte-onként lehet írni az eeprom-ba, illetve olvasni onnan. Nehezen boldogultam ez első long változó kiírásával, mert az ugye 4 byte-os, és nem triviális, hogyan kell byte-onként felbontani. Sikerült! Elkezdtem írni egy általános kezelő függvényt, amivel mindenféle típusú változókat lehet használni. Baromság! Egy ennyire gyakran felmerülő problémára már van a világban megoldás, csak szét kell nézni. Persze alaposabban int én tettem! Szerencsére időben felfedeztem, hogy az EEPROM.write() illetve EEPROM.read() függvényeken kívül van más is van ebben a függvény gyűjteményben. Az EEPROM.put() a leírások szerint bármilyen változót beleír az eeprom-ba egy megadott kezdőcímtől kezdve. Az EEPROM.get() pedig kiolvassa azt egy változóba. Persze a memória változóknak azonos típusúaknak kell lennie olvasáskor a beíráskor használt változó típussal.

Írtam hát gyorsan egy próba programot, hogy lássam tényleg működik a dolog. Nagyon kényelmes, mert struktúrákat is felismer és helyesen tárol. A stringekkel már vannak problémák. Lehetséges, hogy az én ismeret hiányom miatt szaladtam bele a tapasztalt problémákba, de az is lehet, hogy az EEPROM.put() tényleg rosszul van megírva. Bárhogy is van, a string-el vigyázni kell. Tapasztalataimat kommentek formájában a programba írtam.

Itt a demóprogram forrása! Nem szabad megijedni a forráskód hosszától, a program nagy része a kommentekből és a soros portra írásból áll. Az eeprom kezelése csak néhány sor.

#include <EEPROM.h>

bool xbool;         //bool típusú változó.
byte xbyte;         //byte típusú változó.
int xint;           //int típusú változó.
long xlong;         //long típusú változó.
float xfloat;       //float típusú változó.
String xszoveg;     //egy karakter stringet is definiálunk
String yszoveg;     //ezt egy működési hiba vizsgálata miatt csináltam
String zszoveg;     //ez is a működési hiba miatt keletkezett
int eeprom_cim;      //ebben a változóban vezetjük a mindíg soron következő címet, ahová írni fogunk az epromban (olvasásnál is ezt használjuk)

struct datum_ido{   //definiálunk datum_ido névvel egy struktúrát, ebben fogjuk tárolni a dátumot és idopontot
  int ev;
  byte ho;
  byte nap;
  byte ora;
  byte perc;
};
datum_ido xdatum_ido;  //készítünk egy datum_ido típusú változót xdatum_ido névvel


void setup(){
  Serial.begin(9600);

/********************************************************************************************************** 
 * A következő ciklus törli a teljes eeprom-ot. Az EEPROM.lenght() megadja az eeprom-unk teljes hosszát.  *
 * Csak akkor futattam, amikor már alaposan teleforkáltam az eeprom-ot, és tiszta lappal akartam indulni  *
 **********************************************************************************************************/
 // for (unsigned int i = 0 ; i < EEPROM.length() ; i++ )
 //   EEPROM.write(i, 0);
 // Serial.print("EEPROM törölve, mérete:");Serial.println(EEPROM.length());


/********************************************************************************************************************************
 * Ebben a programrészben különféle változó típusokat írunk ki az epromba. "eecim" változó mindíg az aktuális címet tartalmazza *
 * ahonnan kezdve írjuk a változót. Azt, hogy hány byte-ot foglalunk el a változó kiírásával, az nekünk kell kiszámolni.        *
 * Ha visszaolvassuk a memória változó tartalmát az eeprom-ból, akkor ki kell számolni a váltzó címét, ahonnan kezdve kiírtuk.  *
 * Ha íráskor rosszul számoljuk ki a következő szabad eeprom terület kezdőcímét, akkor egymásra írhatjuk a változó tartalmakat, *
 * és visszaolvasáskor marhaságokat kaphatunk.                                                                                  *
 * Ha egyszer lefuttatuk ezt a programrészt, akkor ki lehet kommentezni a programból, mert a tárolt értékeket már lehet         *
 * visszaolvasni tetszőleges számban, és ekkor biztosak lehtünk a program működésében.                                         *
 ********************************************************************************************************************************/

  Serial.println("***************** Irunk az eeprom-ba: ");

  xbool = 1;            
  EEPROM.put( eeprom_cim, xbool);
  Serial.print("Bool: ");
  Serial.print( xbool, BIN);                        //xbool kiírása ellenőrzéshez
  Serial.print("  Merete:");
  Serial.println(sizeof(bool));

  xbyte = 66;          
  eeprom_cim=eeprom_cim+1;                          //a bool 1byte-ot foglal, tehát 1 byte-al kell növelni a következő eeprom címet
  EEPROM.put( eeprom_cim, xbyte);
  Serial.print("Byte: ");
  Serial.print( xbyte);                             //xbyte kiírása ellenőrzéshez
  Serial.print("  Merete:");
  Serial.println(sizeof(byte));

  xint = 29567;          
  eeprom_cim=eeprom_cim+1;                          //a byte 1 byte-ot foglal, tehát 1 byte-al kell növelni a következő eeprom címet
  EEPROM.put( eeprom_cim, xint);
  Serial.print("Int: ");
  Serial.print( xint);                              //xint kiírása ellenőrzéshez
  Serial.print("  Merete:");
  Serial.println(sizeof(int));

  xlong = 234567;    
  eeprom_cim=eeprom_cim+2;                          //az int 2 byte-ot foglal, tehát 2 byte-al kell növelni a következő eeprom címet
  EEPROM.put( eeprom_cim, xlong);
  Serial.print("Long:");
  Serial.print( xlong);                             //xlong kiírása ellenőrzéshez
  Serial.print("  Merete:");
  Serial.println(sizeof(long));

  xfloat = 1.2334567;  
  eeprom_cim=eeprom_cim+4;                          //az long 4 byte-ot foglal, tehát 4 byte-al kell növelni a következő eeprom címet
  EEPROM.put( eeprom_cim, xfloat);
  Serial.print("Float: ");
  Serial.print( xfloat,7);                          //xfloat kiírása ellenőrzéshez 7 tizedesjegy hoszan
  Serial.print("  Merete:");
  Serial.println(sizeof(float));

  xdatum_ido.ev=2010;             
  xdatum_ido.ho=8;
  xdatum_ido.nap=11;
  xdatum_ido.ora=6;
  xdatum_ido.perc=1;
  eeprom_cim=eeprom_cim+4;                          //az float 4 byte-ot foglal, tehát 4 byte-al kell növelni a következő eeprom címet
  Serial.print("Datum1:");
  EEPROM.put( eeprom_cim, xdatum_ido);
  Serial.print(xdatum_ido.ev);Serial.print(".");                        
  Serial.print(xdatum_ido.ho);Serial.print("."); 
  Serial.print(xdatum_ido.nap);Serial.print("  ");
  Serial.print(xdatum_ido.ora);Serial.print(":");
  Serial.print(xdatum_ido.perc);
  Serial.print("  Merete:");
  Serial.println(sizeof(datum_ido));

  // Azért csináltam egy második tartalom kiírást, mert a string változónál tapasztalt hibajelenség miatt, szerettem volna megtudni,
  // hogy struktúra esetén is keletkezhetnek hasonló hibák. Itt nincs hiba, tehát a string változó hossza zavarja meg a működést.
  xdatum_ido.ev=2020;             
  xdatum_ido.ho=9;
  xdatum_ido.nap=18;
  xdatum_ido.ora=7;
  xdatum_ido.perc=11;
  eeprom_cim=eeprom_cim+6;                              //az datum_ido 6 byte-ot foglal, tehát 6 byte-al kell növelni a következő eeprom címet
  Serial.print("Datum2:");
  EEPROM.put( eeprom_cim, xdatum_ido);
  Serial.print(xdatum_ido.ev);Serial.print(".");                        
  Serial.print(xdatum_ido.ho);Serial.print("."); 
  Serial.print(xdatum_ido.nap);Serial.print("  ");
  Serial.print(xdatum_ido.ora);Serial.print(":");
  Serial.print(xdatum_ido.perc);
  Serial.print("  Merete:");
  Serial.println(sizeof(datum_ido));
  
  xszoveg="Ez egy szoveg!";   //ha a kovetkező eeprom írásnál nem yszoveg változót használom, akkor nem ezt a tartalmat írja az eeprom-be
  eeprom_cim=eeprom_cim+6;                              
  Serial.print("String1:");
  Serial.print(xszoveg);                        
  EEPROM.put(eeprom_cim,xszoveg );                   
  Serial.print(" Merete:");
  Serial.println(xszoveg.length());   //itt már nem használhatom sizeof() függvényt, mert a string hossza változik
  
  // Ezen a ponton érdekes dolog történt. Ha xszoveg változónak az xszoveg változót használom de új tartalaommal
  // feltöltve, akkor az előző kiírásban megadott "Ez egy szoveg!" helyett a mostani "Ez egy masik szöveg!" tartalmat
  // írja bele az eepromba (mégaz előző kiírásról van szó), de csonkítva az ottani szöveg hosszával. Pedig azon a 
  // programsoron már túl is vagyunk a végrehajtásban. 
  // Sőt, ha csinálok egy zszoveg változót, és annak is adok értéket, akkor már jó a tartalom
  // de levágja az első két karaktert a szövegből. Nyilván az EEPROM.put() belső működéséből fakad a hibejelenség
  // Megoldás, hogy külön szöveges változót kell deklarálni a szövegek kiírásához. 
  //zszoveg="Ez egy szoveg!";       //ennek csa akkor van szerepel, ha xszoveg változóra írom  következő sorokban az yszoveg változót
  yszoveg="Ez egy masik szoveg!";   //nem használhatom az xszoveg változót, mert rossz tartalmat ír az előző szöveg tárolásban (String1).
  eeprom_cim=eeprom_cim+16;           //a string1 változó 16 byte-ot foglal, tehát 16 byte-al kell növelni a következő eeprom címet
  Serial.print("String2:");
  Serial.print(yszoveg);                         
  EEPROM.put(eeprom_cim,yszoveg );                    
  Serial.print(" Merete:");
  Serial.println(yszoveg.length()); //itt már nem használhatom sizeof() függvényt, mert a string hossza változik

/************************************************************************************************************************
 * E a programrész visszaolvassa az előzőkaben letárolt változók értékét. Itt is figyelni kell az egyes változók kezdő  *
 * címeinek helyes kiszámolására. Érdemes kipróbálni, mi történik, ha valahol rossz címet írunk be. pL a dárum típusnál *
 * az előző olvasási címhez ne 4-et, hanem 3-at adjunk hozzá                                                            *
 ************************************************************************************************************************/
  //töröljük a változó értékekekt, hogy lássuk, tényleg működik a visszaolvasás
  //az xszoveg yszoveg változókkal kapcsolatos hibajelenség itt már nem jelentkezik
  //helyesen fogja visszaolvasni a szövegeket az xszoveg változóba. Láthatóan csak az íráskor van gond
  xbool = 0;            
  xbyte = 0;          
  xint = 0;          
  xlong = 0;    
  xfloat = 0;  
  
  xdatum_ido.ev = 0;             //feltöltjük értékekkel az xdatum nevű változót, ami datum típusú
  xdatum_ido.ho=0;
  xdatum_ido.nap=0;
  //xszoveg="";   //Ha ezt az értékadást használom, akkor lecsípi a szöveg első karakterét az első szöveg kiolvasásáakor
                  //Ha az íráskor xszoveg változót használom, akkor a második szöveg kiolvasás első karakterét csípi le.
                  //Mindamelett a második esetben még az első szöveg is rossz tartalommal kerül az eeprom-ba.
                  //Ezek a hibajelenségek csak akkor keletkeznek, ha az eeprom írással foglalkozó programrész működik
                  //ha kikommentezem azt a részt, akkor már nem okoz problémát ez az értékedás. Az EEPROM.put() csinál
                  //valamit a memóriában, ami megzavarja a működést.
  
  eeprom_cim=0;    //eeprom kezdőcím ujra 0

  Serial.println("***************** Olvasunk az eeprom-bol:");

  Serial.print("Bool:");
  EEPROM.get( eeprom_cim, xbool );
  Serial.println( xbool, BIN );  

  eeprom_cim=eeprom_cim+1; 
  Serial.print("Byte:");
  EEPROM.get( eeprom_cim, xbyte );
  Serial.println( xbyte);  //

  eeprom_cim=eeprom_cim+1; 
  Serial.print("Int:");
  EEPROM.get( eeprom_cim, xint );
  Serial.println( xint);  //

  eeprom_cim=eeprom_cim+2; 
  Serial.print("Long:");
  EEPROM.get( eeprom_cim, xlong );
  Serial.println( xlong);  //

  eeprom_cim=eeprom_cim+4; 
  Serial.print("Float:");
  EEPROM.get( eeprom_cim, xfloat );
  Serial.println( xfloat,7);  //

  eeprom_cim=eeprom_cim+4; 
  Serial.print("Datum1:");
  EEPROM.get(eeprom_cim, xdatum_ido );
  Serial.print(xdatum_ido.ev);Serial.print(".");                         
  Serial.print(xdatum_ido.ho);Serial.print(".");                        
  Serial.print(xdatum_ido.nap);Serial.print("  ");                       
  Serial.print(xdatum_ido.ora);Serial.print(":");                       
  Serial.println(xdatum_ido.perc);  
                       
  eeprom_cim=eeprom_cim+6; 
  Serial.print("Datum2:");
  EEPROM.get(eeprom_cim, xdatum_ido );
  Serial.print(xdatum_ido.ev);Serial.print(".");                         
  Serial.print(xdatum_ido.ho);Serial.print(".");                        
  Serial.print(xdatum_ido.nap);Serial.print("  ");                       
  Serial.print(xdatum_ido.ora);Serial.print(":");                       
  Serial.println(xdatum_ido.perc);                       

  eeprom_cim=eeprom_cim+6; 
  Serial.print("String1:");
  EEPROM.get(eeprom_cim,yszoveg );
  Serial.println(yszoveg);  //

  eeprom_cim=eeprom_cim+16; 
  Serial.print("String2:");
  EEPROM.get(eeprom_cim,yszoveg );
  Serial.println(yszoveg);  //

}

void loop(){ /* ez most üres */ }

Mennyire volt hasznos amit olvastál?

Kattints egy csillagra az értékeléshez!

Sajnálom, hogy amit olvastál nem volt hasznos számodra!

Szeretném ha elégedett lennél!

Írd le kérlek, hogy mi nem tetszett!?