LCD – TFTLCD 原理与配置
TFTLCD(薄膜晶体管液晶显示器)
简介
Thin Film Transistor - Liquid Crystal Display
TFTLCD计技术是微电子技术与液晶显示器技术巧妙结合的一种技术。
TFT-LCD屏可视为两片玻璃基板中间夹着一层液晶,上层的玻璃基板贴合彩色滤波片,下层玻璃有晶体管镶嵌。当有电流通过晶体管产生电场变化,造成液晶分子偏转,借以改变光线的偏极性,再利用偏光片决定像素的明暗状态。此外,上层玻璃因与彩色滤光片贴合,形成每个像素各包含红蓝绿三颜色,像素便构成了皮肤上的图像画面。
每一个像素上都设置有一个薄膜晶体管--->大大提高了图像质量
特点
亮度高 对比度高 层次感强 颜色鲜艳
原理
接口说明: (DB1DB8,DB10DB17,总是按顺序连接MCU的D0~D15) ① LCD_CS:LCD片选信号 ② LCD_WR:LCD写信号 ③ LCD_RD: LCD读信号 ④ DB[17:1]:16位双向数据线 ⑤ LCD_RST:硬复位LCD信号 ⑥ LCD_RS: 命令/数据标志(0:命令,1:数据) ⑦ BL_CTR:背光控制信号 ⑧ T_MISO/T_MOST/T_PEN/T_CS/T_CLK,触摸屏接口信号
驱动
8080并口读/写过程为: 先根据要写入/读取的数据的类型,设置RS为高(数据)/低(命令),然后拉低片选,选中ILI9341,接着根据是读还是写数据置RD/WD 为低 1.读数据:在RD的上升沿,读取数据线上的数据(D[15:0]) 2.写数据:在WR的上升沿,使数据写入到ILI9341里面
驱动流程
硬复位
LCD_RST=0; delay_ms(100); LCD_RST=1;
初始化序列
不同厂家出厂的LCD的初始化序列是不同的,由厂家提供。
设置坐标
写GRAM指令
写入颜色数据(0X2C)
LCD显示
读GRAM指令
读出颜色数据(0X2E)
单片机处理
RGB565格式
ILI9341指令格式说明
几条重要指令
0XD3
用来读取LCD控制器的ID 代码相同,ID不同——>执行不同的LCD驱动初始化——>兼容不同的LCD屏幕
0X36
存储访问控制指令,可以控制ILI9341存储器的读写方向 就是在连续写GRAM的时候,可以控制GRAM指针的增长方向,从而控制显示方式(读GRAM也是一样)
0X2A
列地址设置指令,默认从左向右,从上到下的扫描方式,用于设置横坐标 0<=SC<=EC<=239
0X2B
页(理解是行)地址设置指令,从左到右,从上到下的扫描方式下面,该指令用于设置纵坐标。 0<=SP<=EP<=319
0X2C
写GRAM指令,在发送该指令后,可往LCD的GRAM里面写入颜色数据,支持连续写(地址自动递增)
0X2E
读GRAM指令,用于读取ILI9341的显存,同0X2C指令,该指令支持连续读(地址自动递增) ILI9341收到指令后,第一次输出dummy数据(无效),第二次开始,读取到的才是有效的GRAM数据,输出规律为每个颜色分量占8个位,一次输出2个颜色分量。比如:第一次输出是R1G1,随后的规律为B1R1->G2B2->R3G3->~
FSMC简介
FSMC,灵活的静态存储控制器,能够与同步或异步存储器和16位IPC存储器卡连接。
FSMC驱动LCD
FSMC驱动外部SRAM时,外部SRAM的控制一般有:地址线(如A0A25)、数据线(如D0D15)、写信号(WE,即WR)、读信号(OE,即RD)、片选信号(CS),如果SRAM支持字节控制,那么还有UBLB信号。 而TFTL CD的信号我们在前面介绍过,包括: RS、D0D15、WR、RD、CS.RST和BL等,其中真正在操作LCD的时候需要用到的就只有:RS、DOD15、WR.RD和CS.其操作时序和SRAM的控制完全类似,唯一不同就是TFTLCD有RS信号,但是没有地址信号。 TFTLCD通过RS信号来决定传送的数据是数据还是命令,本质上可以理解为一个地址信号,比如我们把RS接在AO上面,那么当FSMC控制器写地址0的时候,会使得AO变为0,对TFTLCD来说,就是写命令。而FSMC写地址1的时候, A0将会变为1,对TFTLCD来说,就是写数据。这样把数据和命令区分开,对应SRAM操作的两个连续地址。当然RS也可以接在其他地址线上,战舰V3和精英板开发板都是把RS连接在A10上面,而探索者STM32F4把RS接在A6上面。 因此,可以把TFTLCD当成一个SRAM来用,只不过这个SRAM有2个地址,这就是FSMC可以驱动LCD的原理。
NOR PSRAM外设接口
STM32的FSMC将外部存储器划分为固定大小为256M字节的四个存储块
存储块1
Bank1(存储块1)用于驱动NOR FLASH/SRAM/PSRAM,被分为四个区,每区管理54M字节空间,每个区都有独立的寄存器对所连接的存储器进行配置。Bank1 的256M字节空间由28根地址线[HADDR【27:0】]寻址。 HADDR是内部AHB地址总线,其中HADDR【25:0】来自外部存储器地址FSMC_A[25:0],HADDR[26:27]对四个区进行寻址。 当Bank1接的是16位宽度存储器的时候: HADDR[25:1——>FSMC_A[24:0] 当Bank1接的是8位宽度存储器的时候: HADDR[25:0]——>FSMC_A[25:0] 不论外部接8位/16位宽设备,FSMC_A[0]永远接在外部设备地址A[0]
这里使用模式A来驱动LCD
寄存器
对于NORELASH/PSRAM控制器(存储块1),通过ESMC BCRx、FSMC_BTRx和FSMC_ BWTRx寄存器设置(其中x=1~4,对应4个区)。通过这3个寄存器,可E设置FSMC访问外部存储器的时序参数,拓宽了可选用的外部存储器的速度范围。
EXTMOD:扩展模式使能位,控制是否允许读写不同的时序,需设置为1 WREN:写使能位。向TFTLCD写数据,故该位必须设置为1 MWID[1:0]:存储器数据总线宽度。00,表示8位数据模式;01表示16位数据模式;10和11保留。TFTLCD是16位数据线,所以设置WMID[1:0]=01."MTYP[1:0]:存储器类型。00表示SRAM、ROM; 01表示PSRAM:10表示NORFLASH;11保留。LCD当成SRAM,需要设置MTYP[1:0]=00. MBKEN:存储块使能位。设置为1 ACCMOD[1:0]:访问模式。00:模式A;01:模式B:10:模式C;11:模式D. DATAST[7:0]:数据保持时间,等于: DATAST(+1)个HCLK时钟周期,DATAST最大为255。对ILI9341来说,其实就是RD低电平持续时间,最大为355ns,对STM32F1,一个HCLK=13.8ns (1/72M),设置为15;对STM32F4,一个HCLK=6ns(1/168M),设置为60。 ADDSET[3:0]:地址建立时间。表示:ADDSET (+1)个HCLK周期, ADDSET最大为15。对ILI9341来说,这里相当于RD高电平持续时间,为90ns,STM32F1的FSMC性能存在问题,即便设置为0,RD也有190ns的高电平,我们这里设置为1。而对STM32F4,则设置为15。
ACCMOD[1:0]:访问模式。00:模式A;01:模式B:10:模式C;11:模式D, DATAST[7:0]:数据保持时间,等于:DATAST(+1)个HCLK时钟周期, DATAST最大为255。对I LI9341来说,其实就是WR低电平持续时间,为15ns,不过ILI9320等则需要50ns。考虑兼容性,对STM32F1,一个HCLK=13.8ns (1/72M),设置为3;对STM32F4,一个HCLK=6ns(1/168M),设置为9。 ADDSET[3:0]:地址建立时间。表示: ADDSET+1个HCLK周期, ADDSET最大为15。对ILI9341相当于WR高电平持续时间,为15ns。兼容ILI9320,对STM32F1设置为1。STM32F4,设置为8。
寄存器组合
ST官方库提供的寄存器定义,没有定义单独的寄存器,而是将他们进行组合。
FSMC BCR×和FSMC_BTRx,组合成BTCR[8]寄存器组 BTCR[0]对应FSMC BCR1,BTCR[1]对应FSMC BTR1 BTCR[2]对应FSMC BCR2,BTCR[3]对应FSMC BTR2 BTCR[4]对应FSMC_BCR3,BTCR[5]对应FSMC BTR3 BTCR[6]对应FSMC BCR4,BTCR[7]对应FSMC BTR4
F.SMC BWTRX则组合成BWTR[7]: BWTR[O]对应FSMC_BWTR1,BWTR[2]对应FSMC_BWTR2 BWTRI4]对应FSMC BWTR3, BWTR[6]对应FSMC BWTR4
LCD实验源码
硬件连接(STM32F4开发板)
LCD_BL(背光控刷)对应 PBO; LCD_CS对应PGl2即 FSMC_NE4; LCD_RS对应 PG0FSMC_Al0; LCD_wR对应PDS 即 FSMC_NWE; LCD_RD对应PD4即 FSMC_NOE; LCD_D[15:0]则直接连接在FSMC_Dl5~FSMC_D0;
LCD&lcddev结构体
LCD结构体
typedef struct
{
vu16 LCD_ REG;
vu16 LCD RAM;
}LCD_TypeDef;
#define LCD_BASE ((u32)(0x6co0o000|Ox0000007FE))
#define LCD ((LCD_ TypeDef*)LCD_ BASE)
LCD_BASE,根据外部电路的连接来确定,如Bank1.sector4就是从地址OX6C000000开始,而OX000007FE,则是A10的偏移量。以A10为例,7FE换成二进制为:111 11111110,而16位数据时,地址右移一位对齐,对应到地址引脚,就是: A10:A0=011 11111111,此时A10是0,但是如果16位地址再加1(对应到8位地址是加2,即7FE+0X02),那么:A10:A0=100 0000 0000,此时A10就是1了,即实现了对RS的0和1的控制。 将((LCD_ TypeDef)LCD_ BASE)这个地址强制转换为LCD_TypeDef结构体地址,得到LCD->LCD_REG的地址OX6CO0,07FE,对应A10的状态为O(即RS=0),而LCD->LCD_RAM的地址就是0X6C00,0800(结构体地址自增),对应A10的状态为1(即RS=1),从而实现对RS的控制。*
lcddev结构体
typedef struct{
u16 width;
u16 height;
u16 id;
u8 dir;
u16 wramcmd;
u16 setxcmd;
u16 setycmd;
}_Icd_dev;
extern _lcd_dev lcddev;
该结构体参数的赋值,基本都是在LCD_Display_Dir函数完成
底层接口函数
总括:
void LCD WR REG(u16 regval)
void LCD WR DATA(u16 data)
u16 LCD RD DATA(void)
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_WR_REG(vu16 regval)
{
regval=regval;
LCD->LCD_REG=regval;
}
void LcD_WR_DATA(vul6 data)
data=data;
LCD->LCD_RAM=data ;
)
ul6 LCD_RD_DATA (void)
vul6 ram;
ram=LCD->LCD_RAM;
return ram;
void LcD_WriteReg (ul6 LCD_Reg,ul6 LCD_Regvalue)
LCD->LCD_REG= LCD_Reg;
ul6 LCD_ReadReg (ul6 LCD_Reg)
L.CD_WR_REG(LCD_Reg) ;
return LCD_RD_DATA ( );
}
void LCD_writeRAM_Prepare (void)
{
LCD->LCD_REG=lcddev.wramcmd;
}
void LcD_writeRAM (ul6 RGB_code){
LCD->LCD_RAM=RGB_code;
初始化函数
void LCD_Init(void)
{
初始化GPIO;
初始化FSMC;
读取LCD D;
printf( "LCD ID:%Kx\rn", lcddev.id);
根据不同的ID执行LCD初始化代码;
LCD Display Dir(0);
LCD LED=1;
LCD Clear (WHITE);
坐标设置函数
void LCD SetCursor (ul6 Xpos,u16 Ypos)
{
if(lcddev.idoX9341 I|lcddev.id 0X5310)
{
LCD_WR_REG(lcddev.setxcmd);
LCD_WR DATA (Xpos>>8);
LCD_WR DATA (Xpos&OXFF);
LCD_WR_REG(1eddev.setycmd);
LCD_WR_DATA(Ypos>>8);
LCD_WR_ DATA(Ypos&OXFF);
}else if(lcddev. idXXX){}
}
画点函数
void LCD_DrawPoint (u16 x, ul6 y)
{
LCD SetCursor (x,y);
LCD_WriteRAM_Prepare();
LCD->LCD_ RAM=POINT_COLOR;
读点函数
ul6 LCD_ReadPoint (ul6 x,ul6 y){
ul6 r=0, g=o,b=0 ;
if(x>=lcddev.width ||y>=lcddev.height)return 0;
if(lcddev.id==0X9341||lcddev.id==OX6804 ||lcddev.id==OX5310||leddev.id==OX1963)LED_WR_REG(0X2E);
else if (lcddev.id==0X5510)LCD_wR_REG (OX2Eo0);
else LCD_WR_REG(0X22);
if(lcddev.id==0X9320)opt_delay (2);
if ( lcddev.id==0X1963) return r;
opt_delay (2);
r=LCD_RD_DATA( ) ;
if (lcddev.id==0X9341||lcddev.id==OX5310||lcddev.id==OX5510)
{
opt_delay (2);
b=LCD_RD_DATA();
g=r&0XFF;
g<<=8 ;
if(lcddev.id==O0X9325||lcddev. id=O0X4535||lcddev .id==0X4531 ||lcddev .id==O0XB505]||lcddev.id==0XC505)return r;
else if(lcddev.id=0X9341||lcddev.id==0X5310||lcddev.id==0X5510)return ((r>>l)<<I1)|(g>>10)<<5)|(b>>11));
else return LCD_BGR2RGB(r) ;
字符显示函数
void LcD_ShowChar(ul6 x,ul6 y,u8 num, u8 size,u8 mode)
{
u8 temp,tl,t;
ul6 yO=y;
u8 csize=(size/8+((size卺8)?1:0))*(size/2);.
num=num-' ';
for (t=0;t<csize;t++)
{
if(size==l2)temp=asc2_1206[num][t];
else if(size==l6)temp=asc2_1608 [num][t];
else if(size==24)temp=asc2_2412[num][t];
else return;
for (tl=0;tl<8;tl++)
{
if (temp&0x80)LCD_Fast_DrawPoint (x,y,POINT_COLOR) ;
else if (mode==0)LCD_Fast_DrawPoint (x,y,BACK_COLOR);
temp<<=l;
y++;
if(y>=lcddev.height) return;
if( (y-y0 )==size)
{
y=y0;x++;
if(>=lcddev.width) return;
break;
}
}
}
}
|