Урок 7 – графическая библиотека для дисплея st7783

MakiseGUI — бесплатная библиотека графического интерфейса для микроконтроллеров

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

Назвал я её MakiseGui.

Перед началом разработки я поставил себе цели:

  • Простота конечной разработки. Писать интерфейс не должно быть сложнее, чем используя WindowsForms и тп
  • Простота интеграции. Встроить и запустить интерфейс в приложении должно быть максимально просто на любом железе или ПО.
  • Чистый Си. Был использован только gnu-c99 и из библиотек только stdlib
  • Минимальное потребление RAM. Возможность использования на средних микроконтроллерах без внешней памяти(примерно 40kb с цветным дисплеем 320х240).
  • Достаточное количество графических элементов для комфортной разработки. Простое добавление новых.
  • opensource лицензия и бесплатное использование даже в коммерческих проектах

Пример без объяснений

В качестве демонстрации возможностей библиотеки и примеров использования может быть использован проект созданный специально для этих целей: https://github.com/SL-RU/MakiseSDLTest

Он использует SDL2 для отрисовки и ввода и имеет примеры использования всех элементов и почти всех функций системы. Может быть скомпиллирован и запущен на любом linux дистрибутиве. На windows тоже, но лишь теоретически — сам не пробовал.

Видео работы:

Структура

Библиотека состоит из трёх чётко разделённых частей:

1) Ядро. Ядро состоит из интерфейса к драйверу, функций отрисовки в драйвер и функций отрисовки примитивов в буфер.

2) Драйвер. Драйвер обеспечивает всё общение с железом и с ПО, поэтому под каждую задачу придётся писать обычно свой, чтобы учесть все моменты(DMA, прерывания и тд).

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

Ядро и драйвер могут работать отдельно, без GUI.

3) Сам GUI. Занимает бОльшую часть системы, тут воплощены все необходимые функции для работы интерфейса: контейнеры, элементы, системы отрисовки, фокуса, ввода, обработки событий и прочего.

GUI

Разработка графического интерфейса максимально приближена к объектно-ориентированному для максимальной простоты конечного программирования. Благодаря этому она имеет некоторые приятные особенности

Простейший пример, создающий кнопку на экране:

MHost host; //базовая структура системы, root-контейнер, содержащий все другие контейнеры и элементы. //метод будет вызыван при нажатии на кнопку
void click(MButton *b)
{ printf(“Button was clicked”); //выводим сообщение в стандартный поток b->text = “Clicked!”; //меняем текст кнопки }
MButton button; //структура, содержащая всю информацию о кнопке
void create_gui()
{ //создаём кнопку m_create_button(&button, //указатель на структуру кнопки host->host, //контейнер, в который будет добавлена кнопка после создания. В данном случае это контейнер MHost'a mp_rel(20, 20, //координаты элемента относительно левого верхнего угла 90, 30), //ширина, высота “Click me”, //текст кнопки //События &click, //Вызывается при нажатии на кнопку 0, //Вызывается до обработки нажатия, может прервать обработку нажатия 0, //Вызывается при действиях с фокусом кнопки &ts_button //стиль кнопки );
} void main()
{ //тут была инициализация MakiseGui, драйвера, MakiseBuffer и MHost. Запуск драйвера. create_gui(); while(1) { //драйвер вызывает функции рисовки //совершается ввод //и логика }
}

Итого, этот пример создаёт на экране кнопку при нажатии на которую в стандартном потоке вывода появится надпись “Button was clicked” и текст кнопки изменится.

Инициализация

Инициализация предполагает только лишь запуск драйвера, задание размеров и выделение памяти для структур и буферов элементов. Чисто формальная операция. Как инициализировать систему можно поглядеть тут: https://github.com/SL-RU/MakiseSDLTest/blob/master/src/main.c в методе start_m();

Для начала использования GUI нужно создать makise_config.h и сконфигурировать его. В этом файле задаются системные дефайны и выбираются нужные драйверы дисплея. https://github.com/SL-RU/MakiseSDLTest/blob/master/makise_config.h

Ввод

Ввод приспособлен для работы в мультипоточных приложениях — он имеет очередь событий, которые посылаются интерфейсу при вызове makise_gui_input_perform(host);

Любое событие ввода представлено структурой MInputData.

Возможен ввод кнопок(список стандартных в makise_gui_input.h MInputKeyEnum), символов(пока нигде не используется) и ввод курсора(сенсорный экран или мышь). В примере с SDL используется ввод с клавиатуры и ввод мышью.

Контейнеры

MContainer — структура контейнера.

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

Позиция элемента в контейнере прямо влияет на очередь отрисовки и ввода.

Линкованый список осуществляется при помощи указателей на первый и последний элемент списка MElement и в структуре MElement имеются указатели на следующий и предыдущий элемент.

Элементы

Любой элемент представлен ввиде структуры MElement, которая содержит в себе информацию о элементе, указатели на функции отрисовки, ввода, фокуса и тд элемента и указатель на его содержимое.

На данный момент существуют следующие элементы:

  • MButton — кнопка. Которая отображает текст посылает события при нажатии
  • MCanvas — простейший контейнер, который просто содержит элементы.
  • MLable — простейшее текстовое поле
  • MTextField — текстовое поле, поддерживающее перенос слов и переносы
  • MSlider — слайдер
  • MToggle — кнопка имеющая два состояния.
  • MSList — список. Может быть как просто списком, так и radio-кнопками, так и чекбосками. Поддерживает обычные списки и динамические линкованные.
  • MTabs — вкладки. Несколько переключаемых контейнеров.

Лучшей документацией являются примеры, поэтому для каждого элемента есть свои примеры использования. Как сложные, так и простые.

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

Стили

Стиль элемента определяет его внешний вид. Cтиль задаёт цвета элемента в определённом состоянии. За это отвечают структуры MakiseStyle и MakiseStyleTheme. MakiseStyle содержит несколько MakiseStyleTheme для определённых состояний, а так же параметры шрифта.

Для кнопки стиль может выглядеть так:

MakiseStyle ts_button =
{ MC_White, //основной цвет. Не несёт никакого значения &F_Arial24,//Шрифт стиля 0, //межстрочное расстояние //цвет заднего фона | шрифта бортик есть ли двойной бортик {MC_Black, MC_Gray, MC_Gray, 0 }, //когда кнопка не активна {MC_Black, MC_White, MC_White, 0 }, //нормальное состояние {MC_White, MC_Green, MC_White, 0 }, //в фокусе {MC_Green, MC_White, MC_White, 0 }, //когда была кликнута
};

Фокус

Фокус определяет к какому элементу пойдёт ввод. Для управления фокусом существуют следующие функции:

MFocusEnum makise_g_focus(MElement *el, MFocusEnum event); //фокусирует или расфокусирует нужный элемент
MFocusEnum makise_g_host_focus_next(MHost *host);//переведёт фокус на следующий по очереди элемент
MFocusEnum makise_g_host_focus_prev(MHost *host);//на предыдущий

Пример работы на микроконтроллере

Так же был написан пример библиотеки для STM32 микроконтроллеров. Был использован МК STM32f437VGT6 с тактовой частотой 180МГц и 2.2″ дисплей 230х320 пикселей на контроллере ILI9341. Управления с компьютерной клавиатуры по UART.

Код примера: https://github.com/SL-RU/MakiseILI9341Test

Видео примера:

Немножко документации есть в репозитории. Но вся основная документация находиться в комментариях к функциям и в примерах. Задавайте вопросы! На основе них я буду дописывать документацию.

Много моментов не было затронуто в статье или затронуто мимоходом.

Если статья найдёт популярность, то с удовольствием напишу ещё несколько, например про создание драйвера для STM32 + tft дисплей, подключенный по FSMC для данного GUI.

Есть много моментов которые нужно совершенствовать в библиотеки и есть много путей развития. Но на данный момент библиотека является совершенно рабочей и стабильной.

Лицензия проекта — MIT. Вы можете использовать библиотеку и исходный код как хотите и где хотите, даже использовать без проблем в коммерческих проектах, но в то же время я не даю никаких гарантий по работе библиотеки — всё как есть.

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

Буду рад вопросам и пожеланиям!

Источник: https://habr.com/post/325692/

Free Simple HX8352 Graphics Library

Источник: http://hobby-research.at.ua/publ/stati/mikrokontrollery/8-1-0-36

AVR библиотека для LCD с произвольным подключением выводов

Введение

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

Особенности

– работает с компиляторами IAR AVR, CodeVision AVR, GNU GCC,
– поддерживает lcd контроллеры HD44780 и KS0066,
– поддерживает подключение lcd к произвольным выводом микроконтроллера,
– поддерживает 4-х и 8-ми разрядный интерфейс,
– имеет функции вывода строк из ОЗУ и флэш,
– имеет функции добавление пользовательских символов.

Состав библиотеки

compilers_4.h – файл для поддержки трех компиляторов
port_macros.h – макросы виртуальных портов
lcd_lib_2.h – заголовочный файл LCD библиотеки с прототипами функций и настройками
lcd_lib_2.c – файл реализации функций LCD библиотеки

Подключение к проекту

1. Переписываем все файлы библиотеки в папку проекта.
2. Подключаем lcd_lib_2.c к проекту внутри среды разработки.
3. Инклюдим заголовочный файл lcd_lib_2.h к сишному файлу, в котором будут использоваться lcd функции.
4. Настраиваем конфигурацию lcd библиотеки в заголовочном файле lcd_lib_2.h
5. Прописываем в код вызов функций lcd библиотеки.

Настройка конфигурации

   Настройка конфигурации в файле lcd_lib_2.h включает в себя следующие шаги.   1. Настройка виртуального или реального порта, к которому подключается LCD

   Синтаксис объявления виртуального порта подробно описан в файле port_macros.h и в статье посвященной виртуальным портам. В заголовочном файле lcd_lib_2.

h уже объявлен порт, в этих объявления нужно менять только буквы порта (A, B, C..), номера выводов (0, 1, 2, 3 …), тип порта (_REAL, _VIRT), активный уровень (_HI, _NONE). Все остальное (имя порта и имена выводов) трогать не надо. Пример объявление виртуального порта для 8-ми битной шины и реального порта для 4-х битной шины.

   Рамками выделены те части кода, которые нужно настраивать под свой проект. 

   2. Глобальные настройки драйвера

LCD_CHECK_FL_BF – проверять флаг BF или использовать программную задержку. 0 – задержка, 1 – проверка флага.

LCD_BUS_4_8_BIT – используемая шина данных. 0 – 4 разрядная шина, 1 – 8-ми разрядная

   3. Настройка инициализации дисплея

Эти настройки определяют состояние дисплей после вызова функции LCD_Init().

LCD_ONE_TWO_LINE – количество отображаемых строк. 0 – 1 строка; 1 – 2 строки.

LCD_FONT58_FONT511 – тип шрифта. 0 – 5х8 точек; 1 – 5х11 точек.

LCD_DEC_INC_DDRAM – изменения адреса ОЗУ при выводе на дисплей. 0 – курсор движется влево, адрес уменьшается на 1 (текст получается задом наперед) ; 1 – курсор движется вправо, адрес увеличивается на 1.

LCD_SHIFT_RIGHT_LEFT – сдвиг всего дисплея. 0 – при чтении ОЗУ сдвиг не выполняется, 1 – при записи в ОЗУ сдвиг дисплея выполняется согласно установке LCD_DEC_INC_DDRAM (0 – сдвиг вправо, 1 – сдвиг влево)

LCD_DISPLAY_OFF_ON – включение / выключение дисплея. 0 – дисплей выключен, но данные в ОЗУ остаются; 1 – дисплей включен.

LCD_CURSOR_OFF_ON – отображение подчеркивающего курсора. 0 – курсор не отображается, 1 – курсор отображается.

LCD_CURSOR_BLINK_OFF_ON – отображение мигающего курсора. 0 – мигающий курсор не отображается; 1 – мигающий курсор отображается.

LCD_CURSOR_DISPLAY_SHIFT – команда сдвига вправо/влево курсора или дисплея без записи на дисплей. В библиотеке не используется и ни на что не влияет. Затесалась сюда случайно )

Источник: http://chipenable.ru/index.php/item/159

Урок 1: iBoard Pro и дисплейный модуль – калибровка тачскрина, работа с RTC (часы)

Для сегодняшнего урока нам потребуется:

В результате нашего урока должно получиться примерно следующее:

Обратите внимание, что для корректной работы модулю часов реального времени (RTC) обязательно требуется резервная батарейка (очень желательно иметь “свежую” батарейку, чтобы не отлавливать “глюки” в работе часиков, связанную с разряженным резервным источником питания). 

Для установки этого резервного источника питания RTC на плате iBoard Pro предусмотрен соответствующий слот. Подходит батарейка CR1225 или CR1220.

Плата iBoard Pro с установленным дисплеем является серьезным потребителем электричества (и питания от USB-порта точно не хватит) – возьмите подходящий блок питания (например, от ноутбука с подходящим напряжением и разъемом).

В анонсе мы озвучили, что будем использовать дисплей ITDB02-2.

4E, но при подготовке было решено, что для большей наглядности (и чтобы не ломать глаза мелким шрифтом), воспользуемся другим, более крупным дисплеем ITDB02-3.2S (по возможностям он полностью идентичный: то же разрешение 320*240, но обладает экранчиком в 3.2 дюйма по диагонали).

В скетчах будут присутствовать строки для подключения как “маленького”, так и “большого” дисплея – достаточно будет закомментировать одну строчку и раскомментировать – другую. Итак, начинаем.

Сначала необходимо скачать и установить необходимые библиотеки:

  • UTFT – библиотека для работы с TFT-дисплеем
  • UTouch – библиотека для работы с тач-скрином
  • RTC – библиотека для модуля часов реального времени

Установка библиотек очень простая – загруженные файлы с библиотеками нужно распаковать (появятся одноименные папки) и эти папки поместить в каталог libraries внутри каталога arduino  (со средой разработки). Если Arduino IDE был запущен в процессе установки – то необходимо будет его перезапустить, чтобы библиотеки “подхватились”.

Если все сделали правильно, то в IDE через меню “File”-“Examples” (Файл – Примеры) будут доступны примеры соответствующих библиотек.

Теперь можно подключить к компьютеру USB-кабель и к нему – программатор FOCA. Система автоматически определит оборудование и установит необходимые драйвера (для Windows, в MacOS никакой дополнительной установки драйверов не требуется). 

Можно установить дисплейный модуль на плату iBoard Pro (обращайте внимание на совпадение нумерации на плате дисплея и на “материнской” плате).

Для калибровки необходимо открыть пример UTouch_Calibration (“File”-“Examples” – “UTouch” – “Arduino”).

В примере присутствуют строчки:

В первой строке указываются параметры инициализации дисплея, во второй – модуля тачскрина.

В нашем случае их необходимо изменить следующим образом:

Для дисплея ITDB02-2.4E (8 битный режим):
 Для дисплея ITDB02-2.4E (16 битный режим):
После корректировки скетч можно залить в плату. Если все сделано верно – на экране появится инструкция, как произвести калибровку (потребуется тонкий стилус или можно воспользоваться, например, деревянной зубочисткой.).

Результатом работы скетча будет примерно следующее изображение на экране:В нижней части отображаются калибровочные коэффициенты (зависящие от конкретного экземпляра дисплейного модуля). Эти данные необходимо ввести в файл UTouchCD.h (файл находится в папке arduinolibrariesUTouch).

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

Для проверки следует воспользоваться скетчем UTouch_ButtonTest (естественно, надо подправить конфигурационные строчки, как мы это сделали ранее). Скетч позволяет проверить точность калибровки (нажимая на экранные кнопки).

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

Сразу проверим, что все работает правильно. Для этого откроем в Arduino IDE пример для DS1307 (“File”-“Examples” – “RTClib” – “ds1307”). 

Никаких изменений в этом примере производить не требуется. 

После загрузки скетча в нашу плату можно открыть монитор последовательного порта и если все сделано правильно (и модуль часов работает правильно) – появятся строчки типа:

Таким образом, видно, что часы уже идут (в первой строчке должны отображаться правильные данные о времени и дате) и можно производить с этими данными различные вычисления.

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

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

  1. Создаем в Arduino IDE новый скетч (File – New)
  2. Сохраняем его (пусть он пока будет пустой). Имя файла произвольное (пусть будет “iBoardPro”)
  3. Создадим в нашем проекте еще несколько файлов (rtc, graphics) – для этого проще всего воспользоваться клавиатурным сокращением Ctrl+Shift+N и ввести соответствующее имя файла.

Если все сделано правильно, то ваша среда разработки будет выглядеть примерно так:

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

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

Результатом нашего первого урока должен стать скетч, который бы красиво отображал текущее время (которое мы получим от модуля RTC) на экране в любом месте. Аналогичная задача у нас стоит и по отображению текущей даты.

В нашей графической библиотеке создадим функцию time2display с несколькими входными параметрами:

  • смещение по x
  • смещение по y
  • секунды (флаг, указывающий, нужно ли выводить секунды)
  • цвет (составляющая R)
  • цвет (составляющая G)
  • цвет (составляющая B)

Таким образом, вызов этой функции с соответствующими параметрами позволит нам в дальнейшем выводить часы на текущем фоне нужного цвета и желаемого вида (с секундами или без).
Для большего эффекта добавим “моргание” разделителя между часами и минутами.

Аналогично сделаем функцию date2display. Входные параметры следующие:

  • смещение по x
  • смещение по y
  • день недели (флаг, указывающий, нужно ли выводить день недели)
  • цвет (составляющая R)
  • цвет (составляющая G)
  • цвет (составляющая B)
  • шрифт (SmallFont или BigFont)

Для отрисовки экрана создадим функцию myDisplay. Временно эту функцию сделаем предельно простой – включим туда вызовы наших функций для вывода времени и даты в разных вариантах. Позже мы эту функцию модифицируем.

Теперь достаточно написать простую функцию setup(), где производим инициализацию всей используемой периферии:

И простую функцию loop() – основной цикл:
Если все сделано правильно, увидим картинку, схожую с этой:

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

Материалы по нашему уроку (тестовые и результирующий скетч) можно скачать по ссылке.

Продолжение следует

Следите за обновлениями!

Источник: http://devicter.blogspot.com/2013/03/1-iboard-pro-rtc.html

Оснащение 3D-принтера MC7 дисплеем RepRapDiscount Full Graphic Smart Controller и создание своего логотипа

3D TodayRepRapОснащение 3D-принтера MC7 дисплеем RepRapDiscount Full Graphic Smart Controller и создание своего логотипа

masterkit
Загрузка

20.12.16

4374

Мы продолжаем серию статей (, , ) о доработках , разработанного и изготавливаемого компанией Мастер Кит.
Принтер имеет быстросборную модульную конструкцию, состоящую из 5 модулей.

Как показывает практика, собрать принтер можно буквально за 15-20 минут! Некоторое время займут также подключение электроники и настройка, но мы практически уверены, что не более чем через час после распаковки принтер будет печатать.Хорошим дополнением к принтеру MC7 послужит модуль, позволяющий печатать автономно, без подключения к компьютеру.

Наиболее широко для этого применяется модуль RepRapDiscount (или его клоны), содержащий 4-х строчный LCD-дисплей с двадцатью символами в строке, считыватель SD-карт и энкодер для управления принтером.
Гораздо более широкими графическими возможностями обладает RepRapDiscount Full Graphic Smart Controller.

Устройство также оснащено считывателем SD-карт и энкодером, но в отличие от предыдущего модуля имеет графический LCD-дисплей размером 128×64 точки. Контроллер имеет интуитивно понятное меня и позволяет управлять всеми режимами принтера, а также печатать модели из файла, содержащего G-код, который можно формировать любым подходящим слайсером – Cura, Slic3r и т.п.

Контроллер очень просто подключается к блоку электроники на основе плат Arduino Mega 2560 и RAMPS 1.4, которые используются в принтере MC7. Для подключения используются два шлейфа и плата-адаптер.Теоретически, прошивка Marlin позволяет включить русский язык при работе с RepRapDiscount Full Graphic Smart Controller.

Но практика показала, что лучше этого не делать…Пользователи жалуются на появление нечитаемых символов и корявый перевод.
Для того чтобы модуль заработал, необходимо перепрошить плату Arduino Mega 2560. Прежде всего, следует скачать библиотеку U8glib (можно ), необходимую для работы графического дисплея и .

Библиотеку надо разархивировать в каталог, где находятся остальные библиотеки Ардуино. После этого необходимо запустить оболочку Arduino IDE (проверено с версией 1.6.7), загрузить прошивку и запустить процесс ее компиляции и загрузки. Прошивка отличается тем, что в закладке Configuration.h перед определением

#define REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER снят двойной слэш, а строка

//# define REPRAP_ DISCOUNT_ SMART_ CONTROLLER, разрешающая работу строчного дисплея, должна его иметь.То есть, должна быть разрешена работа только одного типа дисплея.

Во время включения питания принтера на графическом экране на пару секунд возникает картинка с логотипом REPRAP.

Логотип в левой части размером 60х64 пикселей можно заменить на свой. Для этого во вкладке DOGMbitmaps.h надо заменить данные внутри конструкции
const unsigned char start_bmp[574] PROGMEM = { //AVR-GCC, WinAVR ваши данные

};

Изначально эта конструкция выглядит следующим образом: const unsigned char start_bmp[574] PROGMEM = { //AVR-GCC, WinAVR 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFF,0xF9,0xFF,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFF,0xF0,0xFF,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFF,0xE0,0x7F,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFF,0xC0,0x3F,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFF,0x80,0x1F,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFF,0x00,0x0F,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFE,0x00,0x07,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFC,0x00,0x03,0xFF,0xFF,0xF0, 0xFF,0xFF,0xF8,0x00,0x01,0xFF,0xFF,0xF0, 0xFF,0xFF,0xF0,0x00,0x00,0xFF,0xFF,0xF0, 0xFF,0xFF,0xE0,0x00,0x00,0x7F,0xFF,0xF0, 0xFF,0xFF,0xC0,0x00,0x00,0x3F,0xFF,0xF0, 0xFF,0xFF,0x80,0x00,0x00,0x3F,0xFF,0xF0, 0xFF,0xFF,0x00,0x00,0x00,0x1F,0xFF,0xF0, 0xFF,0xFE,0x00,0x00,0x00,0x0F,0xFF,0xF0, 0xFF,0xFE,0x00,0x00,0x00,0x07,0xFF,0xF0, 0xFF,0xFC,0x00,0x00,0x00,0x07,0xFF,0xF0, 0xFF,0xFC,0x00,0x00,0x00,0x03,0xFF,0xF0, 0xFF,0xF8,0x00,0x00,0x00,0x03,0xFF,0xF0, 0xFF,0xF8,0x00,0x00,0x00,0x03,0xFF,0xF0, 0xFF,0xF8,0x00,0x00,0x00,0x01,0xFF,0xF0, 0xFF,0xF8,0x00,0x00,0x00,0x01,0xFF,0xF0, 0xFF,0xF8,0x00,0x00,0x00,0x01,0xFF,0xF0, 0xFF,0xF8,0x00,0x00,0x00,0x01,0xFF,0xF0, 0xFF,0xF8,0x00,0x00,0x00,0x01,0xFF,0xF0, 0xFF,0xF8,0x00,0x00,0x00,0x01,0xFF,0xF0, 0xFF,0xF8,0x00,0x00,0x00,0x01,0xFF,0xF0, 0xFF,0xF8,0x00,0x00,0x00,0x01,0xFF,0xF0, 0xFF,0xF8,0x00,0x00,0x00,0x03,0xFF,0xF0, 0xFF,0xF8,0x00,0x00,0x00,0x03,0xFF,0xF0, 0xFF,0xFC,0x00,0x00,0x00,0x03,0xFF,0xF0, 0xFF,0xFC,0x00,0x00,0x00,0x07,0xFF,0xF0, 0xFF,0xFE,0x00,0x00,0x00,0x07,0xFF,0xF0, 0xFF,0xFE,0x00,0x00,0x00,0x0F,0xFF,0xF0, 0xFF,0xFF,0x00,0x00,0x00,0x1F,0xFF,0xF0, 0xFF,0xFF,0x80,0x00,0x00,0x1F,0xFF,0xF0, 0xFF,0xFF,0xC0,0x00,0x00,0x3F,0xFF,0xF0, 0xFF,0xFF,0xE0,0x00,0x00,0x7F,0xFF,0xF0, 0xFF,0xFF,0xF0,0x00,0x01,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFC,0x00,0x03,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFF,0x00,0x1F,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0, 0x83,0xFF,0xFF,0xFE,0x0F,0xFF,0xFF,0xF0, 0x80,0xFF,0xFF,0xFE,0x03,0xFF,0xFF,0xF0, 0x88,0x7F,0xFF,0xFE,0x23,0xFF,0xFF,0xF0, 0x8C,0x70,0x38,0x0E,0x71,0x81,0xC0,0x70, 0x8C,0x60,0x38,0x0E,0x63,0x80,0xC0,0x30, 0x80,0xE3,0x19,0xC6,0x07,0xF8,0xC7,0x30, 0x80,0xE0,0x19,0xC6,0x03,0x80,0xC7,0x10, 0x8C,0x62,0x79,0xC6,0x63,0x9C,0xC7,0x30, 0x8C,0x63,0xF8,0xC6,0x71,0x18,0xC6,0x30, 0x8E,0x30,0x18,0x0E,0x71,0x80,0xC0,0x30, 0x9E,0x38,0x39,0x1E,0x79,0xC4,0xC4,0xF0, 0xFF,0xFF,0xF9,0xFF,0xFF,0xFF,0xC7,0xF0, 0xFF,0xFF,0xF9,0xFF,0xFF,0xFF,0xC7,0xF0, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0 }; Наш логотип получается так: const unsigned char start_bmp[574] PROGMEM = { //AVR-GCC, WinAVR 0, 0, 0, 0, 216, 13, 0, 0, 0, 0, 0, 1, 2, 32, 64, 0,0, 0, 0, 2, 1, 64, 32, 0, 0, 0, 0, 4, 1, 0, 16, 0,0, 0, 0, 0, 0, 128, 16,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 33, 230,0, 0, 0, 0, 0, 0, 49, 1, 128, 0, 0, 0, 0, 4, 73, 2, 80, 0, 0, 0, 0, 14, 117, 226, 40, 0, 0, 0, 0, 10, 64, 4, 52, 0, 0, 0, 0, 137, 7, 240, 73, 0, 0, 0, 0, 248, 127, 254, 33, 128, 0, 0, 128, 65, 255, 255, 210, 64, 0, 1, 128, 35, 25, 196, 5, 160, 0, 7, 128, 2, 57, 196, 0, 64, 0, 15, 0, 2, 121, 135, 156, 0, 0, 31, 0, 32, 121, 135, 158, 0, 0, 30, 0, 96, 121, 7, 158, 0, 0, 62, 0, 96, 121, 7, 159, 0, 131, 254, 0, 224, 56, 7, 159, 0, 31, 254, 0, 226, 56, 71, 159, 128, 255, 254, 1, 226, 24, 71, 159, 128, 15, 254, 1, 227, 24, 199, 159, 128, 0, 31, 129, 227, 8, 199, 159, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 96, 121, 254, 254, 127, 0, 24, 24, 96, 204, 48, 192, 97, 128, 28, 56, 241, 132, 48, 192, 97, 128, 28, 56, 241, 128, 48, 192, 97, 128, 30, 120, 145, 128, 48, 252, 97, 128, 30, 121, 153, 128, 48, 192, 127, 0, 27, 217, 153, 128, 48, 192, 96, 0, 27, 217, 249, 132, 48, 192, 96, 0, 25, 155, 12, 204, 48, 192, 96, 0, 25, 155, 12, 120, 48, 254, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 48, 223, 224, 0, 0, 0, 0, 102, 48, 195, 0, 0, 0, 0, 0, 108, 49, 195, 0, 0, 0, 0, 0, 120, 51, 195, 0, 0, 0, 0, 0, 112, 55, 195, 0, 0, 0, 0, 0, 120, 62, 195, 0, 0, 0, 0, 0, 108, 60, 195, 0, 0, 0, 0, 0, 102, 56, 195, 0, 0, 0, 0, 0, 99, 48, 195, 0, 0, 0, 0, 0, 97, 176, 195, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 227, 240, 0, 0, 0, 0, 0, 3, 51, 24, 0, 0, 0, 0, 0, 0, 51, 12, 0, 0, 0, 0, 3, 128, 51, 12, 28, 0, 0, 0, 15, 224, 227, 12, 127, 0, 0, 0, 3, 128, 51, 12, 28, 0, 0, 0, 0, 0, 51, 12, 0, 0, 0, 0, 0, 0, 51, 12, 0, 0, 0, 0, 0, 3, 51, 24, 0, 0, 0, 0, 0, 1, 227, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; Данные могут быть представлены как в шестнадцатеричном, так и в десятичном представлениях. Эти данные являются битовым массивом, представляющим растровое изображение. Изображение в таком представлении можно нарисовать в каком-либо графическом редакторе, например в обычном Paint, или преобразовать из картинки в формате JPEG в более продвинутом редакторе.

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

Источник: http://3Dtoday.ru/blogs/masterkit/equipment-3d-printer-mc7-display-reprapdiscount-full-graphic-smart-con/

Описание библиотеки Adafruit_GFX для Arduino

Источник: http://robocontroller.ru/news/opisanie_biblioteki_adafruit_gfx_dlja_arduino/2015-04-26-56

Ссылка на основную публикацию
Adblock
detector
",css:{backgroundColor:"#000",opacity:.6}},container:{block:void 0,tpl:"
"},wrap:void 0,body:void 0,errors:{tpl:"
",autoclose_delay:2e3,ajax_unsuccessful_load:"Error"},openEffect:{type:"fade",speed:400},closeEffect:{type:"fade",speed:400},beforeOpen:n.noop,afterOpen:n.noop,beforeClose:n.noop,afterClose:n.noop,afterLoading:n.noop,afterLoadingOnShow:n.noop,errorLoading:n.noop},o=0,p=n([]),h={isEventOut:function(a,b){var c=!0;return n(a).each(function(){n(b.target).get(0)==n(this).get(0)&&(c=!1),0==n(b.target).closest("HTML",n(this).get(0)).length&&(c=!1)}),c}},q={getParentEl:function(a){var b=n(a);return b.data("arcticmodal")?b:(b=n(a).closest(".arcticmodal-container").data("arcticmodalParentEl"),!!b&&b)},transition:function(a,b,c,d){switch(d=null==d?n.noop:d,c.type){case"fade":"show"==b?a.fadeIn(c.speed,d):a.fadeOut(c.speed,d);break;case"none":"show"==b?a.show():a.hide(),d();}},prepare_body:function(a,b){n(".arcticmodal-close",a.body).unbind("click.arcticmodal").bind("click.arcticmodal",function(){return b.arcticmodal("close"),!1})},init_el:function(d,a){var b=d.data("arcticmodal");if(!b){if(b=a,o++,b.modalID=o,b.overlay.block=n(b.overlay.tpl),b.overlay.block.css(b.overlay.css),b.container.block=n(b.container.tpl),b.body=n(".arcticmodal-container_i2",b.container.block),a.clone?b.body.html(d.clone(!0)):(d.before("
"),b.body.html(d)),q.prepare_body(b,d),b.closeOnOverlayClick&&b.overlay.block.add(b.container.block).click(function(a){h.isEventOut(n(">*",b.body),a)&&d.arcticmodal("close")}),b.container.block.data("arcticmodalParentEl",d),d.data("arcticmodal",b),p=n.merge(p,d),n.proxy(e.show,d)(),"html"==b.type)return d;if(null!=b.ajax.beforeSend){var c=b.ajax.beforeSend;delete b.ajax.beforeSend}if(null!=b.ajax.success){var f=b.ajax.success;delete b.ajax.success}if(null!=b.ajax.error){var g=b.ajax.error;delete b.ajax.error}var j=n.extend(!0,{url:b.url,beforeSend:function(){null==c?b.body.html("
"):c(b,d)},success:function(c){d.trigger("afterLoading"),b.afterLoading(b,d,c),null==f?b.body.html(c):f(b,d,c),q.prepare_body(b,d),d.trigger("afterLoadingOnShow"),b.afterLoadingOnShow(b,d,c)},error:function(){d.trigger("errorLoading"),b.errorLoading(b,d),null==g?(b.body.html(b.errors.tpl),n(".arcticmodal-error",b.body).html(b.errors.ajax_unsuccessful_load),n(".arcticmodal-close",b.body).click(function(){return d.arcticmodal("close"),!1}),b.errors.autoclose_delay&&setTimeout(function(){d.arcticmodal("close")},b.errors.autoclose_delay)):g(b,d)}},b.ajax);b.ajax_request=n.ajax(j),d.data("arcticmodal",b)}},init:function(b){if(b=n.extend(!0,{},a,b),!n.isFunction(this))return this.each(function(){q.init_el(n(this),n.extend(!0,{},b))});if(null==b)return void n.error("jquery.arcticmodal: Uncorrect parameters");if(""==b.type)return void n.error("jquery.arcticmodal: Don't set parameter \"type\"");switch(b.type){case"html":if(""==b.content)return void n.error("jquery.arcticmodal: Don't set parameter \"content\"");var e=b.content;return b.content="",q.init_el(n(e),b);case"ajax":return""==b.url?void n.error("jquery.arcticmodal: Don't set parameter \"url\""):q.init_el(n("
"),b);}}},e={show:function(){var a=q.getParentEl(this);if(!1===a)return void n.error("jquery.arcticmodal: Uncorrect call");var b=a.data("arcticmodal");if(b.overlay.block.hide(),b.container.block.hide(),n("BODY").append(b.overlay.block),n("BODY").append(b.container.block),b.beforeOpen(b,a),a.trigger("beforeOpen"),"hidden"!=b.wrap.css("overflow")){b.wrap.data("arcticmodalOverflow",b.wrap.css("overflow"));var c=b.wrap.outerWidth(!0);b.wrap.css("overflow","hidden");var d=b.wrap.outerWidth(!0);d!=c&&b.wrap.css("marginRight",d-c+"px")}return p.not(a).each(function(){var a=n(this).data("arcticmodal");a.overlay.block.hide()}),q.transition(b.overlay.block,"show",1*")),b.overlay.block.remove(),b.container.block.remove(),a.data("arcticmodal",null),n(".arcticmodal-container").length||(b.wrap.data("arcticmodalOverflow")&&b.wrap.css("overflow",b.wrap.data("arcticmodalOverflow")),b.wrap.css("marginRight",0))}),"ajax"==b.type&&b.ajax_request.abort(),p=p.not(a))})},setDefault:function(b){n.extend(!0,a,b)}};n(function(){a.wrap=n(document.all&&!document.querySelector?"html":"body")}),n(document).bind("keyup.arcticmodal",function(d){var a=p.last();if(a.length){var b=a.data("arcticmodal");b.closeOnEsc&&27===d.keyCode&&a.arcticmodal("close")}}),n.arcticmodal=n.fn.arcticmodal=function(a){return e[a]?e[a].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof a&&a?void n.error("jquery.arcticmodal: Method "+a+" does not exist"):q.init.apply(this,arguments)}}(jQuery)}var debugMode="undefined"!=typeof debugFlatPM&&debugFlatPM,duplicateMode="undefined"!=typeof duplicateFlatPM&&duplicateFlatPM,countMode="undefined"!=typeof countFlatPM&&countFlatPM;document["wri"+"te"]=function(a){let b=document.createElement("div");jQuery(document.currentScript).after(b),flatPM_setHTML(b,a),jQuery(b).contents().unwrap()};function flatPM_sticky(c,d,e=0){function f(){if(null==a){let b=getComputedStyle(g,""),c="";for(let a=0;a=b.top-h?b.top-h{const d=c.split("=");return d[0]===a?decodeURIComponent(d[1]):b},""),c=""==b?void 0:b;return c}function flatPM_testCookie(){let a="test_56445";try{return localStorage.setItem(a,a),localStorage.removeItem(a),!0}catch(a){return!1}}function flatPM_grep(a,b,c){return jQuery.grep(a,(a,d)=>c?d==b:0==(d+1)%b)}function flatPM_random(a,b){return Math.floor(Math.random()*(b-a+1))+a}
");let k=document.querySelector(".flat_pm_modal[data-id-modal=\""+a.ID+"\"]");if(-1===d.indexOf("go"+"oglesyndication")?flatPM_setHTML(k,d):jQuery(k).html(b+d),"px"==a.how.popup.px_s)e.bind(h,()=>{e.scrollTop()>a.how.popup.after&&(e.unbind(h),f.unbind(i),j())}),void 0!==a.how.popup.close_window&&"true"==a.how.popup.close_window&&f.bind(i,()=>{e.unbind(h),f.unbind(i),j()});else{let b=setTimeout(()=>{f.unbind(i),j()},1e3*a.how.popup.after);void 0!==a.how.popup.close_window&&"true"==a.how.popup.close_window&&f.bind(i,()=>{clearTimeout(b),f.unbind(i),j()})}f.on("click",".flat_pm_modal .flat_pm_crs",()=>{jQuery.arcticmodal("close")})}if(void 0!==a.how.outgoing){let b,c="0"==a.how.outgoing.indent?"":" style=\"bottom:"+a.how.outgoing.indent+"px\"",e="true"==a.how.outgoing.cross?"":"",f=jQuery(window),g="scroll.out"+a.ID,h=void 0===flatPM_getCookie("flat_out_"+a.ID+"_mb")||"false"!=flatPM_getCookie("flat_out_"+a.ID+"_mb"),i=document.createElement("div"),j=jQuery("body"),k=()=>{void 0!==a.how.outgoing.cookie&&"false"==a.how.outgoing.cookie&&h&&(jQuery(".flat_pm_out[data-id-out=\""+a.ID+"\"]").addClass("show"),j.on("click",".flat_pm_out[data-id-out=\""+a.ID+"\"] .flat_pm_crs",function(){flatPM_setCookie("flat_out_"+a.ID+"_mb",!1)})),(void 0===a.how.outgoing.cookie||"false"!=a.how.outgoing.cookie)&&jQuery(".flat_pm_out[data-id-out=\""+a.ID+"\"]").addClass("show")};switch(a.how.outgoing.whence){case"1":b="top";break;case"2":b="bottom";break;case"3":b="left";break;case"4":b="right";}jQuery("body > *").eq(0).before("
"+e+"
");let m=document.querySelector(".flat_pm_out[data-id-out=\""+a.ID+"\"]");-1===d.indexOf("go"+"oglesyndication")?flatPM_setHTML(m,d):jQuery(m).html(e+d),"px"==a.how.outgoing.px_s?f.bind(g,()=>{f.scrollTop()>a.how.outgoing.after&&(f.unbind(g),k())}):setTimeout(()=>{k()},1e3*a.how.outgoing.after),j.on("click",".flat_pm_out .flat_pm_crs",function(){jQuery(this).parent().removeClass("show").addClass("closed")})}countMode&&(flat_count["block_"+a.ID]={},flat_count["block_"+a.ID].count=1,flat_count["block_"+a.ID].click=0,flat_count["block_"+a.ID].id=a.ID)}catch(a){console.warn(a)}}function flatPM_start(){let a=flat_pm_arr.length;if(0==a)return flat_pm_arr=[],void jQuery(".flat_pm_start, .flat_pm_end").remove();flat_body=flat_body||jQuery("body"),!flat_counter&&countMode&&(flat_counter=!0,flat_body.on("click","[data-flat-id]",function(){let a=jQuery(this),b=a.attr("data-flat-id");flat_count["block_"+b].click++}),flat_body.on("mouseenter","[data-flat-id] iframe",function(){let a=jQuery(this),b=a.closest("[data-flat-id]").attr("data-flat-id");flat_iframe=b}).on("mouseleave","[data-flat-id] iframe",function(){flat_iframe=-1}),jQuery(window).on("beforeunload",()=>{jQuery.isEmptyObject(flat_count)||jQuery.ajax({async:!1,type:"POST",url:ajaxUrlFlatPM,dataType:"json",data:{action:"flat_pm_ajax",data_me:{method:"flat_pm_block_counter",arr:flat_count}}})}).on("blur",()=>{-1!=flat_iframe&&flat_count["block_"+flat_iframe].click++})),flat_userVars.init();for(let b=0;bflat_userVars.textlen||void 0!==a.chapter_sub&&a.chapter_subflat_userVars.titlelen||void 0!==a.title_sub&&a.title_subc&&cc&&c>d&&(b=flatPM_addDays(b,-1)),b>e||cd||c-1!=flat_userVars.referer.indexOf(a))||void 0!==a.referer.referer_disabled&&-1!=a.referer.referer_disabled.findIndex(a=>-1!=flat_userVars.referer.indexOf(a)))&&(c=!0),c||void 0===a.browser||(void 0===a.browser.browser_enabled||-1!=a.browser.browser_enabled.indexOf(flat_userVars.browser))&&(void 0===a.browser.browser_disabled||-1==a.browser.browser_disabled.indexOf(flat_userVars.browser)))){if(c&&void 0!==a.browser&&void 0!==a.browser.browser_enabled&&-1!=a.browser.browser_enabled.indexOf(flat_userVars.browser)&&(c=!1),!c&&(void 0!==a.geo||void 0!==a.role)&&(""==flat_userVars.ccode||""==flat_userVars.country||""==flat_userVars.city||""==flat_userVars.role)){flat_pm_then.push(a),flatPM_setWrap(a),flat_body.hasClass("flat_pm_block_geo_role")||(flat_body.addClass("flat_pm_block_geo_role"),flatPM_ajax("flat_pm_block_geo_role")),c=!0}c||(flatPM_setWrap(a),flatPM_next(a))}}}let b=jQuery(".flatPM_sticky");b.each(function(){let a=jQuery(this),b=a.data("height")||350,c=a.data("top");a.wrap("
");let d=a.parent()[0];flatPM_sticky(this,d,c)}),debugMode||countMode||jQuery("[data-flat-id]:not([data-id-out]):not([data-id-modal])").contents().unwrap(),flat_pm_arr=[],jQuery(".flat_pm_start, .flat_pm_end").remove()}

На создание этой простой графической библиотеки меня подвигло нежелание портировать и разбираться со сторонними библиотеками хотя возможности этой библиотеки и намного скромнее, тем не мение данная бесплатная графическая библиотека позволяет легко реализовать множество графических примитивов и на ее основе достаточно легко реализовать
GUI – графический интерфейс пользователя с использованием 32-и разрядных микроконтроллеров STM32 и цветных QVGA дисплеев.

Программный интерфейс приложения (API) графической библиотеки.

Графическая библиотека легко может быть изменена под монохромные индикаторы и многоцветные CSTN/TFT (16, 65тыс. цветов) дисплеи, имеющие параллельный или последовательный интерфейс связи с микроконтроллером.

Сейчас реализована поддержка только TFT дисплея с контроллером HX8352, применение такого индикатора с контроллером и графической памятью позволяет минимизировать требования по памяти, быстродействию и числу выводов управляющего микроконтроллера, поэтому, графическим цветным TFT-модулем может управлять даже дешевый контроллер, например STM32F100RB.

Поддержка других моделей дисплеев легко реализуема без изменений тела библиотеки, изменения коснутся только уровня драйвера. Библиотека в существующем виде требует до 1Кб ОЗУ и минимум flash памяти.

https://www.youtube.com/watch?v=fAo9LOZdTWc

Библиотека разделена на два уровня:  графические примитивы (Graphics Primitive Layer) и драйвера устройств (Device Driver Layer). Уровень графических примитивов платформонезависим и состоит из реализаций функций отрисовки, таких как линия, прямоугольник, окружность и т.п.

Драйвера устройств специфичны для конкретного дисплея и предоставляют основные функции для более высоких уровней библиотеки.

Так же библиотека содержит еще два уровня для реализации вывода изображений(созданных с помощью утилиты Bitmap2Code) и уровень работы с текстом ( шрифты конвертируются с помощью утилиты TheDotFactory).

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

Архитектура графической библиотеки приведена на рисунке 1.

  1. Application Layer – пользовательская программа, которая использует графическую библиотеку.

  2. Graphics Primitives Layer – этот уровень реализует простейшие графические объекты (линии, прямоугольники, окружности и т.п.).

  3. Image and Text – этот уровень реализует отрисовку изображений, символов, строк и текста.

  4. Device Display Driver – этот уровень управляет индикатором и зависит от типа применяемого дисплея.

  5. Graphics Display Module – графический дисплей

Рис. 1. Архитектура графической библиотеки

Уровень драйверов устройства

Каждый тип дисплея имеет свои характеристики (интерфейс связи, графический контроллер). Для связи библиотеки с дисплеем определен набор функций – драйвер дисплея. Текущая версия графической библиотеки поддерживает один графический контроллер:

однако возможна поддержка и других контроллеров, для этого из всей библиотеки нужно модифицировать лишь функции драйверов устройств.

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

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

Таблица 1. Функции драйвера устройств

Имя функции Описание
LCD_Init Инициализация дисплея.
LCD_SetTextColor Устанавливает текущий цвет отображения текста
LCD_GetTextColor Возвращает текущий цвет отображения текста
LCD_SetGraficsColor Устанавливает текущий цвет отображения графики
LCD_GetGraficsColor Возвращает текущий цвет отображения графики
LCD_SetBackColor Устанавливает текущий цвет фона
LCD_GetBackColor Возвращает текущий цвет отображения фона
LCD_PutPixel Модификация пикселя экрана
LCD_SetCursor Установка курсора по координатам X,Y
LCD_SetArea Установить заданную границами область вывода экрана
LCD_SetFullScreen Установить область вывода в полный экран
LCD_FillScreen Залить весь экран выбранным цветом
LCD_clear_area Очистка или заливка области экрана выбранным цветом
LCD_Change_Direction  Сменить ориентацию дисплея альбом/портрет

Имя функции Описание
set_LCD_DATAPort_Init   Назначение порта/полу-порта под шинну данных LCD 
set_RES_LCDset_RD_LCDset_RS_LCDset_WR_LCDset_CS_LCD Назначение управляющих сигналов для контроллера ЖК, легко модифицируются/объединяются в одну функцию.

 

Графические примитивы

Уровень графических примитивов содержит базовые графические функции и «общается» с индикатором посредством драйверов устройств, поэтому функции графических примитивов становятся независимыми от типа применяемого дисплея. 

Таблица 2. Функции уровня графических примитивов

Имя функции Описание
LCD_DrawPoint Рисует точку по координатам
LCD_DrawLine Рисует линию под прямым углом
LCD_DrawObliqueLine  Рисует произвольную линию по координатам начала и конца
LCD_DrawRect Рисует прямоугольник по координатам нижний левый угол, ширина, высота.
LCD_DrawFillRect Рисует закрашенный прямоугольник по координатам нижний левый угол, ширина, высота.
DrawBeveledRect Рисует прямоугольник с закругленными углами
DrawFillBeveledRect Рисуетзакрашенныйпрямоугольник с закругленными углами
LCD_DrawCircle Рисует окружность с заданным центром и радиусом.

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

Таким образом, размер символа «1» меньше чем символа «W». Задание первого и последнего символа используемого шрифта позволяет уменьшить размер памяти, требуемого для хранения знакогенератора. Это легко сделать при генерации нужного шрифта.

Как результат, для такого знакогенератора потребуется выделение меньшего размера памяти.

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

Рис. 2. TheDotFactory – Утилита для преобразования шрифтов и графических файлов в С-массивы данных

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

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

Таблица 5. Поддерживаемые форматы изображений

Кодировка Тип изображения Описание
1bpp черно-белое изображение Каждый байт содержит 8 пикселей (точек), старшему биту соответствует левый пиксель. Цветовая палитра содержит 2 значения.
8bpp 256 оттенков серого  Каждый байт хранит 1 пиксель.
8bpp 256-и цветные изображения Каждый байт хранит 1 пиксель.
16bpp Hi-color Images Каждые 2 байта (16 бит) хранит один пиксель.Цвета кодируются в формате 5-6-5:Bits[15:11] = Красный (RED)Bits[10:05] = Зеленый (GREEN)Bits[04:00] = Синий (BLUE)

Для преобразования изображений в массивы данных с сжатием или без, используется бесплатная утилита Bitmap2Code, ее описание и т.д. можно посмотреть здесь.

Рис. 3.

Bitmap2Code

– Утилита для преобразования шрифтов и графических файлов в С-массивы данныхПример вывода конвертированного изображения размером 375х178 в формате 1bpp с сжатием:

Практическое использование

Графическая библиотека написана для работы с 32-х разрядными микроконтроллерами STM32. При необходимости, пользовательские шрифты и картинки могут храниться во внешней энергонезависимой памяти.

Библиотека разработана для легкой интеграции в разрабатываемое устройство. Использование готовых графических примитивов требует от программиста минимального количества строк кода.

Библиотека содержит хорошо документированный API.

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

Далее нужно назначить управляющие сигналы дисплея соответствующим выводам МК посредством функций set_LCD_DATAPort_Init() и т.д.

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

/* Функция инициализации выводов дисплея*/

void

LCD_PinsInit(){

  set_LCD_DATAPort_Init(GPIOA, 0);  // Назначаем для шины данных порт GPIOA биты 0-7

 

  set_RES_LCD(GPIOB, 1);        // Назначаем для сигнала сброса дисплея GPIOB вывод P.1

  set_RD_LCD(GPIOC, 4);  set_RS_LCD(GPIOB, 0);  set_WR_LCD(GPIOB, 9);  set_CS_LCD(GPIOC, 5);}

int main(void)

{

  Global_MCU_Init();   // Инициализация МК, периферия, порты и т.д.

  LCD_PinsInit();        // Инициализация управляющих выводов дисплея

  LCD_Init();            

// Инициализация дисплея, установка курсора в позицию X:0, Y:0

  LCD_Change_Direction(0);    // Переключаемся в альбомный режим

 

  LCD_FillScreen(Black);          // Заливаем весь экран черным цветом

 

  LCD_SetTextColor(Green);    // Устанавливаем цвет текста

  LCD_SetBackColor(Black);   

// Устанавливаем цвет фона для текста

  LCD_SetGraficsColor(DarkGreen);  

// Устанавливаем цвет графики

   

  LCD_PutStrig(140, 200, 0, “PRIMITIVES”);       // Печатаем строку по координатам X: 140, Y: 200

 

  DrawBeveledRect(50, 150, 150, 50, 40);          // Рисуем прямоугольник с закругленными углами, координаты центров окружностей X0: 50, Y0: 150

                                                                     

// X1: 150, Y1: 50 , радиус скругления равен 40

  DrawFillBeveledRect(50, 75, 75, 50, R, 0, Green);   // Рисуем за крашеный прямоугольник с закругленными углами

   

  LCD_DrawCircle(100, 100, 50);       // Рисуем окружность с центром в X:100, Y:100 и радиусом 50

    

  LCD_SetTextColor(Blue);                // Изменяем цвет текста на синий

  LCD_SetGraficsColor(White);         

// И цвет графики на белый

  LCD_PutStrig(200, 40, 0, “DrawObliqueLines”);  // Печатаем строку

  LCD_DrawObliqueLine(100, 100, 50, 140);   // Рисуем 3 линии с начальными координатами X:100, Y:100

  LCD_DrawObliqueLine(100, 100, 50, 40);  LCD_DrawObliqueLine(100, 100, 150, 40);}

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

Примеры практического использования библиотеки на разных ЖК:

*Небольшая заметка, изначально библиотека писалась в среде IAR, но затем была перенесена под Keil, и каково же было мое удивление когда работа с дисплеем ускорилась примерно в два раза, код для обеих сред идентичен, почему так происходит не знаю. Я никоим образом не хочу сравнивать эти две среды просто вот такой интересный факт 🙂 Кстати под 8051 silab МК у меня была абсолютно противоположная картина…

Скачать Пожалуйста, если у Вас есть какие замечания, предложения по доработки библиотеки и т.п. свяжитесь со мной. 

  • Bitmap2Code – ссылка
  • TheDotFactory – ссылка

Adafruit_GFX – это библиотека для Arduino, имеющая в своем наборе синтаксис и графические функции для LCD и OLED дисплеев. Она позволяет легко адаптировать скетч Ардуино для работы с дисплеем. Библиотека Adafruit_GFX всегда работает в паре со специализированной библиотекой для используемого дисплея.

Например, если у вас монохромный дисплей OLED 128×64 с чипом SSD1306, вам нужно установить две библиотеки, Adafruit_GFX и Adafruit_SSD1306. Ссылки на библиотеки для различных дисплеев смотрите в конце статьи.
Система координат: Пиксели – это блоки из которых состоят цифровые картинки.

Пиксель имеет фиксированный размер высоты и длинны (квадрат), размер пикселя зависит от разрешения дисплея. Каждый пиксель позиционируется на экране по горизонтальной оси X и вертикальной оси Y. Система координат начинается в левом верхнем углу экрана с точки X = 0, Y = 0 и продолжается с положительным увеличением оси X вправо, оси Y вниз.

Это стандартная Декартовая (прямоугольная) система координат. В зависимости от ориентации дисплея «Портрет», «Пейзаж» или другого специфического расположения, можно указать какой из четырех углов будет обозначен как левый верхний (начальная точка осей).
Цвета: Для цветных дисплеев, цвета представлены в беззнаковом 16-и битном формате.

Некоторые из дисплеев могут передавать цвета с большим количеством битов, но библиотека оперирует только 16-и битными значениями, это упрощает работу Ардуино с различными дисплеями. Цвет складывается из трех основных цветов – красный, зеленый, синий, которые упакованы в одном 16-и битном значении.

Первые 5 бит для красного, средние 6 бит для зеленого, последние 5 бит для синего. Человеческий глаз более чувствителен к зеленому цвету, поэтому для него выделено на 1-бит больше.Для удобства использования большинства основных и вторичных цветов, вы можете добавить в свой код готовый набор. Вы можете использовать любой из 65,536 цветов.

// Color definitions #define BLACK 0x0000 #define BLUE 0x001F #define RED 0xF800 #define GREEN 0x07E0 #define CYAN 0x07FF #define MAGENTA 0xF81F #define YELLOW 0xFFE0

#define WHITE 0xFFFF

Для монохромных (одноцветных) дисплеев, цвет всегда определяется как 1 (светится) или 0 (не светится). Смысл значений «светится/не светится», меняется в зависимости от специфики отображения дисплеев.

На дисплее с OLED подсветкой, значение “1” будет подсвечивать пиксель. На рефлективных дисплеях, значение 1 сделает цвет черным.

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

Простейшая графика:

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

Описанные ниже функции всего лишь прототипы – дисплей может быть объявлен как объект в соответствии со структурой библиотеки используемого устройства. Смотрите пример работы библиотеки для конкретного дисплея. Например, чтобы вывести на экран символы используя команду print(3.

14); Код для вашего дисплея будет содержать имя объявленного устройства непосредственно перед командой print. Если объект вашего дисплея объявлен как screen, то ваша строка будет выглядеть так: screen.print(3.14); На примере OLED 128×64 с чипом SSD1306, дисплей объявляется как объект с именем display.

Тогда строка вывода на экран будет такая: display.print(3.14);.

Пиксель (точка):

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

void drawPixel(uint16_t x, uint16_t y, uint16_t color);

В вашем коде, эта строка будет выглядеть так (пример для монохромного OLED дисплея):

display.drawPixel(10, 15, 1);

10 – x координата расположения пикселя на экране, 15 – y координата расположения пикселя на экране, 1 – color цвет пикселя (светится).

Линия:

Для прорисовки линий используются начальная и конечная точка линии.

void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color);

В вашем коде, эта строка будет выглядеть так (пример для монохромного OLED дисплея):

display.drawLine (5, 10, 19, 3, 1);

5 – x0 начальная координата линии, 10 – y0 начальная координата линии, 19 – x1 конечная координата линии, 3 – y1 конечная координата линии, 1 – color цвет линии (светится).Для горизонтальных и вертикальных линий существует более упрощенная функция. В ней указывается начальные координаты линии, её длинна в пикселях и цвет.

void drawFastVLine(uint16_t x0, uint16_t y0, uint16_t length, uint16_t color);

void drawFastHLine(uin86_t x0, uin86_t y0, uint8_t length, uint16_t color); В вашем коде, строка для вертикальной линии будет выглядеть так (пример для монохромного OLED дисплея):

display.drawFastVLine (7, 12, 20, 1);

7 – x0 начальная координата вертикальной линии, 12 – y0 начальная координата вертикальной линии, 20 – length длинна вертикальной линии в пикселях, 1 – color цвет вертикальной линии (светится).

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

Для прорисовки прямоугольников используются, координаты верхнего левого угла прямоугольника X, Y, ширина w, высота h, цвет. drawRect() – рисует линию по границам сторон прямоугольника. fillRect() – рисует прямоугольник площадь которого залита указанным цветом.

void drawRect(uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, uint16_t color);

void fillRect(uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, uint16_t color); В вашем коде, строка для прорисовки прямоугольника будет выглядеть так (пример для монохромного OLED дисплея):

display.drawRect (3, 2, 12, 10, 1);

3 – x0 начальная координата прямоугольника, 2 – y0 начальная координата прямоугольника, 12 – w ширина прямоугольника в пикселях, 10 – h высота прямоугольника в пикселях, 1 – color цвет прямоугольника (светится), для функции fillRect() – это цвет заливки площади прямоугольника.
Круг: Функция прорисовки круга использует следующие значения: центральные координаты круга X, Y, радиус, цвет. drawCircle() – рисует круг. fillCircle – рисует круг, площадь которого залита выбранным цветом.

void drawCircle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color);

void fillCircle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color); В вашем коде, строка для прорисовки круга будет выглядеть так (пример для монохромного OLED дисплея):

display.drawCircle (14, 8, 7, 1);

14 – x0 центральная координата круга по оси X, 8 – y0 центральная координата круга по оси Y, 7 – r радиус круга в пикселях, 1 – color цвет круга (светится), для функции fillCircle() – это цвет заливки площади круга.
Прямоугольник со скругленными углами: Функция прорисовки прямоугольника со скругленными углами использует: начальные координаты левого верхнего угла прямоугольника X, Y, ширину, высоту, радиус скругления угла в пикселях и цвет. drawRoundRect() – прорисовывает прямоугольник со скругленными углами. fillRoundRect() – прорисовывает прямоугольник со скругленными углами, площадь которого залита выбранным цветом.

void drawRoundRect(uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, uint16_t radius, uint16_t color);

void fillRoundRect(uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, uint16_t radius, uint16_t color);

В вашем коде, строка для прорисовки прямоугольника со скругленными углами будет выглядеть так (пример для монохромного OLED дисплея):

display.drawRoundRect (3, 1, 18, 13, 5, 1);

3 – x0 начальная координата прямоугольника, 1 – y0 начальная координата прямоугольника, 18 – w ширина прямоугольника в пикселях, 13 – h высота прямоугольника в пикселях, 5 – radius радиус скругления углов прямоугольника, 1 – color цвет прямоугольника (светится), для функции fillRoundRect() – это цвет заливки площади прямоугольника.Использование функции прямоугольника со скругленными углами имеет дополнительную возможность. Если радиус скругления углов сделать равным половине ширины или высоты прямоугольника, то вы сможете получить овал. Радиус скругления углов применяется ко всем четырем углам прямоугольника.

Треугольник:

Функция прорисовки треугольника использует следующие параметры: начальные координаты первого угла, координаты второго угла, координаты третьего угла, цвет. drawTriangle() – прорисовывает треугольник.

fillTriangle() – прорисовывает треугольник площадь которого залита выбранным цветом.

void drawTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);

void fillTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);

В вашем коде, строка для прорисовки прямоугольника будет выглядеть так (пример для монохромного OLED дисплея):

display.drawTriangle (6, 13, 9, 2, 18, 9, 1);

7 – x0 координата первого угла, 12 – y0 координата первого угла, 7 – x1 координата второго угла, 12 – y1 координата второго угла, 7 – x2 координата третьего угла, 12 – y2 координата третьего угла, 1 – color цвет треугольника (светится), для функции fillTriangle () – это цвет заливки площади треугольника.
Символы и текст: В библиотеке имеются две простые функции вывода текста на экран. Первая, для вывода одного единственного символа. Вы можете поместить один символ в любое место экрана и задать этому символу нужный цвет. Основной размер символа 5×8 пикселей. Но размеры можно пропорционально изменять. Например, задав символу размер size=2, размер символа станет 10×16 пикселей. Эта скомпонованная функция сделана для уменьшения программы.

void drawChar(uint16_t x, uint16_t y, char c, uint16_t color, uint16_t bg, uint8_t size);

В вашем коде, строка для одного символа будет выглядеть так (пример для монохромного OLED дисплея):

display.drawChar (3, 4, ‘A’, 1, 0, 1);

3 – x координата символа, 4 – y координата символа, ‘A’ – выводимый символ, должен быть заключен в одинарные ковычки, 1 – color цвет символа, 0 – bg фон (бекграунд) символа, 1 – size размер символа,Вывод строки символов (текст), отличается от вывода одного символа. Для того, чтобы задать параметры для строки, нужно использовать несколько функций. Задав координаты, цвет и размеры в разных функциях, строка выводится функцией print() которая использует заданные раннее параметры. Такой способ вывода похож на известную вам функции Serial.print(). Ниже приведен набор функций используемых для вывода строк.

void setCursor(uint16_t x0, uint16_t y0); void setTextColor(uint16_t color); void setTextColor(uint16_t color, uint16_t backgroundcolor); void setTextSize(uint8_t size);

void setTextWrap(boolean w);

В первую очередь, вам нужно задать координаты начала строки, функция setCursor(x, y), задает координаты верхнего левого угла строки. По умолчанию, её значения (0, 0) (верхний левый угол экрана). Затем задаем цвет строки, функция setTextColor(color). По умолчанию, её значение 0 (текст не видим / не светится). Каждый символ в строке имеет свой фон.

Фону можно задать цвет дополнительным (не обязательным) вторым параметром функции setTextColor() (цвет фона задается для всей строки символов) setTextColor(color, backgroundcolor); Далее задаем размер символов в строке setTextSize(size). По умолчанию значение size=1, допустимые значения 2 и 3.

После того как вы установили все нужные настройки, вы можете выводить строку символов на экран, используя функцию print() или println(). Точно также, как вы выводите текст при помощи функции Serial.print(). Например, для того, чтобы вывести строку (текст) на экран, используйте print(“Hello world”) – это первая строка на фотографии экрана.

Вы также можете выводить цифры и переменные, например, print(1234.56) – это вторая строка на фотографии с экраном. И третья строка, это print(0xDEADBEEF, HEX). По умолчанию, длинные строки выводятся слева направо, если строка длиннее размеров экрана, то происходит перенос текста на новую строку. За это отвечает функцию setTextWrap(), по умолчанию setTextWrap(1).

Если применить setTextWrap(0), то длинная строка не будет переноситься и уйдет за пределы экрана, что подходит для скрола (можно сделать бегущую строку). Ваш код для вывода строки символа будет выглядеть так (пример для монохромного OLED дисплея):

// Устанавливаем курсор (X = 5, Y = 3) display.setCursor(5, 3); // Задаем цвет текста (1) (видимый / светится) display.

setTextColor(1); // Если дополнительно нужно задать цвет фона строки, // используем ниже идущую функцию // в этом случае использовать функцию display.setTextColor(1); не нужно. // Указываем цвет текста и фона строки, в данном примере будет темный текст на белом фоне. display.

setTextColor(0, 1); // Указываем размер символов в строке (1), каждый символ размером 5×7 пикселей. display.setTextSize(1); // Выводим текст на экран, текст будет выведен с указанными выше настройками

display.print(“Hello world”);

Bitmaps (растровые изображения):

Вы можете выводить на экран небольшие монохромные (одноцветные) растровые изображения (bitmaps). Функция drawBitmap() хорошо подходит для спрайтов, мини анимации и иконок.

void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color);

Эта функция выводит блок битов на дисплей, где ‘1’ бит выводит (окрашивает) один пиксель на экране. В то время как ‘0’ бит пропускает (не выводит на экран) пиксель. Координаты X, Y, указывают верхний левый угол с которого начинается прорисовка картинки на экране.

w и h, указывают ширину и высоту картинки в пикселях. Bitmap должен быть записан в память устройства, для этого используется PROGMEM директивы. Для ознакомления предлагается прочитать инструкцию по применению PROGMEM (ссылка).

Очистка и заливка экрана:

Функция fillScreen() заливает дисплей выбранным цветом стирая всё что есть на экране. В библиотеках для разных дисплеев могут быть свои функции очистки дисплея.

void fillScreen(uint16_t color);

Поворот экрана:

Вы можете изменять ориентацию выводимой графики и текста на экране. Эта функция не изменяет положение уже выведенных элементов, но изменит расположение системы координат для последующего выведения.

Функция setRotation() может применить всего один раз, в разделе setup(). Можно повернуть экран только на 0, 90, 180 или 270 градусов. Остальные углы требуют более мощного оборудования, это делает невозможным их вычисление на Arduino.

void setRotation(uint8_t rotation);

Параметры поворота экрана могут быть 0, 1, 2, 3. Для разных типов экранов, начальное положение (0 градусов) может быть в разных положениях. Меняйте значение в функции setRotation(), чтобы повернуть экран в нужное положение.В вашем коде, строка для поворота экрана будет выглядеть так (пример для монохромного OLED дисплея):

display.setRotation(1);

1 – rotation угол поворота экрана в градусах: 0 = 0, 1 = 90, 2 = 180, 3 = 270.

Ссылки и информация:

Подробное описание всех функций библиотеки Adafruit_SSD1306 и примеры их применения читайте тут (ссылка скоро появиться).

Описание и технические возможности дисплеев Adafruit ищите на официальном сайте производителя https://www.adafruit.com/

Библиотеки для дисплеев ищите на GitHub Adafruit https://github.com/adafruit (воспользуйтесь поиском).

В статье использовались материалы с сайта https://learn.adafruit.com.