Казалось бы чего проще, берем готовый конвертированный шрифт и выводим... Но хочется чего то универсального - взял понравившейся или подходящий шрифт, конвертировал, пользуйся :) Для этих целей как нельзя лучше подходит утилита BitFontCreator, в ней есть все что нужно - редактирование символов и всякие настройки по выводу данных, но есть одно "но" программа платная и все поиски обхода этого "недостатка" ни к чему не привели, программа все равно генерирует данные не для всех символов, а добавлять их вручную попахивает маразмом :) После этих мытарств и бесплодных поисков похожего софта я пришел к выводу что надо написать свою утилиту, но тут возникает множество трудностей по конвертации шрифта в черно-белое изображение и т.д. И в самом разгаре моих мучений я наткнулся на замечательную бесплатную утилиту - The Dot Factory.
Вот как с помощью этой утилиты создавать и пользоваться шрифтами я и решил немного расписать. Это очень универсальный инструмент и хотя все ниже описанное будет касаться STM32VLDiscovery + HX8352 ее также легко можно использовать на любых платформах.
Итак начнем, для примера я решил вывести на ЖК шрифт Tahoma размером 24, запускаем утилиту, выбираем шрифт Tahoma 24, добавляем символы для конвертации, и клацаем по ключику для входа в настройки конвертации:
В настройках ничего не меняем кроме разворота символов на 90 градусов, это нужно что бы символы на HX8352 отображались в альбомном формате:
Все, можно генерировать массивы для данного шрифта:
Сохраняем файлы куда нибудь и начинаем разбираться что к чему :) Главный файл, в нашем случае - Tahoma24pt.c, содержит в себе два массива и константное описание параметров шрифта const FONT_INFO tahoma24ptFontInfo = {...}; Текст Tahoma24pt.c тут приводить не буду уж слишком он обширен, вот лучше скачайте и посмотрите - Tahoma24pt.c Как же собственно им пользоваться? Все очень просто, в первом массиве содержатся непосредственно данные символов, а во втором необходимая информация для доступа к конкретным символам - такая как ширина символа и его начальный адрес в первом массиве, нам остается только написать простейшую функцию с передачей символа по которому вычисляется индекс второго массива и по данным по этому индексу получим доступ к данным уже непосредственно самого символа в первом массиве. Но мы этим не ограничимся, ведь не зря еще добавлена константа с параметрами шрифта :) Для начала создадим файл font.h и объявим в нем структуру, поля этой структуры будут равны данным в константе:
//Структура для доступа к параметрам используемого шрифта typedef struct { uint8_t Height; // Высота символов uint8_t FirstChar; // Индекс первого символа uint8_t LastChar; // Индекс последнего символа uint8_t FontSpace; // Пробел между символами const FONT_CHAR_INFO *FontTable; // Таблица индексов символов const uint8_t *FontBitmaps; // Указатель на массив с данными о символах } FONT_INFO;
Константные данные генерируются утилитой автоматически и индивидуальны для каждого шрифта, в нашем случае:
// Font information for Tahoma 24pt const FONT_INFO tahoma24ptFontInfo = { 4, // Character height ' ', // Start character '~', // End character 2, // Width, in pixels, of space character tahoma24ptDescriptors, // Character decriptor array tahoma24ptBitmaps, // Character bitmap array };
Затем добавляем в тот же font.h структуру для доступа к массиву с шириной и индексами символов:
//Структура доступа к массиву индексов символов typedef struct FontTable { uint16_t width; // Ширина символа uint16_t start; // Стартовый индекс на первый байт символа в массиве данных символов } FONT_CHAR_INFO;
И наконец объявляем переменную идентификатор шрифта:
extern const FONT_INFO tahoma24ptFontInfo;
И последним не забываем включить в Tahoma24pt.c font.h и stdint.h:
#include <stdint.h> /* Include standard types */ #include "font.h"
Все, мы полностью подготовили шрифт и можем начинать с ним работать, добавляем Tahoma24pt.c в проект, и пишем функцию для вывода символа:
uint8_t DrawChar(uint16_t x, uint16_t y, uint8_t c) { uint16_t i, j, k, mask; uint8_t width = CHAR_WIDTH(c); //Получаем высоту символа uint8_t height = font->Height; // Получаем ширину символа
if(!font) return 0; //Если шрифт для вывода не определен выход if(c < font->FirstChar || c > font->LastChar) return 0; //Если символ не лежит в пределах символов для шрифта то выход
Функцию вывода особо не комментировал поясню тут. Вообще как выводится пиксели на HX8352 я уже описывал тут, но поясню еще раз, устанавливаем курсор в необходимое положение и передаем байт за байтом, контролер сам передвигает курсор после приема двух байтов на одну позицию по координате х, так как у нас символ закодирован из 4-х байт в высоту (4, // Character height) и с переменной шириной, то нам необходимо передать в ЖК сначала первые четыре раскодированных байта, затем установить курсор на позицию следующей линии и так пока не выведем весь символ. Координаты х и y поменяны местами так как у нас альбомный вывод, то есть x - вертикаль, y - горизонталь, для лучшей ясности:
Вот это как раз и делает приведенная функция, ничего в ней сложного нет, так что особо останавливаться на ней не буду. Рассмотрим вывод строки, так как посимвольно выводить текст это не очень удобно :) Собственно вывод строки:
while(*str!=0) { clear_area(x, y, x + (font->Height)*8, y + (CHAR_WIDTH(*str)+CHAR_SPACE), BkColor); if(CharWidth !=0)y += CHAR_SPACE;
CharWidth = DrawChar(x, y, *str); y += CharWidth; str++; } }
Тут все еще проще, очищаем место под выводимый символ, выводим символ, передвигаем курсор для вывода следующего символа и так пока не выведем всю строку.
А теперь еще раз подробней зачем нам вообще понадобились все эти структуры и прочая мутотень, давайте представим, что у нас в проекте несколько шрифтов и нужно выводить то ли один, то ли другой, в разных частях программы, конечно можно обойтись и без структур, но тогда нам бы потребовалось делать кучу проверок типа какой шрифт выводим, какова его ширина, какой размер пробела и т.д. Согласитесь жутко неудобно особенно если это будет встречаться в нескольких местах программы, наш код постепенно будет превращаться в кашу где и мы сами хрен разберемся по прошествии пару дней :)
Ну вот, описав такую жуткую картину теперь посмотрим как у нас происходит вывод разных шрифтов с использованием структур, во первых, при добавлении нового шрифта редактируем font.h дописывая всего одну строчку для добавленного шрифта, если раньше у нас было:
//Установленные шрифты в проекте extern const FONT_INFO tahoma24ptFontInfo;
То при добавлении двух шрифтов bankGothic размером 16 и 36 будет:
Больше ничего в font.h менять не потребуется, весь код font.h полностью:
//Структура доступа к массиву индексов символов typedef struct FontTable { uint16_t width; // Ширина символа uint16_t start; // Стартовый индекс на первый байт символа в массиве данных символов } FONT_CHAR_INFO;
//Структура для доступа к параметрам используемого шрифта typedef struct { uint8_t Height; // Высота символов uint8_t FirstChar; // Индекс первого символа uint8_t LastChar; // Индекс последнего символа uint8_t FontSpace; // Пробел между символами const FONT_CHAR_INFO *FontTable; // Таблица индексов символов const uint8_t *FontBitmaps; // Указатель на массив с данными о символах } FONT_INFO;
Еще нужно написать небольшую функцию для смены шрифта в main.c например:
void SetFont(uint8_t num) { switch(num) { case 0: font = &bankGothicMdBT16ptFontInfo; break; case 1: font = &tahoma24ptFontInfo; break; case 2: font = &bankGothicMdBT36ptFontInfo; break; default: font = 0; } }
Теперь все очень просто, в основном цикле например:
Set_text_Color(RED);
SetFont(0); //Переключаемся на bankGothicMdBT16 Lcd_PutStrig(200, 20, "HELLO WORLD"); SetFont(1); //Переключаемся на tahoma24pt Lcd_PutStrig(110, 20, "HELLO WORLD"); SetFont(2); //Переключаемся на bankGothicMdBT36 Lcd_PutStrig(20, 20, "HELLO WORLD");
Как видно никаких проверок, теперь при выводе символов фунция будет обращатся к той структуре которая соответсвует выбранному шрифту функцией SetFont(); Результаты всех мучений на фото в начале статьи :)
Доброго дня, есть один вопросик про шрифты. Делаю один приборчик на AVR и хочу использовать дисплей LPH-9157. Но когда разварачиваю развёртку на 90 градусов то дисплей не отображает весь экран. У этого дисплея такая память. Вот я и хотел спросить можите помочь заточить ваш код под 8bit AVR контроллер. Компилятор не важно (можно даже под CVAVR). Такой дисплей выбрал потому что и разрешение достаточно, яркий и довольно шустрый. Заранее благодарю.
Добавлять комментарии могут только зарегистрированные пользователи. [ Регистрация | Вход ]