Adatbázis kezelés EEPROM-ban

Tartalom:

  • Szövegek tárolása az Arduino belső EEPROM-jában, annak érdekében, hogy több hely maradjon a flash memóriában illetve a ram-ban a programnak, vagy időnként megváltoztatható szavakat tároljon a program
  • Változó rekordhosszúság, 1-255 karakter hosszú szavak kényelmes tárolására
  • Kijelölhető EEPROM terület a szavaknak, hogy maradjon más adatnak is hely
  • Alapvető adatbáziskezelő függvények, írás, megadott sorszámú szó olvasása, adott sorszámú szó törlése, rendelkezésre álló hely lekérdezése
  • Teljes forráskód példa programmal

———————————————————————————

Ez azért egy kicsit nagyképű kijelentés, de részben igaz. Valóban fel lehet az alábbi függvények segítségével építeni egy szöveges, változó rekordhosszú adatbázist az ATmega eeprom-jában. Az ötletet az adta, hogy szükségem volt egy olyan programra, ami számokat leír szövegesen (és ki is mondja egy mp3 lejátszón). Jó sok string-et kellett a programban definiálnom, ami természetesen az Arduino ram-ba került, és teljesen elfogyott a 2Kbyte ram memória. Arra gondoltam, hogy ezeket a szövegeket beírom az eeprom-ba és onnan használom. Nevezetesen 88 szöveget kellett volna tárolnom, ami az 1kbyte eepromban 1024/88=~11 karakteres szavakat tett volna lehetővé. Ekkor nagyon egyszerű lett volna a program, hiszen konkrétan kiszámolható kezdőcímen kezdődtek volna a szövegek. Igen ám, de nekem ennél hosszabb szövegeim is voltak. Ugyanakkor a legtöbb szövegem ennél jóval rövidebb pl. „öt”. Ugyanakkor terveim között szerepel egy olyan kütyü, amiben a néhány nyomógomb (rotary kapcsoló) segítségével lehet szavakat szerkeszteni, és azokat tárolni kell. Az itt megadott szavak, szövegek jóval hosszabbak is lehetnek mint 10-20 karakter, bár várhatóan a szövegek száma nem lesz több mint 40-50db, de ezt nem lehet előre tudni. Ezért kezdtem el foglalkozni a kérdéssel, hogyan lehetne ezeket a szövegeket változó rekordhosszú adatbázisban tárolni. Túl bonyolult nem lehet az adminisztráció, mert alig van memória. Így kompromisszumokat kellett kötni. Az első és legfontosabb kompromisszum, hogy a szövegeket kizárólag az eeprom-ba írt sorrend alapján keletkező index (sorszám) szerint lehet visszakeresni. A visszakereséskor végig kell olvasni elejétől az adatbázist, bár 1kbyte esetében ez nemfog sokáig tartani. A szövegek maximális hossza is korlátozott, maximum 255 byte lehet, mert a hosszúságot egy byte-on tárolom. Igaz, ilyen hosszú szövegből már csak 4 db férne el.

Mini adatbázis kezelőm ezért a következő képen működik! Az első szöveg tárolásakor kiszámolom a szöveg teljes hosszát, és a legeslegelső byte-ra (0.cím) letárolom a hosszúságot egy byte-on. Ezt követően karakterenként egy byte felhasználásával beírom a szöveget. A szöveg utolsó karaktere után beírok egy 0-át. Ez fogja jelezni az adatbázisom végét, az utolsó rekord után mindig 0 lesz. Amikor be akarok írni egy új szöveget, elindulok az első byte-al (0. cím), kiolvasom az ott található számot. Előre ugrok a memória címben annyit, amennyi a byte tartalma volt plusz egyet. Itt található vagy egy nulla, ha az adott rekor az utolsó volt, vagy egy nullánál nagyobb szám, ami a következő szöveg hosszúsága. Ha nullánál nagyobb számot találok, akkor tovább növelem a címet az ott talált számmal plusz eggyel, és mindezt addig csinálom, amig meg nem találtam a nullát, ami az utolsó szöveget jelzi. Ha meg van a nulla, akkor az felülírom az aktuálisan tárolni kívánt szöveg hosszával, byte-onként tárolom a karaktereket, és lezárom az egészet egy nullával. Hát ennyi az egész! A könnyebb értehetőség kedvéért íme egy két szavas példa, az első szöveg „AAA” betű (ASCII 65), a második szó „BBBBB” betű (ASCII 66):

Kiolvasáskor természetesen meg kell adni a kiolvasni kívánt szöveg sorszámát (indexét), és annyiszor ugrani előre a memória címben, amennyi az index értéke. Ha elértük, byte-onként kiolvasható a szöveg az első byte-ban megadott hosszúságban. Az algoritmus szövegenként egy byte-ot pazarol, ami elviselhető, ha a szavak száma 100 alatt marad.

A fenti algoritmust négy függvénnyel valósítottam meg:

eeprom_txt_ir(szöveg, index);   Beír egy szöveget az adatbázisba. A szöveg mellett paraméterként meg kell adni egy index értéket. Ha ez 0, akkor utolsó rekord mögé írja a szöveget, azaz hozzáfűzi az adatbázishoz. Ha konkrét értéket adunk meg, akkor arra az index értékre írja be a szöveget, de minden későbbi szöveg elveszik. Így pl. teljesen új adatbázist lehet kezdeni, ha az index érték 1.

eeprom_txt_olvas(index); A megadott indexű (sorszámú) szöveget adja vissza

eeprom_txt_torol(index);  A megadott indexű szöveget törli az adatbázisból, a többi szöveg megmarad csak eggyel előrébb lép és mindegyiknek az indexe kisebb lesz eggyel.

eeprom_txt_hely(); Visszaadja a szövegek által elfoglalt helyet byte-okban, valamint visszaadja a maximális szöveg indexet, vagyis azt, hogy hány szöveg található az adatbázisban.

A függvények használatához létre kell hozni egy struktúrát:

struct eeprom {               
  int eeprom_meret=500; //ebben a konstansban tartjuk az adatbázis kezelésre fenntartott eeprom terület maximális méretét
  int foglalt_hely;    //ebben a változóban kapjuk meg a foglalt helyek számát byte-ban
  byte rekord_szam;     //az eddig beírt szavak száma
  bool sikeres;         //értéke 1, ha sikeres volt a tárolás, vagy lekérdezés, és 0, ha nem tudta beírni a megadott szót
};

Látható, hogy nem kell a teljes eeprom-ot elhasználni. Ha csak néhány szót szeretnénk tárolni, akkor az eeprom_meret változót állítsuk kisebbre. A példában 500 byte lett a maximális 1024 helyett (ATmega328). Fontos tudnivaló még, hogy az ékezetes betűket az Arduino IDE fordítója a stringekben két karakteren tárolja UTF8 kódolással. Ha tehát valahol egy szövegben ékezetes betűt használunk, az rögtön két byte helyet fog foglalni. Lehetne itt is spórolni, ha tárolás előtt az ékezetes betűket valamilyen nem használt ASCII tartományba helyezzük, azaz, a két byte-ot egy-re cseréljük. Pl. jó tartomány lehet az 1-31-ig tartó kódtartomány, itt nincsenek betűk vagy számok. Persze ekkor az olvasáskor is kódcserét kell alkalmazni, és az egy byte-ot visszacserélni kettőre. Én ezzel nem vacakoltam, bár a magyar szavakban sok az ékezet, az 1kbyte-hoz képest sokat lehetne megtakarítani. Ha ez a lehetőség valaki érdekel, akkor ajánlom figyelmébe az „Ékezetes betűk írása LCD-re kényelmesen” cikkemet, mert abban lényegileg ugyanezt kellett megvalósítani, csak ott az LCD kijelző miatt kellett a két byte-os ékezetes betűket egy byte-os kódra cserélni az LCD kijelző kedvéért! No persze előtte a gyárilag kijelölt kódokra le kellett tölteni a z LCD-re a magyar ékezetes betűk karakterképét, így ott a fő feladat nem a karakter kód konverzió volt!

Írtam egy példa programot, ami bemutatja a függvények működését. A gyakorlatban eddig még jómagam is csak úgy használtam, hogy egy külön ideiglenes programmal feltöltöttem a szövegekkel az eeprom-ot, egy másik „valamit csináló” programban pedig csak olvasgattam a szövegeket. Bár a távlati terveimben nem ilyen felhasználás szerepel! Dinamikusan, működés közben szeretnék szavakat (címkéket) készíteni, de a program még nem készült el. A program egy „emlékeztető” gép lenne, ami megtanulja, hogy mikor szoktam pl. virágot locsolni, és ha letelt a szokásos idő, akkor villogó led-el és szöveges kiírással is figyelmeztet a feladatra (feladatokra). Nem konkrét dátumokkal fog működni, hanem a két esemény közötti időtartamot állapítja meg és figyeli. Persze legalább a két legelső végrehajtást jelezni kell, így lehet, hogy magamat ismerve mégis el fognak száradni a virágok! Azonban az adatbáziskezelő programmodul már készen van hozzá!

Íme a példaprogram a fenti függvényekkel. A kommentekből sok részlet kiderül, de használathoz nem kell feltétlenül megérteni a működést. A példa programban a setup()-ban, minden lehetséges szituációt bemutatok.

#include <EEPROM.h> 

struct eeprom {               //Ebben a struktúrában adja vissza az adatokat az eeprom_txt..() függvény függvény csoport, kivéve az eeprom_txt_olvas(), mert az string-et ad vissza.
                              //Az eeprom_txt_ir() függvény egyik paramétere a az a méret, amit elfoglalhatunk az eeprom-ból.
                              //Ennek maxmiális értéke ATmega328 esetén 1024 byte, mert ekkor a az eeprom méret, de használhatunk belőle kevesebbet is.
  int eeprom_meret=500;       //ebben a konstansban tartjuk az adatbázis kezelésre fenntartott eeprom terület maximális méretét
  int foglalt_hely;          //ebben a változóban kapjuk meg a foglalt helyek számát byte-ban
  byte rekord_szam;           //az eddig beírt szavak száma
  bool sikeres;               //értéke 1, ha sikeres volt a tárolás, vagy lekérdezés, és 0, ha nem tudta beírni a megadott szót
};

eeprom x;                     //rögtön létre is hozunk egy adat nevű, és eeprom típusú változót
byte xx;                      //segédváltozó

void setup()
{
  Serial.begin(9600);
  
  //törlöm az eeprom teljes tartalmát. Csak azért, hogy üres legyen és jól lehessen látni mi történik
  //az eeprom_txt_ir() függvény használatához nem kell törölni az eeprom-ot.
  Serial.println("EEPROM törlés...");
  for (int i=0;i<512;i++) {
    EEPROM.write(i,0);
  }
  //beírjuk az első adatot az eeprom-ba
  //Most ez eeprom üres, mert előtte töröltük. A megadott paraméter 0, tehát az eeprom_txt_ir()
  //függvény üres helyet keres, de már rögtön az első is üres, mert a kezdő címen is 0 tartalmat talál.
  Serial.println("Beírjuk az első adatot az EEPROM-ba:");
  x=eeprom_txt_ir("AAA",0);
  //kiírom a visszakapott értékeket, hogy lássuk mi történik, a továbbiakban már nem írom ki
  Serial.print("Állapot->");
  Serial.print("foglalt:");Serial.print(x.foglalt_hely);
  Serial.print(" byte, rekord:");Serial.print(x.rekord_szam);
  Serial.print("db Sikeres:");Serial.println(x.sikeres);
  Serial.println("További rekordokat írunk....");
  x=eeprom_txt_ir("BBBBBBBB",0);
  x=eeprom_txt_ir("CCCCCCCCCCCCCCCCCCCCCCCCCC",0);
  x=eeprom_txt_ir("DDDDDDDDD",0);
  x=eeprom_txt_ir("Ékezetes szavakra is van lehetőség!",0);

  //kiolvasom az eeprom első 96 byte-ját (elég ennyi, mert nem írtuk tele)
  Serial.println("Az EEPROM adattartalma a rekordok beírása után:");
  for (byte i=0;i<6;i++) {
    for (byte j=0;j<16;j++) {
      //Serial.print(i*16+j);
      xx=(byte)EEPROM.read(i*16+j);
      //csak azért, hogy szebben legyen kiírva 
     if (xx<10) {Serial.print("  ");Serial.print(xx);} ;    
      if (xx>9 and xx<100) {Serial.print(" ");Serial.print(xx);};
      if (xx>100) {Serial.print(xx);};
      Serial.print(",");
    }
    Serial.println();         //16 kiírt érték után dobunk egy sort
  }
  //lekérdezzük a eepromban lévő helyet és adatokat
  x=eeprom_txt_hely();
  Serial.print("Állapot->");
  Serial.print("foglalt:");Serial.print(x.foglalt_hely);
  Serial.print(" byte, rekord:");Serial.print(x.rekord_szam);
  Serial.print("db Sikeres:");Serial.println(x.sikeres);
  //Kiírjuk a tárolt szavakat
  Serial.println("Tárolt szavak:");
  for (byte i=1;i<x.rekord_szam+1;i++) {
    Serial.println(eeprom_txt_olvas(i));
  }
  
  //kipróbáljuk, mi történik, ha az eeprom_txt_ir() függvénynek konkrét index értéket adunk meg
  //Arra az index-re fog egy új rekordot beírni, és minden más ami utána jönne eltörlődik (azaz elérhetetlen lesz)
  Serial.println("A harmadik rekordot új tartalommal töltjük fel, és mindent eltörlünk mögötte:");
  x=eeprom_txt_ir("Ez lett az utolsó!",3);
  //Kiírjuk a tárolt szavakat
  Serial.println("Tárolt szavak:");
  for (byte i=1;i<x.rekord_szam+1;i++) {
    Serial.println(eeprom_txt_olvas(i));
  }
  x=eeprom_txt_hely();
  Serial.print("Állapot->");
  Serial.print("foglalt:");Serial.print(x.foglalt_hely);
  Serial.print(" byte, rekord:");Serial.print(x.rekord_szam);
  Serial.print("db Sikeres:");Serial.println(x.sikeres);
 
  //kipróbáljuk a törlést is
  Serial.println("Újra töltjük az adatbázist új tartalommal");
  x=eeprom_txt_ir("1111111111111111",1);                        //újra töltjük az adatbázis adatokkal, mert indexnek 1-et adtunk meg. 
                                                                   //Példa arra, hogyan lehet eeprom törlés nélkül teljesen újra kezdeni a szövegek tárolását
  x=eeprom_txt_ir("2222222222",0);
  x=eeprom_txt_ir("33333333333333333333333333",0);
  x=eeprom_txt_ir("444444444444444",0);
  x=eeprom_txt_ir("5555555555555555555555555555",0);
  Serial.println("Tárolt szavak:");
  for (byte i=1;i<x.rekord_szam+1;i++) {
    Serial.println(eeprom_txt_olvas(i));
  }
  Serial.print("Állapot->");
  Serial.print("foglalt:");Serial.print(x.foglalt_hely);
  Serial.print(" byte, rekord:");Serial.print(x.rekord_szam);
  Serial.print("db Sikeres:");Serial.println(x.sikeres);
  Serial.println("A harmadik rekord törlésének bemutatása:");
  x=eeprom_txt_torol(3);                                         //töröljük a 3. rekordot
  //Kiírjuk a tárolt szavakat
  Serial.println("Tárolt szavak:");
  for (byte i=1;i<x.rekord_szam+1;i++) {
    Serial.println(eeprom_txt_olvas(i));
  }
  Serial.print("Állapot->");
  Serial.print("foglalt:");Serial.print(x.foglalt_hely);
  Serial.print(" byte, rekord:");Serial.print(x.rekord_szam);
  Serial.print("db Sikeres:");Serial.println(x.sikeres);
}


void loop()
{

}


eeprom eeprom_txt_ir(String szoveg,int index) 
/*********************************************************************************************
 * Ez a függvény a paraméterként átadott string-et beírja az eeprom-ba. Minden alkalommal    *
 * amikor meghívjuk, megkeresi a következő üres helyet az "adatbázisban". Egy szöveg elé     *
 * letárolja a szöveg karakterekben mért hosszát (az ékezetes betűk 2 byte-osak) és egy       *
 * 0-val zárja le a szöveget. A 0 azért kell a végére, mert a következő szöveg beírásakor    *
 * ez a 0 jelzi, hogy innen lehet írni, vagyis nincs több szöveg a sorban (az adott 0-val    *
 * lezárt szöveg az utolsó a sorban). Egy következő beíráskor azt a 0-át felülírja a         *
 * következő szöveg hosszával. A szövegek kiolvasásakor ezeknek a hosszoknak a               *
 * segítségével keresi mega  következő szöveget. A kiolvasás kizárólag elölről kezdve        *
 * sorrendben lesz lehetséges.                                                               *
 * A függvény paraméterei:                                                                   *
 *  szoveg       - az eepromba beírandó szting, maximum 255 byte hosszú lehet                *
 *  index        - egy olyan érték, ami lehetőséget ad az eepromba írás elkezdésére,         *
 *                 folytatására, illetve egy adott ponttól történő felülírására.             *
 *                 ha index=0, akkor folytatja a szöveg beírást a következő szabad           *
 *                 területtől. Ha az eeprom-ot előtte töröltük (vagy csak az első byte-ot)   *
 *                 akkor az adott szöveg lesz sorrendben az első, és innen folytatja a       *
 *                 többivel. Ha a megadott érték nagyobb mint nulla, akkor a megadott        *
 *                 értéknek megfelelő helyre írja a szöveget. Ha ez 1, akkor rögtön          *
 *                 legelsőnek. Így lehet egy meglévő szöveges adatbázis törölni, mert        *
 *                 elsőnek írja be a szöveget, és ezzel minden más előzményt eltüntet.       *
 *                 Ha pl 3, akkor ez a harmadik szövegnek írja be, és ha több szöveg         *
 *                 is volt, azok már nem lesznek elérhetők.                                  *
 *********************************************************************************************/
{
  eeprom adat;                   //ezt a változó struktúrát fogjuk visszaadni amikor befejeztük az írást
  adat.foglalt_hely=0;           //kezdetben a foglalt hely 0, ezt növelni fogjuk, ahogyan haladunk előre a következő rekord
                                 //keresésekor. Ez egyben a memória cím is, ahonnan adatokat olvasunk, vagy ahová adatoka írunk. 
                                 //Amikor beírtuk a szöveget és a lezáró nullát, értéke éppen az elfoglalt mennyisége byte-okban.
  adat.rekord_szam=0;            //ez jelzi, hogy éppen hányadik rekordnál járunk. A beírást követően ebben adjuk 
                                 //vissza, hogy éppen hány rekord van az adatbázisban
  adat.sikeres=0;                //ez is visszaadásra kerül a beírást követően, ha értéke 1, akkor sikeres volt a szöveg beírása
                                 //he nem sikerült beírni a szöveget, akkor 0.
  byte ertek;                    //ebbe olvassuk ki a szöveget megelőző egy byte-ot, ez lesz az aktuális szöveg hossza.
  byte meret=szoveg.length();    //a beírásra átadott szöveg hossza byte-okban. Ékezetes betűk 2 byte-ot foglalnak
  if (index!=1) {                //ha index nagyobb mint 1, akkor meg lett adva, hogy hányadik rekordnak írjuk be a szöveget
                                 //ha index=1, akkor kihagyjuk a keresést, mert rögtön az elsőnek kell beírni. 
                                 //ha index=0, akkor utolsónak kell beírni, tehát kell a keresés
    do  {
      ertek=EEPROM.read(adat.foglalt_hely);         //ez az aktuális szöveg hossza, ezzel növeljük majd a címet, ha tovább keressük a következő szöveget
      if (ertek==0) { break;}                       //megtaláltuk az utolsó szöveget, mert 0-val van lezárva, kiugrunk a ciklusból, mert ide lehet írni a szöveget
      adat.foglalt_hely=adat.foglalt_hely+ertek+1;  //a következő szöveg hosszát megadó byte címe
      adat.rekord_szam++;                           //a rekordszámot is növeljük, az első megtalált rekord után pont 1
      if (index==adat.rekord_szam) {break;}         //mivel meg lett adva beírási sorszám, és éppen annál járunk, kiugrunk a ciklusból, és 
                                                    //az adat.foglalt_hely változó által kijelölt címre fogjuk beírni a szöveget.
    } while (adat.foglalt_hely<adat.eeprom_meret);       //akkor is kiugrunk a ciklusból, ha elértük a kijelölt terület végét
  }
  
  if (adat.foglalt_hely+3>adat.eeprom_meret) {      //ha már 3 byte-nál kevesebb a szabad hely, akkor kilépünk sikertelen jelzéssel.
                                                    //ekkor előfordulhat, hogy nem tudjuk kiírni a teljes szöveget, hiszen csak 2 byte maradt.
    adat.sikeres=0;return(adat);
  }

  //elkezdjük beírni az adatot az eepromba
  EEPROM.write(adat.foglalt_hely,meret);            //első byte a szöveg mérete byte-okban (max. 255 lehet)
  adat.foglalt_hely++;                              //növeljük a kiírás címét, innen fogjuk írni a tényleges szöveget
  for(byte i=0;i<meret;i++)                         //sorban elővesszük a szöveg karaktereit
  {
    if (adat.foglalt_hely>adat.eeprom_meret) {      //itt is nézzük, hogy nem telt-e meg. Ha igen, akkor sikertelen jelzéssel kilépünk
      adat.sikeres=0;return(adat);
    }
    EEPROM.write(adat.foglalt_hely,szoveg[i]);     //ez itt a soron következő karakter beírása (ékezetes betűk két byte-ot foglalnak két lépésben)
    adat.foglalt_hely++;
  }
  EEPROM.write(adat.foglalt_hely,0);                //ezt azért nullázzuk, mert innen tudjuk legközelebb, hogy ez volt az utolsó rekord
                                                    //így nem kell törölni a teljes eeprom-ot, ha valahová középre írunk adatot
                                                    //az itt következő rekordok viszont automatikusan elvesznek
  adat.rekord_szam++;                               //rekordszám visszatérési érték növelése 1-el, hiszen hozzáírtunk egyet a meglévő szövegekhez
  adat.sikeres=1;                                   //sikeres írás jelzése
  return(adat);
}

eeprom eeprom_txt_hely() 
/************************************************************************************
 * Ez a függvény paraméter nélkül működik. Megkeresi az utolsó rekordot és          *
 * visszaadja a szavak számát, az elfoglalt és a még rendelkező helyet byte-okban.  *
 ************************************************************************************/
{
  eeprom adat;
  adat.foglalt_hely=0;           //Kezdetben a foglalt hely 0, ezt növelni fogjuk, ahogyan haladunk előre a következő rekord
                                 //keresésekor. Ez egyben a memória cím is, ahonnan adatokat olvasunk. Az utolsó rekordnál 
                                 //értéke éppen az elfoglalt mennyisége byte-okban.
  adat.rekord_szam=0;            //Ez jelzi, hogy éppen hányadik rekordnál járunk. A beírást követően ebben adjuk 
                                 //vissza, hogy éppen hány rekord van az adatbázisban
  adat.sikeres=0;                //Ennek az értéke csak 1 lehet, mert a lekérdezés nem tud nem sikeres lenni
  byte ertek;                    //ebbe olvassuk ki a szöveget megelőző egy byte-ot, ez lesz az aktuális szöveg hossza.
  do  {
    ertek=EEPROM.read(adat.foglalt_hely);            //Kiolvassuk az aktuális szöveg hosszát byte-okban
    if (ertek==0) { break;}                          //Ha nulla, akkor elértük az utolsó rekordot
    adat.foglalt_hely=adat.foglalt_hely+ertek+1;     //Ha nem nulla volt az értek, akkor kiszámoljuk a következő rekord kezdőcímét
    adat.rekord_szam++;                              //Növeljük a rekordok darabszám számlálóját
  } while (adat.foglalt_hely<adat.eeprom_meret);     //Akkor is kiugrunk a ciklusból, ha elértük a tárolásra használt epprom terület legvégét
  adat.sikeres=1;                                    //Nem tud nem sikeres lenni
  return(adat);                                      //Visszaadjuk a megállapított adatokat
}

eeprom eeprom_txt_torol(int index) 
/*******************************************************************************************
 * Ez a függvény kitörli a paraméterben megkapott sorszámon tárolt szöveget. A szöveget *
 * az eeprom megfelelő pontjainak végig olvasásával keresi meg. Amikor megtalálta, megkeresi 
 * a következőnek szöveg kezdőcímét, és byte-onként előre másol                            *
 * Ha az utolsó rekord sorszámát adtuk meg, vagy nagyobb sorszámot mint az összes szöveg 
 * darabszáma, akkor nem történik törlés. Törlés után visszaadja a szabd helyet, foglalt 
 * helyet, a szövegek darabszámát, és a törlés sikerességét.
 *******************************************************************************************/
{
  eeprom adat;
  adat.foglalt_hely=0;           //Kezdetben a foglalt hely 0, ezt növelni fogjuk, ahogyan haladunk előre a következő rekord
                                 //keresésekor. Ez egyben a memória cím is, ahonnan adatokat olvasunk. Az utolsó rekordnál 
                                 //értéke éppen az elfoglalt mennyisége byte-okban.
  adat.rekord_szam=0;            //Ez jelzi, hogy éppen hányadik rekordnál járunk. A beírást követően ebben adjuk 
                                 //vissza, hogy éppen hány rekord van az adatbázisban
  adat.sikeres=0;                //Ennek az értéke csak 1 lehet, mert a lekérdezés nem tud nem sikeres lenni
  byte ertek;                    //ebbe olvassuk ki a szöveget megelőző egy byte-ot, ez lesz az aktuális szöveg hossza.
  int kov_cim=0;                 //A következő szöveg kezdőcíme, innen fogunk másolni addig, amíg nullát nem találunk, mert az a szövegek vége
  do  {
    ertek=EEPROM.read(adat.foglalt_hely);                //Kiolvassuk a szöveg hosszát
    if (ertek==0) {                                      //ha ez nulla, akkor az utolsó rekordhoz értünk, és nem tudtunk törölni.
                                                         //Ez csak akkor fordulhat elő, he a paraméterben megadott sorszám nagyobb mint a rekordok száma.
      adat.sikeres=0;return(adat);                       //beállítjuk a sikerességet 0-ra, mert nem volt sikeres a törlés, és visszatérünk
    }                                       
    adat.rekord_szam++;                             //Növeljük a darabszámot, mert érvényes szót találtunk
    if (adat.rekord_szam==index) {                  //Ha a paraméterben megkapott darabszám megegyezik az aktuális szöveg sorszámával, akkor ezt kerestük, ezt kell törölni
       kov_cim=adat.foglalt_hely+ertek+1;           //ez a következő szöveg kezdőcíme, innen fogunk egyenként másolni
       do {
        ertek=EEPROM.read(kov_cim);                 //Kiolvassuk a következő másolandó byte tartalmát
        EEPROM.write(adat.foglalt_hely,ertek);      //Átírjuk a kiolvasott byte-ot a törlendő szöveg első byte-jától kezdve
        kov_cim++;                                  //tovább lépünk eggyel a másolandó címmel
        adat.foglalt_hely++;                        //tovább lépünk eggyel azzal a címmel, ahová másolunk
      } while (ertek!=0 and kov_cim<adat.eeprom_meret);        //akkor ugrunk ki a ciklusból, ha megtaláltuk az utolsó szó lezáró 0 byte-ját, 
                                                    //vagy elérték a tárolásra szolgáló eeprom terület végét
      break;                                        //befejeztük a másolást, mehetünk megszámolni az eeprom terület adatait a normál visszatéréshez
    }
    adat.foglalt_hely=adat.foglalt_hely+ertek+1;
  } while (adat.foglalt_hely<adat.eeprom_meret);               //úgy értük el az eeprom terület végét, hogy nem találtuk meg a törlendő rekordot
                                                    //ez csak akkor fordulhat elő, ha meg volt telve az eeprom, és a megadott törlendő sorszám
                                                    //nagyobb, mint az összes rekord darabszáma

  //a visszaadott paraméterekhez újra végig kell olvasni, mert másolás közben nem figyeltük, hogy hány szöveget másoltunk  
  //A legegyszerűbb megoldással idemásoltam a szabad terület megadó függvény programsorait
  adat.foglalt_hely=0;           
  adat.rekord_szam=0;            
  adat.sikeres=0;           
  do  {
    ertek=EEPROM.read(adat.foglalt_hely);            //Kiolvassuk az aktuális szöveg hosszát byte-okban
    if (ertek==0) { break;}                          //Ha nulla, akkor elértük az utolsó rekordot
    adat.foglalt_hely=adat.foglalt_hely+ertek+1;     //Ha nem nulla volt az értek, akkor kiszámoljuk a következő rekord kezdőcímét
    adat.rekord_szam++;                              //Növeljük a rekordok darabszám számlálóját
  } while (adat.foglalt_hely<adat.eeprom_meret);     //Akkor is kiugrunk a ciklusból, ha elértük a tárolásra használt epprom terület legvégét
  adat.sikeres=1;                                    //Sikeres volt a törlés
  return(adat);                                      //Visszatérési érték a törlés utáni adatokkal.
}


String eeprom_txt_olvas(int index) 
/*********************************************************************************************
 * Ez a függvény visszaadja a paraméterben megkapott sorszámon tárolt szöveget. A szöveget   *
 * az eeprom megfelelő pontjainak végig olvasásával keresi meg. Minél nagyobb a paraméterben *
 * magadott sorszám, annál lassabban találja meg a keresett szöveget. Ha nagyobb sorszámot   *           
 * adunk meg paraméterként mint a szövegek darabszáma, akkor üres stringet ad vissza         *
 *********************************************************************************************/
{
  eeprom adat;
  String szo="";                       //Ebbe a változóba olvassuk vissza szöveget, ha megtaláltuk
  int akt_cim=0;                       //Ebben a változóban tároljuk az aktuális olvasási címet
  int akt_index=0;                     //Ebben a változóban számoljuk a rekordokat, folyamatosan növekszik.
                                       //Ha értéke megegyezik a paraméterben megkapott index-el (sorszámmal)
                                       //akkor megtaláltuk a szöveget
  byte ertek;                          //Ebbe olvassuk be a szövegek hosszának étékét a rekordok legelejéről
  do  {
    ertek=EEPROM.read(akt_cim);          //Kiolvassuk a szöveg hosszát
    if (ertek==0) {return("");}          //ha ez nulla, akkor az utolsó rekordhoz értünk, és üres stringet adunk vissza.
                                         //Ez csak akkor fordulhat elő, he a paraméterben megadott sorszám nagyobb, mint a rekordok száma.
    akt_index++;                         //Növeljük a darabszámot, mert érvényes szót találtunk
    if (akt_index==index) {              //Ha a paraméterben megkapott darabszám megegyezik az aktuális szöveg sorszámával, akkor ezt kerestük
    for (byte i=0;i<ertek;i++) {         //A kezdő byte-on megadott karakterszámot olvassuk végig
        szo=szo+" ";                     //Növeljük a szo nevű string változó hosszát azzal, hogy hozzáadunk egy karaktert
        szo[i]=EEPROM.read(akt_cim+1+i); //A szo nevű stringünk i-dik karakterére úgy tudunk hivatkozni, mintha egy tömb lenne, és így rögtön bele is tudjuk 
                                         //olvasni a tárolt számot, ami a karakter kódja
      }
      return(szo);                       //Az utolsó byte kiolvasása után visszatérünk a string-el 
    }
    akt_cim=akt_cim+ertek+1;             //Ha sorszám még kisebb volt mint a paraméterben kapott kiolvasandó sorszám, akkor kiszámítjuk a következő szó kezdő címét
  } while (akt_cim<adat.eeprom_meret);        //Akkor is kiugrunk a ciklusból, ha a tárolásra rendelkezésre álló eeprom terület végére értünk. Ez akkor fordulhat elő,
                                         //ha olyan nagy értéket adtunk meg a paraméterben, ami nagyobb, mint a tárolt szavak száma, és az eeprom is tele van.
  return("");                            //Visszatérési érték, ha nem találtuk meg a szöveget.
}

Ez pedig a példa program futási eredménye. Azért használtam a szavakban „A”, „B” stb. betűket, mert ezek ASCII kódját ismerem, (pl. az „A” betű kódja 65, a B betű 66 és így tovább) és a memória tartalom kiíratása után az értelmezésben könnyebb dolgom volt!

EEPROM törlés...
Beírjuk az első adatot az EEPROM-ba:
Állapot->foglalt:4 byte, rekord:1db Sikeres:1
További rekordokat írunk....
Az EEPROM adattartalma a rekordok beírása után:
  3, 65, 65, 65,  8, 66, 66, 66, 66, 66, 66, 66, 66, 26, 67, 67,
 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
 67, 67, 67, 67, 67, 67, 67, 67,  9, 68, 68, 68, 68, 68, 68, 68,
 68, 68, 38,195,137,107,101,122,101,116,101,115, 32,115,122, 97,
118, 97,107,114, 97, 32,105,115, 32,118, 97,110, 32,108,101,104,
101,116,197,145,115,195,169,103, 33,  0,  0,  0,  0,  0,  0,  0,
Állapot->foglalt:89 byte, rekord:5db Sikeres:1
Tárolt szavak:
AAA
BBBBBBBB
CCCCCCCCCCCCCCCCCCCCCCCCCC
DDDDDDDDD
Ékezetes szavakra is van lehetőség!
A harmadik rekordot új tartalommal töltjük fel, és mindent eltörlünk mögötte:
Tárolt szavak:
AAA
BBBBBBBB
CCCCCCCCCCCCCCCCCCCCCCCCCC
Ez lett az utolsó!
Állapot->foglalt:60 byte, rekord:4db Sikeres:1
Újra töltjük az adatbázist új tartalommal
Tárolt szavak:
1111111111111111
2222222222
33333333333333333333333333
444444444444444
5555555555555555555555555555
Állapot->foglalt:100 byte, rekord:5db Sikeres:1
A harmadik rekord törlésének bemutatása:
Tárolt szavak:
1111111111111111
2222222222
444444444444444
5555555555555555555555555555
Állapot->foglalt:73 byte, rekord:4db Sikeres:1

Mennyire volt hasznos amit olvastál? Értékelés után szövegesen is leírhatod megjegyzéseidet és véleményedet!

Kattints egy csillagra az értékeléshez!

Szövegesen is leírhatod véleményedet! Ha kérdésed van, ne felejtsd el megadni az email címedet!