Zápisník experimentátora
Hierarchy: Externá EEPROM
V tomto článku budeme rozvíjať kód, ktorý sme vytvorili v predchádzajúcom článku. Navrhneme si triedu, ktorá bude optimalizovaná na zapisovanie pola objektov do EEPROM. Objektom môže byť napríklad nameraná hodnota, ale fantázii sa medze nekladú. V našom príklade budeme ukladať pole 32-bitových hodnôt, ktoré pre nás reprezentujé merané hypotetické údaje. Využijeme pritom šablóny jazyka C++ a doplníme do triedy funkciu push
, ktorá budú plniť túto úlohu. Príklad bude pre 24LC16B, ale až na drobnosti bude tento návod univerzálny pre ľubovolnú EEPROM.
Na tento experiment stačí iba pár súčiastok:
Arduino je upravené tak, že má na I2C (nachádza sa netradične na extra pinoch uprostred Arduina) prispájkovanú pin lištu s otvormi, aby sa pomocou dvoch prepojovacích vodičov dalo ľahko prepojiť s EEPROM.
Dve tlačidlá sa používajú na spustenie konkrétnych testov a sú pripojené na piny 6 a 8 na Arduine. EEPROM je pripojená na napájanie a adresové piny A0, A1 a A2 sú nezapojené. To platí ale iba pre tento konkrétny typ EEPROM. Ostatné musia obvykle pripojiť tieto piny na GND alebo na VCC, čím si nastavia I2C adresu. Treba si vždy skontrolovať datasheet ku konkrétnemu typu a nastaviť to podľa neho.
Kód predchádzajúceho príkladu som trochu upratal. Teraz sa skladá z troch súborov.
eeprom_24lc16b_push.ino
- Hlavný program.dump.h
- Funkcie, ktoré sa v ňom nachádzajú, sú popísané napríklad v článku Dump obsahu premennej na sériový port.push_eeprom.h
- Všetky šablónové triedy som umiestnil sem.Hierarchia tried sa nám utešene rozrastá. Ale prispieva to k čitateľnosti kódu a pekne ukazuje silu dedičnosti v C++.
Tu je kompletný kód šablónovej triedy PushEEPROM
. Šablónú som použil preto, aby som všetky nevyhnutné výpočty hodil na kompilátor a získal generovaný kód podľa mojich požiadaviek.
data
nastavuje veľkosť a typ jedného prvku v poli. Všimnite si v kóde, ako pomocou operátora sizeof
získam jeho veľkosť v bajtoch a ako sa to dá využiť vo výpočtoch veľkosti.capacity
zase nastavuje veľkosť EEPROM. Jednotlivé EEPROM sa od seba líšia iba veľkosťou, ale všetky ostatné parametre aj správanie sú zhodné. Preto je ľahké na ich popísanie využívať šablóny._capacity
, _maxbytes
a _maxitems
sú konštanty a tie sa ľahko odvodia od šablónových parametrov. Použitý dátový typ uint32_t je tam preto, aby sa dali využiť aj veľké EEPROM s hodnotou 2048 Kb._index
. V ňom si ukladám aktuálne miesto na konci zoznamu vložených prvkov. Využitie vidíte vo funkcii push.push
je vďaka využitiu funkcie put
z triedy TemplatedEEPROM (navrhli sme ju v predchádzajúcom článku) tiež jednoduché. Iba si kontrolujem, či nie je prekročená kapacita a keď je ešte voľné miesto, vložím novú položku do EEPROM.
template< typename data, const eeprom_size_t capacity>
class PushEEPROM : public TemplatedEEPROM
{
const uint32_t _capacity = capacity*1024L;
const uint32_t _maxbytes = _capacity/8;
const uint32_t _maxitems = _maxbytes/sizeof(data);
uint32_t _index;
public:
PushEEPROM(byte nDevice = 1, unsigned int pageSize = 16, byte eepromAddr = 0x50)
: TemplatedEEPROM(capacity, nDevice, pageSize, eepromAddr),
_index(0)
{}
const uint32_t getCapacity() { return _capacity; }
const uint32_t getMaxBytes() { return _maxbytes; }
const uint32_t getMaxItems() { return _maxitems; }
bool push(data d) {
if(_index>=_maxitems)
return false;
put(_index*sizeof(data),d);
_index++;
return true;
}
};
V hlavnom programe si includujeme všetky hlavičkové súbory a zadefinujeme si jednu premennú eep
. Použitý zápis hovorí, že chceme ako dáta použiť typ uint32_t
a EEPROM má veľkosť 16 Kb. kbits_16
je enumerácia z hlavičkových súborov knižnice extEEPROM
. Vidíte, že jednoduchšie to už byť nemôže. Dva šablónové parametre nám nastavia správanie triedy PushEEPROM do podoby, ako potrebujeme a vďaka implicitným parametrom v konštruktore som sa vyhol komplikovaným parametrom, ktoré v konečnom dôsledku aj tak na nič zmysluplné neslúžili.
Šablona triedy nám umožňuje nastaviť triedu tak, ako potrebujeme. Napríklad by to bez problémov fungovalo aj takto, pre inú situáciu.
PushEEPROM<uint16_t, kbits_256>
- Pre 16-bitové čísla a EEPROM veľkosti 256 Kb.PushEEPROM<float, kbits_64>
- Pre reálne čísla a EEPROM veľkosti 64 Kb.
#include <extEEPROM.h>
#include "dump.h"
#include "push_eeprom.h"
PushEEPROM<uint32_t, kbits_16> eep;
Rovnako jednoduché je aj ukladanie (tlačenie) údajov do EEPROM. Chceme ich ukladať postupne až do naplnenia EEPROM. Nechceme riešiť, kde je momentálne koniec aktuálnych dát a či ešte máme miesto. O to sa má postarať funkcia push
a vďaka tomu je zápis pochopiteľný aj pre kohokoľvek iného, než je autor.
void loop(void)
{
if (digitalRead(btnStart) == LOW) {
delay(100);
Serial.println(F("Writing..."));
for (uint32_t i = 0; i < eep.getMaxItems(); i++) {
if ((i & 0xFF) == 0)
Serial.println(i);
eep.push(i);
}
DUMP(eep);
dumpEEPROM(0, totalKBytes * 1024);
}
if (digitalRead(btnErase) == LOW) {
delay(100);
eeErase(chunkSize, 0, totalKBytes * 1024);
dumpEEPROM(0, totalKBytes * 1024);
}
}
Vo výpise je vidno.
eep
. Pre nás sú zaujímavé posledné štyri bajty, kde vidíme, že je nastavená 0 v premennej _index
.eep
zmenil a premenná _index
má hodnotu 512. To znamená, že náš kontajner je plný a žiadne ďalšie hodnoty sa do neho nezmestia.EEPROM Capacity: 16384 EEPROM MaxBytes: 2048 EEPROM MaxItems: 512 Dump: eep 02A6 - 50 10 00 01 10 00 08 01 00 00 08 00 00 00 40 00 P.............@. 02B6 - 00 00 08 00 00 00 02 00 00 00 00 00 00 ............. EEPROM DUMP 0x0 0x800 0 2048 0x0000 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ... 0x07F0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF Press button '6' to start write test Press button '8' to start erase test Writing... 0 256 Dump: eep 02A6 - 50 10 00 01 10 00 08 01 00 00 08 00 00 00 40 00 P.............@. 02B6 - 00 00 08 00 00 00 02 00 00 00 02 00 00 ............. EEPROM DUMP 0x0 0x800 0 2048 0x0000 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 ... 0x07F0 FC 01 00 00 FD 01 00 00 FE 01 00 00 FF 01 00 00
Zdrojový kód sa nachádza na serveri GitHub.
15.04.2017