Микроконтроллеры AVR имеют Гарвардскую архитектуру, в которой в отличии от архитектуры фон Неймана, перепрограммируемое пространство (Flash) используется для программ, а RAM для данных, и каждая из них имеет отдельное адресное пространство. Использование утилиты PROGMEM позволяет хранить постоянные данные в программном пространстве, и использовать их в приложении Arduino.
Ключевое слово PROGMEM является модификатором переменной , оно должно быть использовано только с типами данных, определенными в pgmspace.h. Это ключевое слово говорит компилятору "положить эту информацию в флэш-память", а не в SRAM, где ее обычно хранит программа.
PROGMEM является частью библиотеки pgmspace.h. Таким образом, необходимо в первую очередь подключить библиотеку в верхней части скетча:
#include <avr/pgmspace.h>
Синтаксис
dataType variableName[] PROGMEM = {dataInt0, dataInt1, dataInt3...};
dataType - любой тип переменной памяти программы, определенные в pgmspace.h (см ниже).
variableName - имя вашего массива данных.
Обратите внимание, что для модификатора переменной PROGMEM нет жестких правил о том, где он должен находиться, так компилятор Arduino принимает все представленные ниже определения, которые также являются синонимами. Однако эксперименты показали, что в различных версиях Arduino (использующих GCC), PROGMEM может работать в одном месте, а в другом - нет. Ниже представленный пример был протестирован для работы с Arduino 13. Более ранние версии IDE могут работать лучше, если PROGMEM находится после имени переменной.
dataType variableName[] PROGMEM = {}; // используйте эту форму
dataType PROGMEM variableName[] = {}; // НЕ используйте эту форму
PROGMEM dataType variableName[] = {}; // используйте эту форму
В общем, переменные PROGMEM могут быть использованы и для одной переменной, но их использование оправдано только, если у вас есть большие блоки данных, которые необходимо хранить, которые, как правило, представляют собой массивы (структуры данных Си вне нашего настоящего обсуждения) .
Использование PROGMEM является двухэтапной процедурой. После того, как данные сохранены в флэш-памяти, они требуют специальных методов (функций), также определеных в библиотеке pgmspace.h, чтобы считать данные из программной памяти обратно в SRAM, где мы можем сделать что-то полезное с ними.
Как упоминалось выше, важно использовать типы данных, описанные в pgmspace.h . Если использовать обычные типы данных для вызовов данных из программного пространства, то могут генирироваться непонятные ошибки. Ниже представлен список поддерживаемых типов переменных. Числа с плавающей точкой в памяти программ не поддерживается.
prog_char |
signed char |
1 байт |
от -127 до 128 |
prog_uchar |
unsigned char |
1 байт |
от 0 до 255 |
prog_int16_t |
signed int |
2 байта |
от -32 767 до 32 768 |
prog_uint16_t |
unsigned int |
2 байта |
от 0 до 65 535 |
prog_int32_t |
signed long |
4 байта |
от -2 147 483 648 до 2,147,483,647 |
prog_uint32_t |
unsigned long |
4 байта |
от 0 до 4 294 967 295 |
Пример
Следующий фрагмент кода иллюстрируют, как читать и писать данные типа unsigned char (размер 1 байт) и int (размер 2 байта) в PROGMEM.
#include <avr/pgmspace.h>
//создаем некоторые беззнаковые целые
PROGMEM prog_uint16_t charSet[] = { 65000, 32796, 16843, 10, 11234};
//создаем некоторые символы
prog_uchar signMessage[] PROGMEM = {"I AM PREDATOR, UNSEEN COMBATANT. CREATED BY THE UNITED STATES DEPART"};
unsigned int displayInt;
int k; // переменная-счетчик
char myChar;
// считываем по 2 байта в переменную int
displayInt = pgm_read_word_near(charSet + k)
// считываем символ
myChar = pgm_read_byte_near(signMessage + k);
Массивы строк
Часто бывает удобно при работе с большими объемами текста, такие как проекты с LCD-дисплеем, применять массивы строк. Поскольку сами строки являются массивами, то на самом деле это пример использования двумерного массива.
Это обычно крупные структуры, поэтому часто желательно расположить их в памяти программ. Приведенный ниже код иллюстрирует идею.
/*
PROGMEM string demo
Как хранить таблицу строк в памяти программ (Flash),
и извлекать их.
Информация взята из:
http://www.nongnu.org/avr-libc/user-manual/pgmspace.html
Настройка таблицы (массива) строк в программной памяти программ немного сложна,
но здесь представлен хороший шаблон для подражания.
Настройка строк - это двухэтапный процесс. Сначала определите строки.
*/
#include <avr/pgmspace.h>
// "String 0" и т.д. - это строки для хранения данных.
prog_char string_0[] PROGMEM = "String 0";
prog_char string_1[] PROGMEM = "String 1";
prog_char string_2[] PROGMEM = "String 2";
prog_char string_3[] PROGMEM = "String 3";
prog_char string_4[] PROGMEM = "String 4";
prog_char string_5[] PROGMEM = "String 5";
// Затем создаем таблицу для ссылки на строки.
PROGMEM const char *string_table[] =
{
string_0,
string_1,
string_2,
string_3,
string_4,
string_5 };
char buffer[30]; // Убедитесь, что буфер достаточен для размещения самой большой строки
void setup()
{
Serial.begin(9600);
}
void loop()
{
/* Using the string table in program memory requires the use of special functions to retrieve the data.
The strcpy_P function copies a string from program space to a string in RAM ("buffer").
Make sure your receiving string in RAM is large enough to hold whatever
you are retrieving from program space. */
/* Использование таблицы строк в программной памяти требует использования специальных функций для
извлечения данных.
Функция 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 );
}
}
Смотрите также:
массив
string
Справочник
Материалы взяты с официального сайта проекта Arduino и представлены по лицензии Creative Commons Attribution-ShareAlike 3.0 License.
Источник: http://arduino.cc/en/Reference/PROGMEM |