Храните данные во флэш-памяти (программе) вместо SRAM. Существует описание различных типов памяти, доступных на плате Arduino.
PROGMEM - ключевое слово, является модификатором переменной, оно должно быть использовано только с типами данных , определенными в pgmspace.h. Оно говорит компилятору «поместить эту информацию во флэш-память», а не в SRAM, куда она обычно отправляется.
PROGMEM является частью библиотеки pgmspace.h. Он автоматически включается в современные версии IDE, однако, если вы используете версию IDE ниже 1.0 (2011), вам сначала нужно включить библиотеку в верхнюю часть скетча, например:
#include <avr/pgmspace.h>
const dataType variableName [] PROGMEM = {данные0, данные1, данные3...};
dataType - любой тип переменной
variableName - имя для вашего массива данных
Обратите внимание, что, поскольку PROGMEM является модификатором переменной, не существует жесткого и правила относительно того, в какое место его следует поместить, поэтому компилятор Arduino принимает все приведенные ниже определения, которые также являются синонимами. Однако эксперименты показали, что в различных версиях Arduino (имеющих отношение к версии GCC) PROGMEM может работать в одном месте, а не в другом. Приведенный ниже пример «таблицы строк» был протестирован для работы с Arduino 13. Более ранние версии IDE могут работать лучше, если после имени переменной включен PROGMEM.
const dataType variableName[] PROGMEM = {}; // Используйте этот пример. const PROGMEM dataType variableName[] = {}; // Либо этот. const dataType PROGMEM variableName[] = {}; // Не используйте этот пример.
Хотя PROGMEM можно использовать для одной переменной, на самом деле это стоит того, если у вас есть больший блок данных, который необходимо сохранить, что обычно проще всего в массиве (или другой структуре данных C ++ за пределами нашего нынешнего обсуждения).
Использование PROGMEM - двухэтапная процедура. После получения данных во флэш-память требуются специальные методы (функции), также определенные в библиотеке pgmspace.h , для считывания данных из памяти программ обратно в SRAM, чтобы мы могли сделать что-то полезное с этим.
Следующие фрагменты кода иллюстрируют, как читать и записывать символы без знака (байты) и целые числа (2 байта) в PROGMEM.
const PROGMEM uint16_t charSet[] = { 65000, 32796, 16843, 10, 11234}; const char signMessage[] PROGMEM = {"I AM PREDATOR, UNSEEN COMBATANT. CREATED BY THE UNITED STATES DEPART"}; unsigned int displayInt; int k; // Счетчик. char myChar; void setup() { Serial.begin(9600); while (!Serial); // Ждем соединения с последовательным портом. Нужвен свободный USB. // Поместите свой код для настроек здесь, команды выполнятся единожды. for (k = 0; k < 5; k++) { displayInt = pgm_read_word_near(charSet + k); Serial.println(displayInt); } Serial.println(); for (k = 0; k < strlen_P(signMessage); k++) { myChar = pgm_read_byte_near(signMessage + k); Serial.print(myChar); } Serial.println(); } void loop() { // Поместите ваш основной код здесь, команды будут повторяться в цикле. }
Часто при работе с большими объемами текста, такими как проект с ЖК-дисплеем, удобно настраивать массив строк. Поскольку сами строки являются массивами, это фактически является примером двумерного массива.
Как правило, это большие структуры, поэтому часто желательно помещать их в программную память. Код ниже иллюстрирует идею.
/* PROGMEM демо скетч. Как хранить таблицу строк в памяти программы (flash), и извлекать их. Информация законспектирована отсюда: http://www.nongnu.org/avr-libc/user-manual/pgmspace.html Настройка таблицы (массива) строк в памяти программ немного сложна, но вот хороший шаблон. Настройка строк - двухэтапный процесс. Сначала определите строки. */ #include <avr/pgmspace.h> const char string_0[] PROGMEM = "String 0"; // "String 0" и другие - строки, с которыми ведется работа, их можно изменить по необходимости. 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"; // Настраиваем таблицу для обращения к строкам. const char *const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5}; char buffer[30]; // Убедитесь, что размерности массива хватает для самой длинной строки. void setup() { Serial.begin(9600); while (!Serial); // Ждем соединения с последовательным портом. Нужвен свободный USB. Serial.println("OK"); } void loop() { /* Использование таблицы строк в памяти программы требует использования специальных функций для извлечения данных. Функция strcpy_P копирует строку из программного пространства в строку в ОЗУ ("buffer"). Убедитесь, что ваша принимающая строка в ОЗУ достаточно велика, чтобы вместить все, что вы извлекаете из программного пространства. */ for (int i = 0; i < 6; i++) { strcpy_P(buffer, (char *)pgm_read_word(&(string_table[i]))); // Необходимые приведения и разыменования, просто скопируйте. Serial.println(buffer); delay(500); } }
Обратите внимание, что для работы с PROGMEM переменные должны быть либо глобально определены, либо определены с помощью ключевого слова static.
Следующий код НЕ будет работать внутри функции:
const char long_str[] PROGMEM = "Hi, I would like to tell you a bit about myself.\n";
Следующий код будет работать, даже если он определен локально в функции:
const static char long_str[] PROGMEM = "Hi, I would like to tell you a bit about myself.\n"
Когда используется такая конструкция:
Serial.print("Write something on the Serial Monitor");
строка для печати обычно сохраняется в ОЗУ. Если ваш скетч напечатает много материала в последовательный монитор, вы можете легко заполнить оперативную память. Если у вас есть свободное место во флэш-памяти, вы можете легко указать, что строка должна быть сохранена во флэш-памяти, используя синтаксис:
Serial.print(F("Write something on the Serial Monitor that is stored in FLASH"));