Старая версия сайта

микроконтроллеры от ведущих мировых производителей

Графические контроллеры FTDI FTx.

Анимация изображений. Часть 1.

Сергей Долгушин, dsa@efo.ru

 

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

В данной статье мы хотим познакомить вас с функциями графических контроллеров FTDI FT8xx, с помощью которых можно “оживить” изображение на экране TFT-дисплея.

 

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

В качестве рабочей платформы будем использовать графический модуль FTDI на базе микроконтроллера (МК) Atmega 328P – VM800P50. В качестве программных средств будем использовать утилиту Screen Editor 1.17 и среду разработки Arduino 1.0.6. Screen Editor будет использоваться для подготовки изображений, которые будут выводиться на экран дисплея, а также для экспорта проекта в Arduino.

Команды CMD_SPINNER и CMD_SCREENSAVER

Примеры работы с анимацией начнем с двух команд: CMD_SPINNER и CMD_SCREENSAVER. Чем хороши эти команды – это тем, что они не требуют вмешательства МК в свою работу. Вызванные однажды, они будут продолжать свою работу до тех пор, пока управляющий МК не запишет в FT8xx новый дисплей-лист и не даст команду на его выполнение.

Первая команда выводит на экран одно из четырех анимированных изображений, показанных на рисунке 1. Эти элементы можно выводить на экран в процессе выполнения управляющим МК каких-либо длительных операций.

spinner

 Рисунок 1

Процесс создания приложения для вывода на экран такой заставки будет следующим. Во вкладке “Toolbox” Screen Editor из списка виджетов выбираем элемент Spinner и перетаскиваем его в центральное окно утилиты (см. рисунок 2). 

spinner

Рисунок 2

Во вкладке свойств добавленного  элемента “Properties” можно задать координаты элемента на экране, тип (рис.1) и размер. Создание проекта для Arduino выполняется через меню “Scripts” – “Export EVE Arduino Project”. В процессе экспорта откроется новое окно среды Arduino с заготовкой нашего проекта:

FT800IMPL_SPI FTImpl(FT_CS_PIN,FT_PDN_PIN,FT_INT_PIN);

void setup() // инициализация графического контроллера

{

                FTImpl.Init(FT_DISPLAY_RESOLUTION);

                FTImpl.SetDisplayEnablePin(FT_DISPENABLE_PIN);

                FTImpl.SetAudioEnablePin(FT_AUDIOENABLE_PIN);

                FTImpl.DisplayOn();

                FTImpl.AudioOn();

}

void loop() // основная исполняемая программа

{

FTImpl.DLStart();

                FTImpl.Cmd_Spinner(238, 136, 0, 0); // x,y, style, scale

                FTImpl.DLEnd();

                FTImpl.Finish();

while(1){}

}

В экспортированный код был добавлен бесконечный цикл. Он наглядно показывает, что анимация изображения выполняется без вмешательства МК. Элемент “spinner” может быть вызван, в том числе, на фоне основного изображения. Например, добавим перед его вызовом функцию градиентной заливки экрана:

FTImpl.Cmd_Gradient(-3,32,32767,347,162,8388352); 

В результате выполнения нового кода на экране дисплея увидим такое изображение (см. рис.3).

gradient

Рисунок 3

Следующая команда CMD_SCREENSAVER осуществляет плавное перемещение изображения по экрану дисплея в случайном направлении без участия управляющего МК. Покажем ее работу на следующем примере. Создадим новый проект в Screen Editor, во вкладке “Content” добавим наше изображение, которое будет использоваться в качестве анимированной заставки.

Напомним, что графические контроллеры FT8xx могут выводить на экран пользовательские растровые изображения. Изображения хранятся в памяти МК или внешнем носителе в сжатом виде и распаковываются самим FT8xx при их загрузке в RAM_G. Изображения могут быть сжаты по алгоритму deflate или может использоваться JPEG-формат. Утилита Screen Editor использует первый способ сжатия, причем мы можем выбрать формат вывода изображения на экран. Формат определяет качество выводимого изображения и объемы памяти, требуемые для его хранения в ПЗУ МК и в RAM_G FT8xx в распакованном виде. Все требуемые изображения могут быть загружены в RAM_G при начале работы, если их суммарный объем не превышает объем этой области памяти. В случае контроллеров FT80x он составляет 256 кБайт, у FT81x – 1 Мбайт.

 В преддверии новогодних праздников используем для наших примеров картинку с надписью “C Новым годом!”. Добавим это изображение в проект, нажав кнопку "Add" во вкладке "Content" (см. рис.4).

Screensaver

Рисунок 4

 

 Во вкладке “Properties” выберем требуемый формат изображения, (см. рисунок 5).

screen

 Рисунок 5

 

 Оценку качества изображения осуществляем по изображению в центральном окне утилиты, одновременно контролируя размер сжатой и распакованной картинки в блоке “Information” вкладки “Properties”. Изменение формата изображения приводит к изменению размеров. В данном примере остальные настройки во вкладке “Properties” оставляем по умолчанию.

Этап добавления изображения всегда одинаков для любого проекта. Но есть отличия в вызове этого изображения в связке с командой CMD_SCREENSAVER. Это не учитывается утилитой Screen Saver при формировании псевдокода в окне “Coprocessor”, а следовательно будет некорректно перенесено в будущий скетч Arduino или MS Visual Studio (MSVC). Покажем изменения, которые необходимо внести вручную, чтобы команда CMD_SCREENSAVER корректно вызывала наше изображение.

Добавление изображения в проект осуществляется его перетаскиванием из вкладки “Content” в центральное окно Screen Editor. Одновременно с этим в окне “Coprocessor” появится следующий код:

BITMAP_HANDLE(0) // назначение указателя

BITMAP_SOURCE(0) //адрес, по которому изображение хранится в памяти FT8xx

BITMAP_LAYOUT(RGB565, 480, 147) // формат изображения

BITMAP_SIZE(NEAREST, BORDER, BORDER, 240, 147) // параметры вывода его на экран

BEGIN(BITMAPS)

VERTEX2II(125, 57, 0, 0) // вывод изображения на экран

END()

 

Первые четыре функции отвечают за назначение идентификатора данному изображению, указание графическому контроллеру формата, в котором оно хранится, и его размеров. В окне “Coprocessor” не отображаются функции загрузки изображения в RAM_G. При экспорте проекта в Arduino или MSVC эти функции будут добавлены.

Теперь модифицируем этот код в окне “Coprocessor” следующим образом:

 

CLEAR_COLOR_RGB(254, 254, 254) // установка цвета фона

CLEAR(1, 1, 1) // очистка регистров color, stencil и tag

 

CMD_SCREENSAVER() // вызов подпрограммы экранной заставки

BITMAP_SOURCE(0) // адрес изображения в RAM_G, которое будет использоваться в заставке

BITMAP_LAYOUT(RGB565, 480, 147)

BITMAP_SIZE(NEAREST, BORDER, BORDER, 240, 147)

 

BEGIN(BITMAPS) // служебная команда для начала работы с растровым изображением

MACRO(0)  // запуск на выполнение подпрограммы экранной заставки

END()

 

В результате этих изменений наша картинка в центральном окне Screen Editor должна начать двигаться. Теперь можно экспортировать проект в Arduino. Результат экспорта будет необходимо подкорректировать, в результате получится следующий код:

#define RAM_A1 0

static PROGMEM prog_uchar a1[] = { 120,156, … 152,}; // наше изображение, при экспорте в Arduino Screen Editor записывает массив данных в h-файл с именем переменной, в примере a1. Эти данные надо самостоятельно перенести в массив {}. 

FT800IMPL_SPI FTImpl(FT_CS_PIN,FT_PDN_PIN,FT_INT_PIN);

void setup()

{

// инициализация

                FTImpl.Init(FT_DISPLAY_RESOLUTION);

                FTImpl.SetDisplayEnablePin(FT_DISPENABLE_PIN);

                FTImpl.SetAudioEnablePin(FT_AUDIOENABLE_PIN);

                FTImpl.DisplayOn();

                FTImpl.AudioOn();

 

// загрузка изображения в RAM_G

                FTImpl.DLStart();

                FTImpl.Cmd_Inflate(RAM_A1);

                FTImpl.WriteCmdfromflash(a1, sizeof(a1));

                FTImpl.Finish();

 

}

void loop()

{

                FTImpl.DLStart();

                FTImpl.ClearColorRGB(254, 254, 254);

                FTImpl.Clear(1, 1, 1);

                FTImpl.Cmd_ScreenSaver(); // вызов подпрограммы экранной заставки

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

                FTImpl.BitmapSource(0);

                FTImpl.BitmapLayout(FT_RGB332, 240, 147);

                FTImpl.BitmapSize(FT_NEAREST,FT_BORDER,FT_BORDER, 240, 147);        

                FTImpl.Begin(FT_BITMAPS);

                //

                FTImpl.Macro(0); //  запуск подпрограммы заставки

                FTImpl.End();

                FTImpl.DLEnd();

                FTImpl.Finish();

    while(1){}

}

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

 

Команда COLOR_A – изменение прозрачности изображения

Теперь рассмотрим работу функции COLOR_A, которая отвечает за прозрачность выводимого изображения. Вызов функции осуществляется в Arduino следующим образом: FTImpl.ColorA(z), где z может изменяться в пределах от 0 (полная прозрачность изображения) до 255 (полностью непрозрачное изображение). Проиллюстрируем работу данной функции на примере плавного перехода с одного изображения на другое. Первым изображением будет служить наша картинка “C Новым годом”, выводимая в центре экрана (см. рис. 6), вторым изображением – эта же картинка, выводимая в левом верхнем и правом нижнем углах экрана.

color0COLOR_ACOLOR_A

Рисунок 6

 

Код для Arduino будет выглядеть следующим образом:

 

#define RAM_A1 0

 static PROGMEM prog_uchar a1[] = {120, ... 152,};

 FT800IMPL_SPI FTImpl(FT_CS_PIN,FT_PDN_PIN,FT_INT_PIN);

void setup()

{

                FTImpl.Init(FT_DISPLAY_RESOLUTION);

                FTImpl.SetDisplayEnablePin(FT_DISPENABLE_PIN);

                FTImpl.SetAudioEnablePin(FT_AUDIOENABLE_PIN);

                FTImpl.DisplayOn();

                FTImpl.AudioOn();

 

// загрузка изображения в память RAM_G и назначение параметров для его последующего использования в программе

                FTImpl.DLStart();

                FTImpl.Cmd_Inflate(RAM_A1);

                FTImpl.WriteCmdfromflash(a1, sizeof(a1));

                FTImpl.Finish();

                FTImpl.DLStart();

                FTImpl.BitmapHandle(0);

                FTImpl.BitmapSource(0);

                FTImpl.BitmapLayout(FT_RGB332, 240, 147);

                FTImpl.BitmapSize(FT_NEAREST,FT_BORDER,FT_BORDER, 240, 147);

                FTImpl.DLEnd();

                FTImpl.Finish();

}

 

void loop()

{

        uint8_t z=255, x=0;  //начальные значения прозрачности для двух изображений

       

       FTImpl.DLStart();

       FTImpl.ClearColorRGB(254, 254, 254);

       FTImpl.Clear(1, 1, 1);

       FTImpl.DLEnd();

       FTImpl.Finish();             

 

        while(1)

        {     

                 FTImpl.DLStart();

                FTImpl.ClearColorRGB(254, 254, 254);

                FTImpl.Clear(1, 1, 1); 

               

FTImpl.ColorA(z); // изменение прозрачности первого изображения         

                FTImpl.Begin(FT_BITMAPS);

                FTImpl.Vertex2ii(125, 57, 0, 0);  // вызов картинки в центре экрана

                FTImpl.End();

                FTImpl.ColorA(x); // изменение прозрачности второго изображения        

                FTImpl.Begin(FT_BITMAPS);

                FTImpl.Vertex2ii(1, 1, 0, 0);  // вызов картинки в левом верхнем углу

                FTImpl.Vertex2ii(234, 125, 0, 0);  // вызов картинки в правом нижнем углу

                FTImpl.End();

                FTImpl.DLEnd();

                FTImpl.Finish();

        z--;

        x++;

        delay(25);

        if (z<1)

        {

        z=255;

        x=0;

        delay(5000);

        } 

      }

}

 

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

 

Команды вывода растровых изображений VERTEX2II и VERTEX2F

В предыдущем примере мы использовали для вывода изображения на экран команду VERTEX2II. Это базовая команда для вывода растрового изображения из памяти RAM_G на экран дисплея. Вызов команды в Arduino осуществляется так: FTImpl.Vertex2ii(x, y, handle, cell), где x и y – координаты экрана в пределах от 0 до 511; handle – указатель на растровое изображение; cell – индекс. Данная функция предназначена для работы с изображением в пределах экрана, координаты всегда имеют положительное значение. Указатель говорит функции, какое именно изображение или элемент шрифта необходимо вывести на экран. В примере выше указатель изображения был задан равным нулю следующим образом: FTImpl.BitmapHandle(0). Индекс при работе с изображениями в большинстве случаев равен нулю. При работе со шрифтами (шрифты, как и картинки, являются растровыми изображениями) значение индекса будет равно коду символа, который мы хотим вывести на экран.

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

void loop()

{

        uint8_t z=255, x=0;

       

                FTImpl.DLStart();

                FTImpl.ClearColorRGB(254, 254, 254);

                FTImpl.Clear(1, 1, 1);

                FTImpl.DLEnd();

                FTImpl.Finish();    

 

        while(1)

        {     

        FTImpl.DLStart();

        FTImpl.ClearColorRGB(254, 254, 254);

        FTImpl.Clear(1, 1, 1); 

        FTImpl.Begin(FT_BITMAPS);

        FTImpl.Vertex2ii(x, 57, 0, 0);  // вызов картинки

        FTImpl.End();

        FTImpl.DLEnd();

       FTImpl.Finish();

        z--;

        x++;

        delay(25);

        if (z<1)

        {

        z=255;

        x=0;

        delay(5000);

        } 

      }   

Инициализация и загрузка картинки полностью идентична тому, как это было сделано в предыдущем примере. Изменяя координату x, мы имитируем движение изображения от левого края экрана до правого. Команда VERTEX2II всегда выводит картинку на экран целиком, т.е. мы не можем с ее помощью реализовать плавное появление изображения из-за края экрана.

Для создания эффекта появления растрового изображения из-за края экрана на помощь придет функция VERTEX2F. Эта функция, в отличие от VERTEX2II, работает в пределах зоны, изображенной на рисунке 7. C помощью этой функции не составит труда реализовать эффект появления картинки с любой стороны экрана. Формат вызова команды в Arduino такой: FTImpl.Vertex2f(x*16, y*16), где x,y – координаты в пикселях. Коэффициент 16 необходим для удобства привязки к реальным координатам(рис.7). По умолчанию функция VERTEX2F работает с координатами в диапазоне от -16384 до +16383, т.е. с точностью 1/16 пикселя.

Координаты

Рисунок 7

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

Проиллюстрируем отличия на следующем примере (рис.8). 

 vertex2f

Рисунок 8

 

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

#define RAM_A1 0 // стартовый адрес RAM_G для первого изображения

static PROGMEM prog_uchar a1[] = {120,… 152,};

#define RAM_STAR_R 70560 // стартовый адрес RAM_G для второго изображения

static PROGMEM prog_uchar star_r[] = {120,… 134,};

  

FT800IMPL_SPI FTImpl(FT_CS_PIN,FT_PDN_PIN,FT_INT_PIN);

void setup()

{

                FTImpl.Init(FT_DISPLAY_RESOLUTION);

                FTImpl.SetDisplayEnablePin(FT_DISPENABLE_PIN);

                FTImpl.SetAudioEnablePin(FT_AUDIOENABLE_PIN);

                FTImpl.DisplayOn();

                FTImpl.AudioOn();

 

                FTImpl.DLStart();

                FTImpl.Cmd_Inflate(RAM_A1);

                FTImpl.WriteCmdfromflash(a1, sizeof(a1));

                FTImpl.Cmd_Inflate(RAM_STAR_R);

                FTImpl.WriteCmdfromflash(star_r, sizeof(star_r));

                FTImpl.Finish();

               

                FTImpl.DLStart();

                FTImpl.BitmapHandle(0);

                FTImpl.BitmapSource(0);

                FTImpl.BitmapLayout(FT_RGB332, 240, 147);

                FTImpl.BitmapSize(FT_NEAREST,FT_BORDER,FT_BORDER, 240, 147);

 

                FTImpl.BitmapHandle(1); //указатель на изображение звездочки

                FTImpl.BitmapSource(70560);

                FTImpl.BitmapLayout(FT_RGB565, 42, 20);

                FTImpl.BitmapSize(FT_NEAREST,FT_BORDER,FT_BORDER, 21, 20);

 

                FTImpl.DLEnd();

                FTImpl.Finish();

}

 

void loop()

{

        int16_t z=480, x=-240;

       

        FTImpl.DLStart();

        FTImpl.ClearColorRGB(254, 254, 254);

        FTImpl.Clear(1, 1, 1);

        FTImpl.DLEnd();

       FTImpl.Finish();             

 

        while(1)

        {     

        FTImpl.DLStart();

        FTImpl.ClearColorRGB(254, 254, 254);

        FTImpl.Clear(1, 1, 1); 

 

        // ВЫЗОВ ИЗОБРАЖЕНИЯ С НУЛЕВЫМ УКАЗАТЕЛЕМ                           

        FTImpl.Begin(FT_BITMAPS);

        FTImpl.Vertex2f(x*16, 57*16);  // вызов картинки с надписью

        FTImpl.End();

       

        // ВЫЗОВ ИЗОБРАЖЕНИЯ С УКАЗАТЕЛЕМ =1

        FTImpl.Begin(FT_BITMAPS);

        FTImpl.BitmapHandle(1);

        FTImpl.Vertex2f(z*16, 20*16);  // вызов изображения звездочки

        FTImpl.End();

 

       // Бегущая строка

       FTImpl.ColorRGB(199, 0, 4);

        FTImpl.Cmd_Text(x, 19, 28, 0, "HAPPY NEW YEAR");            

       

        FTImpl.DLEnd();

        FTImpl.Finish();

        z--;

        x++;

        delay(25);

        if (x>480)

        {

        z=480;

        x=-240;

        } 

      }

}  

 

По умолчанию, команда VERTEX2F выводит на экран изображение с нулевым указателем. В листинге этот блок из трех команд предваряется комментарием “ВЫЗОВ ИЗОБРАЖЕНИЯ С НУЛЕВЫМ УКАЗАТЕЛЕМ”.

Чтобы вывести на экран изображение, имеющее ненулевой указатель, необходимо в явном виде указать на это. Что мы и делаем во втором блоке, начинающемся комментарием “ВЫЗОВ ИЗОБРАЖЕНИЯ С УКАЗАТЕЛЕМ =1” с помощью команды FTImpl.BitmapHandle(1).  

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

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

Полезные ссылки:

Архив с примерами