uGFX — графическая библиотека для микроконтроллеров.
Часть 3

№ 12’2014
PDF версия
Мы продолжаем знакомить читателей с графической библиотекой uGFX. В статье рассказано, как с помощью uGFX рисовать графические примитивы и выводить на дисплей изображения из графических файлов формата *.bmp и *.gif. Описаны другие возможности модуля GDISP. Статья сопровождается примерами программ и снимками экрана с результатами работы программ на микроконтроллере ARM Cortex-M3 [2].

Все статьи цикла

Модуль GDISP

Модуль GDISP предоставляет программисту простой интерфейс для вывода информации на графический дисплей и имеет богатый набор высокоуровневых API-функций, которые позволяют выводить:

  1. Графические примитивы (например, точка, линия, окружность, прямоугольник и т. д.).
  2. Текстовую информацию (с использованием различных шрифтов).
  3. Изображения в различных форматах (BMP, GIF, NATIVE).

При этом программисту не нужно знать особенности того или иного графического контроллера, задачу взаимодействия с контроллером берет на себя модуль GDISP (рис. 1). Вот почему один и тот же код может использоваться на различных аппаратных платформах.

Взаимодействие модуля GDISP с программой

Рис. 1. Взаимодействие модуля GDISP с программой

В то время как для работы большинства графических библиотек необходимо наличие кадрового буфера (framebuffer), библиотека uGFX, и модуль GDISP в частности, не требуют его наличия. Это позволяет подключать графические дисплеи к микроконтроллерам и другим системам с низкой производительностью, не имеющим достаточно памяти ОЗУ для хранения кадрового буфера.

Некоторые контроллеры графических дисплеев поддерживают аппаратное ускорение для вывода таких графических объектов, как окружности и эллипсы. В этом случае uGFX будет использовать ускорение выбранного контроллера. Если же графический контроллер не поддерживает аппаратное ускорение (в большинстве случаев это так), модуль GDISP эмулирует операции рисования, то есть рисует окружность по отдельным пикселям.

Более того, GDISP поддерживает вывод информации более чем на один дисплей, причем дисплеями могут управлять различные драйверы. Также предусмотрено применение одного или нескольких удаленных дисплеев. Эти возможности uGFX будут описаны в последующих статьях.

 

Типы данных

API-функции библиотеки uGFX принимают аргументы, имеющие тип, отличный от встроенных типов языка С. Это одно из требований по обеспечению независимости библиотеки uGFX от разрядности целевого микроконтроллера. Наиболее важные типы данных, определенные в uGFX, сведены в таблицу 1.

Таблица 1. Некоторые типы данных, используемые в uGFX

Название типа

Описание

coord_t

Целое число со знаком. Координата по вертикали или горизонтали. Размер элемента изображения в пикселях

point_t

Координаты точки на плоскости — пара переменных, имеющих тип coord_t

color_t

Цвет элемента изображения

GDisplay

Структура, определяющая дисплей и его параметры

font_t

Указатель на структуру, которая описывает шрифт

gdispImage

Структура, описывающая файл с изображением в одном из распространенных форматов (BMP, GIF)

bool_t

Логический тип, FALSE означает «ложь», TRUE — «истину»

size_t

Размер областей памяти. Смещение в файле

delaytime_t

Временная задержка, количество милли- или микросекунд

Встроенные целочисленные типы данных (int, char, long и т. д.) не используются, поскольку их размер зависит от разрядности целевого микроконтроллера. Вместо них в исходном коде uGFX применяются целочисленные типы из стандартной библиотеки языка С, определенные в заголовочном файле stdint.h (int8_t, uint32_t и др.). Их особенностью является точно известный занимаемый ими размер памяти и максимальное/минимальное значение, которое может принимать переменная с таким типом. Это также обеспечивает независимость uGFX от платформы, на которой она выполняется.

 

Соглашение об именах функций

Модуль 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_t y — координаты точки внутри окна.

 

Конфигурация и инициализация 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.

Таблица 2. Базовый набор цветов в uGFX

Цвет

Макроопределение

белый

White

черный

Black

серый

Gray, Grey

синий

Blue

красный

Red

пурпурный

Fuchsia, Magenta

зеленый

Green

желтый

Yellow

сене-зеленый

Aqua, Cyan

лайм

Lime

темно-бордовый

Maroon

хаки

Navy

оливковый

Olive

фиолетовый

Purple

серебро

Silver

темный сине-зеленый

Teal

оранжевый

Orange

розовый

Pink

небесно-голубой

SkyBlue

Предоставляется множество макросов для работы с цветом, позволяющих получить составляющие цвета, заданный цвет, а также смешать несколько цветов в один. Для получения цвета во внутреннем представлении из различных форматов служат следующие макросы:

  1. HTML2COLOR(h) — переводит 32‑битный цвет из формата, принятого в языке HTML, во внутренний формат, например HTML2COLOR (0xFF0000) соответствует красному цвету.
  2. RGB2COLOR(r, g, b) — возвращает цвет, заданный тремя составляющими: красной, зеленой и синей, каждая составляющая может принимать значения в диапазоне 0…255.
  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(), ее прототип:

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);

Функция работает грубо — устанавливает значение красной, зеленой и синей составляющих цвета в максимальное или минимальное значение, если те превышают некоторый порог в исходном цвете. В итоге результат выполнения gdispContrastColor() — один из восьми цветов (черный, белый, красный, желтый и т. д.).

 

Система координат

В uGFX используется общепринятая в машинной графике декартова система координат с началом отсчета в верхнем левом углу (рис. 2).

Принятая в uGFX система координат

Рис. 2. Принятая в uGFX система координат

Для координат по оси абсцисс и ординат в файле \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).

Рисование точки

Рис. 3. Рисование точки

Рисование точки осуществляется API-функцией gdispDrawPixel(), ее прототип:

void gdispDrawPixel(coord_t x0, coord_t y0, color_t color);

Аргументы x0, y0 определяют координаты выводимой точки, а color — ее цвет.

Тонкая линия

Рисование тонкой линии (шириной в один пиксель — рис. 4) осуществляется API-функцией gdispDrawLine(), ее прототип:

Рисование тонкой линии

Рис. 4. Рисование тонкой линии

void gdispDrawLine(coord_t x1, coord_t y1, coord_t x2, coord_t y2, color_t color);

Аргументы x1, y1 задают координаты одного конца линии, x2, y2 — координаты второго конца, а color определяет цвет линии.

К недостаткам uGFX можно отнести отсутствие поддержки сглаживания отображаемых линий [4]. Для построения линий применен быстрый алгоритм Брезенхэма [5], особенностью которого является появление эффекта «зубчатости» (рис. 4) у наклонных линий.

Толстая линия

Зачастую необходимо отобразить линию, имеющую толщину более одного пикселя. Для этой цели предназначена API-функция gdispDrawThickLine(), ее прототип:

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

Прямоугольник

uGFX предоставляет возможность отобразить прямоугольник в виде рамки толщиной в 1 пиксель, причем старое изображение внутри прямоугольника не изменяется. Для этого служит 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 определяет цвет рамки прямоугольника.

Рисование прямоугольника

Рис. 6. Рисование прямоугольника

Рисование закрашенного прямоугольника (рис. 7) подобно рисованию обычного, рассмотренного выше. Единственное отличие заключается в том, что область внутри прямоугольника закрашивается заданным цветом. Производится API-функцией gdispFillArea(), ее прототип не отличается от API-функции gdispDrawBox():

Рисование закрашенного прямоугольника

Рис. 7. Рисование закрашенного прямоугольника

void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color);

Прямоугольник со скругленными углами

В uGFX есть также возможность нарисовать прямоугольник со скругленными углами. Для этого предназначены API-функции gdispDrawRoundedBox(), gdispFillRoundedBox(). Первая рисует незакрашенный, вторая — закрашенный прямоугольник со скругленными углами, прототипы у них одинаковые:

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);

По сравнению с соответствующими API-функциями для рисования «простого» прямоугольника появился новый аргумент radius, который определяет радиус закруглений в пикселях (рис. 8, 9).

Прямоугольник со скругленными углами

Рис. 8. Прямоугольник со скругленными углами

Закрашенный прямоугольник со скругленными углами

Рис. 9. Закрашенный прямоугольник со скругленными углами

Окружность и круг

Для рисования обычной окружности (рис. 10) толщиной в 1 пиксель служит API-функция gdispDrawCircle(), ее прототип:

Рисование окружности

Рис. 10. Рисование окружности

void gdispDrawCircle(coord_t x0, coord_t y0, coord_t radius, color_t color);

Аргументы x0, y0 задают центр окружности, radius — ее радиус в пикселях, color — ее цвет.

Рисование круга (закрашенная окружность) показано на рис. 11, выполняется API-функцией gdispFillCircle(), ее прототип:

Рисование круга

Рис. 11. Рисование круга

void gdispFillCircle(coord_t x0, coord_t y0, coord_t radius, color_t color);

Назначение аргументов то же, что и у функции gdispDrawCircle().

В конфигурационном файле gfxconf.h должно быть разрешено рисование окружностей и кругов, то есть задано макроопределение:

#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. Рисование дуги

Рисование сектора (рис. 13) подобно рисованию дуги, выполняется API-функцией gdispFillArc(), ее прототип не отличается от рассмотренной выше gdispDrawArc():

Рисование сектора

Рис. 13. Рисование сектора

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(), закрашенного — gdispFillEllipse(), их прототипы одинаковы:

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 определяет цвет эллипса.

Рисование эллипса

Рис. 14. Рисование эллипса

Рисование закрашенного эллипса

Рис. 15. Рисование закрашенного эллипса

Возможность рисовать эллипсы может быть включена в конфигурационном файле gfxconf.h:

#define GDISP_NEED_ELLIPSE                   TRUE

Многоугольник (полигон)

В uGFX предоставлена возможность выводить произвольные многоугольники, заданные координатами своих вершин. Многоугольники могут быть как закрашенными, так и в виде рамки, причем в случае закрашенного допускается только выпуклый многоугольник [6].

Рисование произвольного обычного многоугольника осуществляет API-функция gdispDrawPoly(), а рисование закрашенного многоугольника — gdispFillConvexPoly(), прототипы у них одинаковые:

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 определяет размер массива. Каждая точка в массиве содержит координаты относительно центра многоугольника (рис. 16). Центр многоугольника может быть выбран произвольно, однако целесообразно поместить его либо в центр многоугольника, либо на ребро, либо на вершину. Пара аргументов (tx, ty) определяет координаты центра многоугольника при выводе его на экран.

Рисование многоугольника

Рис. 16. Рисование многоугольника

Особенность uGFX состоит в том, что на рисование закрашенного многоугольника накладывается ограничение — он должен быть выпуклым. Если попытаться вывести закрашенный невыпуклый многоугольник, то uGFX все-таки его выведет, но сделает его незакрашенным (рис. 17).

Рисование закрашенного многоугольника

Рис. 17. Рисование закрашенного многоугольника

Разрешить возможность рисования многоугольников можно в конфигурационном файле gfxconf.h:

#define GDISP_NEED_CONVEX_POLYGON                        TRUE

Пример программы

Ниже приведена программа, демонстрирующая применение описанных выше API-функций вывода графических примитивов. Программа была скомпилирована для микроконтроллера STM32F100RB и дисплея разрешением 240×320 пикселей, управляемого графическим контроллером ILI9341. Подробно о данной аппаратной платформе написано в [2].

#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();

    // Установить альбомную ориентацию дисплея
    gdispSetOrientation(GDISP_ROTATE_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());
    }

    // Толстая линия
    gdispDrawThickLine(220, 10, 300, 10, RANDOM_COLOR(), 5, FALSE);
    gdispDrawThickLine(220, 30, 300, 30, RANDOM_COLOR(), 10, TRUE);
    gdispDrawThickLine(220, 60, 300, 60, RANDOM_COLOR(), 20, FALSE);
    gdispDrawThickLine(220, 85, 300, 85, RANDOM_COLOR(), 20, TRUE);

// Прямоугольники
    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 приведен результат работы программы непосредственно на устройстве.

Вывод графических примитивов на дисплей, управляемый контроллером ILI9341

Рис. 18. Вывод графических примитивов на дисплей, управляемый контроллером ILI9341

 

Растровые изображения

В модуль 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 — аппаратно-зависимый формат хранения изображения, оптимизированный для данного графического контроллера. Содержит заголовок минимального размера (8 байт), за которым следует массив пикселей, где каждый пиксель записан в формате представления для выбранного графического контроллера. Формат отличается максимально быстрым выводом изображения на дисплей и минимально возможным потреблением памяти. Идеально подходит для хранения изображений во встроенной флэш-памяти.

В будущем планируется добавление поддержки таких распространенных форматов, как *.png и *.jpg.

Отдельно следует сказать о формате NATIVE. Библиотека uGFX предоставляет возможность его отображения, но на официальном сайте [3] автор не нашел описания того, как этот графический формат может быть получен (указывается лишь значение полей его заголовка). Видимо, предполагается, что программист должен сам создать утилиту для конвертирования в формат NATIVE с учетом представления цвета пикселей в выбранном дисплее и графическом контроллере.

Поддержка каждого формата и каждой его разновидности может быть индивидуально разрешена или запрещена с помощью конфигурационного файла gfxconf.h. Запрещать поддержку неиспользуемых форматов следует для экономии памяти программ микроконтроллера. Например, для того чтобы выводить изображения в формате *.bmp, конфигурационный файл должен содержать следующие строки:

#define GDISP_NEED_IMAGE             TRUE
#define GDISP_NEED_IMAGE_BMP         TRUE

При этом все другие форматы автоматически будут запрещены, а все разновидности bmp-формата — разрешены.

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

Пример программы

Простейшая программа, выводящая изображение на дисплей:

#include “gfx.h”
static gdispImage myImage;
int main(void) {
    coord_t     swidth, sheight;

    // Инициализация библиотеки uGFX
    gfxInit();

    // Получить размер дисплея
    // Ширина
    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

// Разрешить работу с BMP-изображениями
#define GDISP_NEED_IMAGE                      TRUE
#define GDISP_NEED_IMAGE_BMP                  TRUE

// Использовать модуль GFILE
#define GFX_USE_GFILE                         TRUE

// Использовать файловую систему ROMFS
#define GFILE_NEED_ROMFS                      TRUE

#endif /* _GFXCONF_H */

Особо следует обратить внимание на активацию файловой системы ROMFS, подробно о которой написано далее. Результат работы программы на аппаратной платформе, указанной ранее (подробнее о ней в [2]), приведен на рис. 19.

Вывод изображения в формате BMP 8 бит на пиксель

Рис. 19. Вывод изображения в формате BMP 8 бит на пиксель

Вывод изображения

Вывод изображения (рис. 20) осуществляется API-функцией gdispImageDraw(), ее прототип:

Принцип вывода изображения на дисплей

Рис. 20. Принцип вывода изображения на дисплей

gdispImageError gdispImageDraw(gdispImage *img, coord_t x0, coord_t y0, coord_t cx, coord_t cy, coord_t sx, coord_t sy);

Аргументы:

  • gdispImage *img— указатель на структуру gdispImage, которая описывает открытое изображение. Предварительно этот указатель должен быть получен при открытии файла с изображением API-функцией gdispImageOpenFile().
  • coord_t x0, coord_t y0— координаты верхнего левого угла выводимого изображения на дисплее.
  • coord_t cx, coord_t cy— размер соответственно по горизонтали и вертикали области на дисплее, в которую будет выведено изображение. Если изображение выходит за пределы этой области, оно будет обрезано. Если изображение меньше этой области, оставшаяся часть дисплея останется нетронутой.
  • coord_t sx, coord_t sy— смещение соответственно по горизонтали и вертикали внутри изображения (от левого верхнего угла), начиная с которого изображение будет выводиться на экран.

Возможность задавать размер области, куда выводится изображение, и смещение внутри изображения позволяет организовать хранение нескольких изображений меньшего размера в одном изображении большего размера. Изображения меньшего размера могут быть, например, изображениями кнопок управления в графическом интерфейсе пользователя.

Если изображение не выводится на дисплей, следует проверить возвращаемое значение для каждой вызываемой API-функции на предмет кода ошибки. Причиной неудавшегося вывода изображения может быть:

  • соответствующий декодер не разрешен в конфигурационном файле;
  • файл с изображением не может быть открыт;
  • недостаточно памяти ОЗУ для декодирования изображения.

Открытие изображения

Интерес представляет открытие файла, которое производится API-функцией gdispImageOpenFile(), ее прототип:

gdispImageError gdispImageOpenFile(gdispImage *img, const char *fname);

Аргументы:

  • gdispImage *img — указатель на структуру gdispImage, в которую будет помещена информация об открытом файле с изображением.
  • 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_testpal8.h, который следует включить в проект, добавив в специальный файл romfs_files.h следующую строку:

// Включить файл “test-pal8.bmp” в файловую систему ROMFS
#include “romfs_testpal8.h”

Для работы с файловой системой ROMFS она должна быть активирована в конфигурационном файле gfxconf.h:

#define GFX_USE_GFILE         TRUE
#define GFILE_NEED_ROMFS      TRUE

Закрытие изображения

Производится API-функцией 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]).

Если программист решил кешировать изображение целиком в памяти ОЗУ (этого не следует делать на микроконтроллерах с малым объемом ОЗУ). Например, хранение изображения размером 320240 пикселей с глубиной цвета 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), то параллельная задача будет приостановлена до завершения потокового вывода.

Для того чтобы оценить преимущество использования потокового вывода, автор сравнил время отрисовки всего дисплея размером 320240 пикселей попиксельно с помощью gdispDrawPixel() и время заполнения этого же дисплея с помощью потокового вывода. Для аппаратной платформы [2] были получены следующие результаты: попиксельное заполнение длилось 5,3 с, потоковый вывод — 0,55 с. То есть выигрыш в скорости составляет почти 10 (!) раз.

 

Другие функции рисования

Очистка дисплея

Под ней подразумевается заполнение всего дисплея выбранным цветом. Очистка осуществляется API-функцией gdispClear(), ее прототип:

void gdispClear(color_t color);

Аргумент color определяет фоновый цвет очищенного дисплея. При очистке дисплея не принимается в расчет заданная область обрезки — дисплей очищается полностью.

Обрезка изображения

В uGFX представлена возможность задать область обрезки изображения, то есть ограничить вывод каких-либо элементов изображения прямоугольником с заданными координатами и размером (рис. 21).

Принцип обрезки изображения

Рис. 21. Принцип обрезки изображения

Для задания области обрезки служит API-функция gdispSetClip(), ее прототип:

void gdispSetClip(coord_t x0, coord_t y0, coord_t cx, coord_t cy);

Аргументы x0, y0 определяют координату верхнего левого угла области; cx, cy — ее размер по горизонтали и вертикали.

Для того чтобы убрать обрезку изображения, следует вызвать API-функцию gdispUnsetClip(), она не имеет аргументов и устанавливает область обрезки равной размеру дисплея.

По умолчанию обрезка разрешена; чтобы ее заблокировать, следует добавить в файл gfxconf.h:

#define GDISP_NEED_CLIP            FALSE

Это ускорит выполнение API-функций рисования, однако делать это следует с осторожностью, так как обрезка по размеру дисплея (исходное состояние) гарантирует, что uGFX не будет рисовать за пределами физического размера дисплея. Вывод же информации за пределами физического размера дисплея может привести к непредсказуемым последствиям, в зависимости от того, как на это отреагирует графический контроллер.

Прокрутка (скроллинг)

Скроллинг, или прокрутка, в uGFX представляет собой сдвиг содержимого прямоугольной области на дисплее на заданное количество пикселей по вертикали. При этом строки изображения, выходящие за обозначенную прямоугольную область, исчезают, а строки, появляющиеся с противоположной стороны прямоугольной области, заполняются заданным цветом.

Скроллинг выполняет API-функция gdispVerticalScroll():

void gdispGVerticalScroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor);

Аргументы x, y, cx, cy определяют координаты верхнего левого угла и ширину/высоту прокручиваемой области. Аргумент lines определяет количество строк прокрутки (может быть положительным и отрицательным, что соответствует прокрутке вниз и вверх). Аргумент bgcolor задает цвет, которым заполняется появляющееся свободное пространство в области прокрутки (рис. 22).

Принцип прокрутки изображения

Рис. 22. Принцип прокрутки изображения

Для того чтобы пользоваться функцией скроллинга, необходимо, чтобы драйвер и графический контроллер поддерживали функцию чтения цвета пикселей с дисплея. Кроме этого, скроллинг должен быть разрешен в конфигурационном файле gfxconf.h:

#define GDISP_NEED_SCROLL              TRUE

Управление отображением

В uGFX есть возможность с помощью высокоуровневых API-функций изменить некоторые параметры дисплея, такие как ориентация изображения, уровень подсветки и контраста. Перед использованием этих возможностей необходимо разрешить их с помощью макроопределения в конфигурационном файле gfxconf.h:

#define GDISP_NEED_CONTROL          TRUE

Все эти возможности являются опциональными. Не каждый графический контроллер и не каждый драйвер поддерживают все возможности, приведенные ниже. Однако вызов API-функции, если драйвер не поддерживает соответствующую возможность, является безопасным — не будет выполнено никаких действий.

Поворот изображения

Предоставлена возможность повернуть изображение на экране на угол с шагом в 90°. Говоря другими словами, это возможность задать, какой из четырех углов дисплея будет соответствовать началу координат. Поддерживаются следующие ориентации изображения: портретная, альбомная и перевернутые портретная и альбомная ориентации. Поворот выполняется API-функцией gdispSetOrientation(), ее прототип:

void gdispSetOrientation(orientation_t orient);

Аргумент orient задает ориентацию и может принимать одно из значений перечисления orientation_t:

  • GDISP_ROTATE_0 — без поворота, ориентация по умолчанию;
  • GDISP_ROTATE_90 — поворот на 90° против часовой стрелки;
  • GDISP_ROTATE_180 — поворот на 180° против часовой стрелки;
  • GDISP_ROTATE_270 — поворот на 270° против часовой стрелки;
  • GDISP_ROTATE_PORTRAIT — портретная ориентация, ширина изображения меньше высоты;
  • GDISP_ROTATE_LANDSCAPE — альбомная ориентация, ширина изображения больше высоты.

Ориентация изображения по умолчанию может быть задана в конфигурационном файле, для этого должно быть задано значение макроопределения GDISP_DEFAULT_ORIENTATION в одно из значений перечисления orientation_t:

#define  GDISP_DEFAULT_ORIENTATION    GDISP_ROTATE_270

Управление потреблением

Большинство графических контроллеров позволяют переходить в различные энерго-сберегающие режимы. В 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://ru.wikipedia.org/wiki/Сглаживание
  5. https://ru.wikipedia.org/wiki/Алгоритм_Брезенхэма
  6. https://ru.wikipedia.org/wiki/Выпуклый_многоугольник
  7. https://ru.wikipedia.org/wiki/BMP
  8. https://ru.wikipedia.org/wiki/GIF

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *