tft彩屏
1.LCD介绍
Liquid Crystal Display,即液晶显示器,由:玻璃基板、背光、驱动IC等组全彩LCD,是一种全彩显示屏(RGB565、RGB888),可以显示各种颜色
优点:成本低,高解析度,高对比度,响应速度快
2.LCD接口分类

3.LCD常见的芯片类型
例如ILI9341等
4.成像原理
在lcd上为什么可以呈现出彩色图像,是因为我们通过三原色合成而来。
所以我们只需要在单片机上显示三原色,并将它们组合就可以显示出各种颜色的事物。
单片机一般用16/24位表示一个颜色(RGB565/RGB888):
RGB565是一个16位的颜色显示,红色5位,绿色6位,蓝色8位组成了RGB565

5.常用指令集与寄存器







以上就是我们常用的指令与寄存器。通过以上指令就可以控制lcd屏幕的开窗大小,以及想显示的范围。
6.代码详解
void lcd_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
FSMC_NORSRAM_TimingTypeDef fsmc_read_handle;
FSMC_NORSRAM_TimingTypeDef fsmc_write_handle;
LCD_CS_GPIO_CLK_ENABLE(); /* LCD_CS脚时钟使能 */
LCD_WR_GPIO_CLK_ENABLE(); /* LCD_WR脚时钟使能 */
LCD_RD_GPIO_CLK_ENABLE(); /* LCD_RD脚时钟使能 */
LCD_RS_GPIO_CLK_ENABLE(); /* LCD_RS脚时钟使能 */
LCD_BL_GPIO_CLK_ENABLE(); /* LCD_BL脚时钟使能 */
.......//引脚初始化代码省略,此处是采用了FSMC外设接口
//跟据不同的屏幕id区分出不同的芯片进行不同的初始化
/* 尝试9341 ID的读取 */
lcd_wr_regno(0XD3);
lcddev.id = lcd_rd_data(); /* dummy read */
lcddev.id = lcd_rd_data(); /* 读到0X00 */
lcddev.id = lcd_rd_data(); /* 读取0X93 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data(); /* 读取0X41 */
if (lcddev.id != 0X9341) /* 不是 9341 , 尝试看看是不是 ST7789 */
{
lcd_wr_regno(0X04);
lcddev.id = lcd_rd_data(); /* dummy read */
lcddev.id = lcd_rd_data(); /* 读到0X85 */
lcddev.id = lcd_rd_data(); /* 读取0X85 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data(); /* 读取0X52 */
if (lcddev.id == 0X8552) /* 将8552的ID转换成7789 */
{
lcddev.id = 0x7789;
}
if (lcddev.id != 0x7789) /* 也不是ST7789, 尝试是不是 NT35310 */
{
lcd_wr_regno(0xD4);
lcddev.id = lcd_rd_data(); /* dummy read */
lcddev.id = lcd_rd_data(); /* 读回0x01 */
lcddev.id = lcd_rd_data(); /* 读回0x53 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data(); /* 这里读回0x10 */
if (lcddev.id != 0x5310) /* 也不是NT35310,尝试看看是不是ST7796 */
{
lcd_wr_regno(0XD3);
lcddev.id = lcd_rd_data(); /* dummy read */
lcddev.id = lcd_rd_data(); /* 读到0X00 */
lcddev.id = lcd_rd_data(); /* 读取0X77 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data(); /* 读取0X96 */
if (lcddev.id != 0x7796) /* 也不是ST7796,尝试看看是不是NT35510 */
{
/* 发送密钥(厂家提供) */
lcd_write_reg(0xF000, 0x0055);
lcd_write_reg(0xF001, 0x00AA);
lcd_write_reg(0xF002, 0x0052);
lcd_write_reg(0xF003, 0x0008);
lcd_write_reg(0xF004, 0x0001);
lcd_wr_regno(0xC500); /* 读取ID低八位 */
lcddev.id = lcd_rd_data(); /* 读回0x55 */
lcddev.id <<= 8;
lcd_wr_regno(0xC501); /* 读取ID高八位 */
lcddev.id |= lcd_rd_data(); /* 读回0x10 */
delay_ms(5); /* 等待5ms, 因为0XC501指令对1963来说就是软件复位指令, 等待5ms让1963复位完成再操作 */
if (lcddev.id != 0x5510) /* 也不是NT5510,尝试看看是不是ILI9806 */
{
lcd_wr_regno(0XD3);
lcddev.id = lcd_rd_data(); /* dummy read */
lcddev.id = lcd_rd_data(); /* 读回0X00 */
lcddev.id = lcd_rd_data(); /* 读回0X98 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data(); /* 读回0X06 */
if (lcddev.id != 0x9806) /* 也不是ILI9806,尝试看看是不是SSD1963 */
{
lcd_wr_regno(0xA1);
lcddev.id = lcd_rd_data();
lcddev.id = lcd_rd_data(); /* 读回0x57 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data(); /* 读回0x61 */
if (lcddev.id == 0x5761) lcddev.id = 0x1963; /* SSD1963读回的ID是5761H,为方便区分,我们强制设置为1963 */
}
}
}
}
}
}
/* 特别注意, 如果在main函数里面屏蔽串口1初始化, 则会卡死在printf
* 里面(卡死在f_putc函数), 所以, 必须初始化串口1, 或者屏蔽掉下面
* 这行 printf 语句 !!!!!!!
*/
//初始化里的参数设置一般都是厂家手册里调好的参数,这里我们无需过多改变
printf("LCD ID:%x\r\n", lcddev.id); /* 打印LCD ID */
if (lcddev.id == 0X7789)
{
lcd_ex_st7789_reginit(); /* 执行ST7789初始化 */
}
else if (lcddev.id == 0X9341)
{
lcd_ex_ili9341_reginit(); /* 执行ILI9341初始化 */
}
else if (lcddev.id == 0x5310)
{
lcd_ex_nt35310_reginit(); /* 执行NT35310初始化 */
}
else if (lcddev.id == 0x7796)
{
lcd_ex_st7796_reginit(); /* 执行ST7796初始化 */
}
else if (lcddev.id == 0x5510)
{
lcd_ex_nt35510_reginit(); /* 执行NT35510初始化 */
}
else if (lcddev.id == 0x9806)
{
lcd_ex_ili9806_reginit(); /* 执行ILI9806初始化 */
}
else if (lcddev.id == 0x1963)
{
lcd_ex_ssd1963_reginit(); /* 执行SSD1963初始化 */
lcd_ssd_backlight_set(100); /* 背光设置为最亮 */
}
//主要关心 lcd_display_dir()这个函数
lcd_display_dir(0); /* 默认为竖屏 */
LCD_BL(1); /* 点亮背光 */
lcd_clear(WHITE);
}
**
* @brief 设置LCD显示方向
* @param dir:0,竖屏; 1,横屏
* @retval 无
*/
void lcd_display_dir(uint8_t dir)
{
lcddev.dir = dir; /* 竖屏/横屏 */
if (dir == 0) /* 竖屏 */
{
lcddev.width = 240;
lcddev.height = 320;
if (lcddev.id == 0x5510)
{
lcddev.wramcmd = 0X2C00; //写GRAM指令
lcddev.setxcmd = 0X2A00; //设置
lcddev.setycmd = 0X2B00;
lcddev.width = 480; //这边是通过宏定义,寄存器地址便宜来实现了设置有效
lcddev.height = 800; //长度与高度,这里参考头文件里的定义
}
else if (lcddev.id == 0X1963)
{
lcddev.wramcmd = 0X2C; /* 设置写入GRAM的指令 */
lcddev.setxcmd = 0X2B; /* 设置写X坐标指令 */
lcddev.setycmd = 0X2A; /* 设置写Y坐标指令 */
lcddev.width = 480; /* 设置宽度480 */
lcddev.height = 800; /* 设置高度800 */
}
else /* 其他IC, 包括: 9341 / 5310 / 7789 / 7796 / 9806 等IC */
{
lcddev.wramcmd = 0X2C;
lcddev.setxcmd = 0X2A;
lcddev.setycmd = 0X2B;
}
if (lcddev.id == 0X5310 || lcddev.id == 0x7796) /* 如果是5310/7796 则表示是 320*480分辨率 */
{
lcddev.width = 320;
lcddev.height = 480;
}
if (lcddev.id == 0X9806) /* 如果是9806 则表示是 480*800 分辨率 */
{
lcddev.width = 480;
lcddev.height = 800;
}
}
else /* 横屏 */
{
lcddev.width = 320; /* 默认宽度 */
lcddev.height = 240; /* 默认高度 */
if (lcddev.id == 0x5510)
{
lcddev.wramcmd = 0X2C00;
lcddev.setxcmd = 0X2A00;
lcddev.setycmd = 0X2B00;
lcddev.width = 800;
lcddev.height = 480;
}
else if (lcddev.id == 0X1963 || lcddev.id == 0x9806)
{
lcddev.wramcmd = 0X2C; /* 设置写入GRAM的指令 */
lcddev.setxcmd = 0X2A; /* 设置写X坐标指令 */
lcddev.setycmd = 0X2B; /* 设置写Y坐标指令 */
lcddev.width = 800; /* 设置宽度800 */
lcddev.height = 480; /* 设置高度480 */
}
else /* 其他IC, 包括: 9341 / 5310 / 7789 / 7796 等IC */
{
lcddev.wramcmd = 0X2C;
lcddev.setxcmd = 0X2A;
lcddev.setycmd = 0X2B;
}
if (lcddev.id == 0X5310 || lcddev.id == 0x7796) /* 如果是5310/7796 则表示是 320*480分辨率 */
{
lcddev.width = 480;
lcddev.height = 320;
}
}
lcd_scan_dir(DFT_SCAN_DIR); /* 默认扫描方向 */
}
设置显示窗口函数
/**
* @brief 设置窗口(对RGB屏无效),并自动设置画点坐标到窗口左上角(sx,sy).
* @param sx,sy:窗口起始坐标(左上角)
* @param width,height:窗口宽度和高度,必须大于0!!
* @note 窗体大小:width*height.
*
* @retval 无
*/
void lcd_set_window(uint16_t sx, uint16_t sy, uint16_t width, uint16_t height)
{
uint16_t twidth, theight;
twidth = sx + width - 1;
theight = sy + height - 1;
if (lcddev.id == 0X1963 && lcddev.dir != 1) /* 1963竖屏特殊处理 */
{
sx = lcddev.width - width - sx;
height = sy + height - 1;
lcd_wr_regno(lcddev.setxcmd);
lcd_wr_data(sx >> 8);
lcd_wr_data(sx & 0XFF);
lcd_wr_data((sx + width - 1) >> 8);
lcd_wr_data((sx + width - 1) & 0XFF);
lcd_wr_regno(lcddev.setycmd);
lcd_wr_data(sy >> 8);
lcd_wr_data(sy & 0XFF);
lcd_wr_data(height >> 8);
lcd_wr_data(height & 0XFF);
}
else if (lcddev.id == 0X5510)
{
lcd_wr_regno(lcddev.setxcmd);
lcd_wr_data(sx >> 8);
lcd_wr_regno(lcddev.setxcmd + 1);
lcd_wr_data(sx & 0XFF);
lcd_wr_regno(lcddev.setxcmd + 2);
lcd_wr_data(twidth >> 8);
lcd_wr_regno(lcddev.setxcmd + 3);
lcd_wr_data(twidth & 0XFF);
lcd_wr_regno(lcddev.setycmd);
lcd_wr_data(sy >> 8);
lcd_wr_regno(lcddev.setycmd + 1);
lcd_wr_data(sy & 0XFF);
lcd_wr_regno(lcddev.setycmd + 2);
lcd_wr_data(theight >> 8);
lcd_wr_regno(lcddev.setycmd + 3);
lcd_wr_data(theight & 0XFF);
}
else /* 9341/5310/7789/1963/7796/9806横屏 等 设置窗口 */
{
lcd_wr_regno(lcddev.setxcmd);
lcd_wr_data(sx >> 8);
lcd_wr_data(sx & 0XFF);
lcd_wr_data(twidth >> 8);
lcd_wr_data(twidth & 0XFF);
lcd_wr_regno(lcddev.setycmd);
lcd_wr_data(sy >> 8);
lcd_wr_data(sy & 0XFF);
lcd_wr_data(theight >> 8);
lcd_wr_data(theight & 0XFF);
}
}
主函数
int main(void)
{
uint8_t x = 0;
uint8_t lcd_id[12];
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
lcd_init(); /* 初始化LCD */
g_point_color = RED;
sprintf((char *)lcd_id, "LCD ID:%04X", lcddev.id); /* 将LCD ID打印到lcd_id数组 */
lcd_set_window(100,100,200,200); //注意在设置以后会立即生效,lcd_clear()这个函数又重新设置
//显示范围,所以你需要修改lcd_clear()函数里的显示范围才有用
while (1)
{
switch (x)
{
case 0:
lcd_clear(WHITE);
break;
case 1:
lcd_clear(BLACK);
break;
case 2:
lcd_clear(BLUE);
break;
case 3:
lcd_clear(RED);
break;
case 4:
lcd_clear(MAGENTA);
break;
case 5:
lcd_clear(GREEN);
break;
case 6:
lcd_clear(CYAN);
break;
case 7:
lcd_clear(YELLOW);
break;
case 8:
lcd_clear(BRRED);
break;
case 9:
lcd_clear(GRAY);
break;
case 10:
lcd_clear(LGRAY);
break;
case 11:
lcd_clear(BROWN);
break;
}
lcd_show_string(10, 40, 240, 32, 32, "STM32", RED);
lcd_show_string(10, 80, 240, 24, 24, "TFTLCD TEST", RED);
lcd_show_string(10, 110, 240, 16, 16, "ATOM@ALIENTEK", RED);
lcd_show_string(10, 130, 240, 16, 16, (char *)lcd_id, RED); /* 显示LCD ID *
if (x == 12)
x = 0;
LED0_TOGGLE(); /*红灯闪烁*/
delay_ms(1000);
}
}
/**
* @brief 清屏函数
* @param color: 要清屏的颜色
* @retval 无
*/
void lcd_clear(uint16_t color)
{
uint32_t index = 0;
uint32_t totalpoint = lcddev.width;
totalpoint *= lcddev.height; /* 得到总点数 */
lcd_set_cursor(0x00, 0x0000); /* 设置光标位置 */ //重新设置了一遍,导致开始设置的不会生效
lcd_write_ram_prepare(); /* 开始写入GRAM */
for (index = 0; index < totalpoint; index++)
{
LCD->LCD_RAM = color;
}
}
213

被折叠的 条评论
为什么被折叠?



