Функция, возвращающая массив байтов
- Войдите на сайт для отправки комментариев
Мне нужно прочитать рисунок из подключенной spi flash памяти и вывести на lcd экран ардуинки нано.
По отдельности работает - рисунок заданный так выводится:
const unsigned char testimg [504] = { 0xC0, 0xC0, 0xE0 .... } lcd.draw(testimg, sizeof(testimg) / sizeof(testimg[0]), true);
Т.к. памяти мало и подключен чип на 4Мб, а размер картинки всегда известен (504 байта под размер дисплея), я просто записываю картинку как массив байтов под опеределённым номером и так же считываю. Функция для чтения 504 байт под определённым номером работает:
void read_from_file (int filenumber) { int byteNum = ((504*filenumber)-504); // Get the number of 1st byte unsigned char testimg [504]; Serial.println("Starting to read image "); for(int i = 0; i < 504; i++){ // Read 504 bytes Serial.print(flash.readByte(byteNum)); Serial.print('.'); byteNum++; } Serial.println("Readen!"); }
Но если я пытаюсь прочитать картинку функцией, подгрузить заранее, а затем вывести на экран, то получается треш:
unsigned char rImage=read_from_file(1); lcd.draw(rImage, 504, true); unsigned char read_from_file (int filenumber) { int byteNum = ((504*filenumber)-504); // Get the number of 1st byte unsigned char testimg [504]; Serial.println("Starting to read image "); for(int i = 0; i < 504; i++){ // Write 504 bytes testimg[i]=flash.readByte(byteNum); byteNum++; } Serial.println("Readen!"); return testimg; }
Как понимаю, это связано с тем, что для экономии памяти массив не живёт после отработки функции. Я буду считывать разные файлы в разное время. Мне нужно, чтобы всегда хранился подгруженный в массив в данный момент и можно было считать новый. Как правильно сделать?
Как правильно сделать?
Сделать массив глобальным - то есть вынести строчку 7 наружу из функции. Но имейте в виду, что при таком решении массив всегда будет занимать в памяти 504 байта.
Вынес. Так не работает. Я перепроверил выводом байтов на экран - файл записан корректно. Проверил выводом массива картинки - корректно выглядит этот массив.
При попытке отрисовать, передав из этой функции - выводится треш.
Вынес. Так не работает.
не может быть :) Покажите код
Обратите внимание на закомментированные строчки - так байты выводятся в консоль правильные. Обратите внимание, что в самом первом посте у меня задано массивом и я могу обратиться к любому элементу, в этом варианте я не могу после выполнения функции к rImage[10] к примеру
Попытайтесь в draw() передавать глобальный массив, а не какой-то случайный байт.
О божеж мой... Все смешалось.
Если у вас массив testimg [504] уже глобальный, зачем вы его возвращаете из функции и приравниваете к другому массиву? Работайте с ним напрямую:
Так всё равно выводится грязь, но теперь другая. Вообще, каждый раз разная.
Так всё равно выводится грязь, но теперь другая. Вообще, каждый раз разная.
как выводите? покажите
Выяснил причину проблемы истинную (вывел на экран начальный массив, потом прочитанный циклом, который функция вернула - всё совпало). Вспомнил, где-то в описании библиотеки SPIMemory что-то было про использование нескольких устройств одновременно. Счас поужинаю и попробую разобраться, думаю тут собака зарыта, раз по отдельности работает.
Создал отдельный топик в Hardware, проблема кроется в использовании двух SPI устройств и так просто не решается, этот тред исчерпан и закрыт.
...этот тред исчерпан и закрыт.
Ну да, на вопрос темы ответс так и нет, а тред исчерпан.
Нет, для Ардуино в большинстве случаев наиболее разумен вариант, о котором здесь написано - глобальный массив. Но этот вариант совершенно не отвечает на вопрос темы.
А по теме, естественно, указатель. Только этот указатель должен указывать не на стек. Либо указатель передается из вызывающей функции, а вызываемая его только заполняет (оптимально, когда заранее известен размер). Либо вызываемая функция сама запрашивает динамическую память и возвращает указатель на нее (это оптимально, когда размер массива заранее не известен).
Нет, для Ардуино в большинстве случаев наиболее разумен вариант, о котором здесь написано - глобальный массив. Но этот вариант совершенно не отвечает на вопрос темы.
В моём случае, проще и правда оказалось отдать 504 байта под глобавльный массив, т.к. картинок большое количество, они подгружаются в него динамически, а размер буфера экрана заранее известен. Сделал дополнительную функцию, которая проигрывает анимацию (нарезанную из гифки по кадрам), приняв начальный адрес и количество кадров.
В случае использования массива большого размера и без необходимости использовать дополнительную память, можно было бы сохранить данные в статической, указав PROGMEM в переменной. Видел сравнение скорости работы:
Несмотря на более долгое время отклика, оно незначительно, т.к. ~0.1мс совершенно неощутимы. Но в моём случае <20K встроенной статической памяти мало, а 4Mb дополнительной - покрывает запросы на хранение картинок с лихвой.
Вообще, этот проект не несёт для меня какой-то практической пользы огромной - будет одна штуковина в подарок одному человеку, а делаю скорее чтобы разобраться в тонкостях работы ардуино, т.к. линукс и микрокомпьютеры к примеру я использую давно, а ардуино начал использовать не слишком много времени назад. Но цены на девайсы настолько разные, что палить из пушки по мухам - просто глупая расточительность. Пока переделал свой старый джойстик от денди на attiny85 за несколько часов на юсб (обошлось <100р) и сделал небольшой девайс с двустрочным дисплеем на нано.
Можно пример кода с указателем на стек?
Пример кода, как делать не нужно?
Объявите локальную переменную и она будет размещена в стеке.
Кстати, я был излишне категоричен: если локальная переменная объявлена в вызывающей функции, то она, естественно, будет на стеке, но вариант окажется вполне работоспособным.