Zápisník experimentátora
Hierarchy: Externá EEPROM
V tomto článku si vysvetlíme, ako môžeme pracovať s externou EEPROM. Externé EEPROM sa obvykle ovládajú protokolom I2C a v tomto článku sa budeme venovať práve takýmto EEPROM. 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.
Na ovládanie EEPROM existuje dobrá knižnica extEEPROM. Nainštalujte si ju prostredníctvom správcu knižníc.
Pri tvorbe tohto vzorového príkladu som vyšiel z toho, čo je priložený ku knižnici. V čase písania tohto článku bol priložený príklad s chybami. Preto sa orientujte podľa môjho vzoru.
Príklad po spustení vypíše obsah EEPROM a čaká na stlačenie tlačidla. Dve tlačidlá môžu vyvolať nasledovnú akciu:
Nebudem komentovať celý zdrojový kód, iba jeho podstatné časti. Funkcie eeErase
, eeWrite
a eeRead
som iba mierne pozmenil voči originálu a nachádzajú sa iba v kompletných zdrojových textoch.
Externá EEPROM 24LC16B dokáže uložiť 2 kB 8-bitových hodnôt. V tomto prípade ju reprezentuje objekt eep
. Chvíľu mi trvalo, kým som zo zdrojových textov uhádol, na čo slúži parameter page size
. Pre vás je dôležitá informácia, že tam treba nechať vždy hodnotu 16. Je to veľkosť údajov, ktoré sa dajú naraz prepraviť a veľkosť je limitovaná aj možnosťami implementácie I2C v Arduine.
#include <extEEPROM.h>
//One 24LC16B EEPROMs on the bus
const uint32_t totalKBytes = 2; // for read and write test functions
const uint8_t chunkSize = 4; // this can be changed, but must be a multiple of 4 since we're writing 32-bit integers
extEEPROM eep(kbits_16, 1, 16); // device size, number of devices, page size
const uint8_t btnStart = 6; // start button
const uint8_t btnErase = 8; // erase button
Vo funkcii setup
nastavím dve tlačidlá ako vstupy a aby som na skúšobné pole nemusel dávať externé rezistory, sú tu aktivované interné pull-up rezistory. To znamená, že na danom pine nameriame hodnotu LOW iba vtedy, keď je mikrospínač stlačený. Sériový port je nastavený na hodnotu 115200, aby boli výpisy údajov rýchle. Po resete Arduina sa vypíše aktuálny obsah EEPROM a legenda so zoznamom funkcií.
void setup(void)
{
pinMode(btnStart, INPUT_PULLUP);
pinMode(btnErase, INPUT_PULLUP);
Serial.begin(115200);
uint8_t eepStatus = eep.begin(twiClock400kHz); //go fast!
if(eepStatus) {
Serial.print(F("extEEPROM.begin() failed, status = "));
Serial.println(eepStatus);
while (1);
}
// dump current EEPROM memory
dump(0,totalKBytes*1024);
Serial.println(F(""));
Serial.println(F("Press button '6' to start write test"));
Serial.println(F("Press button '8' to start erase test"));
}
Funkcia loop
sleduje, či sme nestlačili nejaké tlačidlo. Krátky delay slúži na ošetrenie zákmitov, ale v reáli trvá zapísanie a vypísanie údajov o čosi dlhšie a preto by tam volanie funkcie nemuselo byť.
void loop(void)
{
if(digitalRead(btnStart) == LOW) {
delay(100);
eeWrite(chunkSize);
eeRead(chunkSize);
dump(0,totalKBytes*1024);
}
if(digitalRead(btnErase) == LOW) {
delay(100);
eeErase(chunkSize,0,totalKBytes*1024);
dump(0,totalKBytes*1024);
}
}
Funkcia dump
slúži na kontrolný výpis údajov. Nepísal som ju, len som na jej konci opravil chyby, ktoré zabraňovali tomu, aby bol obsah pamäte pekne formátovaný. Páči sa mi, ako sa jej autor pokúsil prehľadne formátovať údaje. Pokúste sa podľa jej kódu uhádnuť, ako asi vyzerajú výsledné údaje.
void dump(uint32_t startAddr, uint32_t nBytes)
{
Serial.print(F("EEPROM DUMP 0x"));
Serial.print(startAddr, HEX);
Serial.print(F(" 0x"));
Serial.print(nBytes, HEX);
Serial.print(F(" "));
Serial.print(startAddr);
Serial.print(F(" "));
Serial.println(nBytes);
uint32_t nRows = (nBytes + 15) >> 4;
uint8_t d[16];
for(uint32_t r = 0; r < nRows; r++) {
uint32_t a = startAddr + 16 * r;
eep.read(a, d, 16);
Serial.print(F("0x"));
if ( a < 16 * 16 * 16 ) Serial.print(F("0"));
if ( a < 16 * 16 ) Serial.print(F("0"));
if ( a < 16 ) Serial.print(F("0"));
Serial.print(a, HEX); Serial.print(F(" "));
for(int c = 0; c < 16; c++) {
if(d[c] < 16)
Serial.print(F("0"));
Serial.print(d[c], HEX);
Serial.print(c == 7 ? " " : " ");
}
Serial.println(F(""));
}
}
Ak na to nemáte čas alebo článok čítate len zo zvedavosti a nebudete si zapojenie skladať, potom výstup funkcie vyzerá takto.
EPROM DUMP 0x0 0x800 0 2048 0x0000 00 00 00 00 00 00 00 01 00 00 00 02 00 00 00 03 0x0010 00 00 00 04 00 00 00 05 00 00 00 06 00 00 00 07 0x0020 00 00 00 08 00 00 00 09 00 00 00 0A 00 00 00 0B 0x0030 00 00 00 0C 00 00 00 0D 00 00 00 0E 00 00 00 0F
Toto bol krátky úvod ku používanie externých EEPROM. V niektorom z nasledujúcich článkov sa na ukladanie údajov pozrieme z praktickej stránky a ukážeme si, ako ukladať aj zložitejšie údaje pohodlne a bezpečne.
Zdrojový kód sa nachádza na GitHub.
20.03.2017