OK

Při poskytování služeb nám pomáhají soubory cookie. Používáním našich služeb vyjadřujete souhlas s naším používáním souborů cookie. Více informací

Úvodní stránka » Arduino » Arduino v příkladech - V.díl - Jak pracovat s pamětí do třetice

Arduino v příkladech - V.díl - Jak pracovat s pamětí do třetice

Opakování je matka moudrosti – EEPROM je paměť mikrokontroléru, kde zapsaná data zůstanou i po vypnutí napájení. Má omezený počet zápisů, výrobcem deklarovaných min. 100 tis. bylo v praxi více než 12 mil. Je to paměť, kde vy určujete co a kam se zapíše.

Výborně, no a co že nevymaže. Koupíte impulsní vodoměr, napíšete program, který vám zavře ventil pokud bude puštěná voda déle jak 30 minut. Zabráníte tak vytopení domu v případě že praskne voda. Pak půjdete napouštět bazén a každých 30 minut se Vám zavře voda. Řešení je jednoduché. Vytrhnete kabel od ventilu, nebo rozeberete krabičku ve které to máte umístěné a nahrajete nový program. Nebo stačí na to při programování myslet a požadovanou dobu uložíte do EEPROM. Změnit tuho hodnotu můžete za pomoci potenciometru, tlačítka, displeje, wifi a vlastně všeho co umožňuje pracovat s Arduinem.

Paměť EEPROM je tedy výhodné použít vždy, kdy potřebujete za běhu programu měnit jeho parametry, jako je časování čtení čidel a měnit jejich rozlišení, módy čtení, ukládat hesla, mazat a nahrávat adresy RFID klíčenek, uložit heslo, atd. a po každém restartu Arduino to nechcete absolvovat znovu. Také lze napsat funkci, která v případě že program totálně rozladíte, vrátí vše do výchozího nastavení. Jen příklad, když jsem psal program pro zabezpečovací ústřednu, obsadil jsem takto 720 polí a z krabičky Arduino vyndám až shoří.

V každém Arduino může být paměť jinak veliká, je to dáno použitým čipem. Např. Arduino UNO používá čip ATmega328P, který má 1 kB, tedy 1024 byte paměti EEPROM. Paměťové pole má rozsah 8 bit, tedy lze zadat hodnotu v rozsahu 0-255.

Pro naše příklady využijeme právě UNO a výpisy na Serial. Jediné co budeme potřebovat navíc, je knihovna EEPROM, která je součástí standardní instalace Arduino IDE.

Každá buňka EEPROM má svoji adresu, v případě UNO ji voláme v rozsahu 0-1023.

Podíváme se jak zobrazit velikost EEPROM

#include <EEPROM.h> // knihovna pro zapis do pameti EEPROM

void setup() {
  Serial.begin(9600);
}

void loop() {

  // uz vyuzijeme znalosti z SRAM - nevytvarime promennou
  Serial.print(EEPROM.length()); // zobrazime velikost EEPROM

  EEPROM.write(0, 1);

  while (1) delay(10000);
}

ANO je to hodnota 1024. Stále na to zapomínám, začínáme 0, tedy končíme EEPROM.lenght()-1, tj. 1023. Nepokoušejte se zapsat do buňky 1024 – jde to, zapíšete do buňky 0, 1025 do buňky 1 atd.

Přehled funkcí knihovny EEPROM

Ukážeme si jen ty nejčastěji používané:

EEPROM.write(x, y) – zapíše do buňky x, hodnotu y. Pozor na přetečení, zapisujeme vždy hodnotu byte, nebo unsigned char (jsou stejné)

EEPROM.read(x) – přečte hodnotu z buňky x

EEPROM.update(x, y) – porovná hodnotu z buňky x s y a pokud nejsou stejné, zapíše do buňky x, hodnotu y. Tato funkce vykonává v podstatě stejné jako EEPROM.write s tím, že omezuje počet zápisů a je výrazně pomalejší.

Funkce se dá vyjádřit následujícím zápisem

if (EEPROM.read(x) != y) EEPROM.write(x,y);

EEPROM.clear() – přepíše celou paměť hodnotou 0. Osobně preferuji při vyčištění paměti zápis hodnoty 255. Hodnota 0 může přinést neočekávané výsledky třeba v případě, že kontrolujete zda bylo do buňky něco zapsáno. U hodnoty 255 je pravděpodobnost mnohem menší.

Funkční část programu pro mazání paměti

for (int i = 0; i < EEPROM.length(); i++) {
  EEPROM.write(i, 255);
}

Existují ještě funkce pro zápis řetězců, desetinných čísel a jejich čtení, ověření zda se hodnoty zapsaly správně, ale to si můžeme ukázat jindy.

Z funkcí je ještě zajímavá ta, která vám zobrazí, co máte v EEPROM uložené. Výborná věc až budete hledat, proč něco nefunguje.

#include <EEPROM.h>

byte count = 0;

void setup() {
  Serial.begin(9600);
}

void loop() {

  for (long i = 0; i < EEPROM.length(); i++) {
    if (count == 0) {
      Serial.print("EEPROM ");
      Serial.print(i);
      Serial.print(": ");
    }
    Serial.print(EEPROM.read(i));
    count ++;
    if (count < 10) Serial.print(", ");
    if (count == 10) {
      Serial.println();
      count = 0;
    }
  }
  while (1) delay(10000);
}

Praktické příklady

Příklad 1

Následující sketch nám ukáže, jak za pomoci zápisu EEPROM nastavit počet bliknutí diody na Arduinu v zadaném intervalu 5 s. Nahrajte sketch, zapněte Serial monitor, přepněte do režimu "Chybný konec řádky" a zadejte libovolné číslo v rozsahu 0-9. To je počet rychlých bliknutí každých 5 s.

#include <EEPROM.h> // knihovna pro zapis do pameti EEPROM

#define LED 13 // pojmenujeme vystup

unsigned long posledniSpusteni; // pripravime prommenou pro cyklus
int prodleva = 5000; // nastavime prodlevu mezi blikanim

void setup() {
  Serial.begin(9600); // inicializuje serial
  pinMode(LED, OUTPUT); // nastavime pin jako vystupni
  digitalWrite(LED, LOW); // pro jistotu zhasneme diodu
}

void loop() {
  // kdyz odesleme data, precteme je a ulozime do EEPROMM
  if (Serial.available() > 0) { // kdyz prisla data
    char cteni = Serial.read(); // precti je
    String text = (String)cteni; // preved ctenou hodnotu na String
    int pocet = text.toInt(); // preved ulozenou hodnotu na cislo
    EEPROM.update(0, pocet); // uloz cislo do pameti EEPROM

  }
  // a blikame
  if ((unsigned long)(millis() - posledniSpusteni) >= prodleva) { // nastavime podminku pro uplynuti casu
    posledniSpusteni = millis(); // nastavime novy cas spusteni cyklu
    // zablikame diodou tokikrat, kolikrat je ulozeno v EEPROM
    for (byte i = 0; i < EEPROM.read(0); i++) {
      digitalWrite(LED, HIGH);
      delay (100);
      digitalWrite(LED, LOW);
      delay (100);
    }
  }
}

Pokud Vám to nefunguje a dioda nebliká, tak jste zapomněli přepnout do režimu "Chybný konec řádky".

Až budete pracovat s daty ze Serial monitoru zjistíte, že ve skutečnosti NULA odeslaná ze Serial monitoru není NULOU jako číslo, ale číslo 48. Více informací najdete na https://cs.wikipedia.org/wiki/ASCII. Pokud vezmu jazyk Arduino, tak jste dostali hodnotu '0', tedy text. Protože je to seriál především pro začátečníky, zvolil jsem převod na číslo jak ho vidíte, zkušení jistě prominou. Ale to zase odbočuji.

Teď odpojte Arduino od napájení a znovu připojte, dioda začne opět blikat frekvencí kterou jste nastavili. A to je důvod proč používat paměť EEPROM.

Příklad 2

Nyní si zkusíme složitější příklad. Do EEPROM si budeme ukládat telefonní čísla 4 uživatelů a po zadání si je vždy pošleme na Serial monitor pro ověření.

Zadání čísla probíhá tak, že písmena A, B, C a D mám určí kterému uživateli budeme zapisovat číslo a pak zadáme devíti místné číslo. Písmenem V získáme výpis uložených čísel. Tento příklad je vhodný třeba pro změnu čísla, za pomoci displeje na které bude volat GSM modul. Takto si můžete číslo změnit i za pomoci SMS. Jak používat GSM modul, jsme si na našich stránkách již ukázali. Program je napsaný tak, aby vyloučil neplatné znaky. Můžete tedy odeslat "C 800800800" a stejně dostanete správný výsledek.

#include <EEPROM.h> // knihovna pro zapis do pameti EEPROM

void setup() {
  Serial.begin(9600); // inicializuje serial
}

void loop() {

  if (Serial.available() > 0) { // kdyz prisla data
    zapisCisla(); // spustime funkci
  }
}

// funkce pro zapis modu, telefonniho cisla a cteni zapsanych dat
void zapisCisla() {
  // vytvorime prommene
  const int adresaEEPROM[] = {1, 10, 19, 28}; // adresy EEPROM pro zapis tel. cisel
  byte mod = 0;
  byte pocitadlo = 0;
  unsigned long casSpusteni;
  const byte konecBehu = 100;
  char cteni;
  String text;
  // cyklus pro cteni dat ze Serial portu
  do { // cekani na spravnou odpoved
    if (Serial.available() > 0) { // kdyz jsou k dispozici data, precti data
      casSpusteni = millis(); // nastav cas pro ukonceni
      cteni = Serial.read(); // precti data
      if (cteni == 'V') { // kdyz je V nastav mod na vypis cisel
        mod = 3;
      }
      else if (cteni == 'A' || cteni == 'B' || cteni == 'C' || cteni == 'D') { // kdyz je znak ABCD, nastav mod pro zapis na uzivatele ABCD
        mod = 1;
      }
      else if (cteni >= '0' && cteni <= '9') { // kdyz je cislo
        text += cteni; // dopln promennou o dalsi nacteny znam
        if (text.length() == 9) { // kdyz se dosahne 9 mistneho cisla nastav mod na zapis
          mod = 2;
        }
      }
    }
  }
  while (!mod && !((unsigned long)(millis() - casSpusteni) >= konecBehu)); // ceka na spravnou hodnotu, nebo uplynuti casu

  if (mod == 1) { // kdyz je mod 1
    EEPROM.update(0, cteni - 'A'); // zapis do EEPROM 0, ciselnou hodnotu uzivatele ktereho budeme zapisovat
  }
  else if (mod == 2) { // kdyz je mod 2
    for (int i = 0; i < 9; i++) { // zapis do EEPROM tel cislo uzivatele
      EEPROM.update(adresaEEPROM[EEPROM.read(0)] + i, text[i]);
    }
  }
  String text1 = "Telefonni cislo uzivatele "; // promenna pro zobrazeni textu
  if (mod == 2) { // kdyz je mod 2
    Serial.print(text1 + (String)(EEPROM.read(0) + 1) + " : "); // zobraz cislo zapisovaneho uzivatele
    for (int i = 0; i < 9; i++) { // zobraz ulozene telefonni cislo
      Serial.print((char)EEPROM.read(adresaEEPROM[EEPROM.read(0)] + i));
    }
    Serial.println();
    Serial.println();
  }
  if (mod == 3) { // kdyz je mod 3
    for (int i = 0; i < 4; i++) { // zobraz postupne uzivatele
      Serial.print(text1 + (String)(i + 1) + " : ");
      for (int count = 0; count < 9; count++) { // zobraz telefoni cislo uzivatele
        Serial.print((char)EEPROM.read(adresaEEPROM[i] + count));
      }
      Serial.println();
    }
    Serial.println();
  }
}

A hned opět odbočím. Využili jsme techniky, které jsme si popsali v minulých seriálech. Pro nezkušené oko se to může zdát těžko čitelné, ale výrazně jsme si tak zkrátili celý program. Vytvořili jsme si funkci zapisCisla(). Důvodem je zkrátit funkci loop. Až budete psát delší program, je dobré si udržovat krátký loop, jinak se z těch závorek zblázníte. Také ani jednu proměnnou jsme nedefinovali jako globální. Jednak ušetříme místo v SRAM a pak je pokaždé nemusíme nulovat. Pro čtení dat ze Serial portu využíváme cyklus do..while. Ten používám prakticky neustále. Většina periférií posílá ukončovací znak, podle kterého i můžeme ukončit cyklus. Pro zápisy a čtení EEPROM je využit cyklus for, důvodem je opět zkrácení zápisu. Kód je velmi podrobně popsaný, ale rád zodpovím na případné dotazy.

Shrnutí

Pokud budete tvořit projekt, kde se mění základní nastavení a nechcete připojovat počítač k vašemu Arduino, bez práce s EEPROM se neobejdete.

Omezte počet zápisů do EEPROM, neodkládejte tam tzv. pracovní proměnné, které se mění několikrát za vteřinu.

Dávejte pozor kam co zapisujete. Tuto paměť ovládáte vy.

Příště si ukážeme praktický příklad, jak používat periférie právě pro nastavení za pomoci displeje. A vrátíme se k analogovému čtení.

JB

jaroslav.bohac@arduinotech.cz

Přidat komentář

Zvýrazněné položky jsou povinné.


TOP produkty

NodeMCU s ESP8266

NodeMCU s ESP8266
350 Kč s DPH

Arduinotech GSM shield

Arduinotech GSM shield
877 Kč s DPH

Kontakt

Ing. Petr Foltýn
Kunčice pod Ondřejníkem 814, 73913
TOPlist