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 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.
EEPROM_readAnything
.EEPROM_writeAnything
.
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_clear
, eeprom_write
a eeprom_read
.
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:
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.
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.
Ak budete dodržiavať tento postup, nebudete mať nikdy chaos v tom, čo za dáta sú v EEPROM.
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.
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.
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 príkladov nájdete na GitHub.
05.07.2015