Каталог статей
Сайт создан в системе uCoz
Приветствую Вас, Пробегающий мимо · RSS 20.04.2024, 09:41
Главная » Статьи » Статьи » Микроконтроллеры

Работаем с шрифтами на HX8352





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

const FONT_INFO *font = 0;       


#define CHAR_WIDTH(c)              font->FontTable[(c) - font->FirstChar].width       // Ширина символа
#define CHAR_START_INDEX(c)  font->FontTable[(c) - font->FirstChar].start        // Вычисление стартового индекса символа
#define CHAR_DATA(c)                 &font->FontBitmaps[CHAR_START_INDEX(c)]     //Данные символа
#define CHAR_SPACE                    font->FontSpace                                                         //Размер межсимвольного пробела



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;   //Если символ не лежит в пределах символов для шрифта то выход
   
  for(i = 0; i < width; i++)
  {
    LCD_SetCursor(x,(y + i));
    LCD_Write_Index(0x22);
   
    mask=0x80;
   
    for(k = 0; k < height; k++)
    {
      for(j = 0; j < 8; j++)
      {
        CS_LCD_set;
       
        const uint8_t *ptr = CHAR_DATA(c);
       
        if(*ptr & mask) LCD_16B_Write_Data(TextColor);
        else LCD_16B_Write_Data(BkColor);
       
        CS_LCD_clr;
        mask = mask>>1;         
      }
      mask=0x80;
    }
  }
  return width;
}



Функцию вывода особо не комментировал поясню тут. Вообще как выводится пиксели на HX8352 я уже описывал тут, но поясню еще раз, устанавливаем курсор в необходимое положение и передаем байт за байтом, контролер сам передвигает курсор после приема двух байтов на одну позицию по координате х, так как у нас символ закодирован из 4-х байт в высоту (4, //  Character height) и с переменной шириной, то нам необходимо передать в ЖК сначала первые четыре раскодированных байта, затем установить курсор на позицию следующей линии и так пока не выведем весь символ. Координаты х и y поменяны местами так как у нас альбомный вывод, то есть x - вертикаль, y - горизонталь, д
ля лучшей ясности:



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

void Lcd_PutStrig(uint16_t x, uint16_t y, const char *str)
{  
  uint8_t CharWidth = 0;
 
  if(!font || !str) return;
 
  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 будет:

//Установленные шрифты в проекте
extern const FONT_INFO bankGothicMdBT16ptFontInfo;
extern const FONT_INFO bankGothicMdBT36ptFontInfo;
extern const FONT_INFO tahoma24ptFontInfo;


Больше ничего в
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;


//Установленные шрифты в проекте
extern const FONT_INFO bankGothicMdBT16ptFontInfo;
extern const FONT_INFO bankGothicMdBT36ptFontInfo;
extern const FONT_INFO tahoma24ptFontInfo;





Еще нужно написать небольшую функцию для смены шрифта в 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();  Результаты всех мучений на фото в начале статьи :)


------------------------------------------------------------------------------------------------------

Готовый проект IAR 6.10 для STM32VLDdiscovery -FONTS.RAR, это тот же проект что я использовал в предыдущей статье, просто добавил работу с шрифтами.


Категория: Микроконтроллеры | Добавил: LeftRadio (07.08.2011)
Просмотров: 7971 | Комментарии: 2 | Рейтинг: 0.0/0
Всего комментариев: 2
1 CilddolaWag  
да, что-то на подобии этого

2 sdsrem  
Доброго дня, есть один вопросик про шрифты.
Делаю один приборчик на AVR и хочу использовать дисплей LPH-9157.
Но когда разварачиваю развёртку на 90 градусов то дисплей не отображает весь экран.
У этого дисплея такая память.
Вот я и хотел спросить можите помочь заточить ваш код под 8bit AVR контроллер.
Компилятор не важно (можно даже под CVAVR).
Такой дисплей выбрал потому что и разрешение достаточно, яркий и довольно шустрый.
Заранее благодарю.

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]