PROGMEM

Материал из MK90.ORG wiki
Перейти к: навигация, поиск

Справка Язык | Библиотеки | Сравнение | Изменения

PROGMEM

Описание

Указывает, что содержимое переменной должны быть размещено в памяти программ (flash), а не в оперативной памяти данных SRAM.

Ключевое слово PROGMEM - модификатор объявления переменной и может использоваться только для типов из pgmspace.h. Оно указывает компилятору, что переменная будет расположена в постоянной памяти программ (flash), а не как обычно - в оперативной памяти SRAM.

PROGMEM - часть библиотеки pgmspace.h. Поэтому, сначала надо подключить ее к скетчу, добавив в самом начале директиву include:


#include <avr/pgmspace.h>

Синтаксис


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

где:

  • dataType - тип переменной
  • variableName - имя переменной с массивом данных

Помните, что поскольку PROGMEM является лишь модификатором, нет жесткого правила, где именно его указывать в объявлении переменной, и поэтому компилятор воспримет все нижеперечисленные варианты как синонимы. Однако экспериментальным путем выявлено, что в разных версиях ArduinoIDE (в зависимости от версии GCC), PROGMEM может работать в одном месте и не работать в другом. Пример "таблица строк" был протестирован с Arduino 13. Более ранние версии IDE могут потребовать указания PROGMEM после имени переменной.


const dataType variableName[] PROGMEM = {};   
const PROGMEM  dataType  variableName[] = {}; 
const dataType PROGMEM variableName[] = {};   

Действие PROGMEM распространяется только на одну переменную, поэтому часто к ней прибегают для объявления больших блоков данных, которые наиболее удобно представлять в виде массива.

Использование PROGMEM предполагает также, что для обращения к таким переменным также требуются специальные функции (также определены в pgmspace.h).

Примеры

Этот код иллюстрирует как читать и выводить символы (байты) и целые (2-х байтные) из PROGMEM.


#include <avr/pgmspace.h>


// сохранить несколько беззнаковых целых
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-байтных целых
  for (k = 0; k < 5; k++)
  {
    displayInt = pgm_read_word_near(charSet + k);
    Serial.println(displayInt);
  }
  Serial.println();

  // чтение символов
  for (k = 0; k < strlen(signMessage); k++)
  {
    myChar =  pgm_read_byte_near(signMessage + k);
    Serial.print(myChar);
  }

  Serial.println();
}

void loop() {

}

Массивы строк

При работе с большими объемами текста, например в проектах с LCD-дисплеями, часто бывает удобно применять массивы строк. Поскольку строка сама по себе является массивом, в приведенном ниже примере используется двумерный массив символов.

Поскольку размер памяти SRAM весьма ограничен, желательно размещать любые большие объемы констант в памяти программ, что также иллюстрирует этот код.



/*
 Пример PROGMEM string 
 Показывает, как разместить таблицу строк в памяти программ (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);
  Serial.println("OK");
}

void loop()
{
  /* Использование таблицы строк в памяти программ требует специальных функций для их получения.
     Функция strcpy_P копирует строку из памяти программ в память данных (буфер в RAM).
     Убедитесь, что принимаемая в буфер строка никогда не превысит размер самого буфера! */

  for (int i = 0; i < 6; i++)
  {
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); // Необходимые преобразования типов для корректного разыменовывания. Просто скопируйте.
    Serial.println(buffer);
    delay( 500 );
  }
}

Смотри также

Руководство по Wiring


Исправления, пожелания и новые статьи должны быть опубликованы через Форум.

Оригинальные тексты руководств и переводы распространяются Arduino и MK90 на условиях лицензии Creative Commons Attribution-ShareAlike 3.0 License. Примеры исходных кодов и ссылки являются общественным достоянием.