Вопрос чисто практически-экономический возник. Есть к примеру картинка марок.
Для вывода каждой марки я делаю вырезку марки и её массив в конверторе к которому обращаюсь в функции библиотеки , например:
tft.bmp16(0, 0, marka_5, 76, 56);
Но так долго. Проще взять массив всех марок и обращаться к массиву не с нулевого элемента, а с 4/5 от номера последнего. Как это сделать простым способом?
поместите каждую марку в свой массив,
2)или придумайте функцию для вывода картинки начиная с… заканчивая…
3)поместив их в progmem, вроде вообще нет проблем, вывести на дисплей XY координаты, такую то картинку…
const uint8_t* marks[] = {marka_0, marka_1, marka_2, ..., marka_N};
void draw_marka(int index, int x, int y) {
tft.bmp16(x, y, marks[index], 76, 56);
}
Я так уже делал. Тут функция не моя, а библиотечная. Я спрашиваю синтаксис языка, как конкретно это пишется, а не типа: tft.bmp16(x, y, marks[index], 76, 56);
Так меня компиляция пошлёт подальше и всё, или скомпилируется, а работать не будет.
Но с доп.аргументами уже не хочется писать, да и почему то адресация под вывод пикселей не работает ни на этой библиотеке, не на адафрутовской, картинка просто вываливается в начало экрана, как будто нет setAddrWindow. Т.е. одинаково с ней и без неё.
Не совсем понятно, что именно “это”.
Для начала нужно решить, как вообще организовано хранение марок.
Можно, например, хранить каждую марку в своем массиве. Тогда доступ к ней будет наиболее естественным (через массив указателей), но зато придется для рисунка из пяти марок пять раз обращаться к процедуре вывода одной марки.
Можно хранить блоки по 5 марок, но тогда для вывода единственной марки (опять же вопрос - такое может понадобиться?) нужно будет написать процедуру (если ее еще нет в библиотеке) вывода на экран фрагмента картинки.
Все зависит от того, что именно Вам нужно, но Вы забыли написать, прикрывшись словом “это” - мол пусть кто как хочет, так и понимает.
В любом случае, что бы Вы ни делали, начинать, как правило, следует с четкой формулировке по-русски - что же именно Вы хотите сделать.
если уже объявлено, и поскольку я как раз сижу с тфт дисплеями, вот может будет полезно, у кого то в сети подрезал, и чуть переписал, из за того что не запускалось
// Вывод кадра
tft.pushImage(
30, 15, // Позиция X,Y
animation_width, // Ширина
animation_height, // Высота
walk[i] // Данные кадра
);
код вывода картинки из progmem управляется через i (два файла должны лежать вместе)
там же и программа для создания, у кого то все подрезал в сети, но не могу найти… и чуть пришлось переделать код, иначе не работал, запускал на есп 8266
P.S. Попробовал проверить на примерах. Получаеся “const” здесь относится лишь к содержимому ячейки(ячеек)памяти, на которую указывает указатель. Содержимое менять нельзя (read only), а сам указатель - можно. Не знал этого.
Для оптимизации работы с массивом всех марок и доступа к конкретной марке по смещению, вы можете использовать следующие подходы:
1. Объединение всех марок в один массив с фиксированным размером каждой марки
// Предположим, у вас все марки имеют одинаковый размер 76x56 (4256 пикселей = 8512 байт)
const uint8_t all_marks[] PROGMEM = {
// Марка 0
0x00, 0x00, ... // 8512 байт
// Марка 1
0x00, 0x00, ... // следующие 8512 байт
// и так далее...
};
void drawMark(uint8_t markIndex) {
// Размер одной марки в байтах
const uint32_t markSize = 76 * 56 * 2;
// Указатель на начало нужной марки
const uint8_t* markPtr = all_marks + (markIndex * markSize);
tft.bmp16(0, 0, markPtr, 76, 56);
}
2. Использование структуры для организации данных
struct Mark {
uint8_t width;
uint8_t height;
const uint8_t* data;
};
const Mark marks[] PROGMEM = {
{76, 56, marka_0},
{76, 56, marka_1},
// и так далее...
};
void drawMark(uint8_t markIndex) {
Mark mark;
memcpy_P(&mark, &marks[markIndex], sizeof(Mark));
tft.bmp16(0, 0, mark.data, mark.width, mark.height);
}
3. Оптимизированный вариант с предварительным вычислением указателей
// Объявляем все массивы как обычно
const uint8_t marka_0[] PROGMEM = {...};
const uint8_t marka_1[] PROGMEM = {...};
// ...
// Массив указателей на все марки
const uint8_t* const all_marks[] PROGMEM = {
marka_0,
marka_1,
// ...
};
void drawMark(uint8_t markIndex) {
const uint8_t* markPtr;
memcpy_P(&markPtr, &all_marks[markIndex], sizeof(markPtr));
tft.bmp16(0, 0, markPtr, 76, 56);
}
4. Если марки имеют разный размер, но хранятся последовательно
// Все марки объединены в один массив с метаданными
const uint8_t all_marks[] PROGMEM = {
// Марка 0
76, 56, // ширина, высота
0x00, 0x00, ... // данные
// Марка 1
80, 60, // ширина, высота
0x00, 0x00, ... // данные
// и так далее...
};
void drawMark(uint8_t markIndex) {
const uint8_t* ptr = all_marks;
uint16_t offset = 0;
// Пропускаем предыдущие марки
for(uint8_t i = 0; i < markIndex; i++) {
uint8_t w, h;
memcpy_P(&w, ptr + offset, 1);
memcpy_P(&h, ptr + offset + 1, 1);
offset += 2 + w * h * 2;
}
// Читаем размер текущей марки
uint8_t w, h;
memcpy_P(&w, ptr + offset, 1);
memcpy_P(&h, ptr + offset + 1, 1);
// Указатель на данные марки
const uint8_t* markData = ptr + offset + 2;
tft.bmp16(0, 0, markData, w, h);
}
Рекомендация:
Если все марки одинакового размера, используйте первый или третий вариант - они самые простые и быстрые.
Если марки разного размера, используйте четвертый вариант.
Для AVR-микроконтроллеров не забывайте использовать PROGMEM и функции чтения из программной памяти.
Пример вызова:
// Нарисовать марку с индексом 5
drawMark(5);
Это позволит вам легко обращаться к любой марке по индексу без необходимости хранить отдельные вызовы для каждой марки.