Interná EEPROM

Page

Stránky / Arduino / Pod kapotou Arduina /

Každé Arduino má tri druhy pamäte. Flash, v ktorej je program, RAM, v ktorej sa uchovávajú údaje počas behu programu a EEPROM, ktorá slúži na trvalé ukladanie údajov. Rôzne verzie Arduina majú EEPROM rôznej veľkosti. Vzhľadom na to, že si tu obvykle budete uchovávať iba údaje o konfigurácii, bez problémov vám táto veľkosť bude stačiť.

IDE 1.6.2

IDE 1.6.2 prinieslo také zmeny, ktoré umožňujú pracovať s EEPROM pohodlným spôsobom. Na ovládanie EEPROM slúži trieda EEPROMClass, ktorá je pre programátora prístupná pomocou globálnej premennej EEPROM. Trieda má nasledovné funkcie.

  • operator [] - Prístup do EEPROM ako do pola bajtov.
  • read - Čítanie z EEPROM.
  • write - Zapisovanie do EEPROM.
  • update - Zapisovanie do EEPROM, ale len v prípade, že sa nová hodnota líši. Šetrí to opotrebovanie EEPROM, ale to vám hrozí iba vtedy, ak budete s EEPROM narábať neopatrne.
  • get - Šablónová funkcia na čítanie celých objektov. V starších verziách IDE môžete použiť funkciu EEPROM_readAnything.
  • put - Šablónová funkcia na zapisovanie celých objektov. V starších verziách IDE môžete použiť funkciu EEPROM_writeAnything.
  • length - Funkciou možno zistiť aktuálnu veľkosť prístupnej EEPROM pre váš model Arduina.

 

IDE 1.6.1 a staršie

Nasledujúci text popisuje ovládanie EEPROM pre staršie verzie IDE Arduina.

V tomto článku sa budeme venovať internej EEPROM, ktorá sa nachádza v Arduine. Budeme predpokladať, že máte naštudované základné príklady, ktoré sú dodávané k Arduinu. Ak nie, pozrite si príklady, ktoré sa nachádzajú v programoch eeprom_cleareeprom_write a eeprom_read.

Programátor je pohodlný tvor

Ak si pozriete, ako sa používajú funkcie read a write, zistíte, že sú dobré pre čítanie a zapisovanie jednotlivých znakov, na zložitejšie údaje je ich použitie trošku nepraktické. Preto nie je od veci trošku si prácu uľahčiť. Našťastie celú prácu vykonal už niekto za nás a napísal všetok kód za nás na stránke http://playground.arduino.cc/Code/EEPROMWriteAnything.

#include <EEPROM.h>
#include <Arduino.h>  // for type definitions

template <class T> int EEPROM_writeAnything(int ee, const T& value)
{
    const byte* p = (const byte*)(const void*)&value;
    unsigned int i;
    for (i = 0; i < sizeof(value); i++)
	  EEPROM.write(ee++, *p++);
    return i;
}

template <class T> int EEPROM_readAnything(int ee, T& value)
{
    byte* p = (byte*)(void*)&value;
    unsigned int i;
    for (i = 0; i < sizeof(value); i++)
	  *p++ = EEPROM.read(ee++);
    return i;
}

Keďže nie každý sa živí programovaním profesionálne, na prvý pohľad sa môžu tieto dve šablónové funkcie javiť nepochopiteľne. Ale je to len vtipné využitie šablónových funkcií, ktoré kompilátor vie použiť. Nebudeme si vysvetľovať podrobnosti o šablónach, na to by sme mohli potrebovať veľa stránok textu. Záujemcovia o podrobnosti si môžu rozšíriť vedomosti na Wikipédii v článkoch Template (C++) a Standard Template Library.

Zameriame sa len na to, ako funkcie fungujú. Základom na pochopenie je to, že kompilátor dokáže namiesto class T doplniť definíciu ľubovoľného typu (aj štruktúry, alebo triedy) a vygenerovať k tom zdrojový kód. Urobí to vtedy, keď na natrafí na nejaký kód, ktorý použije definovanú šablónu. Pri bližšom pohľade na kód vidíme, že robí nasledovnú vec:

  • Vytvorí pointer na začiatok dát, ktoré funkcia dostala ako argument T.
  • Pomocou funkcie sizeof si spočíta dĺžku typu T v pamäti.
  • A potom už len zapíše alebo prečíta údaje.

Ak chceme používať tieto funkcie, musíme si ich uložiť do súboru EEPROMAnything.h a uložiť ho alebo do adresára s funkciami EEPROM, alebo súbor iba priložiť do adresára v vášmu projektu.

Algoritmus ukladania údajov

Keďže v EEPROM sú implicitne uložené náhodné údaje (aj keď čisté Arduino tu bude mať uložené nuly), ktoré môžu byť ešte náhodnejšie po vašich predchádzajúcich experimentoch, je dobré sa nespoliehať na túto náhodu a použiť nasledovný algoritmus.

  • Svoje údaje si uložte do štruktúry.
  • Na začiatku štruktúry umiestnite 2-4 rozoznávacích znakov, pomocou ktorých zistíte, či EEPROM obsahuje náhodné znaky, alebo je sformátovaná s vašimi údajmi.
  • V prvom kroku načítate EEPROM do dočasnej premennej. Ak sa rozoznávacie znaky zhodujú, prekopírujete dočasnú premennú do globálnej, kde si ukladáte svoje konfigurácie.
  • Ak sa nezhoduje, zapíšete do EEPROM obsah globálnej premennej, kde sú implicitné údaje.
  • Následne zapisujete do EEPROM obsah globálnej premennej len vtedy, keď dôjde ku zmene konfiguračných údajov.

Ak budete dodržiavať tento postup, nebudete mať nikdy chaos v tom, čo za dáta sú v EEPROM.

EEPROM prakticky pre Arduino Uno

Poďme teraz predchádzajúci algoritmus odskúšať na konkrétnom príklade. Údaje sa ukladajú v štruktúre cfg. Máme jednu globálnu premennú typu cfg s menom c, ktorá má nastavené implicitné hodnoty. Vo funkcii setup vidíme, ako si vytvoríme lokálnu premennú tmp, do ktorej prečítame obsah EEPROM. Ak sa identifikačné znaky v tmp nezhodujú s reťazcom T1, potom predpokladáme prvé spustenie programu na neskonfigurovanom systéme a uložíme obsah nášho implicitného nastavenia do EEPROM. Ak je nájdená zhoda, zapíšeme iba obsah tmp do c(c++ je natoľko inteligentné, aby za nás doplnilo kód operátora priradenia). Aby sme ale aj niečo videli, pri každom načítaní z EEPROM mierne upravíme obsah oboch premenných. Takto pri každom stlačení tlačidla reset uvidíme zmenu v uložených údajoch.

#include <EEPROM.h>
#include "EEPROMAnything.h"

struct cfg {
  char ident[2];
  int minimum;
  int maximum;
};

cfg c={{'T','1'},0,1234};

const int address = 0;

void setup()
{
  Serial.begin(9600);
  Serial.println("Arduino Uno EEPROM demo");
  
  cfg tmp;
  EEPROM_readAnything(address,tmp);
  if(!(tmp.ident[0]=='T' && tmp.ident[1]=='1'))
    {
    Serial.println("Default value");  
    EEPROM_writeAnything(address,c);
    }
  else
    {
    Serial.println("EEPROM stored value");  
    c=tmp;
    c.minimum++;
    c.maximum--;
    EEPROM_writeAnything(address,c);
    }
    
Serial.print("cfg.minimum=");
Serial.println(c.minimum);  
Serial.print("cfg.maximum=");
Serial.println(c.maximum);  
}

Zdrojový kód príkladu je v súbore eeprom_practical_01.zip.

EEPROM prakticky pre ATtiny85

Aby sme odskúšali aj malého bračeka Arduina, môžeme si vyskúšať príklad aj na ňom. Zdrojový kód je skoro identický, je tam iba použitá knižnica SoftwareSerial na obsluhu sériového portu. Aby tento príklad fungoval, je potrebné prepojiť ATtiny85 a napríklad Arduino MEGA 2560 podľa tohto návodu. Zdrojový kód príkladu je v súbore eeprom_practical_02.zip.

Veľkosti EEPROM

V nasledovnej tabuľke je uvedená veľkosť EEPROM pre bežné druhy Arduina.

 Typ Veľkosť 
 Uno 1024
 MEGA 2560 4096
 ATtiny85 512
 Due  *
 Zero 16kb emulácia **

* Do dnešného dňa som žil v presvedčení, že by mala byť EEPROM na Arduino Due emulovaná cez flash. Ale momentálne na stránke nič takého nemajú uvedené. Takže keď si nájdem čas, preskúmam tento problém podrobnejšie.

** A pravdepodobne ani Zero emuláciu nakoniec nemá.

Zdrojové texty

Zdrojové texty príkladov nájdete na GitHub.


05.07.2015


Menu