Вывод картинок на дисплей Nokia 1616
В продолжение поста Подключение дисплея Nokia 1616 на примере LPC1343 займемся выводом на дисплей картинок.
Вывод упакованного изображения
Упакованное изображение будет самого простого формата. Вначале идет один байт количества повторений, а за ним по 3 байта данные о цвете. Если старший бит байта повторений 1, то цвет надо повторить N+1 раз. Если же старший бит нулевой, то дальше без дублирований перечислены N+1 пикселей. В обоих случаях N – младшие 7 бит от байта повторений. такой формат легко распаковать, и он не требует много памяти. Худший случай будет, когда ни один пиксель не повторяется – размер увеличиться где-то на 1% (1 байт на каждые 128 пикселей), что вполне терпимо.
Конечно, можно было и по 2 байта на пиксель сохранять, или палитру добавить, но это вы при желании сделаете и сами. А я приведу свой пример:
void DrawImage(const uint8_t *data, uint16_t len)
{
uint8_t n;
uint8_t r, g, b;
while(len > 3) {
n = *data;
len--; data++;
if(n & 0x80) {
// Повторение одного пикселей одного цвета
n = (n & 0x7f) + 1;
r = data[0];
g = data[1];
b = data[2];
len -= 3; data += 3;
while(n--) {
NextPoint(RGB(r, g, b));
}
} else {
// Пиксели разного цвета
n = (n) + 1;
while(n-- && len >= 3) {
r = data[0];
g = data[1];
b = data[2];
len -= 3; data += 3;
NextPoint(RGB(r, g, b));
}
}
}
}
Данная функция предполагает, что область вывода была установлена зарание. Это позволяет провести настройку области вывода, а затем порциями отдавать само изображение (полезно при чтении данных с SD карточки или приеме по UART/USB. Единственное, порция данных должна содержать целое число блоков.
Вызывается так:
uint8_t img[] = { 0x84, 0xFF, 0x00, 0xFF, // 5 пикселей фиолетового цвета
0x02, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 // 3 пикселя синий, зелёный, красный
};
BeginDraw(30, 30, 4, 2);
DrawImage(img, sizeof(img));
// ... дополнительные вызовы DrawImage если надо
EndDraw();
фотографии не приведу, бо пиксели не видно на снимках с китайской мобилы :)
Скорость вывода на 9МГц получилась порядка ~24 кадров в секунду.
Как ни странно, но в итоге вывод картинок мне не пригодился (ну лень мне было логотип на дисплей создавать). Собственно этим и объясняется явная недоработка и необходимость отдельной установки границ вывода. Однака тестовые примеры были, о чем осталось память:
Вывод иконок
По сути, иконка это такое же изображение, только в моем случае оно ограничено двумя цветами и размером всегда 8х8 пикселей. Это многое нам упрощает, включая их создание. Так, приведённый набор был создан просто в паинте, а затем просто переведен из двоичной системы в шестнадцатиричную. В итоге получаем следующий код:
// Константы номеров иконок
#define ICON_CLOCK 0
#define ICON_CONNECT 1
#define ICON_DISK 2
#define ICON_FLASH 3
#define ICON_HEART 4
#define ICON_HEART3 5
#define ICON_LAN 6
#define ICON_MAIL 7
#define ICON_SOUND 8
#define ICON_POWER 9
#define ICON_PRINTER 10
#define ICON_RECIVE 11
#define ICON_SEND 12
#define ICON_STATUS 13
#define ICON_WAN 14
#define ICON_WLAN 15
#define ICON_WIRELESS 16
#define ICON_POINT 17
#define ICON_NOCONNECT 18
const uint8_t icons8x8[] = {
0x3C, 0x42, 0x91, 0x95, 0x99, 0x81, 0x42, 0x3C, // clock
0x50, 0x50, 0xF8, 0x89, 0x8A, 0x72, 0x24, 0x18, // connect
0x3C, 0x5A, 0xA5, 0xDB, 0xDB, 0xA5, 0x5A, 0x3C, // disk
0x2A, 0x2A, 0xFF, 0x81, 0xC1, 0xFF, 0x2A, 0x2A, // flash
0x66, 0xDB, 0x81, 0x81, 0xC3, 0x42, 0x24, 0x18, // heart
0x24, 0x7E, 0x9F, 0xBF, 0xFF, 0x7E, 0x3C, 0x18, // heart2
0x7E, 0x42, 0x42, 0x42, 0x7E, 0x00, 0xFF, 0xFF, // lan
0x00, 0xFF, 0xC3, 0xA5, 0x99, 0x81, 0xFF, 0x00, // mail
0x19, 0x3A, 0xE8, 0xCB, 0xC8, 0xEA, 0x39, 0x18, // music
0x18, 0x18, 0x5A, 0x99, 0x99, 0x99, 0x42, 0x3C, // power
0x3C, 0x24, 0xFF, 0xFF, 0xC3, 0xC3, 0xFF, 0xFF, // printer
0x18, 0x18, 0x18, 0x18, 0xFF, 0x7E, 0x3C, 0x18, // recive
0x18, 0x3C, 0x7E, 0xFF, 0x18, 0x18, 0x18, 0x18, // send
0x3C, 0x42, 0x99, 0xBD, 0xBD, 0x81, 0x42, 0x3C, // status
0x18, 0x34, 0x28, 0x18, 0x66, 0xD5, 0xAB, 0x66, // wan
0x18, 0x99, 0xDB, 0x7E, 0x3C, 0x18, 0x18, 0x18, // wireless
0x30, 0x64, 0xC9, 0xDA, 0xDA, 0xC9, 0x64, 0x30, // wireless2
0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, // point
0x52, 0x54, 0xF8, 0x99, 0xAA, 0x72, 0xA4, 0x18, // disconnect
};
Следующие функции на самом деле были созданы для вывода текста, но т.к. иконки у нас тоже двуцветные, то почему бы не объединить похожие сущности?
uint32_t colorFace; // цвет текста/пера
uint32_t colorGround; // цвет фона/заливки
void SetFaceColor(uint32_t color) {
colorFace = color;
}
void SetGroundColor(uint32_t color) {
colorGround = color;
}
Ну и собственно Вывод иконки получается до безобразия простым. Но в данном случае область отображения мы выставляем сами. Далее просто последовательно прозодим по битам иконки и выбираем один из двух цветов для вывода.
void DrawIcon8x8(int16_t x, int16_t y, uint8_t id)
{
if(id >= sizeof(icons8x8)/8) return;
const uint8_t *data = &icons8x8[info->icon * 8];
if(!data) return;
// Установка области вывода
if(BeginDraw(x, y, 8, 8)) {
uint8_t i, j, mask;
for(i = 0; i < 8; ++i) {
mask = *data++;
for(j = 0; j < 8; ++j) {
NextPoint( (mask & 0x80) ? colorFace : colorGround );
mask<<=1;
}
}
EndDraw();
}
}
Вызов функций элементарный
SetFaceColor(ox00FF00FF); // иконка фиолетового цвета
SetGroundColor(0x00FFFFFF); // белый фон
DrawIcon(0, 152, ICON_CONNECT);
SetFaceColor(ox0000FF00); // иконка зелёного цвета
DrawIcon(10, 152, ICON_RECIVE);
К сожалению сии 64 пикселя так же трудно рассмотреть на полученных фотографиях. Поблагодарим нашего спонсора - магазин китайских телефонов. :)
При работе на 9МГц в теории получится ~7000 иконок в секунду. Практических замеров не будет, с меня хватило замеров с дисплеем 6100. Для него теория с практикой на 4МГц различалась не более процента (всё изображение попадает на экран, в итоге отсечение отключается и упор идет в шину SPI).
< Предидущая Следующая >