Использование PROGMEM для экономии оперативной памяти

Мне удалось поместить и получить массив символов во флэш-память Arduino с помощью PROGMEM массивы символов.

Я создаю свое приложение, используя файлы заголовков с определением/реализацией класса, и хотел бы хранить строки в одном файле заголовка.

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

Вот мой тестовый код:

  lcd.clear();
  lcd.print(*strFlashDebug[0]);  // в CDebug
  lcd.setCursor(0,1);
  lcd.print(*strFlashTrack[0]);  // в CTrack

Если я помещу оба определения в один и тот же заголовочный файл, он будет работать только с одним включенным lcd.print, а не закомментированным.

Похоже, что можно определить и скомпилировать несколько массивов PROGMEM, но фактически можно использовать только один. Какое объяснение?

, 👍1

Обсуждение

Пожалуйста, опубликуйте также определения своих массивов или, еще лучше, полный компилируемый пример с достаточным количеством кода, чтобы проиллюстрировать проблему., @user2973


2 ответа


0

Определение переменной PROGMEM (т. е. объявление) выделяет память во FLASH. Вам необходимо использовать предложение extern в заголовочном файле и физическое объявление в коде C, связанное с вашим кодом. Это также выгодно для потенциальных свойств статического класса.

Также проверьте, принимает ли lcd.print() массив PROGMEM, т. е. определена и вызвана перегруженная процедура.

Обратите внимание, что я рекомендую использовать гораздо более эффективное форматирование строк с помощью файловых потоков (FILE) и fprintf_P().

,

2

Для PROGMEM важно знать, что чип AVR, который вы используете, не имеет ни одного плоское адресное пространство. Т.е. он не использует архитектуру фон Неймана; вместо этого он использует определенную версию так называемой Гарвардской архитектуры: она имеет отдельные адресные пространства для оперативной памяти и программной памяти. и ЭСППЗУ. Все они начинаются с 0. Это означает, что, хотя разыменование нулевого указателя технически все еще является неопределенным поведением в C++, оно может быть (и часто является) совершенно допустимым в коде Arduino.

Краткая версия: если у вас есть указатель PROGMEM, любая функция, которой вы его передаете, должна работать с указателями PROGMEM. lcd.print нет, и, насколько я могу судить, функция не может каким-либо образом обнаружить, что это не указатель ОЗУ. Вам придется вызвать другую функцию, если она изначально есть.

См. PROGMEM (справочник по Arduino) для примеров использования данных PROGMEM.< /п>

,

Чтобы дополнить это прекрасное описание, вы можете в качестве обходного пути временно скопировать в ОЗУ данные PROGMEM, которые вам нужно передать в lcd.print(), и передать ему эту копию. Функция-обертка, скажем, lcd_print_PMEM(), может инкапсулировать детали, а используемая оперативная память будет выделяться буквально только на время этого вызова., @JRobert