Diese Seite ist auch in 2 anderen Sprachen verfügbar.
Sprache wechseln  

PROGMEM

[Utilities]

Beschreibung

Speichere Daten im Flash-/Programm-Speicher statt im SRAM. Eine Beschreibung der unterschiedlichen Arten von Speicher des Arduinos findest du hier.

PROGMEM ist ein Variablenmodifikator, welcher nur mit den Datentypen in pgmspace.h verwendet werden sollte. Es ist eine Anweisung an den Compiler, um die Daten im Flash-/Programm-Speicher statt im SRAM zu speichern.

PROGMEM gehört zur pgmspace.h-Softwarebibliothek. Diese ist in allen modernen IDE-Versionen standardmäßig enthalten. Solltest du eine IDE-Version niedriger als 1.0 (von 2011) besitzen, musst du die Bibliothek erst händisch einbinden. Dies funktioniert wie folgt:

#include <avr/pgmspace.h>

Syntax

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

dataType - Beliebiger Variablentyp variableName - Der Variablenname

PROGMEM ist ein variabler Modifikator, weshalb die Arduino-IDE alle folgenden synonymen Versionen der Syntax akzeptiert. Durch Experimente wurde allerdings festgestellt, dass in einigen Versionen der Arduino-IDE (Durch die unterschiedlichen GCC-Versionen) an einigen Stellen funktioniert und an anderen nicht. Die Beispiele unten funktionieren mit der Arduino IDE Version 13. Frühere Versionen der IDE arbeiten besser, wenn PROGMEM nach dem Variablennamen eingefügt wird.

const dataType variableName[] PROGMEM = {}; // Benutze dies
const PROGMEM dataType variableName[] = {}; // oder das,+ const dataType PROGMEM variableName[] = {}; // aber nicht diese Version!

PROGMEM kann auch für einzelne Variablen benutzt werden, dies ist aber nur sinnvoll, wenn ein großer Block von Daten gespeichert werden soll. Normalerweise ist das bei Arrays, Strings (die auch Arrays sind) und weiteren komplizierteren Datenstrukturen der Fall.

Die Benutzung von PROGMEM erfolgt in 2 Schritten. Nachdem die Daten in den Flash-/Programm-Speicher geladen wurden, müssen spezielle Methoden verwendet werden, um diese Variablen wieder auszulesen und zu bearbeiten. Diese sind auch in der pgmspace.h-Softwarebibliothek definiert.

Beispielcode

Das folgende Code-Fragment zeigt, wie ein unsigned chars (bytes) und ints (2 bytes) in PROGMEM geschrieben und wieder ausgelesen werden können.

// Speichere einige unsigned ints
const PROGMEM uint16_t charSet[] = { 65000, 32796, 16843, 10, 11234};

// Speichere einen String
const char signMessage[] PROGMEM = {"I AM PREDATOR, UNSEEN COMBATANT. CREATED BY THE UNITED STATES DEPART"};

unsigned int displayInt; // Rückgabewert der Funktion zum Auslesen der Daten
char myChar; // Definiere einen Char, um diesen zu bearbeiten

void setup() {
  Serial.begin(9600); // Initialisiere den seriellen Port
  while (!Serial);  // Warte, bis der serielle Port verbunden ist

  // Setup code:
  // Lies einen 2-Byte-Int
  for (byte k = 0; k < 5; k++) {
    displayInt = pgm_read_word_near(charSet + k); // Lies den charSet-Wert wieder aus dem Flash-/Programm-Speicher
    Serial.println(displayInt); // Gib den gelesenen Wert aus
  }

  Serial.println(); // Schreibe eine neue Zeile

  // Lies einen Char
  for (byte k = 0; k < strlen_P(signMessage); k++) {
    myChar = pgm_read_byte_near(signMessage + k); // Lies den signMessage-Wert wieder aus dem Flash-/Programm-Speicher
    Serial.print(myChar); // Gib den gelesenen Wert aus
  }

  Serial.println(); // Schreibe eine neue Zeile
}

void loop() {
  // ...
}

Array von Strings

Wenn mit einer großen Menge an Text gearbeitet wird (Beispiel: Projekt mit LCD-Display), ist es häufig nötig, Texte in ein Array von Strings zu packen. Dadurch, dass Strings bereits selbst Arrays sind, entsteht dadurch ein 2-dimensionales Array.

Diese großen Datenstrukturen können in den Flash-/Programm-Speicher geladen werden. Das Beispiel unten zeigt das.

/*
 PROGMEM string demo
 Wie man ein Stringarray in den Flash-/Programm-Speicher lädt und wieder liest.

 Für weitere Informationen siehe:
 http://www.nongnu.org/avr-libc/user-manual/pgmspace.html

 Stringarrays in den Flash-/Programm-Speicher zu laden, ist etwas komplizierter,
 das Beispiel ziegt dies jedoch.
*/

#include <avr/pgmspace.h>
const char string_0[] PROGMEM = "String 0"; // Definiere deine Strings "String 0" ist hier nur ein Beispiel
const char string_1[] PROGMEM = "String 1"; // Definiere deine Strings "String 1" ist hier nur ein Beispiel
const char string_2[] PROGMEM = "String 2"; // Definiere deine Strings "String 2" ist hier nur ein Beispiel
const char string_3[] PROGMEM = "String 3"; // Definiere deine Strings "String 3" ist hier nur ein Beispiel
const char string_4[] PROGMEM = "String 4"; // Definiere deine Strings "String 4" ist hier nur ein Beispiel
const char string_5[] PROGMEM = "String 5"; // Definiere deine Strings "String 5" ist hier nur ein Beispiel

// Initialisiere die Tabelle von Strings
const char* const string_table[] PROGMEM = { string_0, string_1, string_2, string_3, string_4, string_5 };

char buffer[30]; // Der Buffer zum Lesen der Daten muss so lang sein wie der längste String!

void setup() {
  Serial.begin(9600); // Initialisiere den seriellen Port
  while(!Serial); // Warten, bis der serielle Port verfügbar ist
  Serial.println("OK"); // Schreibe "OK" auf den seriellen Port
}

void loop() {
  /* Spezielle Funktionen zum Lesen der Daten sind nötig. "strcpy_P" kopiert den String vom
     Flash-/Programm-Speicher in dem SRAM/ den Buffer. Stelle sicher, dass der empfangende
	 String lang genug ist für den String.
  */

  // Iteriere über das Array: 6-mal, da 6 Strings im Array sind
  for (int i = 0; i < 6; i++) {
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); // Casts und Dereferenzierung des Speichers
    Serial.println(buffer); // Gib den gelesenen Wert aus
    delay(500); // Warte eine halbe Sekunde
  }
}

Anmerkungen und Warnungen

Bitte beachte, dass die Variablen entweder global definiert oder als static definiert sein müssen, um mit PROGMEM zu funktionieren.

Der folgende Code wird nicht funktionieren, wenn er in einer Funktion ausgeführt wird:

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

Der folgende Code wird funktionieren, wenn er in einer Funktion ausgeführt wird:

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

Das F()-Makro

Wenn eine Instruktion wie

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

benutzt wird, wird der String bevor er auf den seriellen Ausgang geschrieben wird, normalerweise in den RAM gespeichert. Der RAM kann aber sehr leicht volllaufen, wenn der Code sehr viel auf den seriellen Port schreibt. Wenn du noch freien Flash-/Programm-Speicher hast, kannst du dem Compiler sagen, dass er die Werte in den Flash-/Programm-Speicher schreiben soll:

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

Siehe auch