STM32F4——TFT-LCD原理及FSMC

来源:互联网 发布:大数据 应用 编辑:程序博客网 时间:2024/05/22 12:55

TFT-LCD

一、简介:

    TFT-LCD即薄膜晶体管液晶显示器,依据其尺寸、分辨率和驱动芯片的不同有很多分类,下边会依据2.8寸320X240分辨率以ILI9341芯片驱动的TFT-LCD做相关介绍。

二、接口:

    模块采用16位并方式与外部连接,其相关接口图及信号线功能如下:

    CS:TFTLCD片选信号。WR:向TFTLCD写数据。RD:从TFTLCD读取数据。D[15:0]:16位数据线。RS:命令/数据标示(0,读写命令;1,读写数据)。

三、驱动时序:

    对于写时序:CS拉低做片选,RS表示是要写数据还是要写命令,在WR信号线的上升沿获取数据线D[0:15]上的数据,在写时序上RD信号线总是处于高电平。对于读时序同理。

四、驱动流程:

    对于LCD的驱动流程可由下图表示:

    首先通过LCD_RST引脚做复位,再进行初始化序列,由于本人现阶段水平有限,先不去研究相关初始化序列,所以就直接运用LCD商家给出的初始化序列代码。无论是读写指令,都需要设置好坐标,再做出读写GRAM的相关指令。在随后涉及到颜色数据的相关处理,下边就针对颜色数据做一下相关说明。

    对于颜色的设定也有多种格式,在这里只是针对RGB565颜色格式做说明。RGB565这样看(Red)[5位](Green)[6位](Blue)[5位],组成16位颜色深度。

五、指令:

    对于ILI9341的指令有很多,下边对ILI9341驱动芯片的个别指令做相关说明:1、0XD3:该指令用于读取芯片ID。由此可以依据不同的LCD做相关初始化,做到更好的兼容。2、OX36:存储器访问控制指令,可以在读写数据过程中控制GRAM指针的增长方向,简单说明就是控制像素的扫描方式。3、0X2A:用于设置列地址,也就是在从左到右从上到下的扫描方式下,设置x坐标。即用于设置x坐标的范围。4、0X2B:与OX2A类似,该指令用于设置y坐标。需要说明的是在OX2A和OX2B的控制下就可以在屏幕上开窗显示了。5、0X2C:该指令用于向GRAM中写入颜色数据。6、0X2E:读取GRAM中的颜色数据。


FSMC

一、简介:

    FSMC即灵活静态存储控制器,用于静态存储器的扩展。对于TFT-LCD显示中将LCD当做一个SRAM来进行操作,下边会有所介绍。

二、框图结构:

       对于FSMC的引脚已经在框图中有所标注,对于下边的存储块的图是FSMC对其存储器的管理方式,每个存储块大小为256M,由于LCD是要当做SRAM来处理的,那么就要有存储块1的扩展来使得LCD工作。存储块1由28根地址线(HADDR[27:0])寻址,由于每个存储块分为四个区,HADDR[27:26]用于做相关区域选择。注意:由于在这里LCD作为一个16位宽的存储器,而内部的存储是以字节为单位的,则需要HADDR[25:1]对应到FSMC[24:0],即相当于内部的存储地址除以2(右移1位),从而与外部地址对应上。

三、相关寄存器:

    1、FSMC_BCRx:SRAM/NOR闪存片选控制寄存器。

    相关位:EXTMOD:控制是否允许读写使用不同的时序。WREN:写使能。MWID[1:0]:设置数据总线宽。MTYP[1:0]:配置存储器类型。MBKEN:存储块使能。

    2、FSMC_BTRx:SRAM/NOR闪存片选时序寄存器。

    相关位:ACCMOD[1:0]:设置访问模式。DATAST[7:0]:数据保持时间。ADDSET[3:0]:地址建立时间设置。

    3、FSMC_BWTRx:SRAM/NOR闪存写时序控制器。

    相位位同FSMC_BTRx对应位相同。


TFT-LCD显示部分代码参考   

一、LCD地址结构体分析

//LCD地址结构体typedef struct{u16 LCD_REG;u16 LCD_RAM;} LCD_TypeDef;//使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11 A6作为数据命令区分线 //注意设置时STM32内部会右移一位对其! 111 1110=0X7E    #define LCD_BASE        ((u32)(0x6C000000 | 0x0000007E))#define LCD             ((LCD_TypeDef *) LCD_BASE)

    由于存储块1的第4区的起始地址为0X6C000000,又由于A6作为数据和命令的区分线,根据代码可得:LCD是将LCD_BASE地址经过强制类型转换,装换为结构体类型,由此知:LCD_REG表示的为写命令地址,LCD_RAM表示为写数据地址。

二、LCD重要参数结构体

//LCD重要参数集typedef struct  {    u16 width;//LCD 宽度u16 height;//LCD 高度u16 id;//LCD IDu8  dir;//横屏还是竖屏控制:0,竖屏;1,横屏。u16 wramcmd;        //开始写gram指令u16 setxcmd;        //设置x坐标指令u16 setycmd;        //设置y坐标指令 }_lcd_dev; 

三、读写寄存器或数据函数(底层接口函数)

//写寄存器函数//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();//返回读到的值}   //开始写GRAMvoid 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}

四、设置坐标(根据不同的芯片选择不同的设置方式)

//设置光标位置//Xpos:横坐标//Ypos:纵坐标void LCD_SetCursor(u16 Xpos, u16 Ypos){  if(lcddev.id==0X9341||lcddev.id==0X5310){    LCD_WR_REG(lcddev.setxcmd); LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);  LCD_WR_REG(lcddev.setycmd); LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF); }else if(lcddev.id==0X6804){if(lcddev.dir==1)Xpos=lcddev.width-1-Xpos;//横屏时处理LCD_WR_REG(lcddev.setxcmd); LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF); LCD_WR_REG(lcddev.setycmd); LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF); }else if(lcddev.id==0X1963){   if(lcddev.dir==0)//x坐标需要变换{Xpos=lcddev.width-1-Xpos;LCD_WR_REG(lcddev.setxcmd); LCD_WR_DATA(0);LCD_WR_DATA(0); LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);  }else{LCD_WR_REG(lcddev.setxcmd); LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF); LCD_WR_DATA((lcddev.width-1)>>8);LCD_WR_DATA((lcddev.width-1)&0XFF);  }LCD_WR_REG(lcddev.setycmd); LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF); LCD_WR_DATA((lcddev.height-1)>>8);LCD_WR_DATA((lcddev.height-1)&0XFF);  }else if(lcddev.id==0X5510){LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(Xpos>>8); LCD_WR_REG(lcddev.setxcmd+1);LCD_WR_DATA(Xpos&0XFF); LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(Ypos>>8);  LCD_WR_REG(lcddev.setycmd+1);LCD_WR_DATA(Ypos&0XFF);}else{if(lcddev.dir==1)Xpos=lcddev.width-1-Xpos;//横屏其实就是调转x,y坐标LCD_WriteReg(lcddev.setxcmd, Xpos);LCD_WriteReg(lcddev.setycmd, Ypos);} }

五、画点函数

//画点//x,y:坐标//POINT_COLOR:此点的颜色void LCD_DrawPoint(u16 x,u16 y){LCD_SetCursor(x,y);//设置光标位置 LCD_WriteRAM_Prepare();//开始写入GRAMLCD->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; }

    两个函数一个是调用函数,一个是直接快速设置。功能相同。

六、读点函数

//读取个某点的颜色值 //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}

    这是TFT-LCD显示基本的一些函数,这是有关TFT-LCD的初步认识,后边还会继续学习和认识有关其操作和应用。


0 0