Interná EEPROM

IDE 1.6.2

[IDE 1.6.2 prinieslo také zmeny k lepšiemu, že bude potrebné mierne prepracovať tento článok.]

IDE 1.6.1 a staršie


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_clear, eeprom_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ávoduZdrojový 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 (zatiaľ nie je na trhu)

* 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.
ċ
eeprom_practical_01.zip
(1k)
Robo Ulbricht,
16. 1. 2015, 10:31
ċ
eeprom_practical_02.zip
(2k)
Robo Ulbricht,
16. 1. 2015, 10:31
Comments