STM32F4——TFT-LCD原理及FSMC

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地址结构体分析

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

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

二、LCD重要参数结构体

[cpp]  view plain  copy
 print ?
  1. //LCD重要参数集  
  2. typedef struct    
  3. {                                             
  4.     u16 width;          //LCD 宽度  
  5.     u16 height;         //LCD 高度  
  6.     u16 id;             //LCD ID  
  7.     u8  dir;            //横屏还是竖屏控制:0,竖屏;1,横屏。     
  8.     u16 wramcmd;                //开始写gram指令  
  9.     u16 setxcmd;                //设置x坐标指令  
  10.     u16 setycmd;                //设置y坐标指令   
  11. }_lcd_dev;   

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

[cpp]  view plain  copy
 print ?
  1. //写寄存器函数  
  2. //regval:寄存器值  
  3. void LCD_WR_REG(vu16 regval)  
  4. {     
  5.     regval=regval;      //使用-O2优化的时候,必须插入的延时  
  6.     LCD->LCD_REG=regval;    //写入要写的寄存器序号    
  7. }  
  8. //写LCD数据  
  9. //data:要写入的值  
  10. void LCD_WR_DATA(vu16 data)  
  11. {      
  12.     data=data;          //使用-O2优化的时候,必须插入的延时  
  13.     LCD->LCD_RAM=data;          
  14. }  
  15. //读LCD数据  
  16. //返回值:读到的值  
  17. u16 LCD_RD_DATA(void)  
  18. {  
  19.     vu16 ram;           //防止被优化  
  20.     ram=LCD->LCD_RAM;      
  21.     return ram;    
  22. }                        
  23. //写寄存器  
  24. //LCD_Reg:寄存器地址  
  25. //LCD_RegValue:要写入的数据  
  26. void LCD_WriteReg(u16 LCD_Reg,u16 LCD_RegValue)  
  27. {     
  28.     LCD->LCD_REG = LCD_Reg;      //写入要写的寄存器序号       
  29.     LCD->LCD_RAM = LCD_RegValue;//写入数据                  
  30. }        
  31. //读寄存器  
  32. //LCD_Reg:寄存器地址  
  33. //返回值:读到的数据  
  34. u16 LCD_ReadReg(u16 LCD_Reg)  
  35. {                                            
  36.     LCD_WR_REG(LCD_Reg);        //写入要读的寄存器序号  
  37.     delay_us(5);            
  38.     return LCD_RD_DATA();       //返回读到的值  
  39. }     
  40. //开始写GRAM  
  41. void LCD_WriteRAM_Prepare(void)  
  42. {  
  43.     LCD->LCD_REG=lcddev.wramcmd;     
  44. }      
  45. //LCD写GRAM  
  46. //RGB_Code:颜色值  
  47. void LCD_WriteRAM(u16 RGB_Code)  
  48. {                                 
  49.     LCD->LCD_RAM = RGB_Code;//写十六位GRAM  
  50. }  

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

[cpp]  view plain  copy
 print ?
  1. //设置光标位置  
  2. //Xpos:横坐标  
  3. //Ypos:纵坐标  
  4. void LCD_SetCursor(u16 Xpos, u16 Ypos)  
  5. {      
  6.     if(lcddev.id==0X9341||lcddev.id==0X5310)  
  7.     {             
  8.         LCD_WR_REG(lcddev.setxcmd);   
  9.         LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);             
  10.         LCD_WR_REG(lcddev.setycmd);   
  11.         LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF);        
  12.     }else if(lcddev.id==0X6804)  
  13.     {  
  14.         if(lcddev.dir==1)Xpos=lcddev.width-1-Xpos;//横屏时处理  
  15.         LCD_WR_REG(lcddev.setxcmd);   
  16.         LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);   
  17.         LCD_WR_REG(lcddev.setycmd);   
  18.         LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF);   
  19.     }else if(lcddev.id==0X1963)  
  20.     {                     
  21.         if(lcddev.dir==0)//x坐标需要变换  
  22.         {  
  23.             Xpos=lcddev.width-1-Xpos;  
  24.             LCD_WR_REG(lcddev.setxcmd);   
  25.             LCD_WR_DATA(0);LCD_WR_DATA(0);        
  26.             LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);             
  27.         }else  
  28.         {  
  29.             LCD_WR_REG(lcddev.setxcmd);   
  30.             LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);        
  31.             LCD_WR_DATA((lcddev.width-1)>>8);LCD_WR_DATA((lcddev.width-1)&0XFF);                        
  32.         }     
  33.         LCD_WR_REG(lcddev.setycmd);   
  34.         LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF);        
  35.         LCD_WR_DATA((lcddev.height-1)>>8);LCD_WR_DATA((lcddev.height-1)&0XFF);                      
  36.           
  37.     }else if(lcddev.id==0X5510)  
  38.     {  
  39.         LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(Xpos>>8);        
  40.         LCD_WR_REG(lcddev.setxcmd+1);LCD_WR_DATA(Xpos&0XFF);               
  41.         LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(Ypos>>8);            
  42.         LCD_WR_REG(lcddev.setycmd+1);LCD_WR_DATA(Ypos&0XFF);              
  43.     }else  
  44.     {  
  45.         if(lcddev.dir==1)Xpos=lcddev.width-1-Xpos;//横屏其实就是调转x,y坐标  
  46.         LCD_WriteReg(lcddev.setxcmd, Xpos);  
  47.         LCD_WriteReg(lcddev.setycmd, Ypos);  
  48.     }      
  49. }  

五、画点函数

[cpp]  view plain  copy
 print ?
  1. //画点  
  2. //x,y:坐标  
  3. //POINT_COLOR:此点的颜色  
  4. void LCD_DrawPoint(u16 x,u16 y)  
  5. {  
  6.     LCD_SetCursor(x,y);     //设置光标位置   
  7.     LCD_WriteRAM_Prepare(); //开始写入GRAM  
  8.     LCD->LCD_RAM=POINT_COLOR;   
  9. }  
  10. //快速画点  
  11. //x,y:坐标  
  12. //color:颜色  
  13. void LCD_Fast_DrawPoint(u16 x,u16 y,u16 color)  
  14. {        
  15.     if(lcddev.id==0X9341||lcddev.id==0X5310)  
  16.     {  
  17.         LCD_WR_REG(lcddev.setxcmd);   
  18.         LCD_WR_DATA(x>>8);LCD_WR_DATA(x&0XFF);               
  19.         LCD_WR_REG(lcddev.setycmd);   
  20.         LCD_WR_DATA(y>>8);LCD_WR_DATA(y&0XFF);               
  21.     }else if(lcddev.id==0X5510)  
  22.     {  
  23.         LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(x>>8);    
  24.         LCD_WR_REG(lcddev.setxcmd+1);LCD_WR_DATA(x&0XFF);       
  25.         LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(y>>8);    
  26.         LCD_WR_REG(lcddev.setycmd+1);LCD_WR_DATA(y&0XFF);   
  27.     }else if(lcddev.id==0X1963)  
  28.     {  
  29.         if(lcddev.dir==0)x=lcddev.width-1-x;  
  30.         LCD_WR_REG(lcddev.setxcmd);   
  31.         LCD_WR_DATA(x>>8);LCD_WR_DATA(x&0XFF);          
  32.         LCD_WR_DATA(x>>8);LCD_WR_DATA(x&0XFF);          
  33.         LCD_WR_REG(lcddev.setycmd);   
  34.         LCD_WR_DATA(y>>8);LCD_WR_DATA(y&0XFF);          
  35.         LCD_WR_DATA(y>>8);LCD_WR_DATA(y&0XFF);          
  36.     }else if(lcddev.id==0X6804)  
  37.     {             
  38.         if(lcddev.dir==1)x=lcddev.width-1-x;//横屏时处理  
  39.         LCD_WR_REG(lcddev.setxcmd);   
  40.         LCD_WR_DATA(x>>8);LCD_WR_DATA(x&0XFF);               
  41.         LCD_WR_REG(lcddev.setycmd);   
  42.         LCD_WR_DATA(y>>8);LCD_WR_DATA(y&0XFF);          
  43.     }else  
  44.     {  
  45.         if(lcddev.dir==1)x=lcddev.width-1-x;//横屏其实就是调转x,y坐标  
  46.         LCD_WriteReg(lcddev.setxcmd,x);  
  47.         LCD_WriteReg(lcddev.setycmd,y);  
  48.     }              
  49.     LCD->LCD_REG=lcddev.wramcmd;   
  50.     LCD->LCD_RAM=color;   
  51. }  

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

六、读点函数

[cpp]  view plain  copy
 print ?
  1. //读取个某点的颜色值    
  2. //x,y:坐标  
  3. //返回值:此点的颜色  
  4. u16 LCD_ReadPoint(u16 x,u16 y)  
  5. {  
  6.     u16 r=0,g=0,b=0;  
  7.     if(x>=lcddev.width||y>=lcddev.height)return 0;    //超过了范围,直接返回             
  8.     LCD_SetCursor(x,y);       
  9.     if(lcddev.id==0X9341||lcddev.id==0X6804||lcddev.id==0X5310||lcddev.id==0X1963)LCD_WR_REG(0X2E);//9341/6804/3510/1963 发送读GRAM指令  
  10.     else if(lcddev.id==0X5510)LCD_WR_REG(0X2E00);   //5510 发送读GRAM指令  
  11.     else LCD_WR_REG(0X22);                          //其他IC发送读GRAM指令  
  12.     if(lcddev.id==0X9320)opt_delay(2);              //FOR 9320,延时2us          
  13.     r=LCD_RD_DATA();                                //dummy Read         
  14.     if(lcddev.id==0X1963)return r;                  //1963直接读就可以   
  15.     opt_delay(2);       
  16.     r=LCD_RD_DATA();                                //实际坐标颜色  
  17.     if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X5510)     //9341/NT35310/NT35510要分2次读出  
  18.     {  
  19.         opt_delay(2);       
  20.         b=LCD_RD_DATA();   
  21.         g=r&0XFF;       //对于9341/5310/5510,第一次读取的是RG的值,R在前,G在后,各占8位  
  22.         g<<=8;  
  23.     }   
  24.     if(lcddev.id==0X9325||lcddev.id==0X4535||lcddev.id==0X4531||lcddev.id==0XB505||lcddev.id==0XC505)return r;  //这几种IC直接返回颜色值  
  25.     else if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X5510)return (((r>>11)<<11)|((g>>10)<<5)|(b>>11));//ILI9341/NT35310/NT35510需要公式转换一下  
  26.     else return LCD_BGR2RGB(r);                     //其他IC  
  27. }  

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

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值