历史上的今天
返回首页

历史上的今天

今天是:2025年04月17日(星期四)

正在发生

2018年04月17日 | STM32F4——TFT-LCD原理及FSMC

2018-04-17 来源:eefocus

一、简介:

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


  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重要参数结构体


  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;   

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

 

  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. }  

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


  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. }  

五、画点函数

  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. }  

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

六、读点函数


  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的初步认识,后边还会继续学习和认识有关其操作和应用。


推荐阅读

史海拾趣

Bharat Electronics Ltd公司的发展小趣事

随着技术的不断积累和发展,BEL逐渐摆脱了对外部技术的依赖,开始自主研发和生产电子产品。公司不仅成功开发出一系列具有自主知识产权的产品,还打造了知名的BEL品牌。这些产品以其高性能、高可靠性在市场中赢得了广泛认可,使BEL成为印度乃至全球电子行业中的佼佼者。

ECS公司的发展小趣事

ECS公司成立于XXXX年,由一群热衷于云计算技术的工程师创立。在创立初期,公司就明确了以提供高效、弹性的云服务为目标。他们深入研究了虚拟化技术、自动化管理等关键技术,成功推出了ECS服务,为客户提供按需分配的计算资源。这一创新的服务模式迅速吸引了众多客户的关注,ECS公司开始在云服务市场崭露头角。

Alorium Technology公司的发展小趣事

ECS公司成立于XXXX年,由一群热衷于云计算技术的工程师创立。在创立初期,公司就明确了以提供高效、弹性的云服务为目标。他们深入研究了虚拟化技术、自动化管理等关键技术,成功推出了ECS服务,为客户提供按需分配的计算资源。这一创新的服务模式迅速吸引了众多客户的关注,ECS公司开始在云服务市场崭露头角。

CAROLCABLE公司的发展小趣事

CAROLCABLE公司的创立,标志着电子线缆行业迎来了一位新的竞争者。在电子科技飞速发展的时代背景下,创始人凭借对线缆技术的深刻理解和市场需求的敏锐洞察,决定创立CAROLCABLE公司。公司初期,面临着资金短缺、技术瓶颈和市场认知度低等多重挑战。然而,创始人凭借着坚定的信念和不懈的努力,带领团队克服了一个又一个困难。他们积极研发新产品,优化生产工艺,提高产品质量,逐渐在市场上站稳了脚跟。

随着公司业务的不断拓展,CAROLCABLE开始与一些知名的电子企业建立合作关系,为其提供高质量的线缆产品。这些合作不仅为公司带来了稳定的订单和收入,也进一步提升了CAROLCABLE在行业内的知名度和影响力。

Dytran Instruments Inc公司的发展小趣事

尽管已经被收购并进行了业务整合,但Dytran并没有停止其创新的步伐。公司继续加大研发投入,推动传感器技术的不断创新和升级。同时,Dytran还积极探索新的应用领域和市场空间,以满足不断变化的客户需求。

在未来,Dytran将继续致力于为客户提供高质量、高性能的传感器产品和解决方案。同时,公司还将积极参与国际竞争和合作,推动传感器技术的国际化和标准化进程。通过不断创新和发展,Dytran有望在电子行业中继续保持其领先地位并实现更加辉煌的未来。

以上五个故事框架概述了Dytran Instruments Inc.公司在电子行业中的发展历程、技术创新、市场拓展、被收购与业务整合以及未来展望等方面的重要事件和里程碑。这些故事展示了Dytran如何凭借其技术实力和市场洞察力在竞争激烈的电子行业中脱颖而出并实现持续发展。

亿佰特(EBYTE)公司的发展小趣事

亿佰特始终坚持以质量为核心的发展理念。公司建立了严格的质量控制体系,从原材料采购到生产制造,再到产品检验,每一个环节都严格把关。通过精细化的管理,亿佰特确保了产品的优良品质。同时,公司还注重售后服务,为客户提供全方位的支持。正是凭借卓越的品质和优质的服务,亿佰特赢得了客户的信赖和市场的认可。

问答坊 | AI 解惑

华为逻辑电平设计规范教材

华为逻辑电平设计规范教材…

查看全部问答>

怎么学好单片机

我是一个刚上大二的学生,看着单片机的一些东西觉得很感兴趣想学,但是又不知从何学起?希望高手指点一下帮我规划一下?小弟不胜感激。。。…

查看全部问答>

8051f单片机silicon ide编译请教

  我编译时提示 LInker not found C:\\Silabs...\\BIN\\bi51.exe是怎么回事,是我的软件没有装好吗? 可是我卸载了又装了还是这样 怎么回事刚开始用不懂 谢谢了…

查看全部问答>

STM32F10xx时钟系统框图:时钟是整个系统的脉搏

下图是STM32F10xx时钟系统的框图,通过这个图可以一目了然地看到各个部件时钟产生的路径,还可以很方便地计算出各部分的时钟频率。STM32的四个时钟源(HSI、HSE、LSI和LSE)也在图中标出;图中间的时钟监视系统(CSS)是在很多ST7的单片机中就出现 ...…

查看全部问答>

STM32串口控制寄存器疑问

准备采用中断法发送数据,看到datasheet描述USART_CR1位7(TXEIE)和位8(TCIE),不是太明白。采用那一种比较好?…

查看全部问答>

求助:利用MSP430制作函数发生器

我是一个菜鸟,目前有任务利用MSP430F1611制作一个函数发生器,信号最后经DAC12输出,函数波形方波,正弦波,三角波等,频率要求不高200Hz以下,请问各位高手应如何入手,有什么思路,小弟在此谢谢了。…

查看全部问答>

电子时钟控制程序

最近写了一个有关电子时钟控制的程序(我是初学者),程序调试时发现:当调节参数时,数码管显示不稳定。程序我修改了无数遍,就是不知道原因出在哪里!希望可以在各位大虾的帮助找出原因!!!!!   程序如下:   /*------ ...…

查看全部问答>

MXCHIP open

    玩这块板子,涵盖的知识太过广泛,刚开始熟悉大概流程,试过几个例子之后。觉得就那样,都是别人写好的代码,自己移植过去,自己想要一个深刻的理解,所以看了一些另外的一些协议之类的东西,也没着急弄这个东西,看了这么长时间后, ...…

查看全部问答>

直流/直流转换器数据表——系统效率揭秘

市面上售有各种类型的稳压器,但很难选择一款直流/直流稳压器。大多数汽车应用都要求在整个负载范围内保持高效率,因为它们一直在耗电。但话又说回来,许多工业应用在高负载时需要高效率,而在轻负载时,效率并不是很重要。因此必须了解直流/直流稳 ...…

查看全部问答>