PROGMEM

[Segédprogramok]

Leírás

Az adatok a flash (program) memória helyett az SRAM-ban tárolódnak. Itt leírás található az Arduino kártyán elérhető különféle memóriatípusokról.

A PROGMEM kulcsszó egy változó módosító, csak a pgmspace.h-ban definiált adattípusokkal használható. Azt mondja a fordítónak, hogy "tegye ezt az információt a flash memóriába", ahelyett, hogy az SRAM-ba, ahova általában kerülne.

A PROGMEM a pgmspace.h könyvtár része. Ez automatikusan szerepel az IDE modern verzióiban. Ha azonban 1.0 (2011) alatti IDE-verziót használ, először fel kell vennie a könyvtárat a vázlat tetejére, például:

#include <avr/pgmspace.h> Míg a PROGMEM használható egyszerű változón, akkor tényleg csak akkor éri meg a felhajtást, ha nagyobb adattömböt kell tárolni, ami általában egy tömbben a legegyszerűbb (vagy egy másik C++ adatszerkezetben, amely a jelen tárgyalásunkon túl van).

A PROGMEM használata szintén kétlépéses eljárás. Az adatok Flash memóriába kerülése után speciális, szintén a pgmspace.h könyvtárban definiált módszerek (függvények) szükségesek ahhoz, hogy a programmemóriából visszaolvassák az adatokat SRAM-ba, így tudunk vele valami hasznosat tenni.

Szintaxis

const dataType variableName[] PROGMEM = {data0, data1, data3…​};

Ne feledje, hogy mivel a PROGMEM egy változó módosító, nincs szigorú szabály arra vonatkozóan, hogy hová kell mennie, ezért az Arduino fordító elfogadja az összes alábbi definíciót, amelyek szintén szinonimák. A kísérletek azonban azt mutatták, hogy az Arduino különböző verzióiban (amelyek a GCC-verzióhoz kapcsolódnak) a PROGMEM működhet az egyik helyen, a másikon nem. Az alábbi „sztring táblázat” példát teszteltük, hogy az Arduino 13-mal működik-e. Az IDE korábbi verziói jobban működhetnek, ha a PROGMEM szerepel a változó neve után.

const dataType variableName[] PROGMEM = {}; // használja ezt a formát
const PROGMEM dataType variableName[] = {}; // vagy ezt
const dataType PROGMEM variableName[] = {}; // ezt ne

Paraméterek

dataType: Engedélyezett adattípusok: bármilyen változótípus.
variableName: az adattömb neve.

Példa

A következő kódrészletek bemutatják, hogyan lehet unsigned char-t (byte-okat) és int-et (2 bájt) beolvasni és írni a PROGMEM-be.

// néhány unsigned int tárolása
const PROGMEM uint16_t charSet[] = { 65000, 32796, 16843, 10, 11234};

// néhány char tárolása
const char signMessage[] PROGMEM = {"I AM PREDATOR,  UNSEEN COMBATANT. CREATED BY THE UNITED STATES DEPART"};

unsigned int displayInt;
char myChar;


void setup() {
  Serial.begin(9600);
  while (!Serial);  // várja meg a soros port csatlakozását. Natív USB-hez szükséges

  // írja be ide a setup kódot, hogy egyszer lefusson:
  // 2-byte int visszaolvasása
  for (byte k = 0; k < 5; k++) {
    displayInt = pgm_read_word_near(charSet + k);
    Serial.println(displayInt);
  }
  Serial.println();

  // char visszaolvasása
  for (byte k = 0; k < strlen_P(signMessage); k++) {
    myChar = pgm_read_byte_near(signMessage + k);
    Serial.print(myChar);
  }

  Serial.println();
}

void loop() {
  // írja be ide a fő kódját, hogy ismételten lefusson:
}

String tömbök

Ha nagy mennyiségű szöveggel dolgozik, például egy LCD-projekttel, akkor gyakran kényelmes karakterláncok tömbjének beállítása. Mivel maguk a karakterláncok tömbök, ez valójában egy kétdimenziós tömb példája.

Ezek általában nagy struktúrák, így gyakran kívánatos a programmemóriába helyezésük. Az alábbi kód illusztrálja az ötletet.

/*
  PROGMEM string demo
  Hogyan tárolhatunk sztringtáblázatot a programmemóriában
  (flash), és hogyan lehet visszakeresni azokat.

  Információk összegzése innen:
  http://www.nongnu.org/avr-libc/user-manual/pgmspace.html

  A karakterláncok táblázatának (tömbjének) beállítása a programmemóriában kissé bonyolult,
  de itt van egy jó sablon, amelyet követni kell.

  A karakterláncok beállítása kétlépéses folyamat. Először határozza meg a karakterláncokat.
*/

#include <avr/pgmspace.h>
const char string_0[] PROGMEM = "String 0"; // "String 0" stb. tárolandó karakterláncok – változtasd meg a megfelelőre.
const char string_1[] PROGMEM = "String 1";
const char string_2[] PROGMEM = "String 2";
const char string_3[] PROGMEM = "String 3";
const char string_4[] PROGMEM = "String 4";
const char string_5[] PROGMEM = "String 5";


// Ezután állítson fel egy táblázatot a karakterláncokra hivatkozva.

const char *const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5};

char buffer[30];  // győződjön meg arról, hogy ez elég nagy ahhoz a legnagyobb karakterlánchoz, amelyet tartania kell

void setup() {
  Serial.begin(9600);
  while (!Serial);  // várja meg a soros port csatlakozását. Natív USB-hez szükséges
  Serial.println("OK");
}


void loop() {
  /* A karakterlánc-tábla programmemóriában való használata speciális függvények használatát igényli az adatok lekéréséhez.
     Az strcpy_P függvény egy karakterláncot másol a programtérből a RAM-ban ("puffer") lévő karakterláncba.
     Győződjön meg arról, hogy a fogadó karakterlánc a RAM-ban elég nagy ahhoz, hogy elférjen benne,
     amit a programterületről tölt le. */


  for (int i = 0; i < 6; i++) {
    strcpy_P(buffer, (char *)pgm_read_word(&(string_table[i])));  // Szükséges castok és hivatkozások megszüntetése, csak másold.
    Serial.println(buffer);
    delay(500);
  }
}

Megjegyzések és figyelmeztetések

Kérjük, vegye figyelembe, hogy a változókat vagy globálisan, VAGY a statikus kulcsszóval kell meghatározni, hogy működjenek a PROGMEM-mel.

A következő kód NEM fog működni, ha egy függvényen belül van:

const char long_str[] PROGMEM = "Hi, I would like to tell you a bit about myself.\n";

A következő kód akkor is működni FOG, ha helyileg van definiálva egy függvényen belül:

const static char long_str[] PROGMEM = "Hi, I would like to tell you a bit about myself.\n"

Az F() makró

Amikor egy utasítást, mint:

Serial.print("Write something on  the Serial Monitor");

használatakor a nyomtatandó karakterlánc általában a RAM-ban van elmentve. Ha a vázlat sok dolgot nyomtat a soros monitoron, könnyen feltöltheti a RAM-ot. Ha van szabad FLASH memóriaterülete, könnyen jelezheti, hogy a karakterláncot el kell menteni a FLASH-ba a szintaxis használatával:

Serial.print(F("Write something on the Serial Monitor that is stored in FLASH"));

See also