Считывание байтов из массива 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]);
                      ~~~~~~~~^

Это меня не так сильно беспокоило, и я просто проигнорировал их. Однако после загрузки на дисплее просто появились произвольные узоры вместо линий, которые я велел ему нарисовать.

После того, как я удалил ПРОГМЕМУ, она работала безупречно, однако память была недостаточно большой для хранения массива (не того, который я привел в качестве примера).

Я мог бы придумать две причины:

  1. В официальной документации PROGMEMговорится, что вы должны вернуть переменные обратно в память. Однако ни один из методов, которые они предоставили, не сработал для меня.
  2. В аналогичном вопросе на ASEи в ответе, и в комментариях говорится, что вложенные массивы не поддерживаются, но мои знания C++ недостаточно хороши, чтобы понять ответ.

, 👍1

Обсуждение

@Juraj Это можно загрузить через IDE. Это называется Gamer.h., @gurkensaas

@Juraj В "Массивах строк" говорит мне сделать что-то вроде этого: strcpy_P(буфер, (символ *)pgm_read_word(&(кадры[1]))); arduino.printImage(буфер); Однако это просто говорит мне, что `буфер "не был объявлен в этой области", @gurkensaas


1 ответ


2

На вопрос, на который вы ссылаетесь, принятый ответ предлагает изменить библиотеку. Это может быть наиболее эффективным вариантом. Однако менее инвазивным решением было бы скопировать данные из флэш -памяти в оперативную память и использовать функцию 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