TFTLCD
TDTLCD即在液晶显示屏的每个像素上设置薄膜晶体管液晶显示器(TFT),图像质量高
一般TFTLCD模块位3.3V供电,不支持5V电压MCU,如果使用5V MCU信号线串联120R电阻使用
LCD与16位80并口驱动OLED并口驱动相似
使用电容触摸模块SPI串口驱动
制造商可以提供配置文件或参考数据手册LCD以及触摸屏的驱动配置
LCD驱动流程
- 硬复位
- 发送初始化序列(根据制造商提供的设置)
- 设置坐标
- 写点或读点
- 写点步骤:
- 写GRAM指令
- 写入颜色数据
- LCD显示点
- 读点步骤
- 读GRAM指令
- 阅读颜色数据
- 输出数据给单片机处理
RGB565格式
LCD模块对外采用16位80并口,颜色深度为16为,格式为RGB565
对应关系如下:5位R、6位G、5位B——RGB565
数据线 | D15 | D14 | D13 | D12 | D11 | D10 | D9 | D8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
LCD GRAM | R[4] | R[3] | R[2] | R[1] | R[0] | G[5] | G[4] | G[3] | G[2] | G[1] | G[0] | B[4] | B[3] | B[2] | B[1] | B[0] |
重点代码
font.h
///这里省略 ///可以使用字符点阵绘图软件或已有字库导出相应字符的点阵集 //应#include到lcd.c文件中
lcd.h
#ifndef __LCD_H #define __LCD_H #include "sys.h" #include "stdlib.h" /*-----------------LCD定义重要参数集----------------*/ typedef struct {
u16 width; //LCD 宽度 u16 height; //LCD 高度 u16 id; //LCD ID u8 dir; //横屏或竖屏控制:0,竖屏;1.横屏 u16 wramcmd; //开始写gram指令 u16 setxcmd; //设置x坐标指令 u16 setycmd; //设置y坐标指令 }_lcd_dev; //LCD参数 extern _lcd_dev lcddev;//管理LCD重要参数 extern u16 POINT_COLOR;///画笔颜色,默认红色 extern u16 BACK_COLOR;//背景色.默认为白色 /*-----------------LCD定义重要参数集----------------*/ /*-----------------LCD端口定义----------------*/ #define LCD_LED PBout(15) //LCD背光 PB15 /*-----------------LCD端口定义----------------*/ /*-----------------LCD地址定义----------------*/ //LCD地址结构体 typedef struct {
vu16 LCD_REG; vu16 LCD_RAM; } LCD_TypeDef;
//使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11 A6作为数据命令区分线
//注意设置时STM32内部会右移一位对其! 111 1110=0X7E
#define LCD_BASE ((u32)(0x6C000000|0x0000007E))
//Bank1Sector4基地址为0x6C000000,A10的偏移地址为0x000007EF
#define LCD ((LCD_TypeDef *) LCD_BASE)
//将上述地址强制转换为LCD地址结构体指针,即得到LCD->LCD_REG的地址,实现对RS的控制
/*-----------------LCD地址定义----------------*/
//扫描方向定义
#define L2R_U2D 0
//从左到右,从上到下
#define L2R_D2U 1
//从左到右,从下到上
#define R2L_U2D 2
//从右到左,从上到下
#define R2L_D2U 3
//从右到左,从下到上
#define U2D_L2R 4
//从上到下,从左到右
#define U2D_R2L 5
//从上到下,从右到左
#define D2U_L2R 6
//从下到上,从左到右
#define D2U_R2L 7
//从下到上,从右到左
#define DFT_SCAN_DIR L2R_U2D
//默认的扫描方向
//画笔颜色
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define BROWN 0XBC40
//棕色
#define BRRED 0XFC07
//棕红色
#define GRAY 0X8430
//灰色
//GUI颜色
#define DARKBLUE 0X01CF
//深蓝色
#define LIGHTBLUE 0X7D7C
//浅蓝色
#define GRAYBLUE 0X5458
//灰蓝色
//以上三色为PANEL的颜色
#define LIGHTGREEN 0X841F
//浅绿色
//#define LIGHTGRAY 0XEF5B //浅灰色(PANNEL)
#define LGRAY 0XC618
//浅灰色(PANNEL),窗体背景色
#define LGRAYBLUE 0XA651
//浅灰蓝色(中间层颜色)
#define LBBLUE 0X2B12
//浅棕蓝色(选择条目的反色)
void
LCD_Init
(
void
)
;
//初始化LCD
void
LCD_DisplayOn
(
void
)
;
//开显示
void
LCD_DisplayOff
(
void
)
;
//关显示
void
LCD_Clear
(u16 Color
)
;
//清屏
void
LCD_SetCursor
(u16 Xpos
, u16 Ypos
)
;
//设置光标
void
LCD_DrawPoint
(u16 x
,u16 y
)
;
//画点
void
LCD_Fast_DrawPoint
(u16 x
,u16 y
,u16 color
)
;
//快速画点 u16
LCD_ReadPoint
(u16 x
,u16 y
)
;
//读点
void
LCD_Draw_Circle
(u16 x0
,u16 y0
,u8 r
)
;
//画圆
void
LCD_DrawLine
(u16 x1
, u16 y1
, u16 x2
, u16 y2
)
;
//画线
void
LCD_DrawRectangle
(u16 x1
, u16 y1
, u16 x2
, u16 y2
)
;
//画矩形
void
LCD_Fill
(u16 sx
,u16 sy
,u16 ex
,u16 ey
,u16 color
)
;
//填充单色
void
LCD_Color_Fill
(u16 sx
,u16 sy
,u16 ex
,u16 ey
,u16
*color
)
;
//填充指定颜色
void
LCD_ShowChar
(u16 x
,u16 y
,u8 num
,u8 size
,u8 mode
)
;
//显示一个字符
void
LCD_ShowNum
(u16 x
,u16 y
,u32 num
,u8 len
,u8 size
)
;
//显示一个数字
void
LCD_ShowxNum
(u16 x
,u16 y
,u32 num
,u8 len
,u8 size
,u8 mode
)
;
//显示 数字
void
LCD_ShowString
(u16 x
,u16 y
,u16 width
,u16 height
,u8 size
,u8
*p
)
;
//显示一个字符串,可用12/16字体
void
LCD_WriteReg
(u16 LCD_Reg
, u16 LCD_RegValue
)
; u16
LCD_ReadReg
(u16 LCD_Reg
)
;
void
LCD_WriteRAM_Prepare
(
void
)
;
void
LCD_WriteRAM
(u16 RGB_Code
)
;
void
LCD_SSD_BackLightSet
(u8 pwm
)
;
//SSD1963 背光控制
void
LCD_Scan_Dir
(u8 dir
)
;
//设置屏扫描方向
void
LCD_Display_Dir
(u8 dir
)
;
//设置屏幕显示方向
void
LCD_Set_Window
(u16 sx
,u16 sy
,u16 width
,u16 height
)
;
//设置窗口
//LCD分辨率设置参数
#define SSD_HOR_RESOLUTION 800
//LCD水平分辨率
#define SSD_VER_RESOLUTION 480
//LCD垂直分辨率
//LCD驱动设置参数
#define SSD_HOR_PULSE_WIDTH 1
//水平脉宽
#define SSD_HOR_BACK_PORCH 46
//水平前廊
#define SSD_HOR_FRONT_PORCH 210
//水平后廊
#define SSD_VER_PULSE_WIDTH 1
//垂直脉宽
#define SSD_VER_BACK_PORCH 23
//垂直前廊
#define SSD_VER_FRONT_PORCH 22
//垂直前廊
//如下几个参数,自动计算
#define SSD_HT (SSD_HOR_RESOLUTION+SSD_HOR_BACK_PORCH+SSD_HOR_FRONT_PORCH)
#define SSD_HPS (SSD_HOR_BACK_PORCH)
#define SSD_VT (SSD_VER_RESOLUTION+SSD_VER_BACK_PORCH+SSD_VER_FRONT_PORCH)
#define SSD_VPS (SSD_VER_BACK_PORCH)
#endif
lcd.c
这里仅写了显示函数(读写数据函数),LCD控制函数参考正点原子示例文档
u16 POINT_COLOR=0x0000;//画笔颜色
u16 BACK_COLOR=0xFFFF;//背景色
//默认为竖屏
_lcd_dev lcddev;
//写寄存器函数
//regval:寄存器值
void LCD_WR_REG(vu16 regval)
{
regval=regval;//使用-O2优化的时候,必须插入的延时
LCD->LCD_REG=regval;//写入要写的寄存器序号
}
//写LCD数据
//data:要写入的值
void LCD_WR_DATA(vu16 data)
{
data=data;//使用-O2优化的时候,必须插入的延时
LCD->LCD_RAM=data;
}
//读LCD数据
//返回值:读到的值
u16 LCD_RD_DATA(void)
{
vu16 ram;//防止被优化
ram=LCD->LCD_RAM;
return ram;
}
//写寄存器
//LCD_Reg:寄存器地址
//LCD_RegValue:要写入的数据
void LCD_WriteReg(u16 LCD_Reg,u16 LCD_RegValue)
{
LCD->LCD_REG=LCD_Reg;//写入要写的寄存器序号
LCD->LCD_RAM=LCD_RegValue;//写入数据
}
//读寄存器
//LCD_Reg:寄存器地址
//返回值:读到的数据
u16 LCD_ReadReg(u16 LCD_Reg)
{
LCD_WR_REG(LCD_Reg);//写入要读的寄存器序号
delay_us(5);
return LCD_RD_DATA();//返回读到的值
}
//开始写GRAM
void LCD_WriteRAM_Prepare(void)
{
LCD->LCD_REG=lcddev.wramcmd;
}
//LCD写GRAM
//RGB_Code:颜色值
void LCD_WriteRAM(u16 RGB_Code)
{
LCD->LCD_RAM = RGB_Code;//写十六位GRAM
}
//从ILI93xx读出的数据为GBR格式,而我们写入的时候为RGB格式。
//通过该函数转换
//c:GBR格式的颜色值
//返回值:RGB格式的颜色值
u16 LCD_BGR2RGB(u16 c)
{
u16 r,g,b,rgb;
b=(c>>0)&0x1f;
g=(c>>5)&0x3f;
r=(c>>11)&0x1f;
rgb=(b<<11)+(g<<5)+(r<<0);
return(rgb);
}
//当mdk -O1时间优化时需要设置
//延时i
void opt_delay(u8 i)
{
while(i--);
}
//读取个某点的颜色值
//x,y:坐标
//返回值:此点的颜色
u16 LCD_ReadPoint(u16 x,u16 y)
{
u16 r=0,g=0,b=0;
if(x>=lcddev.width||y>=lcddev.height)return 0;//超过了范围,直接返回
LCD_SetCursor(x,y);
if(lcddev.id==0X9341||lcddev.id==0X6804||lcddev.id==0X5310||lcddev.id==0X1963)LCD_WR_REG(0X2E);//9341/6804/3510/1963 发送读GRAM指令
else if(lcddev.id==0X5510)LCD_WR_REG(0X2E00); //5510 发送读GRAM指令
else LCD_WR_REG(0X22); //其他IC发送读GRAM指令
if(lcddev.id==0X9320)opt_delay(2); //FOR 9320,延时2us
r=LCD_RD_DATA(); //dummy Read
if(lcddev.id==0X1963)return r; //1963直接读就可以
opt_delay(2);
r=LCD_RD_DATA(); //实际坐标颜色
if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X5510)//9341/NT35310/NT35510要分2次读出
{
opt_delay(2);
b=LCD_RD_DATA();
g=r&0XFF;//对于9341/5310/5510,第一次读取的是RG的值,R在前,G在后,各占8位
g<<=8;
}
if(lcddev.id==0X9325||lcddev.id==0X4535||lcddev.id==0X4531||lcddev.id==0XB505||lcddev.id==0XC505)
return r;//这几种IC直接返回颜色值
else if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X5510)
return (((r>>11)<<11)|((g>>10)<<5)|(b>>11));//ILI9341/NT35310/NT35510需要公式转换一下
else
return LCD_BGR2RGB(r); //其他IC
}
//LCD开启显示
void LCD_DisplayOn(void)
{
if(lcddev.id==0X9341||lcddev.id==0X6804||lcddev.id==0X5310||lcddev.id==0X1963)
LCD_WR_REG(0X29);//开启显示
else if(lcddev.id==0X5510)
LCD_WR_REG(0X2900);//开启显示
else
LCD_WriteReg(0X07,0x0173);//开启显示
}
//LCD关闭显示
void LCD_DisplayOff(void)
{
if(lcddev.id==0X9341||lcddev.id==0X6804||lcddev.id==0X5310||lcddev.id==0X1963)
LCD_WR_REG(0X28);//关闭显示
else if(lcddev.id==0X5510)
LCD_WR_REG(0X2800);//关闭显示
else
LCD_WriteReg(0X07,0x0);//关闭显示
}
//画点
//x,y:坐标
//POINT_COLOR:此点的颜色
void LCD_DrawPoint(u16 x,u16 y)
{
LCD_SetCursor(x,y);//设置光标位置
LCD_WriteRAM_Prepare();//开始写入GRAM
LCD->LCD_RAM=POINT_COLOR;
}
//快速画点
//x,y:坐标
//color:颜色
void LCD_Fast_DrawPoint(u16 x,u16 y,u16 color)
{
if(lcddev.id==0X9341||lcddev.id==0X5310)
{
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA(x>>8);
LCD_WR_DATA(x&0XFF);
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA(y>>8);
LCD_WR_DATA(y&0XFF);
}
else if(lcddev.id==0X5510)
{
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA(x>>8);
LCD_WR_REG(lcddev.setxcmd+1);
LCD_WR_DATA(x&0XFF);
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA(y>>8);
LCD_WR_REG(lcddev.setycmd+1);
LCD_WR_DATA(y&0XFF);
}
else if(lcddev.id==0X1963)
{
if(lcddev.dir==0)
x=lcddev.width-1-x;
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA(x>>8);
LCD_WR_DATA(x&0XFF);
LCD_WR_DATA(x>>8);
LCD_WR_DATA(x&0XFF);
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA(y>>8);
LCD_WR_DATA(y&0XFF);
LCD_WR_DATA(y>>8);
LCD_WR_DATA(y&0XFF);
}
else if(lcddev.id==0X6804)
{
if(lcddev.dir==1)
x=lcddev.width-1-x;//横屏时处理
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA(x>>8);
LCD_WR_DATA(x&0XFF);
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA(y>>8);
LCD_WR_DATA(y&0XFF);
}
else
{
if(lcddev.dir==1)
x=lcddev.width-1-x;//横屏其实就是调转x,y坐标
LCD_WriteReg(lcddev.setxcmd,x);
LCD_WriteReg(lcddev.setycmd,y);
}
LCD->LCD_REG=lcddev.wramcmd;
LCD->LCD_RAM=color;
}
//清屏函数
//color:要清屏的填充色
void LCD_Clear(u16 color)
{
u32 index=0;
u32 totalpoint=lcddev.width;
totalpoint*=lcddev.height;//得到总点数
if((lcddev.id==0X6804)&&(lcddev.dir==1))//6804横屏的时候特殊处理
{
lcddev.dir=0;
lcddev.setxcmd=0X2A;
lcddev.setycmd=0X2B;
LCD_SetCursor(0x00,0x0000);//设置光标位置为初始位置
lcddev.dir=1;
lcddev.setxcmd=0X2B;
lcddev.setycmd=0X2A;
}
else
LCD_SetCursor(0x00,0x0000);//设置光标位置
LCD_WriteRAM_Prepare