AVR Урок 34. Дисплей TFT 240×320 8bit. Часть 7

 

 

 

 

Урок 34

Часть 7

 

Дисплей TFT 240×320 8bit

 

 

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

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

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

 

//—————————————————————

//font 8

const unsigned char chars8[][8] PROGMEM ={

//SPACE

{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},

// !

{0x04,0x04,0x04,0x04,0x00,0x04,0x00,0x00},

// "

{0x0A,0x0A,0x0A,0x00,0x00,0x00,0x00,0x00},

// #

{0x0A,0x0A,0x1F,0x0A,0x1F,0x0A,0x0A,0x00},

// $

{0x04,0x0F,0x14,0x0E,0x05,0x1E,0x04,0x00},

// %

{0x18,0x19,0x02,0x04,0x08,0x13,0x03,0x00},

// &

{0x0C,0x12,0x14,0x08,0x14,0x12,0x0D,0x00},

// '

{0x0C,0x04,0x08,0x00,0x00,0x00,0x00,0x00},

// (

{0x02,0x04,0x08,0x08,0x08,0x04,0x02,0x00},

// )

{0x08,0x04,0x02,0x02,0x02,0x04,0x08,0x00},

// *

{0x00,0x04,0x15,0x0E,0x15,0x04,0x00,0x00},

// +

{0x00,0x04,0x04,0x1F,0x04,0x04,0x00,0x00},

// ,

{0x00,0x00,0x00,0x00,0x0C,0x04,0x08,0x00},

// —

{0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00},

// .

{0x00,0x00,0x00,0x00,0x00,0x0C,0x0C,0x00},

// /

{0x00,0x01,0x02,0x04,0x08,0x10,0x00,0x00},

// 0

{0x0E,0x11,0x13,0x15,0x19,0x11,0x0E,0x00},

// 1

{0x04,0x0C,0x04,0x04,0x04,0x04,0x0E,0x00},

// 2

{0x0E,0x11,0x01,0x02,0x04,0x08,0x1F,0x00},

// 3

{0x1F,0x02,0x04,0x02,0x01,0x11,0x0E,0x00},

// 4

{0x02,0x06,0x0A,0x12,0x1F,0x02,0x02,0x00},

// 5

{0x1F,0x10,0x1E,0x01,0x01,0x11,0x0E,0x00},

// 6

{0x06,0x08,0x10,0x1E,0x11,0x11,0x0E,0x00},

// 7

{0x1F,0x01,0x02,0x04,0x08,0x08,0x08,0x00},

// 8

{0x0E,0x11,0x11,0x0E,0x11,0x11,0x0E,0x00},

// 9

{0x0E,0x11,0x11,0x0F,0x01,0x02,0x0C,0x00},

// :

{0x00,0x01,0x02,0x04,0x08,0x10,0x00,0x00},

// ;

{0x00,0x0C,0x0C,0x00,0x0C,0x04,0x08,0x00},

// <

{0x02,0x04,0x08,0x10,0x08,0x04,0x02,0x00},

// =

{0x00,0x00,0x1F,0x00,0x1F,0x00,0x00,0x00},

// >

{0x08,0x04,0x02,0x01,0x02,0x04,0x08,0x00},

// ?

{0x0E,0x11,0x01,0x02,0x04,0x00,0x04,0x00},

// @

{0x0E,0x11,0x01,0x0D,0x15,0x15,0x0E,0x00},

// A

{0x0E,0x11,0x11,0x11,0x1F,0x11,0x11,0x00},

// B

{0x1E,0x11,0x11,0x1E,0x11,0x11,0x1E,0x00},

// C

{0x0E,0x11,0x10,0x10,0x10,0x11,0x0E,0x00},

// D

{0x1C,0x12,0x11,0x11,0x11,0x12,0x1C,0x00},

// E

{0x1F,0x10,0x10,0x1E,0x10,0x10,0x1F,0x00},

// F

{0x1F,0x10,0x10,0x1E,0x10,0x10,0x10,0x00},

// G

{0x0E,0x11,0x10,0x17,0x11,0x11,0x0E,0x00},

// H

{0x11,0x11,0x11,0x1F,0x11,0x11,0x11,0x00},

// I

{0x0E,0x04,0x04,0x04,0x04,0x04,0x0E,0x00},

// J

{0x07,0x02,0x02,0x02,0x02,0x12,0x0C,0x00},

// K

{0x11,0x12,0x14,0x18,0x14,0x12,0x11,0x00},

// L

{0x10,0x10,0x10,0x10,0x10,0x10,0x1F,0x00},

// M

{0x11,0x1B,0x15,0x15,0x11,0x11,0x11,0x00},

// N

{0x11,0x11,0x19,0x15,0x13,0x11,0x11,0x00},

// O

{0x0E,0x11,0x11,0x11,0x11,0x11,0x0E,0x00},

// P

{0x1E,0x11,0x11,0x1E,0x10,0x10,0x10,0x00},

// Q

{0x0E,0x11,0x11,0x11,0x15,0x12,0x0D,0x00},

// R

{0x1E,0x11,0x11,0x1E,0x14,0x12,0x11,0x00},

// S

{0x0F,0x10,0x10,0x0E,0x01,0x01,0x1E,0x00},

// T

{0x1F,0x04,0x04,0x04,0x04,0x04,0x04,0x00},

// U

{0x11,0x11,0x11,0x11,0x11,0x11,0x0E,0x00},

// V

{0x11,0x11,0x11,0x11,0x11,0x0A,0x04,0x00},

// W

{0x11,0x11,0x11,0x11,0x15,0x15,0x0E,0x00},

// X

{0x11,0x11,0x0A,0x04,0x0A,0x11,0x11,0x00},

// Y

{0x11,0x11,0x11,0x0A,0x04,0x04,0x04,0x00},

// Z

{0x1F,0x01,0x02,0x04,0x08,0x10,0x1F,0x00},

// [

{0x0E,0x08,0x08,0x08,0x08,0x08,0x0E,0x00},

//

{0x11,0x0A,0x1F,0x04,0x1F,0x04,0x04,0x00},

// ]

{0x0E,0x02,0x02,0x02,0x02,0x02,0x0E,0x00},

// ^

{0x04,0x0A,0x11,0x00,0x00,0x00,0x00,0x00},

// _

{0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00},

// '

{0x08,0x04,0x00,0x00,0x00,0x00,0x00,0x00},

// a

{0x00,0x00,0x0E,0x01,0x0F,0x11,0x0F,0x00},

// b

{0x10,0x10,0x1E,0x11,0x11,0x11,0x1E,0x00},

// c

{0x00,0x00,0x0E,0x10,0x10,0x11,0x0E,0x00},

// d

{0x01,0x01,0x0D,0x13,0x11,0x11,0x0F,0x00},

// e

{0x00,0x00,0x0E,0x11,0x1F,0x10,0x0E,0x00},

// f

{0x06,0x09,0x08,0x1C,0x08,0x08,0x08,0x00},

// g

{0x00,0x0F,0x11,0x11,0x0F,0x01,0x0E,0x00},

// h

{0x10,0x10,0x16,0x19,0x11,0x11,0x11,0x00},

// i

{0x04,0x00,0x0C,0x04,0x04,0x04,0x0E,0x00},

// j

{0x02,0x00,0x06,0x02,0x02,0x12,0x0C,0x00},

// k

{0x10,0x10,0x12,0x14,0x18,0x14,0x12,0x00},

// l

{0x18,0x08,0x08,0x08,0x08,0x08,0x1C,0x00},

// m

{0x00,0x00,0x1A,0x15,0x15,0x11,0x11,0x00},

// n

{0x00,0x00,0x16,0x19,0x11,0x11,0x11,0x00},

// o

{0x00,0x00,0x0E,0x11,0x11,0x11,0x0E,0x00},

// p

{0x00,0x00,0x1E,0x11,0x1E,0x10,0x10,0x00},

// q

{0x00,0x00,0x0F,0x11,0x0F,0x01,0x01,0x00},

// r

{0x00,0x00,0x16,0x19,0x10,0x10,0x10,0x00},

// s

{0x00,0x00,0x0E,0x10,0x0E,0x01,0x1E,0x00},

// t

{0x08,0x08,0x1C,0x08,0x08,0x09,0x06,0x00},

// u

{0x00,0x00,0x11,0x11,0x11,0x13,0x0D,0x00},

// v

{0x00,0x00,0x11,0x11,0x11,0x0A,0x04,0x00},

// w

{0x00,0x00,0x11,0x11,0x11,0x15,0x0A,0x00},

// x

{0x00,0x00,0x11,0x0A,0x04,0x0A,0x11,0x00},

// y

{0x00,0x00,0x11,0x11,0x0F,0x01,0x0E,0x00},

// z

{0x00,0x00,0x1F,0x02,0x04,0x08,0x1F,0x00}

};

//—————————————————————

 

 

Теперь добавим функцию по выводу символа определённой высоты в определённое место экрана

 

//—————————————————————

void TFT9341_Draw_Char(int x, int y, unsigned int color, unsigned int phone, unsigned char charcode, unsigned char size)

{

}

//—————————————————————

 

Во входных параметрах будут координаты вывода символа, цвет символа, цвет фона, код символа и размер символа.

Добавим возможность отслеживания размера с помощью операции ветвления

 

void TFT9341_Draw_Char(int x, int y, unsigned int color, unsigned int phone, unsigned char charcode, unsigned char size)

{

  switch(size)

  {

    int i,h;

    case 1:

    break;

    case 2:

    break;

    case 3:

    break;

    case 4:

    break;

  }

}

 

вариант 1 будет у нас для шрифта размером 8 пикселей, а вариант 2 для 16 пиксельного, остальные два варианта пока будут в запасе.

Начнем заполнять первый кейс, написав туда двухмерный цикл

 

case 1:

  for(h=0;h<8;h++)

  {

    for(i=0;i<8;i++)

    {

    }

  }

  break;

 

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

Теперь внутри внутреннего цикла будет условие, которое в зависимости от значения проверяемого бита в элементе массива будет отрисовывать точку определённого цвета. При единице будет цвет символа, а при нуле — цвет фона

 

for(i=0;i<8;i++)

{

  if ((pgm_read_byte(&chars8[charcode-0x20][h])>>(7-i))&0x01)

  {

    TFT9341_DrawPixel(x+i,y+h,color);

  }

  else

  {

    TFT9341_DrawPixel(x+i,y+h,phone);

  }

}

 

В случае второго варианта (размер шрифта 16 пикселей) будет также двухмерный цикл, только h уже будет доходить до 16, а не до восьми

 

case 2:

  for(h=0;h<16;h++)

  {

    for(i=0;i<8;i++)

    {

    }

  }

  break;

 

Далее в теле внутреннего цикла у нас будет уже два условия, одно — для первого байта горизонтали, а второе — для второго

 

for(i=0;i<8;i++)

{

  if ((pgm_read_byte(&chars16[charcode-0x20][h*2])>>(7-i))&0x01)

  {

    TFT9341_DrawPixel(x+i,y+h,color);

  }

  else

  {

    TFT9341_DrawPixel(x+i,y+h,phone);

  }

  if ((pgm_read_byte(&chars16[charcode-0x20][h*2+1])>>(7-i))&0x01)

  {

    TFT9341_DrawPixel(x+i+8,y+h,color);

  }

  else

  {

    TFT9341_DrawPixel(x+i+8,y+h,phone);

  }

}

 

Создадим прототип нашей функции и попробуем в функции main() что-то написать на экране

 

TFT9341_FillScreen(BLACK);

TFT9341_Draw_Char(10,10,RED,GREEN,0x21,2);

TFT9341_Draw_Char(26,10,RED,GREEN,0x22,2);

TFT9341_Draw_Char(42,10,RED,GREEN,0x23,2);

TFT9341_Draw_Char(58,10,RED,GREEN,0x24,2);

TFT9341_Draw_Char(74,10,RED,GREEN,0x25,2);

TFT9341_Draw_Char(10,26,RED,GREEN,0x21,1);

TFT9341_Draw_Char(18,26,RED,GREEN,0x22,1);

TFT9341_Draw_Char(26,26,RED,GREEN,0x23,1);

TFT9341_Draw_Char(34,26,RED,GREEN,0x24,1);

TFT9341_Draw_Char(42,26,RED,GREEN,0x25,1);

_delay_ms(1000);

 

Соберём код, прошьём контроллер и посмотрим результат

 

image17

 

Теперь попробуем написать функцию отрисовки целой строки на экране

 

//—————————————————————

void TFT9341_String(unsigned int x, unsigned int y, unsigned int color,unsigned int phone,char *str, unsigned char size)

{

  while(*str)

  {

    if((x + (size*8)) > X_SIZE)

    {

      x = 1;

      y = y + (size*8);

    }

    TFT9341_Draw_Char(x, y, color, phone,*str, size);

    x += size*8;

    *str++;

  }

}

//—————————————————————

 

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

Также напишем прототип данной функции и в main() напишем тест для проверки данной функции

 

_delay_ms(1000);

TFT9341_FillScreen(BLACK);

TFT9341_String(1, 1, RED,GREEN,"12345ABCDE", 1);

TFT9341_String(1, 9, RED,GREEN,"EDCBA54321", 1);

TFT9341_String(10, 17, RED,GREEN,"ABCDEabcde", 1);

_delay_ms(1000);

TFT9341_FillScreen(BLACK);

while (1)

 

Соберём код, прошьём контроллер и посмотрим наши строки на практике

 

image18

 

А также в бесконечный цикл мы напишем тест вывода случайных нулей и единиц размером 8 пикселей в случайные места экрана

 

  TFT9341_FillScreen(BLACK);

  while (1)

  {

    TFT9341_Draw_Char((rand()%15)*16,(rand()%20)*16,GREEN,BLACK,0x21+(rand()%2),2);

  }

}

 

Скомпилируем наш код, прошьём контроллер и посмотрим результат

 

image19

 

Я думаю, просмотрев полностью данное занятие, вы стали гораздо грамотнее в программировании микроконтроллеров, а также немного начали разбираться в написании кода для контроллеров дисплеев с параллельным подключением.

 

Предыдущая часть Программирование МК AVR Следующий урок

 

Исходный код

 

 

Техническая документация на контроллер дисплея ILI9341

 

Программатор и символьный дисплей LCD 20×4 можно приобрести здесь:

Программатор (продавец надёжный) USBASP USBISP 2.0

Дисплей LCD 20×4

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

AVR Дисплей TFT 240×320 8bit