Progmem

PROGMEM — это ключевое слово, используемое при объявлении переменной, которая сохраняет данные во флэш-памяти, а не копирует их в SRAM. Это часть библиотеки pgmspace.h. Используйте этот тег для обсуждения использования этого атрибута.


Типы памяти на Arduino

Оперативная память очень ценна для микроконтроллера, а PROGMEM (память программ) не так важна. На Arduino Uno (с использованием Atmega328P) у вас есть:

  • 1 КБ EEPROM
  • 2 КБ ОЗУ
  • 32 КБ PROGMEM (флэш-память - место, где хранится ваша программа)

Очевидно, что памяти программ гораздо больше, чем ОЗУ.


Константы обычно копируются из PROGMEM в оперативную память

Константы в вашей программе изначально хранятся в PROGMEM (где еще они могут храниться при отключении питания?), но копируются в оперативную память кодом инициализации, сгенерированным компилятором, в самом начале выполнения вашего скетча (программа).

Например:

Serial.println ("Hello, world!");

Постоянная строка "Hello, world!" изначально находится в PROGMEM, но копируется в оперативную память при запуске. Это означает, что для него должно быть предусмотрено место в ОЗУ а также во флэш-памяти.

Это использует ценную оперативную память для того, что на самом деле является просто копией чего-то, что никогда не изменится.

Другой пример:

const int NUMBER_OF_ELEMENTS = 10;
const float table[NUMBER_OF_ELEMENTS] = 
      { 1.0, 34.234, 324.234, 23.1, 52.0, 3.6, 5.6, 42.42, 1908, 23.456 } ;

Хотя эта таблица значений с плавающей запятой не изменится, она также будет скопирована в оперативную память. Если у вас большая таблица, у вас скоро закончится оперативная память.


Атрибут PROGMEM

Вы можете предотвратить это копирование в оперативную память, добавив PROGMEM в объявление данных, например:

const int NUMBER_OF_ELEMENTS = 10;
const float table[NUMBER_OF_ELEMENTS] PROGMEM = 
      { 1.0, 34.234, 324.234, 23.1, 52.0, 3.6, 5.6, 42.42, 1908, 23.456 } ;

Доступ к константам PROGMEM

К сожалению, компилятор (по крайней мере, на AVR Arduino) ожидает, что все данные будут в ОЗУ, и не позволяет получить доступ к данным непосредственно из PROGMEM.

Можно сделать небольшую библиотеку PROGMEM_readAnything.h:

#include <Arduino.h>  // для определений типов

template <typename T> void PROGMEM_readAnything (const T * sce, T& dest)
  {
  memcpy_P (&dest, sce, sizeof (T));
  }

template <typename T> T PROGMEM_getAnything (const T * sce)
  {
  static T temp;
  memcpy_P (&temp, sce, sizeof (T));
  return temp;
  }

Скопируйте вышеприведенное в текстовый файл, сохраните его как PROGMEM_readAnything.h и поместите его в папку с именем PROGMEM_readAnything и поместите эту папку в ваш Arduino libraries, которая находится внутри папки вашего альбома. Вот так:

(sketchbook location)/libraries/PROGMEM_readAnything/PROGMEM_readAnything.h

Теперь вы можете получить доступ к константе PROGMEM следующим образом:

float thisOne;
PROGMEM_readAnything (&table[3], thisOne);

Или:

float thisOne = PROGMEM_getAnything (&table[3]);

Макрос F()

Для простых строковых констант можно использовать макрос F(), чтобы легко сохранять строки в PROGMEM, например:

Serial.println (F("Hello, world!"));

Вопросы, связанные с [progmem]:

  • 1