Считывание байтов из массива PROGMEM
Отказ от ответственности: Я только начал использовать C++, и я немного новичок. Имейте это в виду при ответе.
Поэтому я недавно купил свой первый Arduino. Он изготовлен по индивидуальному заказу и к нему прикреплен дисплей 8x8. Чтобы отобразить что-то на дисплее, компания, у которой я его купил, рекомендует хранить инструкции для дисплея в двумерном массиве байтов.
Теперь у меня есть более длинная анимация, которую я хочу воспроизвести, поэтому я исследовал и нашел PROGMEM, который позволяет мне хранить гораздо больше данных. Поэтому я пишу что-то вроде:
const byte frames[2][8] PROGMEM {
{
B10000100,
B10000100,
B10000100,
B10000100,
B10000100,
B10000100,
B10000100,
B10000100,
},
{
B10010100,
B10010100,
B10010100,
B10010100,
B10010100,
B10010100,
B10010100,
B10010100,
}
};
void setup() {
arduino.begin();
}
void loop() {
arduino.printImage(frames[0]);
delay(1000);
arduino.printImage(frames[1]);
delay(1000);
}
После компиляции он выдает мне несколько ошибок:
warning: invalid conversion from 'const byte* {aka const unsigned char*}' to 'byte* {aka unsigned char*}' [-fpermissive]
arduino.printImage(frames[0]);
~~~~~~~~^
Это меня не так сильно беспокоило, и я просто проигнорировал их. Однако после загрузки на дисплее просто появились произвольные узоры вместо линий, которые я велел ему нарисовать.
После того, как я удалил ПРОГМЕМУ, она работала безупречно, однако память была недостаточно большой для хранения массива (не того, который я привел в качестве примера).
Я мог бы придумать две причины:
- В официальной документации PROGMEMговорится, что вы должны вернуть переменные обратно в память. Однако ни один из методов, которые они предоставили, не сработал для меня.
- В аналогичном вопросе на ASEи в ответе, и в комментариях говорится, что вложенные массивы не поддерживаются, но мои знания C++ недостаточно хороши, чтобы понять ответ.
@gurkensaas, 👍1
Обсуждение1 ответ
На вопрос, на который вы ссылаетесь, принятый ответ предлагает
изменить библиотеку. Это может быть наиболее эффективным вариантом. Однако менее
инвазивным решением было бы скопировать данные из флэш
-памяти в оперативную память и использовать функцию printImage()
как есть.
Очевидно, что копирование всего в оперативную память противоречит цели PROGMEM. Но
вам нужно копировать только один кадр за раз и удерживать его в памяти
чуть дольше, чем время вызова printImage()
:
void printProgmemFrame(const byte flashFrame[8]) {
byte ramFrame[8];
memcpy_P(ramFrame, flashFrame, 8);
arduino.printImage(ramFrame);
}
void loop() {
printProgmemFrame(frames[0]);
delay(1000);
printProgmemFrame(frames[1]);
delay(1000);
}
Я попробовал ваш подход, и, к сожалению, он по-прежнему отображает произвольные шаблоны. Нужно ли мне делать что-либо еще, кроме вставки вашей функции "printProgmemFrame" и замены функции "цикл"?, @gurkensaas
@gurkensaas: В принципе, вам больше ничего не нужно. Я не могу проверить это, так как у меня нет оборудования. Однако для меня это работает с макетом объекта "arduino"., @Edgar Bonet
Код отлично компилируется, он отлично загружается, но проблемы с произвольными шаблонами остаются прежними., @gurkensaas
Я думаю, что вы возвращаете "рамФрейм", который выделяется в стеке при вызове "printProgmemFrame". Попробуйте еще раз добавить "статический" в объявление переменной:
статический байтовый рамфрейм[8];
, @Eugenio Pace
@EugenioPace Это породило еще один случайный шаблон., @gurkensaas
Разве в объявлении printProgmemFrame() не должно быть чего-то дополнительного? Что-то вроде void printProgmemFrame(const byte flashFrame[8] PROGMEM)
?, @Peter Mortensen
@PeterMortensen: Увы, нет. В отличие от ключевого слова [__flash
](https://gcc.gnu.org/onlinedocs/gcc/Named-Address-Spaces.html#AVR-Named-Address-Spaces-1), которое работает как квалификатор типа (например, летучий
или const
), PROGMEM
на самом деле является всего лишь уловкой, позволяющей компилятору выделить переменную в определенном разделе программы. Это работает только тогда, когда переменная действительно объявлена: нет смысла объявлять указатель как «указатель на данные PROGMEM». Жаль, что __flash
поддерживается только в режиме C (не в C++)., @Edgar Bonet
- Как функция/метод может определить, является ли передаваемый массив const PROGMEM (flash) или нет (RAM)?
- Можно ли во время выполнения определить, объявлен ли указатель PROGMEM?
- Я думаю, что израсходовал всю свою память Arduino Uno
- Проблема с переменной char* malloc/free. Пустое содержимое в переменной получателя после использования free
- Как использовать SPI на Arduino?
- Библиотека DHT.h не импортируется
- Светодиоды: разница между общим анодом и общим катодом
- Получить доступ к EEPROM ATtiny с помощью кода Arduino?
@Juraj Это можно загрузить через IDE. Это называется Gamer.h., @gurkensaas
@Juraj В "Массивах строк" говорит мне сделать что-то вроде этого:
strcpy_P(буфер, (символ *)pgm_read_word(&(кадры[1]))); arduino.printImage(буфер);
Однако это просто говорит мне, что `буфер "не был объявлен в этой области", @gurkensaas