Вывод символов и строк на TFT дисплей, на примере ILI9341.

Вывод символов и строк на TFT дисплей, на примере ILI9341.

В прошлой статье мы рассмотрели как инициализировать TFT дисплей, под управлением драйвера ILI9341, в этой будем учиться выводить символы и строки.
Но для начала надо разобраться с одним моментом, если у SSD1289 для вывода точки на дисплей необходимо указать две её координаты и цвет точки, то у ILI9341 указывается 4 координаты, которые ограничивают рабочую область, затем указывается цвет вновь отрисовываемой точки, а порядок отрисовки точек задаётся при инициализации.

Что касается порядка отрисовки точек, то он задаётся после отправки команды 36h.
Вывод символов и строк на TFT дисплей, на примере ILI9341.

Для того чтобы понять, что там написано надо мысленно провести две оси, ось Х по горизонтали и ось У по вертикали, тогда:

  • MХ – определяет с какой стороны дисплея Х будет равен нулю, с правой или с левой, соответственно с другой стороны дисплея Х будет максимальным
  • MY – то же самое только для оси У
  • MV – меняет оси X и Y местами
  • ML – определяет порядок обновления выделенной области по вертикали
  • MH – определяет порядок обновления выделенной области по горизонтали

Вывод символов и строк на TFT дисплей, на примере ILI9341.

Изменение значений ML и MH, не давали никакого результата, с этим ещё предстоит разобраться.

Для отрисовки чего-либо на экране необходимо выполнить следующую последовательность действий:

  • отправляем команду 2А, затем координаты начала и конца области по горизонтали
  • отправляем команду 2B, затем координаты начала и конца области по вертикали
  • отправляем команду 2С, то есть говорим: “Сейчас будем писать в видеоОЗУ”
  • посылаем кодировку цвета, который хотим вывести в текущей ячейке
  • снова посылаем кодировку цвета, при этом координаты сами изменятся по выбранному при инициализации алгоритму


Тогда код для отрисовки одного пикселя будет выглядеть так

void TFT_Send_Data(uint16_t data)
{
	uint8_t data1 = data>>8;
	uint8_t data2 = data&0xff;
	TFT_Write_Data(data1);
	TFT_Write_Data(data2);
}

/*ф-ция ограничивает координаты  рабочей области по оси Х*/
void TFT_Set_Column(uint16_t start_column,uint16_t end_colunm)
{
	TFT_Send_Cmd(0x2A);                                           
	TFT_Send_Data(start_column);
	TFT_Send_Data(end_colunm);
}

/*ф-ция ограничивает координаты  рабочей области по оси Y*/
void TFT_Set_Page(uint16_t start_page,uint16_t end_page)
{
	TFT_Send_Cmd(0x2B);                                                      
	TFT_Send_Data(start_page);
	TFT_Send_Data(end_page);
}

/*ф-ция ограничивает координаты  рабочей области*/
void TFT_Set_XY(uint16_t x, uint16_t y)
{
	TFT_Set_Column(x, x);
	TFT_Set_Page(y, y);
}

/*ф-ция отрисовывает пиксель по заданным координатам*/
void TFT_Draw_Pixel(uint16_t x, uint16_t y,uint16_t color)
{
	TFT_Set_XY(x, y);
	TFT_Send_Cmd(0x2c);
	TFT_Write_Data16(color);
}


А теперь, как и обещал в прошлой статье, давайте рассмотрим как залить экран выбранным цветом.

uint16_t constrain(uint16_t a, uint16_t b, uint16_t c)
{
	if (a < b)
	{
		return b;
	}
	if (c < a)
	{
		return c;
	}
	else return a;
}

void TFT_Fill_Screen(uint16_t x_left, uint16_t x_right, uint16_t y_up, uint16_t y_down, uint16_t color)
{
	unsigned long  xy=0;
	unsigned long i=0;
	if(x_left > x_right)
	{	
		x_left = x_left^x_right;       //если координата левого края больше
		x_right = x_left^x_right;      //координаты правого края они поменяются
		x_left = x_left^x_right;       //местами, было x_left = 5 x_right = 3 
					       //стало x_left = 3 x_right = 5
	}
	if(y_up > y_down)
	{
		y_up = y_up^y_down;		//то же самое для оси y							
		y_down = y_up^y_down;		//название этой операции
		y_up = y_up^y_down;		//"swap без временной переменной"
	}
	//контролируем, что бы передаваемые в функцию координаты
	//входили в область допустимых значений
	x_left = constrain(x_left, MIN_X,MAX_X);
	x_right = constrain(x_right, MIN_X,MAX_X);
	y_up = constrain(y_up, MIN_Y,MAX_Y);
	y_down = constrain(y_down, MIN_Y,MAX_Y);

	xy = (x_right - x_left+1);		//рассчитываем количество точек
	xy = xy*(y_down - y_up+1);		//которое надо закрасить

	TFT_Set_Column(x_left,x_right);	        //задаём рабочую область по x
	TFT_Set_Page(y_up, y_down);		//задаём рабочую область по y
	TFT_Send_Cmd(0x2c);			//будем писать в видео ОЗУ
	
	for(i=0; i < xy; i++)
	{
		TFT_Write_Data16(color);	//передаём кодировку цвета
	}
}

Надеюсь, что как работает функция понятно из комментариев.

Теперь давайте рассмотрим как рисовать символы на дисплее. Каждая буква размером 8х8 представляет собой массив из 8 элементов, на рисунке ниже видно как он формируется .
Вывод символов и строк на TFT дисплей, на примере ILI9341.

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


Функция для отрисовки символов выглядит так.

void TFT_Draw_Char(uint16_t x, uint16_t y, uint16_t color, uint16_t phone, uint8_t ascii, uint8_t size)
{
	for (int i = 0; i < FONT_Y; i++ )
	{
		for(uint8_t f = 0; f < FONT_X; f++)
		{
			if((pgm_read_byte(&simbols[ascii-0x20][i])>>(7-f))&0x01)
			{
				 TFT_Fill_Rectangle(x+f*size, y+i*size, size, size, color);
			}
			else
			{	
				 TFT_Fill_Rectangle(x+f*size, y+i*size, size, size, phone);
			}
		}
	}
}

Работает она следующим образом, с помощью функции
pgm_read_byte(&simbols[ascii-0x20][i])
из флэша извлекается i-тый байт нужного нам символа. А как мы помним, символ кодируется 8 байтами, а каждый байт, в свою очередь, хранит в себе информацию о том как закрашивать строку. У этого байта смещаем в правую крайнюю позицию интересующий нас бит
(pgm_read_byte(&simbols[ascii-0x20][i])>>(7-f))
и с помощью операции побитового и определяем чему он равен
(pgm_read_byte(&simbols[ascii-0x20][i])>>(7-f))&0x01
Если он равен единице рисуем точку соответствующую цвету символа, иначе точку цвета фона. Таким образом, построчно отрисовываются символы.

А вот и функция для вывода строк.

void TFT_Draw_String(uint16_t x, uint16_t y, uint16_t color,uint16_t phone,char *string, uint8_t size)
{
        //определить конец строки очень просто если знать, что она ВСЕГДА заканчивается нулём
	while(*string)
	{      
                //проверяем не вылезем ли мы за пределы экрана при отрисовке следующего символа,
                // если да, то переходим на следующую строчку
		if((x + FONT_X) > MAX_X)
		{
			x = 1;
			y = y + FONT_X*size;
		}
		TFT_Draw_Char(x, y, color, phone,*string, size);//отрисовываем символ
		x += FONT_X*size;     //изменяем координату для отрисовки следующего символа
		*string++;           //увеличиваем значение указателя, чтобы он ссылался на следующий символ
	}
}

Думаю, как работает эта функция тоже понятно из комментариев.
Вывод символов и строк на TFT дисплей, на примере ILI9341.

В следующей статье мы будем учиться рисовать геометрические фигуры.
Проект для Atmega16 в Atmel Studio 6.2 в архиве ili9341_i8080_example.rar [9,84 Kb] (cкачиваний: 1021).
комментарии
6