Сегодня мы подключим TFT экран на драйвере R61520 (аналог драйвера ILI9341).
Данный экран будет у нас подключен по параллельному интерфейсу 8080. Документацию на данный экран можно посмотреть тут.
Схема подключения экрана к микроконтроллеру STM32F103:
Основные команды драйвера, которые нам понадобятся:
#define SWRESET 0x01 // программный сброс
#define DISPOFF 0x28 // выключение дисплея
#define DISPON 0x29 // включение дисплея
#define CASET 0x2A // выбор первого и последнего пикселя по оси X
#define PASET 0x2B // выбор первого и последнего пикселя по оси Y
#define RAMWR 0x2C // запись пикселя в дисплей
#define PWCTR1 0xC0 // настройка питания
#define SLPIN 0x10 // перевод дисплея в режим сна
#define SLPOUT 0x11 // пробуждение
#define PIXFMT 0x3A // установка формата пикселя
#define MADCTL 0x36 // настройки порядка вывода пикселей на экран
#define TRANSFER 0xB0 // Управление режимом интерфейса
#define WBCONTROL 0x55 // настройка параметров управления яркостью
//0x21 — Инверсия дисплея включена
//0x22 — Инверсия дисплея выключена
Код программы:
/* USER CODE BEGIN 0 */
#define LCD_IOP GPIOB // LCD_PINS
#define LCD_CTP GPIOC // LCD_CONT
#define CS GPIO_PIN_0
#define RS GPIO_PIN_1
#define WR GPIO_PIN_2
#define RD GPIO_PIN_3
#define RST GPIO_PIN_11
// reset
#define RESET_IDLE HAL_GPIO_WritePin(GPIOA,GPIO_PIN_11 ,SET);
#define RESET_ACTIVE HAL_GPIO_WritePin(GPIOA,GPIO_PIN_11,RESET);
// chip select
#define CS_IDLE HAL_GPIO_WritePin(GPIOC,GPIO_PIN_0 ,SET);
#define CS_ACTIVE HAL_GPIO_WritePin(GPIOC,GPIO_PIN_0,RESET);
// command/data
#define RS_IDLE HAL_GPIO_WritePin(GPIOC,GPIO_PIN_1 ,SET);
#define RS_ACTIVE HAL_GPIO_WritePin(GPIOC,GPIO_PIN_1,RESET);
//read
#define RD_IDLE HAL_GPIO_WritePin(GPIOC,GPIO_PIN_3 ,SET);
#define RD_ACTIVE HAL_GPIO_WritePin(GPIOC,GPIO_PIN_3,RESET);
//write
#define WR_IDLE HAL_GPIO_WritePin(GPIOC,GPIO_PIN_2 ,SET);
#define WR_ACTIVE HAL_GPIO_WritePin(GPIOC,GPIO_PIN_2,RESET);
//write strobe
#define WR_STROBE {WR_ACTIVE; WR_IDLE;}
void TFT1520_SendCommand(uint16_t index);
void TFT1520_Reset();
void TFT1520_init();
void pushData(unsigned char data);
void TFT1520_SendCommand(uint16_t index);
void TFT1520_SendData(uint16_t data);
void TFT1520_InvertDisplay(uint8_t i);
void TFT1520_SetRotation(uint8_t r);
void TFT1520_SetAddrWindow(uint16_t x, uint16_t y, uint16_t x1, uint16_t y1);
void TFT1520_Reset() {
CS_IDLE ; RD_IDLE ; WR_IDLE ;
RESET_IDLE ;
HAL_Delay(1);
RESET_ACTIVE ;
HAL_Delay(1);
RESET_IDLE ;
HAL_Delay(1);
}
void TFT1520_init() {
TFT1520_Reset();
TFT1520_SendCommand(SWRESET);
HAL_Delay(3);
TFT1520_SendCommand(DISPOFF);
TFT1520_SendCommand(TRANSFER );
TFT1520_SendData(0x00); //40 ?
TFT1520_SendCommand(PWCTR1);
TFT1520_SendData(0x0A);
TFT1520_SendCommand(SLPOUT);
HAL_Delay(2);
TFT1520_SendCommand(DISPON);
TFT1520_SendCommand(PIXFMT);
TFT1520_SendData(WBCONTROL);
TFT1520_SetRotation(0);
TFT1520_InvertDisplay(0);
}
// Формирование команды на порту
void pushData(unsigned char data) {
LCD_IOP->ODR = (int)((int)data << 8);
WR_STROBE;
}
void TFT1520_SendCommand(uint16_t index) {
CS_ACTIVE;
RS_ACTIVE;
pushData(index);
CS_IDLE; }
void TFT1520_SendData(uint16_t data) {
CS_ACTIVE;
RS_IDLE;
pushData(data);
CS_IDLE;
}
void TFT1520_InvertDisplay(uint8_t i) {
TFT1520_SendCommand(i ? 0x21 : 0x20);
}
uint16_t X_SIZE = 0;
uint16_t Y_SIZE = 0;
void TFT1520_SetRotation(uint8_t r) {
TFT1520_SendCommand(0x36);
switch(r) {
case 0:
TFT1520_SendData(0x48);
X_SIZE = 240;
Y_SIZE = 320;
break;
case 1:
TFT1520_SendData(0x28);
X_SIZE = 320;
Y_SIZE = 240;
break;
case 2:
TFT1520_SendData(0x88);
X_SIZE = 240;
Y_SIZE = 320;
break;
case 3:
TFT1520_SendData(0xE8);
X_SIZE = 320;
Y_SIZE = 240;
break;
}
}
void TFT1520_SetAddrWindow(uint16_t x, uint16_t y, uint16_t x1, uint16_t y1) {
TFT1520_SendCommand(0x2A);
TFT1520_SendData(x >> 8);
TFT1520_SendData(x);
TFT1520_SendData(x1 >> 8);
TFT1520_SendData(x1);
TFT1520_SendCommand(0x2B);
TFT1520_SendData(y >> 8);
TFT1520_SendData(y);
TFT1520_SendData(y1 >> 8);
TFT1520_SendData(y1);
}
void TFT1520_DrawPixel(uint16_t x, uint16_t y, uint16_t color) {
if((x<0)||(y<0)||(x>=X_SIZE)||(y>=Y_SIZE))
return;
TFT1520_SetAddrWindow(x, y, x, y);
TFT1520_SendCommand(0x2C);
TFT1520_SendData(color >> 8);
TFT1520_SendData(color & 0xFF);
}
/* USER CODE END 0 */
/* USER CODE BEGIN 2 */
uint16_t x = 0;
uint16_t y = 0;
TFT1520_init();
HAL_Delay(1000);
TFT1520_SetRotation(1);
/* USER CODE END 2 */
/* USER CODE BEGIN 3 */
for(x = 0; x < 320; x++) {
for(y = 0; y < 240; y++) {
// заполнение дисплея белым по пиксельно
TFT1520_DrawPixel(x, y, 0xFFFF);
}
}
for(x = 0; x < 320; x++) {
for(y = 0; y < 240; y++) {
// заполнение дисплея чёрным по пиксельно
TFT1520_DrawPixel(x, y, 0x0000);
}
}
for(x = 0; x < 320; x++) {
for(y = 0; y < 240; y++) {
// заполнение дисплея чёрным по пиксельно
TFT1520_DrawPixel(x, y, 0x00FF);
}
}
for(x = 0; x < 320; x++) {
for(y = 0; y < 240; y++) {
// заполнение дисплея чёрным по пиксельно
TFT1520_DrawPixel(x, y, 0xFF00);
}
}
/* USER CODE END 3 */
Теперь мы с Вами научимся выводим на экран геометрические фигуры, а так же выведем символы в виде букв и цифр.
По сути нам надо написать алгоритм по которому мы будем включать или выключать пиксели.
В качестве примера сделаем прорисовку линии. Линия у нас обладает несколькими наборами данных: начальная точка (x1, y1) конечная точка (x2, y2) и цветом (clor).
Для начала нам нужно определиться в каком направлении мы будем двигаться, то есть, нам нужно понять где находятся начальная и конечная точка линии, далее указываем цвет и делаем прорисовку. По такому алгоритму мы свами прорисовываем остальные геометрические фигуры. Для отрисовки букв, мы включаем в нужном месте пиксель и тем самым формируем нужный символ:
Остальная часть программного кода для отображения геометрических фигур и текста:
/* USER CODE BEGIN 0 */
#define swap(a,b) {int16_t t=a;a=b;b=t;}
void TFT1520_SetAddrWindow(uint16_t x, uint16_t y, uint16_t x1, uint16_t y1);
void TFT9341_DrawLine(uint16_t color, uint16_t x1, uint16_t y1,uint16_t x2, uint16_t y2);
void TFT9341_DrawRect(uint16_t color, uint16_t x1, uint16_t y1,uint16_t x2, uint16_t y2);
void vivod_char(uint8_t g,uint8_t x, uint8_t y, uint16_t color, uint16_t fon);
uint16_t z[91][8]={ {0x00,0x0E,0x11,0x19,0x15,0x13,0x11,0x0E},// 0
{0x00,0x0E,0x04,0x04,0x04,0x04,0x0C,0x04},// 1
{0x00,0x1F,0x08,0x04,0x02,0x01,0x11,0x0E},// 2
{0x00,0x0E,0x11,0x01,0x02,0x04,0x02,0x1F},// 3
{0x00,0x02,0x02,0x1F,0x12,0x0A,0x06,0x02},// 4
{0x00,0x0E,0x11,0x01,0x01,0x1E,0x10,0x1F},// 5
{0x00,0x0E,0x11,0x11,0x1E,0x10,0x08,0x06},// 6
{0x00,0x08,0x08,0x08,0x04,0x02,0x01,0x1F},// 7
{0x00,0x0E,0x11,0x11,0x0E,0x11,0x11,0x0E},// 8
{0x00,0x0C,0x02,0x01,0x0F,0x11,0x11,0x0E},// 9
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},// square 10
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},// probel
{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,0x08,0x04,0x0C,0x00,0x00,0x00,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},// /
{0x0E,0x11,0x01,0x0D,0x15,0x15,0x0E,0x00},// @
{0x0E,0x11,0x11,0x11,0x1F,0x11,0x11,0x00},// A
{0x1E,0x11,0x11,0x1E,0x11,0x11,0x1E,0x00},// B
{0x0E,0x11,0x10,0x10,0x10,0x11,0x0E,0x00},// C
{0x1C,0x12,0x11,0x11,0x11,0x12,0x1C,0x00},// D
{0x1F,0x10,0x10,0x1E,0x10,0x10,0x1F,0x00},// E
{0x1F,0x10,0x10,0x1E,0x10,0x10,0x10,0x00},// F
{0x0E,0x11,0x10,0x17,0x11,0x11,0x0E,0x00},// G
{0x11,0x11,0x11,0x1F,0x11,0x11,0x11,0x00},// H
{0x0E,0x04,0x04,0x04,0x04,0x04,0x0E,0x00},// I
{0x07,0x02,0x02,0x02,0x02,0x12,0x0C,0x00},// J
{0x11,0x12,0x14,0x18,0x14,0x12,0x11,0x00},// K
{0x10,0x10,0x10,0x10,0x10,0x10,0x1F,0x00},// L
{0x11,0x1B,0x15,0x15,0x11,0x11,0x11,0x00},// M
{0x11,0x11,0x19,0x15,0x13,0x11,0x11,0x00},// N
{0x0E,0x11,0x11,0x11,0x11,0x11,0x0E,0x00},// O
{0x1E,0x11,0x11,0x1E,0x10,0x10,0x10,0x00},// P
{0x0E,0x11,0x11,0x11,0x15,0x12,0x0D,0x00},// Q
{0x1E,0x11,0x11,0x1E,0x14,0x12,0x11,0x00},// R
{0x0F,0x10,0x10,0x0E,0x01,0x01,0x1E,0x00},// S
{0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x1F},// T
{0x11,0x11,0x11,0x11,0x11,0x11,0x0E,0x00},// U
{0x11,0x11,0x11,0x11,0x11,0x0A,0x04,0x00},// V
{0x11,0x11,0x11,0x11,0x15,0x15,0x0E,0x00},// W
{0x11,0x11,0x0A,0x04,0x0A,0x11,0x11,0x00},// X
{0x11,0x11,0x11,0x0A,0x04,0x04,0x04,0x00},// Y
{0x1F,0x01,0x02,0x04,0x08,0x10,0x1F,0x00},// Z
{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},// ‘
{0x00,0x00,0x0E,0x01,0x0F,0x11,0x0F,0x00},// a
{0x10,0x10,0x1E,0x11,0x11,0x11,0x1E,0x00},// b
{0x00,0x00,0x0E,0x10,0x10,0x11,0x0E,0x00},// c
{0x01,0x01,0x0D,0x13,0x11,0x11,0x0F,0x00},// d
{0x00,0x00,0x0E,0x11,0x1F,0x10,0x0E,0x00},// e
{0x06,0x09,0x08,0x1C,0x08,0x08,0x08,0x00},// f
{0x00,0x0F,0x11,0x11,0x0F,0x01,0x0E,0x00},// g
{0x10,0x10,0x16,0x19,0x11,0x11,0x11,0x00},// h
{0x04,0x00,0x0C,0x04,0x04,0x04,0x0E,0x00},// i
{0x02,0x00,0x06,0x02,0x02,0x12,0x0C,0x00},// j
{0x10,0x10,0x12,0x14,0x18,0x14,0x12,0x00},// k
{0x18,0x08,0x08,0x08,0x08,0x08,0x1C,0x00},// l
{0x00,0x00,0x1A,0x15,0x15,0x11,0x11,0x00},// m
{0x00,0x00,0x16,0x19,0x11,0x11,0x11,0x00},// n
{0x00,0x00,0x0E,0x11,0x11,0x11,0x0E,0x00},// o
{0x00,0x00,0x1E,0x11,0x1E,0x10,0x10,0x00},// p
{0x00,0x00,0x0F,0x11,0x0F,0x01,0x01,0x00},// q
{0x00,0x00,0x16,0x19,0x10,0x10,0x10,0x00},// r
{0x00,0x00,0x0E,0x10,0x0E,0x01,0x1E,0x00},// s
{0x08,0x08,0x1C,0x08,0x08,0x09,0x06,0x00},// t
{0x00,0x00,0x11,0x11,0x11,0x13,0x0D,0x00},// u
{0x00,0x00,0x11,0x11,0x11,0x0A,0x04,0x00},// v
{0x00,0x00,0x11,0x11,0x11,0x15,0x0A,0x00},// w
{0x00,0x00,0x11,0x0A,0x04,0x0A,0x11,0x00},// x
{0x00,0x00,0x11,0x11,0x0F,0x01,0x0E,0x00},// y
{0x00,0x00,0x1F,0x02,0x04,0x08,0x1F,0x00},// z
{0x17,0x15,0x15,0x15,0x17,0x00,0x00,0x00},// 10
{0x17,0x11,0x17,0x14,0x17,0x00,0x00,0x00},// 12
{0x17,0x14,0x17,0x11,0x17,0x00,0x00,0x00},// 15
{0x01,0x05,0x09,0x1F,0x08,0x04,0x00,0x00},//
{0x00,0x00,0xFF,0x00,0xFF,0x00,0x00,0x00}// =
};//
void TFT9341_DrawLine(uint16_t color, uint16_t x1, uint16_t y1,uint16_t x2, uint16_t y2){
int steep = abs(y2-y1)>abs(x2-x1);
if (steep){
swap(x1,y1);
swap(x2,y2);
}
if(x1>x2){
swap(x1,x2);
swap(y1,y2);
}
int dx,dy;
dx=x2-x1;
dy=abs(y2-y1);
int err=dx/2;
int ystep;
if(y1<y2) ystep = 1;
else ystep = -1;
for (;x1<=x2;x1++){
if (steep) TFT1520_DrawPixel(y1,x1,color);
else TFT1520_DrawPixel(x1,y1,color);
err-=dy;
if (err<0){
y1 += ystep;
err+=dx;
}
}
}
void TFT9341_DrawRect(uint16_t color, uint16_t x1, uint16_t y1,uint16_t x2, uint16_t y2){
TFT9341_DrawLine(color,x1,y1,x2,y1);
TFT9341_DrawLine(color,x2,y1,x2,y2);
TFT9341_DrawLine(color,x1,y1,x1,y2);
TFT9341_DrawLine(color,x1,y2,x2,y2);
}
void TFT9341_DrawCircle(uint16_t x0, uint16_t y0, int r, uint16_t color){
int f = 1-r;
int ddF_x=1;
int ddF_y=-2*r;
int x = 0;
int y = r;
TFT1520_DrawPixel(x0,y0+r,color);
TFT1520_DrawPixel(x0,y0-r,color);
TFT1520_DrawPixel(x0+r,y0,color);
TFT1520_DrawPixel(x0-r,y0,color);
while (x<y){
if (f>=0){
y—;
ddF_y+=2;
f+=ddF_y;
}
x++;
ddF_x+=2;
f+=ddF_x;
TFT1520_DrawPixel(x0+x,y0+y,color);
TFT1520_DrawPixel(x0-x,y0+y,color);
TFT1520_DrawPixel(x0+x,y0-y,color);
TFT1520_DrawPixel(x0-x,y0-y,color);
TFT1520_DrawPixel(x0+y,y0+x,color);
TFT1520_DrawPixel(x0-y,y0+x,color);
TFT1520_DrawPixel(x0+y,y0-x,color);
TFT1520_DrawPixel(x0-y,y0-x,color);
}
}
void vivod_char(uint8_t g,uint8_t x2, uint8_t y2, uint16_t color, uint16_t fon){
uint8_t x1=0,y1=0;
uint8_t x,y;
char t=0;
uint16_t w=0x0000000000000001;
uint16_t zr[91][8];
for (x1=0;x1!=91;x1++){
for(y1=0;y1!=8;y1++){
zr[x1][y1]=z[x1][y1];
}
}
for(y=0;y!=8;y++ ){
for(x=0; x!=8; x++) {
t=w&zr[g][y];
if (t==1){
TFT1520_DrawPixel(x+x2,y+y2, color);
}
else
TFT1520_DrawPixel(x+x2,y+y2, fon);
zr[g][y]=zr[g][y]>>1;
}
}
}
/* USER CODE END 0 */
/* USER CODE BEGIN WHILE */
for(x = 0; x < 320; x++) {
for(y = 0; y < 240; y++) {
TFT1520_DrawPixel(x, y, 0x0000);
}
}
vivod_char(47,220,100, 0x0FF0, 0x0000);
vivod_char(90,210,100, 0x0FF0, 0x0000);
vivod_char(1,(200-0*8),100, 0x0FF0, 0x0000);
vivod_char(3,(200-1*8),100, 0x0FF0, 0x0000);
vivod_char(23, (200-2*8),100, 0x0FF0, 0x0000);
vivod_char(5,(200-3*8),100, 0x0FF0, 0x0000);
while (1)
{
/* USER CODE END WHILE */
Запустив последний код, Вы увидите следующую картинку на экране:
***картинка***