Tlačíme dáta do externej EEPROM

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.

Použité súčiastky

Na tento experiment stačí iba pár súčiastok:

  • Arduino Pro Mini (link) - Použil som ho preto, lebo sa zmestí aj na najmenšie skúšobné pole.
  • Breadboard 400 Holes (link) - Na ňom máme dosť miesta na dva mikrospínače.
  • Prevodník CP2102 USB to Serial (link) - Prevodník slúži na naprogramovanie Arduina.
  • Mikrospínače (link, link) - potrebujeme dva kusy. Do skúšobného pola sa dajú použiť aj štvorpinové aj dvojpinové. Niekedy sú piny dlhé, alebo majú podivné výstupky. Nebojte sa tie konce odstrihnúť, aby sa lepšie dali zastrčiť.
  • EEPROM 24LC16B

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.

Príklad

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++.

  • extEEPROM
    • TemplatedEEPROM
      • PushEEPROM

PushEEPROM

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.

  • Šablónový parameter 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.
  • Šablónový parameter 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.
  • Jediná premenná v triede je _index. V ňom si ukladám aktuálne miesto na konci zoznamu vložených prvkov. Využitie vidíte vo funkcii push.
  • A samotná funkcia 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;
  }
 
};

Hlavný program

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);
  }
}

Výpisy zo sériového portu

Vo výpise je vidno.

  • ​Základné parametre EEPROM. Vidíme veľkosť nášho kontajnera na 32-bitové hodnoty.
  • Výpis obsahu premennej eep. Pre nás sú zaujímavé posledné štyri bajty, kde vidíme, že je nastavená 0 v premennej _index.
  • Ak si pustíme program na vymazanú EEPROM, budú mať všetky bajty hodnotu 0xFF.
  • Po zapísaní si môžete všimnúť, že sa obsah premennej 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

Zdrojový kód sa nachádza na serveri GitHub.


15.04.2017


Menu