Page
Stránky / Arduino / Pod kapotou Arduina /
Každé Arduino má tři druhy paměti. Flash, ve které je program, RAM, ve které se uchovávají údaje během běhu programu a EEPROM, která slouží k trvalému ukládání údajů. Různé verze Arduina mají EEPROM různé velikosti. Vzhledem k tomu, že si zde obvykle budete uchovávat pouze data o konfiguraci, bez problémů vám tato velikost bude stačit.
IDE 1.6.2 přineslo takové změny, které umožňují pracovat s EEPROM pohodlným způsobem. K ovládání EEPROM slouží třída EEPROMClass
, která je pro programátora přístupná pomocí globální proměnné EEPROM
. Třída má následující funkce.
EEPROM_readAnything
.EEPROM_writeAnything
.
Následující text popisuje ovládání EEPROM pro starší verze IDE Arduina.
V tomto článku se budeme věnovat interní EEPROM, která se nachází v Arduinu. Budeme předpokládat, že máte nastudovány základní příklady, které jsou dodávány k Arduinu. Pokud ne, podívejte se na příklady, které se nacházejí v programech eeprom_clear
, eeprom_write
a eeprom_read
.
Pokud si prohlédnete, jak se používají funkce read a write, zjistíte, že jsou dobré pro čtení a zapisování jednotlivých znaků, na složitější údaje je jejich použití trošku nepraktické. Proto není od věci trošku si práci usnadnit. Naštěstí celou práci vykonal už někdo za nás a napsal veškerý kód za nás na stránce 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;
}
Jelikož ne každý se živí programováním profesionálně, na první pohled se mohou tyto dvě šablonové funkce jevit nepochopitelně. Ale je to jen vtipné využití šablonových funkcí, které kompilátor umí použít. Nebudeme si vysvětlovat podrobnosti o šablonách, k tomu bychom mohli potřebovat mnoho stránek textu. Zájemci o podrobnosti si mohou rozšířit znalosti na Wikipedii v článcích Template (C++) a Standard Template Library.
Zaměříme se jen na to, jak funkce fungují. Základem pro pochopení je to, že kompilátor dokáže namísto class T doplnit definici libovolného typu (i struktury, nebo třídy) a vygenerovat k tomu zdrojový kód. Udělá to tehdy, když se natrefí na nějaký kód, který použije definovanou šablonu. Při bližším pohledu na kód vidíme, že dělá následující věc:
Pokud chceme používat tyto funkce, musíme si je uložit do souboru EEPROMAnything.h a uložit jej nebo do adresáře s funkcemi EEPROM, nebo soubor pouze přiložit do adresáře v vašem projektu.
Jelikož v EEPROM jsou implicitně uloženy náhodné údaje (i když čisté Arduino zde bude mít uloženy nuly), které mohou být ještě náhodnější po vašich předchozích experimentech, je dobré se nespoléhat na tuto náhodu a použít následující algoritmus.
Pokud budete dodržovat tento postup, nebudete mít nikdy chaos v tom, co za data jsou v EEPROM.
Pojďme nyní předchozí algoritmus odzkoušet na konkrétním příkladu. Údaje se ukládají ve struktuře cfg. Máme jednu globální proměnnou typu cfg se jménem c, která má nastavené implicitní hodnoty. Ve funkci setup vidíme, jak si vytvoříme lokální proměnnou tmp, do které přečteme obsah EEPROM. Pokud se identifikační znaky v tmp neshodují s řetězcem T1, pak předpokládáme první spuštění programu na nezkonfigurovaném systému a uložíme obsah našeho implicitního nastavení do EEPROM. Je-li nalezena shoda, zapíšeme pouze obsah tmp do c(c++ je natolik inteligentní, aby za nás doplnilo kód operátora přiřazení). Abychom ale i něco viděli, při každém načtení z EEPROM mírně upravíme obsah obou proměnných. Takto při každém stisku tlačítka reset uvidíme změnu v uložených údajích.
#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 příkladu je v souboru eeprom_practical_01.zip.
Abychom odzkoušeli i malého bratříčka Arduina, můžeme si vyzkoušet příklad i na něm. Zdrojový kód je skoro identický, je tam pouze použitá knihovna SoftwareSerial k obsluze sériového portu. Aby tento příklad fungoval, je třeba propojit ATtiny85 a například Arduino MEGA 2560 podle tohoto návodu. Zdrojový kód příkladu je v souboru eeprom_practical_02.zip.
V následující tabulce je uvedena velikost EEPROM pro běžné druhy Arduina.
Typ | Velikost |
Uno | 1024 |
MEGA 2560 | 4096 |
ATtiny85 | 512 |
Due | * |
Zero | 16kb emulácia ** |
* Do dnešního dne jsem žil v přesvědčení, že by měla být EEPROM na Arduino Due emulována přes flash. Ale momentálně na stránce nic takového nemají uvedeno. Takže když si najdu čas, prozkoumám tento problém podrobněji.
** A pravděpodobně ani Zero emulaci nakonec nemá.
Zdrojové texty příkladů naleznete na GitHub.
17.02.2022