Spei­cher­ma­nage­ment

Lese­zeit: 6 Minu­ten

Der Spei­cher des Ardui­nos wird für grö­ße­re Pro­gram­me oft knapp. Das geschieht beson­ders dann, wenn vie­le ➨Varia­ble und ➨Arrays ver­wen­det wer­den oder die Anwei­sung ➨Serial.print häu­fig benutzt wird.

Es gibt ver­schie­de­ne Mög­lich­kei­ten, den ver­wen­de­ten Spei­cher zu opti­mie­ren.

Ver­wen­dung von Varia­blen mit dem geringst­mög­li­chen Spei­cher­be­darf

Je nach Ver­wen­dungs­zweck und der benö­tig­ten Grö­ße soll­test du den Varia­blen­typ ver­wen­den, der die Anfor­de­run­gen erfüllt und gleich­zei­tig den gerings­ten Spei­cher­platz bean­sprucht.

Varia­bleGel­tungs­be­reichSpei­cher­be­darfBezeich­nung in C
byteGan­zah­len 0 bis 2551 Byte (8 Bits)char
intGanz­zah­lenah­len -32.768 bis 32.7672 Bytes /16 Bits)int16_t
unsi­gned intGanz­zah­len 0 bis 65.5354 Bytes (32 Bits)uint32_t
long-2.147.483.648 bis 2.147.483.6474 Byte (32 Bits)int32_t
unsi­gned long0 bis 4.294.967.2954 Byte (32 Bits)unsi­gned lon
floatDezi­mal­zah­len4 Byte (32 Bits)float

F-Makro

In vie­len Pro­gram­men wer­den ➨Serial.print/Serial.println-Anwei­sun­gen aus­ge­führt. Jede die­ser Anwei­sun­gen belegt Spei­cher­platz im Pro­gramm­spei­cher. Da es sich aber nicht um eine Varia­ble han­delt, ist die dau­er­haf­te Spei­che­rung nicht not­wen­dig.

Das F-Makro sorgt dafür, dass der Text nicht im Pro­gramm­spei­cher ver­bleibt, er wird viel­mehr im ➨SRAM abge­legt und stellt so Spei­cher­platz im Pro­gramm­spei­cher zur Ver­fü­gung.

Bei­spiel:

Serial.println(F("Initialisierung abgeschlossen")); 
Serial.println(F("Schreibe Messdaten in die Datei Messung.csv: ")); 
Serial.println(F("-----------------------------------");

PROGMEM

PROGMEM weist den Com­pi­ler an, die Daten im➨Flash-Speicher abzu­le­gen.

Dies gilt aber nur für Varia­ble, die einen unver­än­der­li­chen Wert (Kon­stan­te) haben. Sie müs­sen glo­bal im Kopf des Pro­gramms defi­niert wer­den.

Das Pro­gramm erstellt ein Array von belie­bi­gen Zah­len klei­ner als 255. Anschlie­ßend wird eine zufäl­li­ge Posi­ti­on im Array bestimmt und die sich dort befin­den­de Zahl wird ange­zeigt.

So sieht es aus:

Das fol­gen­de Pro­gramm wur­de ohne die Opti­mie­rung des Spei­cher­plat­zes erstellt:

int ZufallsZahl[] = {11, 23, 27, 31, 22, 35, 47, 76, 25, 12, 13, 14, 15, 91, 77, 99};
int Minimum = 1;
int Maximum = sizeof(ZufallsZahl) / sizeof(ZufallsZahl[0]);

void setup ()
{
  // Zufallsgenerator starten
  randomSeed(analogRead(0));
  Serial.begin(9600);
  Serial.println("Zahlen anzeigen:");
  Serial.println("----------------------------------------");
 
  for (byte i = 0; i < Maximum; i++)
  {
    byte GezogeneZahl =  random(Minimum, Maximum);
    Serial.print("Position im Array: \t");
    Serial.print(GezogeneZahl);
    Serial.print("\tZahl: ");
    Serial.println(ZufallsZahl[GezogeneZahl]);
  }
}

void loop()
{
  // bleibt leer, Programm läuft nur einmal
}

Das Pro­gramm mit Opti­mie­rung:

  • es wur­de ein Varia­blen­typ ver­wen­det, der weni­ger Spei­cher­platz ver­braucht (byte statt int)
  • alle kon­stan­ten Varia­blen wur­den mit PROGMEM defi­niert
  • alle Serial.print/Serial.println-Anweisungen wer­den mit dem ➨F-Makro aus­ge­führt

// alle Konstanten ins SRAM kopieren
const byte ZufallsZahl[] PROGMEM = {11, 23, 27, 31, 22, 35, 47, 76, 25, 12, 13, 14, 15, 91, 77, 99};
const byte Minimum PROGMEM = 1;
const byte Maximum PROGMEM = sizeof(ZufallsZahl);

// Zahl kann nicht ausgelagert werden
// -> ist dynamisch, wird im Programm verändert
byte Zahl;

void setup ()
{
  // Zufallsgenerator starten
  randomSeed(analogRead(0));
  Serial.begin(9600);
  Serial.println(F("Zahlen anzeigen:"));
  Serial.println(F("----------------------------------------"));
 
  for (byte i = 0; i < sizeof(ZufallsZahl); i++)
  {
    byte GezogeneZahl =  random(Minimum, Maximum);
  
    // pgm_read_word + GezogeneZahl = Wert im Array an der Postion GezogeneZahl lesen 
    Zahl = pgm_read_word(ZufallsZahl + GezogeneZahl); 
    Serial.print(F("Position im Array: \t")); 
    Serial.print(GezogeneZahl);
    Serial.print(F("\tZahl: "));
    Serial.println(Zahl);
  }
}

void loop()
{
  // bleibt leer, Programm läuft nur einmal
}

Ein wei­te­res, aus­führ­li­che­res Bei­spiel:

const byte ZufallsZahl[] PROGMEM = {11, 23, 27, 31, 22, 35, 47, 76, 25, 12, 13, 14, 15, 91, 77, 99};
const byte Minimum PROGMEM = 1;
const byte Maximum PROGMEM = sizeof(ZufallsZahl);
const char Buchstaben[] PROGMEM = {"abcdefghijklmnopqrstuvwxyz"};

// Zahl kann nicht ausgelagert werden
// -> ist dynamisch, wird im Programm verändert
byte Zahl;

void setup ()
{
  // Zufallsgenerator starten
  randomSeed(analogRead(0));
  Serial.begin(9600);

  // Buchstabensalat
  Serial.println(F("Buchstabensalat:"));
  for (byte i = 0; i < strlen_P(Buchstaben); i++)
  {
    byte GezogeneZahl =  random(Minimum, Maximum);
    char EinzelnerBuchstabe = pgm_read_byte_near(Buchstaben + GezogeneZahl);
    Serial.print(EinzelnerBuchstabe);
  }
  Serial.println(F("\n----------------------------------------"));
 
  // Anzahl der Elemente im Array Zahlen anzeigen
  byte AnzahlElemente = pgm_read_byte(&Maximum);
  Serial.print(AnzahlElemente);
  Serial.println(F(" Elemente im Array Zahlen"));
  Serial.println(F("Zahlen der Reihe nach anzeigen:"));
  Serial.println(F("----------------------------------------"));

  // Array Zahlen der Reihe nach anzeigen
  for (byte i = 0; i < sizeof(ZufallsZahl); i++)
  {
    Zahl = pgm_read_byte(ZufallsZahl + i);
    Serial.print(Zahl);
    Serial.print(F(" "));
  }
  Serial.println(F("\n----------------------------------------"));

  Serial.println(F("Zahlen in zuf\u00e4lliger Reihefolge anzeigen:"));
  Serial.println(F("----------------------------------------"));
  for (byte i = 0; i < sizeof(ZufallsZahl); i++)
  {
    byte GezogeneZahl =  random(Minimum, Maximum);
   
    // pgm_read_word + GezogeneZahl = Wert im Array
    // an der Postion GezogeneZahl lesen
    Zahl = pgm_read_byte(ZufallsZahl + GezogeneZahl); 
    Serial.print(F("Position im Array: \t")); 
    Serial.print(GezogeneZahl); Serial.print(F("\tgezogene Zahl: \t")); 
    Serial.println(Zahl); //Serial.print(F("\t "));
  }
}

void loop()
{
  // bleibt leer, Programm läuft nur einmal
}

Obwohl das Pro­gramm deut­lich umfang­rei­cher ist, wird nicht mehr Spei­cher ver­braucht.

Das Pro­gramm ohne Opti­mie­rung benö­tigt mehr als dop­pelt so viel Spei­cher:

int ZufallsZahl[] = {11, 23, 27, 31, 22, 35, 47, 76, 25, 12, 13, 14, 15, 91, 77, 99};
int Minimum = 1;
int Maximum = sizeof(ZufallsZahl) / sizeof(ZufallsZahl[0]);
char Buchstaben[] = {"abcdefghijklmnopqrstuvwxyz"};

void setup ()
{
  // Zufallsgenerator starten
  randomSeed(analogRead(0));
  Serial.begin(9600);

  // Buchstabensalat
  Serial.println("Buchstabensalat:");
  for (byte i = 0; i < sizeof(Buchstaben); i++)
  {
    byte GezogeneZahl =  random(Minimum, Maximum);
    Serial.print(Buchstaben[GezogeneZahl]);
  }
  Serial.println("\n----------------------------------------");
 
  // Anzahl der Elemente im Array Zahlen anzeigen
  Serial.print(Maximum);
  Serial.println(" Elemente im Array Zahlen");
  Serial.println("Zahlen der Reihe nach anzeigen:");
  Serial.println("----------------------------------------");

  // Array Zahlen der Reihe nach anzeigen
  for (int i = 0; i < Maximum; i++)
  {
    Serial.print(ZufallsZahl[i]);
    Serial.print(" ");
  }
  Serial.println("\n----------------------------------------");

  Serial.println("Zahlen in zuf\u00e4lliger Reihefolge anzeigen:");
  Serial.println("----------------------------------------");
  for (int i = 0; i < Maximum; i++)
  {
    int GezogeneZahl =  random(Minimum, Maximum);
    Serial.print("Position im Array: \t");
    Serial.print(GezogeneZahl);
    Serial.print("\tgezogene Zahl: \t");
    Serial.println(ZufallsZahl[GezogeneZahl]);
  }
}

void loop()
{
  // bleibt leer, Programm läuft nur einmal
}

SRAM EEPROM Flash

Letzte Aktualisierung: 21. Jun 2020 @ 9:30