PROGMEM
PROGMEM
Зберігайте дані у флеш-пам’яті (програмній) замість SRAM. Опис типів пам’яті, що використовується платами Arduino, на сторінці типи пам’яті.
Ключове слово PROGMEM — це модифікатор змінної, який має використовуватися лише з типами даних, визначеними командою pgmspace.h. Вона каже компілятору “помістити цю інформацію у флеш-пам’ять” замість SRAM, куди вона була б спрямована за звичайних умов.
PROGMEM є частиною бібліотеки pgmspace.h, яка доступна лише в архітектурі AVR. Тому спершу слід включити бібліотеки на початку скетчу:
#include <avr/pgmspace.h>
Синтаксис
const dataType variableName[] PROGMEM = {data0, data1, data3...};
dataType — будь-який тип змінної
variableName — ім’я масиву даних
Зверніть увагу, що оскільки PROGMEM є модифікатором змінної, нема жорстких і швидких правил щодо того, куди він повинен спрямовуватися, тому компілятор Arduino приймає всі визначення нижче, які також є синонімами. Але, як показали експерименти, у різних версіях Arduino 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.
#include <avr/pgmspace.h>
// збережіть деякі unsigned ints
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);
// помість код налаштування сюди, щоб запустити одного разу:
// зчитайте 2-байтовий int
for (k = 0; k < 5; k++)
{
displayInt = pgm_read_word_near(charSet + k);
Serial.println(displayInt);
}
Serial.println();
// зчитайте символ
int len = strlen_P(signMessage);
for (k = 0; k < len; k++)
{
myChar = pgm_read_byte_near(signMessage + k);
Serial.print(myChar);
}
Serial.println();
}
void loop() {
// помістіть головний код тут, щоб запустити повторно:
}
Масиви рядків
При роботі з великими обсягами тексту, такими як проект з рідкокристалічним дисплеєм, часто зручно встановлювати масив рядків. Насправді, це приклад двовимірного масиву, оскільки рядки самі є масивами.
Як правило, вони є великими структурами, тому поміщати їх в програмну пам’ять часто небажано. Наведений нижче код ілюструє цю ідею.
#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);
Serial.println("OK");
}
void loop()
{
for (int i = 0; i < 6; i++)
{
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); // необхідне, просто скопіюйте
Serial.println(buffer);
delay( 500 );
}
}
Примітка
Зверніть увагу, що змінні повинні бути визначені як глобальні або з допомогою ключового слова static для того, щоб працювати з PROGMEM.
Наступний код не працюватиме всередині функції:
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"
Макрос F()
Коли використовується інструкція на кшталт
Serial.print("Напишіть щось у серійний монітор");
надрукований рядок зберігається в RAM. Якщо Ваш скетч друкує багато матеріалів у серійний монітор, Ви можете легко заповнити оперативну пам'ять. Якщо у Вас є вільний простір флеш-пам'яті, можна легко вказати, що рядок повинен бути збережений у флеш, використовуючи синтаксис:
Serial.print(F("Напишіть щось у серійний монітор, що буде збережене у флеш-пам’яті"))
Повернутись до головної
Коментарі 0