uGFX —
графическая библиотека для микроконтроллеров.
Часть 3
Андрей Курниц
kurnits@stim.by
Мы продолжаем знакомить читателей с графической библиотекой uGFX. В статье рассказано, как с помощью uGFX рисовать графические примитивы и выводить на дисплей изображения из графических файлов формата *.bmp и *.gif. Описаны другие возможности модуля GDISP. Статья сопровождается примерами программ и снимками экрана с результатами работы программ на микроконтроллере ARM Cortex-M3 [2].
Модуль GDISP
Модуль GDISP предоставляет программисту простой интерфейс для вывода информации на графический дисплей и имеет богатый набор высокоуровневых API-функций, которые позволяют выводить:
1. Графические примитивы (например, точка, линия, окружность, прямоугольник и т. д.).
2. Текстовую информацию (с использованием различных шрифтов).
3. Изображения в различных форматах (BMP, GIF, NATIVE).
При этом программисту не нужно знать особенности того или иного графического контроллера, задачу взаимодействия с контроллером берет на себя модуль GDISP (рис. 1). Вот почему один и тот же код может использоваться на различных аппаратных платформах.
В то время как для работы большинства графических библиотек необходимо наличие кадрового буфера (framebuffer), библиотека uGFX, и модуль GDISP в частности, не требуют его наличия. Это позволяет подключать графические дисплеи к микроконтроллерам и другим системам с низкой производительностью, не имеющим достаточно памяти ОЗУ для хранения кадрового буфера.
Прикладное приложение
Модуль GDISP
Высокоуровневый программный интерфейс (API)
Конфигурационный файл
Драйвер
Файл поддержки платформы
Аппаратная платформа
Некоторые контроллеры графических дисплеев поддерживают аппаратное ускорение для вывода таких графических объектов, как окружности и эллипсы. В этом случае uGFX будет использовать ускорение выбранного контроллера. Если же графический контроллер не поддерживает аппаратное ускорение (в большинстве случаев это так), модуль GDISP эмулирует операции рисования, то есть рисует окружность по отдельным пикселям.
Более того, GDISP поддерживает вывод информации более чем на один дисплей, причем дисплеями могут управлять различные драйверы. Также предусмотрено применение одного или нескольких удаленных дисплеев. Эти возможности uGFX будут описаны в последующих статьях.
Типы данных
API-функции библиотеки uGFX принимают аргументы, имеющие тип, отличный от встроенных типов языка С. Это одно из требований по обеспечению независимости библиотеки uGFX от разрядности целевого микроконтроллера. Наиболее важные типы данных, определенные в uGFX, сведены в таблицу 1.
Встроенные целочисленные типы данных (int, char, long и т. д.) не используются, поскольку их размер зависит от разрядности целевого микроконтроллера. Вместо них в исходном коде uGFX применяются целочисленные типы из стандартной библиотеки языка С, определенные в заголовочном файле stdint.h (int8_t, uint32_t и др.). Их особенностью является точно известный занимаемый ими размер памяти и максимальное/минимальное значение, которое может принимать переменная с таким типом. Это также обеспечивает независимость uGFX от платформы, на которой она выполняется.
рис. 1. Взаимодействие модуля GDISP с программой
Таблица 1. Некоторые типы данных, используемые в uGFX
название типа Описание
coord_t Целое число со знаком. Координата по вертикали или горизонтали. Размер элемента изображения в пикселях
point_t Координаты точки на плоскости — пара переменных, имеющих тип coord_t
color_t Цвет элемента изображения
GDisplay Структура, определяющая дисплей и его параметры
font_t Указатель на структуру, которая описывает шрифт
gdispImage Структура, описывающая файл с изображением в одном из распространенных форматов (BMP, GIF)
bool_t Логический тип, FALSE означает «ложь», TRUE — «истину»
size_t Размер областей памяти. Смещение в файле
delaytime_t Временная задержка, количество милли- или микросекунд
Соглашение об именах функций
Модуль GDISP предоставляет множество API-функций для рисования отдельных пикселей, графических примитивов, шрифтов и целых изображений на дисплее.
Имена всех API-функций, принадлежащих к модулю GDISP, начинаются с префикса gdisp. Далее может следовать буква G: если используется конфигурация с несколькими дисплеями, то должны применяться соответствующие API-функции с именем, начинающимся на gdispG... При этом первый аргумент функции определяет дисплей, на котором надо что-либо нарисовать. Если же имеется единственный дисплей, то должны использоваться API-функции, начинающиеся на gdisp., и аргумента, определяющего дисплей, соответственно нет. Например:
// Конфигурация с множеством дисплеев GDisplay *g; // ...
// Вывод пикселя на дисплей, который определен указателем g. void gdispGDrawPixel(GDisplay *g, x, y, color);
// Конфигурация с единственным дисплеем // Вывод пикселя на единственный дисплей. void gdispDrawPixel(x, y, color);
Следует отметить, что все API-функции, представленные в модуле GDISP, доступны также в GWIN-модуле, но рисование в этом случае производится внутри текущего окна. Тогда соответствующие API-функции принимают аргумент GHandle, определяющий, в каком окне следует рисовать. Например, API-функция рисования одного пикселя внутри окна:
void gwinDrawPixel(GHandle gh, coord_t x, coord_t y);
Ее аргументы:
• GHandle gh — дескриптор окна, в котором осуществляется рисование;
• coord_t x, coord_ty — координаты точки внутри окна.
Конфигурация и инициализация uGFX
Конфигурация
Библиотека uGFX предоставляет программисту средства для тонкой настройки. Настройка заключается во включении или отключении:
• определенных модулей библиотеки;
• возможностей библиотеки, предоставляемых включенным модулем. Отключив неиспользуемые модули и их
возможности, можно добиться значительного снижения объема двоичного файла прошивки, что оказывается очень полезно в условиях малых объемов памяти программ в микроконтроллерах.
Настройка осуществляется редактированием конфигурационного файла gfxconf.h пу-
тем задания значений макроопределениям. Так, для использования возможностей модуля GDISP конфигурационный файл должен содержать строку:
#define GFX_USE_GDISP TRUE
Далее эти макроопределения применяются в исходном коде uGFX препроцессором языка С для условной компиляции тех или иных API-функций и даже их частей.
Если какое-либо конфигурационное макроопределение не задано в конфигурационном файле, то оно принимает значение по умолчанию, которое может соответствовать как «истине» (TRUE), так и «лжи» (FALSE). Для модуля GDISP значения по умолчанию запрограммированы в файле \src\gdisp\sys_options.h. Например, кратковременный вывод логотипа uGFX на дисплей сразу после старта программы по умолчанию включен, отключить его можно, добавив в конфигурационный файл gfxconf.h следующее:
#define GDISP_NEED_STARTUP_LOGO FALSE
При написании программы, использующей библиотеку uGFX, можно пойти двумя путями:
1. Взять готовый конфигурационный файл из наиболее близкого по используемым возможностям демонстрационного проекта.
2. Взять за основу шаблон конфигурационного файла gfxconf.example.h, находящийся в дистрибутиве uGFX. В шаблоне перечислены все возможные конфигурационные макроопределения, им присвоены значения по умолчанию.
Инициализация
Первой вызываемой API-функцией в программе, применяющей uGFX, должна быть gfxInit() — функция инициализации библиотеки uGFX. Вызов какой-либо API-функции до gfxInit() может привести к программному сбою и непредсказуемому поведению.
Типичная программа, использующая uGFX, должна выглядеть так:
#include "gfx.h" int main(void) {
// Инициализация библиотеки gfxInit();
// Остальная программа // ...
}
цвет
Модуль GDISP может работать со всеми распространенными форматами представления цвета — от монохромного изображения (1 бит на пиксель) и оттенков серого до поддержки цвета TrueColor (24 бита на пиксель).
Поддерживается упакованный формат представления цвета, когда один байт или одно слово содержит информацию о нескольких пикселях — например, в один байт можно записать 4 пикселя, если глубина цвета — 4 уровня серого. Однако внутреннее представление цвета всегда неупакованное — максимум один пиксель на байт или слово. На практике эта особенность сказывается только в работе с изображениями в формате NATIVE.
Если имеется один дисплей, то внутренний формат цвета совпадает с форматом для используемого графического контроллера. Для случая применения нескольких дисплеев одновременно внутренний формат цвета должен быть задан в конфигурационном файле gfxconf.h и драйверы контроллеров будут транслировать внутренний формат цвета uGFX в родной формат для каждого контроллера.
Тип для внутреннего представления цвета — color_t. Этот тип определен внутри библиотеки uGFX так, что прикладному приложению не надо заботиться о деталях реализации представления цвета в uGFX.
Как и в других графических библиотеках, в uGFX встроен базовый набор цветов, таких как черный, серый, красный, розовый и т. п. Они определены в файле /src/gdisp/gdisp_colors.h как макроопределения с соответствующим именем: Black, Gray, Red, Pink и т. д. Полный список встроенных цветов приведен в таблице 2.
Предоставляется множество макросов для работы с цветом, позволяющих получить составляющие цвета, заданный цвет, а также смешать несколько цветов в один. Для получения цвета во внутреннем представлении из различных форматов служат следующие макросы:
1) HTML2COLOR(h) — переводит 32-битный цвет из формата, принятого в языке HTML, во внутренний формат, например HTML2COLOR (0xFF0000) соответствует красному цвету.
2) RGB2COLOR(r, g, b) — возвращает цвет, заданный тремя составляющими: красной, зеленой и синей, каждая составляющая может принимать значения в диапазоне 0.255.
Таблица 2. Базовый набор цветов в uGFX
цвет Макроопределение
белый White
черный Black
серый Gray, Grey
синий Blue
красный Red
пурпурный Fuchsia, Magenta
зеленый Green
желтый Yellow
сене-зеленый Aqua, Cyan
лайм Lime
темно-бордовый Maroon
хаки Navy
оливковый Olive
фиолетовый Purple
серебро Silver
темный сине-зеленый Teal
оранжевый Orange
розовый Pink
небесно-голубой SkyBlue
3) LUMA2COLOR(l) — переводит заданный оттенок серого (l) во внутренний формат, оттенок серого (l) может принимать значения 0-255.
Есть также макросы для выделения составляющих цвета. Макросы RED_OF(c), GREEN_OF(c), BLUE_OF(c) выделяют соответственно красную, зеленую и синюю составляющие, их аргумент должен иметь тип color_t.
Макрос LUMA_OF(c) возвращает соответствующий цвету оттенок серого (обесцвечивает). При этом выделение производится грубо, но быстро — с помощью операций побитового сдвига.
Те же операции можно выполнить более точно с помощью макросов EXACT_RED_OF(c), EXACT_GREEN_OF(c), EXACT_BLUE_OF(c), EXACT_LUMA_OF(c), однако они несколько медленнее, поскольку применяют арифметические операции умножения и деления.
uGFX не поддерживает представление цвета с использованием палитры. Это относится к внутреннему представлению цвета, что же касается изображений в форматах *.bmp и *.gif, использующих палитру цветов, то uGFX поддерживает их в полной мере.
Если необходимо внутреннее представление цвета с помощью палитры, то предусмотрена возможность написать собственный драйвер для использования, например, 8-битной (256 цветов) палитры. Задать цвета палитры можно с помощью API-функции gdispControl().
Есть возможность смешать два цвета в заданной пропорции. Для этого служит API-функция gdispBlendColor(), ее прототип:
Для координат по оси абсцисс и ординат в файле \ugfx\src\gdisp\sys_ defs.h определен тип coord_t как 16-битное число со знаком:
typedef int16_t coord_t;
Там же определен тип point_t, описывающий положение точки на плоскости как пару координат по оси X и оси Y:
typedef struct point { coord_t x, y; } point, point_t;
Графические примитивы
Ниже рассмотрены графические примитивы, доступные для рисования в uGFX, и соответствующие им API-функции.
Пиксель (точка)
Пиксель — неделимый элемент растрового изображения, который можно задать координатами и цветом (рис. 3).
0, 0 Хо X
color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha);
где fg — подмешиваемый цвет, bg — основной цвет, alpha — пропорция подмешиваемого цвета, число в диапазоне 0-255. Если alpha = 0, то результирующий цвет — основной, если alpha = 255, то результирующий цвет — подмешиваемый.
Предоставлена также возможность увеличения контраста для заданного цвета, для этого служит API-функция gdispContrastColor():
color_t gdispContrastColor(color_t color);
Уо
V
рис. 3. Рисование точки
Функция работает грубо — устанавливает значение красной, зеленой и синей составляющих цвета в максимальное или минимальное значение, если те превышают некоторый порог в исходном цвете. В итоге результат выполнения gdi$pContrastColor() — один из восьми цветов (черный, белый, красный, желтый и т. д.).
Рисование точки осуществляется API-функцией gdispDrawPixel(), ее прототип:
void gdispDrawPixel(coord_t x0, coord_t y0, color_t color);
Система координат
В uGFX используется общепринятая в машинной графике декартова система координат с началом отсчета в верхнем левом углу (рис. 2).
0 1 2 ... X
0
1
2
3 * строка
с \
т ^пиксель
О
л
б
е
У , ц
рис. 2. Принятая в uGFX система координат
Аргументы xO, y0 определяют координаты выводимой точки, а color — ее цвет.
Тонкая линия
Рисование тонкой линии (шириной в один пиксель — рис. 4) осуществляется API-функцией gdispDrawLine(), ее прототип:
void gdispDrawLine(coord_t x1, coord_t y1, coord_t x2, coord_t y2, color_t color);
Агрументы xl, y1 задают координаты одного конца линии, x2, y2 — координаты второго конца, а color определяет цвет линии.
К недостаткам uGFX можно отнести отсутствие поддержки сглаживания отображаемых линий [4]. Для построения линий применен быстрый алгоритм Брезенхэма [5], особенностью которого является появление эффекта «зубчатости» (рис. 4) у наклонных линий.
Толстая линия
Зачастую необходимо отобразить линию, имеющую толщину более одного пикселя. Для этой цели предназначена API-функция gdispDrawThickLine(), ее прототип:
Рис. 4. Рисование тонкой линии Рис. 6. Рисование прямоугольника
void gdispDrawThickLine(coord_t x1, coord_t y1, coord_t x2, coord_t y2, color_t color, coord_t width, bool_t round);
Как и для тонкой линии, аргументы (x1, y1) и (x2, y2) определяют координаты начала и конца линии, a color—ее цвет. Дополнительный аргумент width задает толщину линии, а round — вид концов линии (рис. 5). Можно получить скругленные концы, если задать аргумент round = TRUE, если же round = FALSE, то концы линии имеют прямоугольную форму (рис. 5).
Рис. 5. Рисование толстой линии
При большой ширине линии становится заметно, что закругление реализовано не окружностью, а восьмиугольником. При дальнейшем анализе API-функции gdispDrawThickLine() выяснилось, что uGFX рисует толстую линию в виде закрашенного многоугольника. Вот почему для того, чтобы пользоваться API-функцией gdispDrawThickLine(), в конфигурационном файле gfxconf.h должно быть разрешено рисование многоугольников, то есть задано макроопределение GDISP_NEED_CONVEX_POLYGON:
#define GDISP_NEED_CONVEX_POLYGON TRUE
три прямоугольника не изменяется. Для этого служит API-функция gdispDrawBox(), ее прототип:
void gdispDrawBox(coord_t x0, coord_t y0, coord_t cx, coord_t cy, color_t color);
Аргументы x0, y0 определяют координаты верхнего левого угла прямоугольника, аргумент cx определяет ширину прямоугольника в пикселях, cy — его высоту (рис. 6). Аргумент color определяет цвет рамки прямоугольника.
0,0, *0 X
Уо
&
сх
У'
Рис. 7. Рисование закрашенного прямоугольника
Рисование закрашенного прямоугольника (рис. 7) подобно рисованию обычного, рассмотренного выше. Единственное отличие заключается в том, что область внутри прямоугольника закрашивается заданным цветом. Производится API-функцией gdispFillArea(), ее прототип не отличается от API-функции gdispDrawBox():
void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color);
Прямоугольник со скругленными углами
В uGFX есть также возможность нарисовать прямоугольник со скругленными углами. Для этого предназначены API-функции gdispDrawRoundedBox(), gdispFillRoundedBox(). Первая рисует незакрашенный, вторая — закрашенный прямоугольник со скругленными углами, прототипы у них одинаковые:
Прямоугольник
uGFX предоставляет возможность отобразить прямоугольник в виде рамки толщиной в 1 пиксель, причем старое изображение вну-
void gdispDrawRoundedBox(coord_t x0, coord_t y0, coord_t cx, coord_t cy, coord_t radius, color_t color); void gdispFillRoundedBox(coord_t x0, coord_t y0, coord_t cx, coord_t cy, coord_t radius, color_t color);
0,0, Хо X
— центр
Уо
радиус M-►
У"
рис. 11. Рисование круга
0,0
*о
радиус
Уо
<1
Рисование круга (закрашенная окружность) показано на рис. 11, выполняется API-функцией gdispFiUCircleO, ее прототип:
void gdispFillCircle(coord_t x0, coord_t y0, coord_t radius, color_t color);
Назначение аргументов то же, что и у функции gdispDrawCircle(). В конфигурационном файле gfxconf.h должно быть разрешено рисование окружностей и кругов, то есть задано макроопределение:
У
рис. 9. Закрашенный прямоугольник со скругленными углами
По сравнению с соответствующими API-функциями для рисования «простого» прямоугольника появился новый аргумент radius, который определяет радиус закруглений в пикселях (рис. 8, 9).
Окружность и круг
Для рисования обычной окружности (рис. 10) толщиной в 1 пиксель служит API-функция gdispDrawCircleO, ее прототип:
void gdispDrawCircle(coord_t x0, coord_t y0, coord_t radius, color_t color);
Аргументы x0, y0 задают центр окружности, radius — ее радиус в пикселях, color — ее цвет.
0,0, хо X
Г \ — центр
Уо [
0 радиус <-
У 1
рис. 10. Рисование окружности
#define GDISP_NEED_CIRCLE TRUE
Дуга и сектор
Дугу в uGFX рисует API-функция gdispDrawArc(), ее прототип:
void gdispDrawArc(coord_t x0, coord_t y0, coord_t radius, coord_t startangle, coord_t endangle, color_t color);
Дуга указывается как часть окружности следующими параметрами (рис. 12):
• Координаты центра окружности, которой принадлежит рисуемая дуга, — аргументы x0, y0.
• Радиус этой окружности — аргумент radius.
• Угол начала и угол конца дуги — аргументы startangle и endangle. Углы задаются не в радианах, а в градусах. Принимаются как положительные, так и отрицательные значения, положительное значение соответствует отсчету угла против часовой стрелки, отрицательное — по часовой стрелке (рис. 12).
• Цвет задает аргумент color.
рис. 12. Рисование дуги
0,0, X
!—центр
начало отсчета
углов
Уо
угол конца радиус м-► 44 угол начала
У'
Рис. 13. Рисование сектора
Рисование сектора (рис. 13) подобно рисованию дуги, выполняется API-функцией gdispFülArc(), ее прототип не отличается от рассмотренной выше gdispDrawArc():
void gdispFillArc(coord_t x0, coord_t y0, coord_t radius, coord_t startangle, coord_t endangle, color_t color);
В конфигурационном файле gfxconf.h должно быть разрешено рисование дуг и секторов:
#define GDISP_NEED_ARC TRUE
Эллипс
Рисование незакрашенного эллипса осуществляется API-функцией gdispDrawEllipse(), закрашенного — gdispFittEttipse(), их прототипы одинаковы:
void gdispDrawEllipse(coord_t x0, coord_t y0, coord_t a, coord_t b, color_t color);
void gdispFillEllipse(coord_t x0, coord_t y0, coord_t a, coord_t b, color_t color);
Аргументы (x0, y0) определяют центр эллипса, a и b — его полуоси, ориентированные соответственно по оси абсцисс (в горизонтальном направлении) и по оси ординат (вертикальное направление) (рис. 14, 15). Аргумент color определяет цвет эллипса.
Возможность рисовать эллипсы может быть включена в конфигурационном файле gfxconf.h:
#define GDISP_NEED_ELLIPSE TRUE
Многоугольник (полигон)
В uGFX предоставлена возможность выводить произвольные многоугольники, заданные координатами своих вершин. Многоугольники могут быть как закрашенными, так и в виде рамки, причем в случае закрашенного допускается только выпуклый многоугольник [6].
Рисование произвольного обычного многоугольника осуществляет API-функция gdispDrawPoly(), а рисование закрашенного многоугольника — gdispFillConvexPolyO, прототипы у них одинаковые:
void gdispDrawPoly(coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color); void gdispFillConvexPoly(coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color);
Вершины многоугольника в виде массива точек задаются массивом pntarray, аргумент cnt определяет размер массива. Каждая точка в массиве содержит координаты относительно центра многоугольни-
0,0 Хо х
Уо
Г, полуось Ь
!
У' центр —' полуось а
Рис. 14. Рисование эллипса
Рис. 15. Рисование закрашенного эллипса
относительно центра
Рис. 16. Рисование многоугольника
ка (рис. 16). Центр многоугольника может быть выбран произвольно, однако целесообразно поместить его либо в центр многоугольника, либо на ребро, либо на вершину. Пара аргументов ty) определяет координаты центра многоугольника при выводе его на экран.
Особенность uGFX состоит в том, что на рисование закрашенного многоугольника накладывается ограничение — он должен быть выпуклым. Если попытаться вывести закрашенный невыпуклый
многоугольник, то uGFX все-таки его выведет, но сделает его незакрашенным (рис. 17).
Разрешить возможность рисования многоугольников можно в конфигурационном файле gfxconf.h^.
Пример программы
Ниже приведена программа, демонстрирующая применение описанных выше АР1-функций вывода графических примитивов. Программа была скомпилирована для микроконтроллера STM32F100RB и дисплея разрешением 240x320 пикселей, управляемого графическим контроллером Ш9341. Подробно о данной аппаратной платформе написано в [2].
// Прямоугольники
gdispDrawBox(10, 110, 50, 50, RANDOM_COLOR()); gdispFillArea(65, 110, 50, 50, RANDOM_COLOR()); gdispDrawRoundedBox(120, 110, 50, 50, 10, RANDOM_COLOR()); gdispFillRoundedBox(175, 110, 50, 50, 10, RANDOM_COLOR());
// Окружность и круг
gdispDrawCircle(260, 135, 25, RANDOM_COLOR()); gdispFillCircle(290, 135, 25, RANDOM_COLOR());
// Дуга и сектор
gdispFillArc(10, 230, 55, 5, 85, RANDOM_COLOR()); gdispDrawArc(10, 230, 65, 0, 90, RANDOM_COLOR());
// Эллипсы
gdispDrawEllipse(100, 200, 20, 30, RANDOM_COLOR()); gdispFillEllipse(150, 200, 20, 30, RANDOM_COLOR());
// Незакрашенный многоугольник (полигон) point points[10];
for (z = 0, x0 = 0; z < 360; z += 360 / 10, x0++) { if (x0 % 2) {
x = 40 * cos(z * 3.14 / 180.0); y = 40 * sin(z * 3.14 / 180.0); } else {
x = 15 * cos(z * 3.14 / 180.0);
y = 15 * sin(z * 3.14 / 180.0); } >
points[x0].x = x; points[x0].y = y;
}
gdispDrawPoly(210, 200, points, 10, RANDOM_COLOR());
// Закрашенный многоугольник (полигон) for (z = 0, x0 = 0; z < 360; z += 360 / 5, x0++) { x = 35 * cos(z * 3.14 / 180.0); y = 35 * sin(z * 3.14 / 180.0); points[x0].x = x; points[x0].y = y;
}
gdispFillConvexPoly(280, 200, points, 5, RANDOM_COLOR());
// Бесконечный цикл while(TRUE) { gfxSleepMilliseconds(1000);
}
}
Для того чтобы программа компилировалась без ошибок, uGFX должна быть настроена с помощью конфигурационного файла gfxconf.h, его содержимое.
#ifndef _GFXCONF_H #define _GFXCONF_H
// Без операционной системы #define GFX_USE_OS_RAW32 TRUE
// Использовать модуль GDISP #define GFX_USE_GDISP TRUE
// Активация отдельных возможностей модуля GDISP #define GDISP_NEED_CONTROL TRUE
#define GDISP_NEED_ .VALIDATION TRUE
#define GDISP_NEED_ _CLIP TRUE
#define GDISP_NEED_ _CIRCLE TRUE
#define GDISP_NEED_ _CONVEX_POLYGON TRUE
#define GDISP_NEED_ _ARC TRUE
#define GDISP_NEED_ _ELLIPSE TRUE
#endif /* _GFXCONF_ H */
Кроме этого, для использования тригонометрических функций в настройках линков-щика должна быть подключена математическая библиотека (для среды CooCox IDE настройка следующая: Configuration ^ Link ^ Linked Libraries ^ Add ^ «m»).
На рис. 18 приведен результат работы программы непосредственно на устройстве.
растровые изображения
В модуль GDISP встроена поддержка декодирования растровых изображений. Декодер позволяет открыть изображения из файлов различных форматов и отобразить их на дисплее. Графические файлы могут быть сохранены в различные типы памяти, будь то встроенная флэш-память или внешняя память, например SD-карта памяти. Это достигается благодаря использованию внутри модуля GDISP модуля поддержки файловых систем — GFILE.
На данный момент uGFX поддерживает декодирование изображений из следующих форматов:
• BMP — аппаратно-независимый растровый формат, разработанный Microsoft [7]. Поддерживается большинство разновидностей формата *. bmp по глубине цвета: 1 бит на пиксель, 4 бита, 8 бит, 16 бит (HiColor), 24 и 32 бита (TrueColor). Для форматов 4 и 8 бит на пиксель поддерживаются сжатые bmp-файлы (по алгоритму RLE).
• GIF — аппаратно-независимый растровый формат изображений, поддерживающий максимум 256 цветов (8 бит на пиксель) [6]. Поддерживается прозрачность и анимированные gif-изображения.
• NATIVE — аппаратно-зависимый формат хранения изображения, оптимизирован-
#include "gfx.h" #include "math.h"
// Макрос для получения случайного цвета
#define RANDOM_COLOR() RGB2COLOR(rand() % 256, rand()
% 256, rand() % 256)
int main(void) {
int x, y, z; int x0, y0;
// Инициализация библиотеки gfxInit();
// Установить альбомную ориентацию дисплея gdispSet0rientation(GDKP_R0TATE_270);
// Рисование по пикселям for (x = 10; x < 100; x += 5) { for (y = 10; y < 100; y += 5) {
gdispDrawPixel(x, y, RANDOM_COLOR());
}
}
// Тонкая линия for (z = 0; z < 360; z += 5) { x = 50 * cos(z * 3.14 / 180.0); y = 50 * sin(z * 3.14 / 180.0); x0 = 20 * cos(z * 3.14 / 180.0); y0 = 20 * sin(z * 3.14 / 180.0);
gdispDrawLine(x0 + 150, y0 + 50, x + 150, y + 50, RANDOM_
COLOR());
}
// Толстая линия
gdispDrawTbickLine(220, 10, 300, 10, RANDOM_COLOR(), 5, FALSE); gdispDrawTbickLme(220, 30, 300, 30, RANDOM_COLOR(), 10, TRUE); gdispDrawTbickLine(220, 60, 300, 60, RANDOM_COLOR(), 20, FALSE); gdispDrawThickLine(220, 85, 300, 85, RANDOM_COLOR(), 20, TRUE);
#define GDISP_NEED_CONVEX_POLYGON TRUE
ный для данного графического контроллера. Содержит заголовок минимального размера (8 байт), за которым следует массив пикселей, где каждый пиксель записан в формате представления для выбранного графического контроллера. Формат отличается максимально быстрым выводом изображения на дисплей и минимально возможным потреблением памяти. Идеально подходит для хранения изображений во встроенной флэш-памяти. В будущем планируется добавление поддержки таких распространенных форматов, как *.png и *.jpg.
Отдельно следует сказать о формате NATIVE. Библиотека uGFX предоставляет возможность его отображения, но на официальном сайте [3] автор не нашел описания того, как этот графический формат может быть получен (указывается лишь значение полей его заголовка). Видимо, предполагается, что программист должен сам создать утилиту для конвертирования в формат NATIVE с учетом представления цвета пикселей в выбранном дисплее и графическом контроллере.
Поддержка каждого формата и каждой его разновидности может быть индивидуально разрешена или запрещена с помощью конфигурационного файла gfxconf.h. Запрещать поддержку неиспользуемых форматов следует для экономии памяти программ микроконтроллера. Например, для того чтобы выводить изображения в формате *.bmp, конфигурационный файл должен содержать следующие строки:
#define GDISP_NEED JMAGE TRUE
#define GDISP_NEED _IMAGE_BMP TRUE
При этом все другие форматы автоматически будут запрещены, а все разновидности Ьтр-формата — разрешены.
Для того чтобы еще уменьшить размер двоичного файла прошивки, можно запретить неиспользуемые разновидности Ьтр-формата и оставить только одну используемую, например сжатый Ьтр-формат с глубиной цвета 8 бит:
#define GDISP_NEED_ IMAGE_ BMP_ _1 FALSE
#define GDISP_NEED_ IMAGE_ BMP_ 4 FALSE
#define GDISP_NEED_ IMAGE_ BMP_ _4_RLE FALSE
#define GDISP_NEED_ IMAGE_ BMP_ 8 FALSE
#define GDISP_NEED_ IMAGE_ BMP_ _8_RLE TRUE
#define GDISP_NEED_ IMAGE_ BMP_ _16 FALSE
#define GDISP_NEED_ IMAGE_ BMP_ 24 FALSE
#define GDISP_NEED_ IMAGE_ BMP_ 32 FALSE
Пример программы
Простейшая программа, выводящая изображение на дисплей:
// Получить размер дисплея // Ширина
swidth = gdispGetWidth(); // Высота
sheight = gdispGetHeight();
// Открыть изображение из файла "test-pal8.bmp"
gdispImageOpenFile(&myImage, "test-pal8.bmp");
// Вывести полное изображение в левый верхний угол дисплея
gdispImageDraw(&myImage, 0, 0, swidth, sheight, 0, 0);
// Закрыть изображение
gdispImageClose(&myImage);
// Бесконечный цикл while(1) {
gfxSleepMilliseconds(1000);
}
return 0;
}
Для успешной сборки проекта uGFX должна быть соответствующим образом настроена:
#ifndef GFXCONF H
#define _GFXCONF_H
// Без операционной системы
#define GFX USE OS RAW32 TRUE
// Использовать модуль GDISP #define GFX_USE_GDISP TRUE
// Разрешить работу с ВМР-изображениями #define GDISP_NEEDJMAGE #define GDISP_NEED_IMAGE_BMP TRUE TRUE
// Использовать модуль GFILE #define GFX_USE_GFILE TRUE
// Использовать файловую систему ROMFS #define GFILE_NEED_ROMFS TRUE
#endif /* _GFXCONF_H */
Особо следует обратить внимание на активацию файловой системы ROMFS, подробно о которой написано далее. Результат работы программы на аппаратной платформе, указанной ранее (подробнее о ней в [2]), приведен на рис. 19.
Вывод изображения
Вывод изображения (рис. 20) осуществляется АР1-функцией gdispImageDrawO, ее прототип:
#include "gfx.h"
static gdispImage mylmage;
int main(void) {
coord_t swidth, sheight;
// Инициализация библиотеки uGFX gfxInit();
0,0
Уо
*o
Дисплей
-координата изображения на дисплее
область - вывода изображения
Изображение
Рис. 20. Принцип вывода изображения на дисплей
gdisplmageError gdispImageDraw(gdispImage *img, coord_t x0, coord_t y0, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
Аргументы:
• gdispImage *img — указатель на структуру gdisplmage, которая описывает открытое изображение. Предварительно этот указатель должен быть получен при открытии файла с изображением API-функцией gdispImageOpenFile().
• coord_tx0, coord_t y0 — координаты верхнего левого угла выводимого изображения на дисплее.
• coord_t cx, coord_t cy — размер соответственно по горизонтали и вертикали области на дисплее, в которую будет выведено изображение. Если изображение выходит за пределы этой области, оно будет обрезано. Если изображение меньше этой области, оставшаяся часть дисплея останется нетронутой.
• coord_t sx, coord_t sy — смещение соответственно по горизонтали и вертикали внутри изображения (от левого верхнего угла), начиная с которого изображение будет выводиться на экран. Возможность задавать размер области, куда
выводится изображение, и смещение внутри изображения позволяет организовать хранение нескольких изображений меньшего размера в одном изображении большего размера. Изображения меньшего размера могут быть, например, изображениями кнопок управления в графическом интерфейсе пользователя.
Если изображение не выводится на дисплей, следует проверить возвращаемое значение для каждой вызываемой API-функции на предмет кода ошибки. Причиной неудавшегося вывода изображения может быть:
• соответствующий декодер не разрешен в конфигурационном файле;
• файл с изображением не может быть открыт;
• недостаточно памяти ОЗУ для декодирования изображения.
Открытие изображения
Интерес представляет открытие файла, которое производится API-функцией gdispImageOpenFile(), ее прототип:
gdisplmageError gdispImageOpenFile(gdispImage *img, const char *fname);
Аргументы:
• gdispImage *img — указатель на структуру gdisplmage, в которую будет помещена информация об открытом файле с изображением.
• const char *fname — нуль-терминальная строка, содержащая имя файла с изображением.
Если изображение успешно открыто, то gdispImageOpenFile() возвращает GDISP_ IMAGE_ERR_OK, в противном случае возвращается код ошибки, например GDISP_
IMAGE_ERR_BADFORMAT — неверный формат файла. Коды ошибок определены в файле gdisp_image. h
Файловая система ROMFS
Файловая система ROMFS предназначена для хранения файлов во встроенной флэш-памяти микроконтроллера. Особенности ROMFS:
• доступ к файлам возможен только в режиме чтения;
• поддерживаются только файлы, каталоги не поддерживаются;
• набор файлов и их содержимое жестко задается на этапе компиляции программы. Отдельные элементы файловой системы — файлы, которые представлены в исходном коде программы в виде заголовочных файлов языка С. Каждый файл, который необходимо добавить в файловую систему, должен быть конвертирован в заголовочный файл, содержащий массив байт — побитовую копию добавляемого файла. Все полученные заголовочные файлы должны перечисляться в специальном файле romfs_files.h.
Операция конвертации автоматизирована — для этого служит утилита file2c, которая входит в дистрибутив библиотеки uGFX и расположена в каталоге /tools/file2c. Предоставляется две версии утилиты file2c для Windows и Linux.
Утилита file2c создает из файла с изображением (не обязательно с изображением — может из любого файла) файл с расширением *h, который следует включить в проект. Например, чтобы добавить в файловую систему ROMFS файл test-pal8.bmp из программы выше, следует поместить этот файл и выполняемый файл file2c (file2c.exe для Windows) в один каталог и выполнить следующую команду:
file2c -dcs test-pal8.bmp romfs_testpal8.h
В результате будет создан файл romfs_ testpal8h, который следует включить в проект, добавив в специальный файл romfs_files.h следующую строку:
// Включить файл "test-pal8.bmp" в файловую систему ROMFS #include "romfs_testpal8.h"
Для работы с файловой системой ROMFS она должна быть активирована в конфигурационном файле gfxconf.h^.
#define GFX_USE_GFILE TRUE
#define GFILE_NEED_ROMFS TRUE
Закрытие изображения
Производится АР1-функцией gdispImageClose(). При этом осуществляется освобождение всех ресурсов, занятых для вывода изображения, в том числе и закрытие файла с изображением. Поэтому gdispImageClose() должна вызываться после
завершения всех операций с изображением, когда перерисовка изображения не потребуется в течение длительного времени.
Вывод анимированных изображений
uGFX позволяет выводить анимирован-ные GIF-изображения, представляющие собой набор статичных кадров с указанием, сколько времени каждый кадр должен отображаться на экране.
Для поддержки анимированных изображений GIF (в будущем — и форматов, хранящих несколько изображений одновременно, например TIFF) в uGFX представлена API-функция gdispImageNext(). Она переводит внутренний указатель в структуре gdispImage на следующий кадр в изображении так, что после ее вызова вызов gdispImageDraw() выведет уже следующий кадр.
Пример программы, осуществляющей непрерывное воспроизведение анимирован-ного GIF-изображения:
#include "gfx.h"
static gdispImage myImage;
int main(void) {
delaytime_t delay;
// Инициализация библиотеки uGFX gfxInit();
// Открыть изображение
gdispImageOpenFile(&myImage, "testanim.gif");
// Бесконечный цикл while(1) {
// Вывести очередной кадр gdispImageDraw( &myImage, 0, 0,
myImage.width, myImage.height,
0, 0);
// Перейти к следующему кадру, // выяснить паузу до показа следующего кадра delay = gdispImageNext(&myImage); // Если пауза не равна нулю. if (delay != TIME_IMMEDIATE) { // Пауза
gfxSleepMilliseconds(delay);
}
}
return 0;
}
API-функция gdispImageNext() имеет следующий прототип:
delaytime_t gdispImageNext(gdispImage *img);
Аргумент img — указатель на структуру gdispImage, которая описывает открытое ранее изображение. gdispImageNext() может возвращать:
• Количество миллисекунд — пауза, которую следует выждать перед вызовом gdispImageDraw().
• Макроопределение TIME_IMMEDIATE — означает, что следующий должен быть выведен прямо сейчас, либо то, что первый кадр не был еще выведен до вызова gdispImageNext().
• Макроопределение TIME_INFINITE — для GIF-изображения означает ошибку.
Использование памяти
Декодеры изображения используют память ОЗУ для работы алгоритмов декодирования. Декодеры изображения были спроектированы с нуля с целью уменьшить потребление памяти насколько это возможно. Чтобы избежать переполнения памяти, для микроконтроллеров с малым объемом ОЗУ формат изображений следует выбирать с осторожностью.
Декодеры изображения не выделяют память ОЗУ для хранения всего декодированного изображения, как большинство других декодеров. Вместо этого изображение декодируется заново, если требуется его повторно отобразить. При этом память ОЗУ расходуется:
• На хранение информации о самом изображении. Эта информация используется при открытии изображения. Размер — обычно от 200 до 300 байт, может незначительно отличаться для различных форматов изображений (например, хранение палитры цветов для bmp-формата с глубиной цвета 4 и 8 бит).
• Память для обслуживания алгоритма декодирования, по завершении декодирования память освобождается. GIF-формат дополнительно требует около 12 кбайт ОЗУ, bmp и native — не требуют дополнительного объема памяти (это обусловлено тем, что GIF-изображения сжаты по алгоритму LZW [8]).
• Если программист решил кешировать изображение целиком в памяти ОЗУ (этого не следует делать на микроконтроллерах с малым объемом ОЗУ). Например, хранение изображения размером 320x240 пикселей с глубиной цвета 16 бит потребует около 150 кбайт памяти ОЗУ.
• Память стека. Возможно, потребуется увеличить размер стека, если могут произойти прерывания во время декодирования изображения. Для декодирования некоторых форматов может понадобиться до нескольких сотен байт стека.
Подсчет объема памяти
Есть возможность получить точный объем памяти, который был использован при открытии изображения. Для этого в конфигурационном файле макроопределение GDISP_ NEED_IMAGE_ACCOUNTING должно быть установлено в TRUE.
При этом в структуру gdispImage добавляется два поля: memused и maxmemused. Первое содержит текущий объем памяти, требуемый для обслуживания изображения, второе — максимальный объем памяти за все время использования изображения. Просмотреть значения этих полей можно с помощью отладчика.
Хеширование изображения
Под кешированием понимается считывание информации о цвете всех пикселей изображения в память ОЗУ. В uGFX возможность
кешировать изображение предоставлена с помощью API-функции gdispImageCache():
gdispImageError gdispImageCache(gdispImage *img);
Если изображение не кешировано, то каждый раз при его выводе на дисплей (API-функцией gdispImageDraw()) оно будет заново считано из флэш-памяти, декодировано и выведено на дисплей.
Если же изображение кешировано в ОЗУ, то для его вывода на дисплей следует лишь скопировать его из ОЗУ в видеопамять графического контроллера. Эти действия занимают гораздо меньше времени, чем чтение из флэш-памяти и декодирование. Разница во времени особенно велика для форматов *.gif, *.png и *.jpg, которым необходимы довольно сложные алгоритмы для декодирования.
Однако кеширование требует очень большого по меркам микроконтроллеров объема памяти ОЗУ, особенно при кешировании анимированных изображений GIF и изображений большого размера.
Перед кешированием изображение должно быть открыто API-функцией gdispImageOpen(). Если закрыть кеши-рованное изображение (API-функция gdispImageClose()), это приведет к освобождению всей памяти, отведенной для хранения изображения.
Вызов API-функции gdispImageCache() однозначно не определяет, будет ли изображение кешировано. Например, изображение не будет кешировано, если памяти ОЗУ оказалось недостаточно для его размещения. В этом случае изображение будет каждый раз декодироваться при запросе на его вывод на дисплей.
Потоковый вывод
Иногда требуется достичь максимальной скорости передачи информации в графический контроллер (в частности, при программировании анимации). Для ее достижения в uGFX предусмотрен потоковый вывод. Имеется ряд API-функций потокового вывода на дисплей, которые напрямую манипулируют с пикселями внутри прямоугольной области на экране. Чтобы использовать потоковый вывод, следует разрешить его, добавив в файл конфигурации следующую строку:
#define GDISP_NEED_STREAMING TRUE
Потоковый вывод складывается из трех шагов:
• Обозначить прямоугольную область, в которую будет осуществляться вывод, с помощью API-функции gdispStreamStart():
void gdispStreamStart(coord_t x, coord_t y, coord_t cx, coord_t cy);
где x, y — координаты верхнего левого угла области вывода; cx, cy — ее размер по горизонтали и вертикали.
• Вывести столько пикселей, сколько нужно в эту область, с помощью gdispStreamColor():
void gdispStreamColor(color_t color);
• Как только все пиксели переданы, завершить потоковый вывод, вызвав gdispStreamStop():
void gdispStreamStop();
Каждый вызов gdispStreamColor() будет автоматически сдвигать курсор на позицию следующего пикселя слева направо. Как только будет достигнут правый край области, курсор автоматически переместится на следующую строку сверху вниз.
Между началом потокового вывода (вызов gdispStreamStart()) и его окончанием (вызов gdispStreamStop()) не допускается вызов никаких API-функций, кроме gdispStreamColor() и gdispBlendColor(). Если вызов иной API-функции произойдет в параллельной задаче (в случае многозадачной среды выполнения uGFX), то параллельная задача будет приостановлена до завершения потокового вывода.
Для того чтобы оценить преимущество использования потокового вывода, автор сравнил время отрисовки всего дисплея размером 320x240 пикселей попиксельно с помощью gdispDrawPixel() и время заполнения этого же дисплея с помощью потокового вывода. Для аппаратной платформы [2] были получены следующие результаты: попик-сельное заполнение длилось 5,3 с, потоковый вывод — 0,55 с. То есть выигрыш в скорости составляет почти 10 (!) раз.
Другие функции рисования
Очистка дисплея
Под ней подразумевается заполнение всего дисплея выбранным цветом. Очистка осуществляется API-функцией gdispClear(), ее прототип:
void gdispClear(color_t color);
Аргумент color определяет фоновый цвет очищенного дисплея. При очистке дисплея не принимается в расчет заданная область обрезки — дисплей очищается полностью.
Обрезка изображения
В uGFX представлена возможность задать область обрезки изображения, то есть ограничить вывод каких-либо элементов изображения прямоугольником с заданными координатами и размером (рис. 21).
рис. 21. Принцип обрезки изображения
Для задания области обрезки служит АР1-функция gdispSetClip(), ее прототип.
Аргументы x0, у0 определяют координату верхнего левого угла области; cx, cy — ее размер по горизонтали и вертикали.
Для того чтобы убрать обрезку изображения, следует вызвать АР1-функцию gdispUnsetClip(), она не имеет аргументов и устанавливает область обрезки равной размеру дисплея.
По умолчанию обрезка разрешена; чтобы ее заблокировать, следует добавить в файл gfxconf.h^.
Это ускорит выполнение API-функций рисования, однако делать это следует с осторожностью, так как обрезка по размеру дисплея (исходное состояние) гарантирует, что uGFX не будет рисовать за пределами физического размера дисплея. Вывод же информации за пределами физического размера дисплея может привести к непредсказуемым последствиям, в зависимости от того, как на это отреагирует графический контроллер.
Прокрутка (скроллинг)
Скроллинг, или прокрутка, в uGFX представляет собой сдвиг содержимого прямоугольной области на дисплее на заданное количество пикселей по вертикали. При этом строки изображения, выходящие за обозначенную прямоугольную область, исчезают, а строки, появляющиеся с противоположной стороны прямоугольной области, заполняются заданным цветом.
Скроллинг выполняет API-функция gdispVerticalScroll():
Аргументы x, y, cx, cy определяют координаты верхнего левого угла и ширину/высоту прокручиваемой области. Аргумент lines определяет количество строк прокрутки (может быть положительным и отрицательным, что соответствует прокрутке вниз и вверх). Аргумент bgcolor задает цвет, которым заполняется появляющееся свободное пространство в области прокрутки (рис. 22).
Для того чтобы пользоваться функцией скроллинга, необходимо, чтобы драйвер и графический контроллер поддерживали функцию чтения цвета пикселей с дисплея. Кроме этого, скроллинг должен быть разрешен в конфигурационном файле gfxconf.h:
Управление отображением
В uGFX есть возможность с помощью высокоуровневых API-функций изменить некоторые параметры дисплея, такие как ориентация изображения, уровень подсветки и контраста. Перед использованием этих возможностей необходимо разрешить их с помощью макроопределения в конфигурационном файле gfxconf.h:
#define GDISP_NEED_CONTROL TRUE
Все эти возможности являются опциональными. Не каждый графический контроллер и не каждый драйвер поддерживают все возможности, приведенные ниже. Однако вызов API-функции, если драйвер не поддерживает соответствующую возможность, является безопасным — не будет выполнено никаких действий.
Поворот изображения
Предоставлена возможность повернуть изображение на экране на угол с шагом в 90°. Говоря другими словами, это возможность задать, какой из четырех углов дисплея будет соответствовать началу координат. Поддерживаются следующие ориентации изображения: портретная, альбомная и перевернутые портретная и альбомная ориентации. Поворот выполняется API-функцией gdispSetOrientation(), ее прототип:
void gdispSetOrientation(orientation_t orient);
Аргумент orient задает ориентацию и может принимать одно из значений перечисления orientation_t:
• GDISP_R0TATE_0 — без поворота, ориентация по умолчанию;
• GDISP_R0TATE_90 — поворот на 90° против часовой стрелки;
• GDISP_R0TATE_180 — поворот на 180° против часовой стрелки;
• GDISP_R0TATE_270 — поворот на 270° против часовой стрелки;
• GDISP_ROTATE_PORTRAIT — портретная ориентация, ширина изображения меньше высоты;
• GDISP_ROTATE_LANDSCAPE — альбомная ориентация, ширина изображения больше высоты.
Ориентация изображения по умолчанию может быть задана в конфигурационном файле, для этого должно быть задано значение макроопределения GDISP_DEFAULT_ORIENTATION в одно из значений перечисления orientation_t:
#define GDISP_DEFAULT_ORIENTATION GDISP_R0TATE_270
0,0, Хо с о к Л 3 а г с 1Г VI гея X
УоЭ
У' h с п fl с г 3 » а а К] а и л т е а л ь h с к \ \ р о о б к г 3 а в т 9 л р f П и Область прокрутки
рис. 22. Принцип прокрутки изображения
#define GDISP NEED SCROLL TRUE
void gdispSetClip(coord_t x0, coord_t y0, coord_t cx, coord_t cy);
#defne GDISP_NEED_CLIP FALSE
void gdispGVerticalScroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor);
Управление потреблением
Большинство графических контроллеров позволяют переходить в различные энергосберегающие режимы. В uGFX поддерживается четыре состояния: дисплей включен, дисплей выключен, режим сна и режим глубокого сна. Потребление электроэнергии и доступные функции для данного режима энергосбережения зависят от конкретного типа графического контроллера.
Переключение между энергосберегающими режимами выполняется API-функцией gdispSetPowerMode():
void gdispSetPowerMode(powermode_t mode);
Аргумент mode может принимать одно из значений перечисления powermode_t
• powerOn — питание включено, нормальная работа;
• powerSleep — режим сна;
• powerDeepSleep — режим глубокого сна;
• powerOff — питание выключено.
Подсветка и контраст
uGFX позволяет установить уровень подсветки дисплея (если такую функцию поддерживает драйвер). Для этого служит API-функция gdispSetBacklight():
void gdispSetBacklight(unsigned percent);
Аргумент percent задает уровень подсветки в процентах (0 — подсветка выключена, 100 — максимальный уровень подсветки).
Есть также возможность изменять контраст изображения с помощью API-функции gdispSetContrast():
void gdispSetContrast(unsigned percent);
Здесь аргумент тоже задается в процентах и может принимать значения от 0 до 100.
Текущий уровень подсветки и контраста можно получить с помощью API-функций gdispGetBacklight() и gdispGetContrast() соответственно.
Чтение размера дисплея
Для написания легко портируемых программ, которые могут работать с различными разрешениями дисплея, требуется наличие API-функций, возвращающих размеры дисплея в пикселях. В uGFX для этих целей служат:
• gdispGetWdith() — возвращает ширину дисплея в пикселях;
• gdispGetHeight() — возвращает высоту дисплея в пикселях.
Выводы
За рамками статьи осталась одна из важнейших функций модуля GDISP — вывод текста на дисплей. В следующей статье этот пробел будет заполнен. Речь пойдет о таких темах:
• задание шрифта для выводимого текста;
• поддержка Unicode;
• сглаживание и кернинг;
• добавление своего шрифта. ■
Литература
1. Курниц А. uGFX — графическая библиотека для микроконтроллеров // Компоненты и технологии. 2014. № 10.
2. Курниц А. uGFX — графическая библиотека для микроконтроллеров // Компоненты и технологии. Часть 2. 2014. № 11.
3. http://wiki.ugfx.org/
4. https://ш.wikipedia.org/wiki/Сглаживание
5. https://ru.wikipedia.org/wiki/Алгоритм_ Брезенхэма
6. https://ш.wikipedia.org/wiki/Вьшуклый_мнош-угольник
7. https://ru.wikipedia.org/wiki/BMP
8. https://ru.wikipedia.org/wiki/GIF