Esta página também está disponível em outros 2 idiomas.

PROGMEM

[Utilities]

Descrição

Armazena dados na memória flash (memória de programa) em vez da SRAM. Uma descrição dos vários tipos de memória das placas Arduino pode ser encontrada (Em Inglês) nessa página.

A palavra-chave PROGMEM é um modificador de variáveis, que pode ser usada apenas com os modificadores de variáveis definidos em pgmspace.h. Ela diz ao compilador "armazene essa informação na memória flash", em vez da SRAM, onde seria normalmente armazenada.

PROGMEM é parte da biblioteca pgmspace.h. Essa biblioteca é incluída automaticamente em versões modernas da IDE, porém se você estiver usando uma versão da IDE anterior à 1.0 (2011), iŕa precisar incluir ela no topo do seu sketch, da seguinte forma:

#include <avr/pgmspace.h>

Sintaxe

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

Onde:

dataType - qualquer tipo de dados

variableName - o nome do seu vetor de dados

Note que porque PROGMEM é um modificador de variável, não há uma regra rigorosa de onde ele deve ir, então o compilador aceita todos os tipos de definição abaixo, que também são sinônimos. Mesmo assim, experimentos indicaram que, em várias versões do Arduino (relacionado a versão do GCC), PROGMEM pode funcionar em uma localização e não em outra. O exemplo da "tabela de strings" abaixo foi testado com a versão 13 do Arduino. Versões mais antigas da IDE podem funcionar melhor se PROGMEM for incluído depois do nome da variável.

const dataType variableName[] PROGMEM = {}; // use essa forma
const PROGMEM dataType variableName[] = {}; // ou essa
const dataType PROGMEM variableName[] = {}; // mas não essa

Enquanto PROGMEM pode ser usada em uma única variável, realmente só vale a pena o trabalho de usá-lo se você tiver um bloco de dados maior para ser armazenado, o que geralmente é mais fácil de fazer com vetores (ou outra estrutura de dados da linguagem C++ fora do escopo da nossa discussão atual).

Usar PROGMEM é também um procedimento realizado em dois passos. Depois de resgatar os dados da memória flash, são requeridas funções especiais, também definidas na biblioteca pgmspace.h, para ler os dados da memória de programa para a memória SRAM, tal que possamos fazer algo com eles.

Código de Exemplo

Os fragmentos de código abaixo ilustram como ler e escrever unsigned chars (bytes) e ints (2 bytes) com PROGMEM.

// armazena alguns unsigned ints
const PROGMEM uint16_t conjunto[] = {65000, 32796, 16843, 10, 11234};

// armazena alguns chars
const char mensagem[] PROGMEM = {"Um pequeno jabuti xereta viu dez cegonhas felizes"};

unsigned int displayInt;
char meuChar;


void setup() {
  Serial.begin(9600);
  while (!Serial);  // Espera a porta serial conectar. Necessário para placas com USB nativa

  // Lê da memória flash um int (2-bytes, ou word)
  for (byte k = 0; k < 5; k++) {
    displayInt = pgm_read_word_near(conjunto + k);
    Serial.println(displayInt);
  }
  Serial.println();

  // Lê um caractere da flash
  for (byte k = 0; k < strlen_P(mensagem); k++) {
    meuCHar = pgm_read_byte_near(mensagem + k);
    Serial.print(meuCHar);
  }

  Serial.println();
}

void loop() {
  //Nada aqui
}

Vetores de strings

É frequentemente conveniente, quando se trabalha com grandes quantidade de texto, como um projeto com display LCD, por exemplo, preparar vetores de strings. Porque strings por si próprias já são vetores, este é genuinamente um exemplo de um vetor bidimensional.

Essas estruturas tendem a ser muito grandes, de forma que colocá-las na memória pode ser desejável. O código abaixo ilustra a ideia.

/*
  demo com strings e PROGMEM
  Como armazenar uma tabela de strings na memória de programa (flash),
  e recuperá-los.

  Informação resumida de:
  http://www.nongnu.org/avr-libc/user-manual/pgmspace.html

  Preparar uma tabela (vetor) de strings na memória de programa é relativamente complicado,
  mas esse template pode ser seguido.

  Preparar as strings é um processo em dois passos. O primeiro é definir as strings.
*/

#include <avr/pgmspace.h>
const char string_0[] PROGMEM = "String 0"; // "String 0" etc são as strings a serem armazenadas - adapte ao seu programa.
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";


// Então crie uma tabela para apontar para as suas strings.

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

char buffer[30];  // Tenha certeza que esse buffer é grande o suficiente para armazenar a maior string

void setup() {
  Serial.begin(9600);
  while (!Serial);  // Espera a porta serial conectar. Necessário para placas com USB nativa
  Serial.println("OK");
}


void loop() {
  /* Usar a tabela de strings da memória de programa requer o uso de funções especiais para recuperar os dados.
     A função strcpy_P copia uma string do espaço de programa para uma string na RAM (em um "buffer").
     Tenha certeza que o seu buffer na RAM é grande o suficiente para armazenar o que quer que seja
     que você estiver lendo da memória de programa. */


  for (int i = 0; i < 6; i++) {
    strcpy_P(buffer, (char *)pgm_read_word(&(string_table[i]))); // Casts e desreferência necessários, apenas copie.
    Serial.println(buffer);
    delay(500);
  }
}

Notas e Advertências

Por favor note que as variáveis devem ser definidas globalmente OU com a palavra-chave static, para funcionarem com PROGMEM.

O código a seguir não funcionará dentro de uma função:

const char long_str[] PROGMEM = "Olá, gostaria de falar um pouco sobre mim mesmo.\n";

O código a seguir irá funcionar, mesmo se definido localmente dentro de uma função:

const static char long_str[] PROGMEM = "Olá, gostaria de falar um pouco sobre mim mesmo.\n";

A macro F()

Quando uma instrução do tipo:

Serial.print("Escreve algo no Monitor Serial");

é usada, a string a ser impressa é normalmente salva na RAM. Se o seu sketch imprime muita coisa no Monitor Serial, você pode facilmente encher a RAM. Se você tiver espaço livre na memória flash, você pode facilmente indicar ao compilador que a string deve ser salva na FLASH usando a sintaxe:

Serial.print(F("Esse texto foi guardado na memória flash do Arduino"));

Ver Também

DEFINIÇÃO array
DEFINIÇÃO string