TFTtft lcd显示屏驱动中提到的GRAM是显存吗

查看: 11042|回复: 5
STM32之TFT-LCD液晶学习
TFT-LCD即薄膜晶体管液晶显示器。其英文全称为:Thin Film Transistor-Liquid Crystal Display。TFT-LCD与无源TN-LCD、STN-LCD的简单矩阵不同,它在液晶显示屏的每一个象素上都设置有一个薄膜晶体管(TFT),可有效地克服非选通时的串扰,使显示液晶屏的静态特性与扫描线数无关,因此大大提高了图像质量。TFT-LCD也被叫做真彩液晶显示器。
TFT液晶原理:
*背光模组:提供光源
*上下偏光片,TFT Glass Substrate, 液晶:形成偏振光,控制光线的通过与否
*彩色滤光片:提供TFT LCD R/G/B(三原色)的来源
*ITO透明导电层:提供透明的导电通路
*Photo Spacer:提供一个固定高度给彩色滤光片和TFT Glass Substrate,作为灌入液晶的空间,以及做为上下两层Glass的支撑
TFT-LCD使用的液晶为TN(Twist Nematic)型液晶,分子成椭圆状。TN型液晶一般是顺着长轴方向串接,长轴间彼此平行方式排列;当接触到槽状表面时,液晶分子就会顺着槽的方向排列与槽中
当液晶被包含在两个槽状表面中间,且槽的方向相互垂直,则液晶分子的排列为:
a)上表面分子:沿着a方向;
b)下表面分子:沿着b方向;
c)介于上下表面中间的分子:产生旋转的效应。
& &&&因此液晶分子在两槽状表面间产生90°的旋转
当线性偏极光射入上层槽状表面时,此光线随着液晶分子的旋转也产生旋转。
& & 当线性偏极光射出下层槽状表面时,此光线已经产生了90度的旋转
当在上下表面之间加电压时,液晶分子会顺着电场方向排列,此时入射光线不再会旋转,因而光线直线射出下表面&&
偏光片特性:
&&将非偏极光(一般光线)过滤成偏振光。
当非偏极光通过a方向的偏光片时,光线被过滤成与a方向平行的线性偏极光
上图:偏振方向相同,线性偏极光继续前进,通过第二片偏光片时,光线通过。
下图:偏振方向不同,通过第二片时,光线被完全阻挡
偏振光透过液晶分子,偏振方向发生旋转,光线可通过偏光片
当液晶分子呈如图方向排列时,光线偏振方向将不再发生旋转,最终无法通过偏光片
TFT上下各有一片偏振方向垂直的偏光片,背光板发出的光经背光模组散射后,先通过下层偏光片形成偏振光
& && &之后通过液晶分子,并由液晶分子的旋转角度决定通过液晶分子后的偏振方向
& && &在经过彩色滤光片产生红、绿、蓝三色光,最后通过上偏光片,并由偏振光偏振方向与偏光片偏振方向夹角决定最终输出的光强,以形成不同的色彩。
发光强弱由MOS管控制液晶偏转角度,从而控制光线出口强弱达到控制色彩目的.
假设240*320分辨率液晶则由于 基本色彩是3原色 所以总共有240*320*3个 MOS管
“像素”(Pixel) 是由 Picture(图像) 和 Element(元素)这两个单词的字母所组成的,是用来计算数码影像的一种单位,如同摄影的相片一样,数码影像也具有连续性的浓淡阶调,我们若把影像放大数倍,会发现这些连续色调其实是由许多色彩相近的小方点所组成,这些小方点就是构成影像的最小单位“像素”(Pixel)。这种最小的图形的单元能在屏幕上显示通常是单个的染色点。越高位的像素,其拥有的色板也就越丰富,越能表达颜色的真实感。
每个点显示的颜色如何由确定?
由于TFT 液晶我使用的是2.8寸的240*320分辨率(像素),16位真彩显示(接近自然色)
该模块采用的是显尚光电的DST2001PH TFTLCD,DST2001PH的控制器为ILI9320(可能为其他),采用16位的80并口。
驱动芯片显存GRAM与色彩关系:
由于是16为数据,所以最低5位代表蓝色,中间6位为绿色,最高5位为红色。数值越大,表示该颜色越深。
就是向显存里面写入不同数据,产生不同的颜色.
常见颜色确定:
利用画图工具里面3原色可能确定需要的显存数据。
本人使用ALIENTEK MiniSTM32开发板自配2.8寸液晶
液晶驱动芯片硬件接口:
采用16位数据线(低了速度太慢,用彩色就没什么效果了)。该模块的80并口有如下一些信号线:
CS:TFTLCD片选信号。
WR:向TFTLCD写入数据。
RD:从TFTLCD读取数据。
D[15:0]:16位双向数据线。
RST:硬复位TFTLCD。
RS:命令/数据标志(0,读写命令;1,读写数据)。
ILI9320常用寄存器指令:
R0,这个命令,有两个功能,如果对它写,则最低位为OSC,用于开启或关闭振荡器。而如果对它读操作,则返回的是控制器的型号。这个命令最大的功能就是通过读它可以得到控制器的型号,而我们代码在知道了控制器的型号之后,可以针对不同型号的控制器,进行不同的初始化。因为93xx系列的初始化,其实都比较类似,我们完全可以用一个代码兼容好几个控制器。
R3,入口模式命令。我们重点关注的是I/D0、I/D1、AM这3个位,因为这3个位控制了屏幕的显示方向。
//------------------------------------------------------------------------------------------------------------------------------------------
AM:控制GRAM更新方向。当AM=0的时候,地址以行方向更新。当AM=1的时候,地址以列方向更新。
I/D[1:0]:当更新了一个数据之后,根据这两个位的设置来控制地址计数器自动增加/减少1,
/--------------------------------------------------------------------------------------------------------------------------------------------
R7:显示控制命令。该命令CL位用来控制是8位彩色,还是26万色。为0时26万色,为1时八位色。D1、D0、BASEE这三个位用来控制显示开关与否的。当全部设置为1的时候开启显示,全0是关闭。我们一般通过该命令的设置来开启或关闭显示器,以降低功耗。
R32,R33:设置GRAM的行地址和列地址。R32用于设置列地址(X坐标,0~239),R33用于设置行地址(Y坐标,0~319)。当我们要在某个指定点写入一个颜色的时候,先通过这两个命令设置到改点,然后写入颜色值就可以了.
R34:写数据到GRAM命令,当写入了这个命令之后,地址计数器才会自动的增加和减少。该命令是我们要介绍的这一组命令里面唯一的单个操作的命令,只需要写入该值就可以了,其他的都是要先写入命令编号,然后写入操作数.
R80~R83:行列GRAM地址位置设置。这几个命令用于设定你显示区域的大小,我们整个屏的大小为240*320,但是有时候我们只需要在其中的一部分区域写入数据,如果用先写坐标,后写数据这样的方式来实现,则速度大打折扣。此时我们就可以通过这几个命令,在其中开辟一个区域,然后不停的丢数据,地址计数器就会根据R3的设置自动增加/减少,这样就不需要频繁的写地址了,大大提高了刷新的速度。
//--------------------------------------------------------------------------------------------------------
我们接下来看看要如何才能驱动ALIENTEK TFTLCD模块,TFTLCD显示需要的相关设置步骤如下:
1)设置STM32与TFTLCD模块相连接的IO。
这一步,先将我们与TFTLCD模块相连的IO口设置为输出,具体使用哪些IO口,这里需要根据连接电路以及TFTLCD模块的设置来确定。
2)初始化TFTLCD模块。
其实这里就是上和上面OLED模块的初始化过程差不多。通过向TFTLCD写入一系列的设置,来启动TFTLCD的显示。为后续显示字符和数字做准备。
3)通过函数将字符和数字显示到TFTLCD模块上。
MiniSTM32开发板的IO口对应关系如下:
LCD_LED对应PC10;
LCD_CS对应PC9;
LCD _RS对应PC8;
LCD _WR对应PC7;
LCD _RD对应PC6;
LCD _D[17:1]对应PB[15:0];
基本GUI接口函数简介(一)80并口时序图:
//------写数据函数--------- 这里我们采用了宏定义的方式,以提高速度(由于显示图像写入读出频繁):
#define LCD_WR_DATA(data){\
LCD_RS_SET;\& && && && && && && && && && &//选择数据& && &
LCD_CS_CLR;\& && && && && && && && && &&&//选择片
DATAOUT(data);\& && && && && && && && & //把数据放入端口
LCD_WR_CLR;\& && && && && && && && && &//WR写数据来个上升沿(将数据写入)
LCD_WR_SET;\
LCD_CS_SET;\& && && && && && && && && && & //CS上升沿 写入数据完成
上面函数中的‘\’是C语言中的一个转义字符,用来连接上下文,因为宏定义只能是一个串,而当你的串过长(超过一行的时候),就需要换行了,此时就必须通过反斜杠来连接上下文。这里的‘\’正是起这个作用
因为该函数使用频率不是很高 ,不使用宏定义
//----向寄存器发送指令函数------
void LCD_WR_REG(u8 data)
LCD_RS_CLR;& && & //选择指令
LCD_CS_CLR;& && & //选中芯片
DATAOUT(data);& &//端口放上指令
LCD_WR_CLR;& && &//WR写数据来个上升沿(将数据写入)
LCD_WR_SET;
LCD_CS_SET;& && & //CS上啦完成操作
由下面2个寄存器设置快速IO
//-------读取寄存器值函数---------
u16 LCD_ReadReg(u8 LCD_Reg)
LCD_WR_REG(LCD_Reg);& & //写入要读的寄存器号
GPIOB-&CRL=0x;& && & //将端口PORTB设置成输入模式
GPIOB-&CRH=0x;
GPIOB-&ODR=0& && && && && &//端口上拉预备输入
#ifdef LCD_FAST_IO& && && && & //判断快速IO口是否宏定义过
LCD_RS_SET;& && && && && && && && &//运用快速IO口& &(例:#define LCD_CS_SET&&GPIOC-&BSRR=1&&9& & //片选口&&PC9)
LCD_CS_CLR;& && && && && && && && && && && && && && && && && && && && &
LCD_RD_CLR;
LCD_RD_SET;& &//RD脚产生上升沿
LCD_CS_SET;
GPIOB-&CRL=0x;& && && && && && & //恢复输出状态
GPIOB-&CRH=0x;
GPIOB-&ODR=0
 # 很不错# 51黑有你更精彩!!
 不错!!!!!!!!!!
原理很形象
不错&&很有用
2.4寸和这个类似吗
Powered by查看: 2654|回复: 2
新手请教:ALIENTEK 教程中,TFTLCD 显示实验部分;结构体 _lcd_成员内容,在哪
主题帖子精华
新手上路, 积分 44, 距离下一级还需 6 积分
在线时间4 小时
工程中有:
//LCD重要参数集
typedef struct &
& & & &&//LCD 宽度
//LCD 高度
& & & &&//横屏还是竖屏控制:0,竖屏;1,横屏。
//开始写gram指令
//设置x坐标指令
//设置y坐标指令 &
extern _lcd_ //管理LCD重要参数
只有在初始化函数 Lcd_Init() 中,找到有 lcddev.id = LCD_ReadReg(0x0000);
其它成员找不到赋值的地方;函数中直接使用了,如:
void LCD_Clear(u16 color)
u32 index=0; & & &
u32 totalpoint=lcddev.
LCD_WriteRAM_Prepare(); & & //开始写入GRAM
void LCD_WriteRAM_Prepare(void)
& LCD-&LCD_REG=lcddev.
& lcddev. ...等...的内容在哪里?Lcd.c .h中没有。 不明白。
& &请老师们解答下。谢谢!
主题帖子精华
高级会员, 积分 713, 距离下一级还需 287 积分
在线时间0 小时
void&LCD_Display_Dir(u8&dir)你可以看看这个函数,之所以用结构体管理是为了兼容各个型号的驱动芯片
主题帖子精华
新手上路, 积分 44, 距离下一级还需 6 积分
在线时间4 小时
谢谢楼上。明白了。
Powered by&&国之画&&&& &&
版权所有 京ICP备号-2
迷上了代码!21ic官方微信-->
后使用快捷导航没有帐号?
查看: 16953|回复: 25
【连载】STM32开发指南--第十八章 TFTLCD显示实验
&&已结帖(0)
主题帖子积分
高级技术员, 积分 614, 距离下一级还需 386 积分
高级技术员, 积分 614, 距离下一级还需 386 积分
主题帖子积分
专家等级:结帖率:100%
主题帖子积分
高级技术员, 积分 614, 距离下一级还需 386 积分
高级技术员, 积分 614, 距离下一级还需 386 积分
本帖最后由 正点原子 于
18:26 编辑
第十八章 TFTLCD显示实验 上一章我们介绍了OLED模块及其显示,但是该模块只能显示单色/双色,不能显示彩色,而且尺寸也较小。本章我们将介绍ALIENTEK 2.8寸TFT LCD模块,该模块采用TFTLCD面板,可以显示16位色的真彩图片。在本章中,我们将使用战舰STM32开发板上的LCD接口,来点亮TFTLCD,并实现ASCII字符和彩色的显示等功能,并在串口打印LCD控制器ID,同时在LCD上面显示。本章分为如下几个部分:18.1 TFTLCD简介18.2 硬件设计18.3 软件设计18.4 下载验证18.1 TFTLCD&FSMC简介 本章我们将通过STM32的FSMC接口来控制TFTLCD的显示,所以本节分为两个部分,分别介绍TFTLCD和FSMC。18.1.1 TFTLCD简介 TFT-LCD即薄膜晶体管液晶显示器。其英文全称为:Thin Film Transistor-Liquid Crystal Display。TFT-LCD与无源TN-LCD、STN-LCD的简单矩阵不同,它在液晶显示屏的每一个象素上都设置有一个薄膜晶体管(TFT),可有效地克服非选通时的串扰,使显示液晶屏的静态特性与扫描线数无关,因此大大提高了图像质量。TFT-LCD也被叫做真彩液晶显示器。上一章介绍了OLED模块,本章,我们给大家介绍ALIENTEK TFTLCD模块,该模块有如下特点:1,2.4’/2.8’/3.5’3种大小的屏幕可选。2,320×240的分辨率(3.5’分辨率为:320*480)。3,16位真彩显示。4,自带触摸屏,可以用来作为控制输入。本章,我们以2.8寸的ALIENTEK TFTLCD模块为例介绍,该模块支持65K色显示,显示分辨率为320×240,接口为16位的80并口,自带触摸屏。该模块的外观图如图18.1.1.1所示:
& && && && && &&&图18.1.1.1 ALIENTEK 2.8寸TFTLCD外观图& && & 模块原理图如图18.1.1.2所示:
图18.1.1.2&&ALIENTEK 2.8寸TFTLCD模块原理图TFTLCD模块采用2*17的2.54公排针与外部连接,接口定义如图18.1.1.3所示:图18.1.1.3&&ALIENTEK 2.8寸TFTLCD模块接口图从图18.1.1.3可以看出,ALIENTEK TFTLCD模块采用16位的并方式与外部连接,之所以不采用8位的方式,是因为彩屏的数据量比较大,尤其在显示图片的时候,如果用8位数据线,就会比16位方式慢一倍以上,我们当然希望速度越快越好,所以我们选择16位的接口。图18.1.3还列出了触摸屏芯片的接口,关于触摸屏本章我们不多介绍,后面的章节会有详细的介绍。该模块的80并口有如下一些信号线:& && & CS:TFTLCD片选信号。& && & WR:向TFTLCD写入数据。& && & RD:从TFTLCD读取数据。& && & D[15:0]:16位双向数据线。& && & RST:硬复位TFTLCD。& && & RS:命令/数据标志(0,读写命令;1,读写数据)。80并口在上一节我们已经有详细的介绍了,这里我们就不再介绍,需要说明的是,TFTLCD模块的RST信号线是直接接到STM32的复位脚上,并不由软件控制,这样可以省下来一个IO口。另外我们还需要一个背光控制线来控制TFTLCD的背光。所以,我们总共需要的IO口数目为21个。这里还需要注意,我们标注的DB1~DB8,DB10~DB17,是相对于LCD控制IC标注的,实际上大家可以把他们就等同于D0~D15,这样理解起来就比较简单一点。ALIENTEK提供的2.8寸TFTLCD模块,其驱动芯片有很多种类型,比如有:ILI9320/ILI9325/ILI9328/ILI9341/SSD1289/LGDP4531/LGDP/ SPFD5408/ RM68021等(具体的型号,大家可以通过下载本章实验代码,通过串口或者LCD显示查看),这里我们仅以ILI9320控制器为例进行介绍,其他的控制基本都类似,我们就不详细阐述了。ILI9320液晶控制器自带显存,其显存总大小为0*320*18/8),即18位模式(26万色)下的显存量。模块的16位数据线与显寸的对应关系为565方式,如图18.1.1.4所示:
图18.1.1.4&&16位数据与显存对应关系图最低5位代表蓝色,中间6位为绿色,最高5位为红色。数值越大,表示该颜色越深。接下来,我们介绍一下ILI9320的几个重要命令,因为ILI9320的命令很多,我们这里不可能一一介绍,有兴趣的大家可以找到ILI9320的datasheet看看。里面对这些命令有详细的介绍。这里我们要介绍的命令列表如表18.1.1.1所示:表18.1.1.1 ILI9320常用命令表R0,这个命令,有两个功能,如果对它写,则最低位为OSC,用于开启或关闭振荡器。而如果对它读操作,则返回的是控制器的型号。这个命令最大的功能就是通过读它可以得到控制器的型号,而我们代码在知道了控制器的型号之后,可以针对不同型号的控制器,进行不同的初始化。因为93xx系列的初始化,其实都比较类似,我们完全可以用一个代码兼容好几个控制器。R3,入口模式命令。我们重点关注的是I/D0、I/D1、AM这3个位,因为这3个位控制了屏幕的显示方向。AM:控制GRAM更新方向。当AM=0的时候,地址以行方向更新。当AM=1的时候,地址以列方向更新。I/D[1:0]:当更新了一个数据之后,根据这两个位的设置来控制地址计数器自动增加/减少1,其关系如图18.1.1.5所示:
图18.1.1.5&&GRAM显示方向设置图通过这几个位的设置,我们就可以控制屏幕的显示方向了,这种方法虽然简单,但是不是很通用,比如不同的液晶,可能这里差别就比较大,有的甚至无法通用!比如就完全不通用。R7,显示控制命令。该命令CL位用来控制是8位彩色,还是26万色。为0时26万色,为1时八位色。D1、D0、BASEE这三个位用来控制显示开关与否的。当全部设置为1的时候开启显示,全0是关闭。我们一般通过该命令的设置来开启或关闭显示器,以降低功耗。R32,R33,设置GRAM的行地址和列地址。R32用于设置列地址(X坐标,0~239),R33用于设置行地址(Y坐标,0~319)。当我们要在某个指定点写入一个颜色的时候,先通过这两个命令设置到改点,然后写入颜色值就可以了。R34,写数据到GRAM命令,当写入了这个命令之后,地址计数器才会自动的增加和减少。该命令是我们要介绍的这一组命令里面唯一的单个操作的命令,只需要写入该值就可以了,其他的都是要先写入命令编号,然后写入操作数。R80~R83,行列GRAM地址位置设置。这几个命令用于设定你显示区域的大小,我们整个屏的大小为240*320,但是有时候我们只需要在其中的一部分区域写入数据,如果用先写坐标,后写数据这样的方式来实现,则速度大打折扣。此时我们就可以通过这几个命令,在其中开辟一个区域,然后不停的丢数据,地址计数器就会根据R3的设置自动增加/减少,这样就不需要频繁的写地址了,大大提高了刷新的速度。命令部分,我们就为大家介绍到这里,我们接下来看看要如何才能驱动ALIENTEK TFTLCD模块,这里TFTLCD模块的初始化和我们前面介绍的OLED模块的初始化框图是一样的,只是初始化代码部分不同。接下来我们也是将该模块用来来显示字符和数字。通过以上介绍,我们可以得出TFTLCD显示需要的相关设置步骤如下:1)设置STM32与TFTLCD模块相连接的IO。这一步,先将我们与TFTLCD模块相连的IO口进行初始化,以便驱动LCD。这里我们用到的是FSMC,FSMC将在18.1.2节向大家详细介绍。 2)初始化TFTLCD模块。其实这里就是上和上面OLED模块的初始化过程差不多。通过向TFTLCD写入一系列的设置,来启动TFTLCD的显示。为后续显示字符和数字做准备。3)通过函数将字符和数字显示到TFTLCD模块上。这里就是通过我们设计的程序,将要显示的字符送到TFTLCD模块就可以了,这些函数将在软件设计部分向大家介绍。通过以上三步,我们就可以使用ALIENTEK TFTLCD模块来显示字符和数字了, 并且可以显示各种颜色的背景。18.1.2 FSMC简介 大容量,且引脚数在100脚以上的STM32F103芯片都带有FSMC接口,ALIENTEK战舰STM32开发板的主芯片为STM32F103ZET6,是带有FSMC接口的。FSMC,即灵活的静态存储控制器,能够与同步或异步存储器和16位PC存储器卡接口,STM32的FSMC接口支持包括SRAM、NAND FLASH、NOR FLASH和PSRAM等存储器。FSMC的框图如图18.1.2.1所示:图18.1.2.1 FSMC框图& && & 从上图我们可以看出,STM32的FSMC将外部设备分为3类:NOR/PSRAM设备、NAND设备、PC卡设备。他们共用地址数据总线等信号,他们具有不同的CS以区分不同的设备,比如本章我们用到的TFTLCD就是用的FSMC_NE4做片选,其实就是将TFTLCD当成SRAM来控制。这里我们介绍下为什么可以把TFTLCD当成SRAM设备用:首先我们了解下外部SRAM的连接,外部SRAM的控制一般有:地址线(如A0~A18)、数据线(如D0~D15)、写信号(WE)、读信号(OE)、片选信号(CS),如果SRAM支持字节控制,那么还有UB/LB信号。而TFTLCD的信号我们在18.1.1节有介绍,包括:RS、D0~D15、WR、RD、CS、RST和BL等,其中真正在操作LCD的时候需要用到的就只有:RS、D0~D15、WR、RD和CS。其操作时序和SRAM的控制完全类似,唯一不同就是TFTLCD有RS信号,但是没有地址信号。TFTLCD通过RS信号来决定传送的数据是数据还是命令,本质上可以理解为一个地址信号,比如我们把RS接在A0上面,那么当FSMC控制器写地址0的时候,会使得A0变为0,对TFTLCD来说,就是写命令。而FSMC写地址1的时候,A0将会变为1,对TFTLCD来说,就是写数据了。这样,就把数据和命令区分开了,他们其实就是对应SRAM操作的两个连续地址。当然RS也可以接在其他地址线上,战舰STM32开发板是把RS连接在A10上面的。STM32的FSMC支持8/16/32位数据宽度,我们这里用到的LCD是16位宽度的,所以在设置的时候,选择16位宽就OK了。我们再来看看FSMC的外部设备地址映像,STM32的FSMC将外部存储器划分为固定大小为256M字节的四个存储块,如图18.1.2.2所示:图18.1.2.2 FSMC存储块地址映像
我的STM32开发板店铺:
我的技术论坛论坛:
主题帖子积分
高级技术员, 积分 614, 距离下一级还需 386 积分
高级技术员, 积分 614, 距离下一级还需 386 积分
主题帖子积分
专家等级:结帖率:100%
主题帖子积分
高级技术员, 积分 614, 距离下一级还需 386 积分
高级技术员, 积分 614, 距离下一级还需 386 积分
本帖最后由 正点原子 于
18:27 编辑
从上图可以看出,FSMC总共管理1GB空间,拥有4个存储块(Bank),本章,我们用到的是块1,所以在本章我们仅讨论块1的相关配置,其他块的配置,请参考《STM32参考手册》第19章(324页)的相关介绍。& && & STM32的FSMC存储块1(Bank1)被分为4个区,每个区管理64M字节空间,每个区都有独立的寄存器对所连接的存储器进行配置。Bank1的256M字节空间由28根地址线(HADDR[27:0])寻址。& && & 这里HADDR是内部AHB地址总线,其中HADDR[25:0]来自外部存储器地址FSMC_A[25:0],而HADDR[26:27]对4个区进行寻址。如表18.1.2.1所示:表18.1.2.1 Bank1存储区选择表& && & 表18.1.2.1中,我们要特别注意HADDR[25:0]的对应关系:当Bank1接的是16位宽度存储器的时候:HADDR[25:1]à FSMC[24:0]。当Bank1接的是8位宽度存储器的时候:HADDR[25:0]à FSMC[25:0]。不论外部接8位/16位宽设备,FSMC_A[0]永远接在外部设备地址A[0]。 这里,TFTLCD使用的是16位数据宽度,所以HADDR[0]并没有用到,只有HADDR[25:1]是有效的,对应关系变为:HADDR[25:1]à FSMC[24:0],相当于右移了一位,这里请大家特别留意。另外,HADDR[27:26]的设置,是不需要我们干预的,比如:当你选择使用Bank1的第三个区,即使用FSMC_NE3来连接外部设备的时候,即对应了HADDR[27:26]=10,我们要做的就是配置对应第3区的寄存器组,来适应外部设备即可。STM32的FSMC各Bank配置寄存器如表18.1.2.2所示:表18.1.2.2 FSMC各Bank配置寄存器表& && & 对于NOR FLASH控制器,主要是通过FSMC_BCRx、FSMC_BTRx和FSMC_BWTRx寄存器设置(其中x=1~4,对应4个区)。通过这3个寄存器,可以设置FSMC访问外部存储器的时序参数,拓宽了可选用的外部存储器的速度范围。FSMC的NOR FLASH控制器支持同步和异步突发两种访问方式。选用同步突发访问方式时,FSMC将HCLK(系统时钟)分频后,发送给外部存储器作为同步时钟信号FSMC_CLK。此时需要的设置的时间参数有2个:  1,HCLK与FSMC_CLK的分频系数(CLKDIV),可以为2~16分频;  2,同步突发访问中获得第1个数据所需要的等待延迟(DATLAT)。对于异步突发访问方式,FSMC主要设置3个时间参数:地址建立时间(ADDSET)、数据建立时间(DATAST)和地址保持时间(ADDHLD)。FSMC综合了SRAM/ROM、PSRAM和NOR Flash产品的信号特点,定义了4种不同的异步时序模型。选用不同的时序模型时,需要设置不同的时序参数,如表18.1.2.3所列:
表18.1.2.3 NOR FLASH控制器支持的时序模型在实际扩展时,根据选用存储器的特征确定时序模型,从而确定各时间参数与存储器读/写周期参数指标之间的计算关系;利用该计算关系和存储芯片数据手册中给定的参数指标,可计算出FSMC所需要的各时间参数,从而对时间参数寄存器进行合理的配置。本章,我们使用异步模式A(ModeA)方式来控制TFTLCD,模式A的读操作时序如图18.1.2.3所示:
图18.1.2.3 模式A读操作时序图& && & 模式A支持独立的读写时序控制,这个对我们驱动TFTLCD来说非常有用,因为TFTLCD在读的时候,一般比较慢,而在写的时候可以比较快,如果读写用一样的时序,那么只能以读的时序为基准,从而导致写的速度变慢,或者在读数据的时候,重新配置FSMC的延时,在读操作完成的时候,再配置回写的时序,这样虽然也不会降低写的速度,但是频繁配置,比较麻烦。而如果有独立的读写时序控制,那么我们只要初始化的时候配置好,之后就不用再配置,既可以满足速度要求,又不需要频繁改配置。& && & 模式A的写操作时序如图18.1.2.4所示:
图18.1.2.4 模式A写操作时序& && & 从模式A的读写时序图,我们可以看出,读操作还存在额外的2个HCLK周期,用于数据存储,所以同样的配置读操作一般比写操作会慢一点。图18.1.2.3和图18.1.2.4中的ADDSET与DATAST,是通过不同的寄存器设置的,接下来我们讲解一下Bank1的几个控制寄存器& && & 首先,我们介绍SRAM/NOR闪存片选控制寄存器:FSMC_BCRx(x=1~4),该寄存器各位描述如图18.1.2.5所示:18.1.2.5 FSMC_BCRx寄存器各位描述该寄存器我们在本章用到的设置有:EXTMOD、WREN、MWID、MTYP和MBKEN这几个设置,我们将逐个介绍。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表示NOR FLASH;11保留。前面提到,我们把TFTLCD当成SRAM用,所以需要设置MTYP[1:0]=00。& && & MBKEN:存储块使能位。这个容易理解,我们需要用到该存储块控制TFTLCD,当然要使能这个存储块了。& && & 接下来,我们看看SRAM/NOR闪存片选时序寄存器:FSMC_BTRx(x=1~4),该寄存器各位描述如图18.1.2.6所示:
图18.1.2.6 FSMC_BTRx寄存器各位描述& && & 这个寄存器包含了每个存储器块的控制信息,可以用于SRAM、ROM和NOR闪存存储器。如果FSMC_BCRx寄存器中设置了EXTMOD位,则有两个时序寄存器分别对应读(本寄存器)和写操作(FSMC_BWTRx寄存器)。因为我们要求读写分开时序控制,所以EXTMOD是使能了的,也就是本寄存器是读操作时序寄存器,控制读操作的相关时序。本章我们要用到的设置有:ACCMOD、DATAST和ADDSET这三个设置。& && & ACCMOD[1:0]:访问模式。00表示访问模式A;01表示访问模式B;10表示访问模式C;11表示访问模式D,本章我们用到模式A,故设置为00。& && & DATAST[7:0]:数据保持时间。0为保留设置,其他设置则代表保持时间为: (DATAST +1)个HCLK时钟周期,最大为256个HCLK周期。对ILI9320来说,其实就是RD低电平持续时间,一般为150ns。而一个HCLK时钟周期为13.8ns左右(1/72Mhz),为了兼容其他屏,我们这里设置DATAST为15,也就是16个HCLK周期,时间大约是234ns(未计算数据存储的2个HCLK时间)。& && & ADDSET[3:0]:地址建立时间。其建立时间为:(ADDSET+1)个HCLK周期,最大为16个HCLK周期。对ILI9320来说,这里相当于RD高电平持续时间,本来这里我们应该设置和DATAST一样,但是由于CS切换延时的存在,我们这里可以设置ADDSET为较小的值,本章我们设置ADDSET为1,即2个HCLK周期,同样可以正常使用。最后,我们再来看看SRAM/NOR闪写时序寄存器:FSMC_BWTRx(x=1~4),该寄存器各位描述如图18.1.2.7所示:图18.1.2.7 FSMC_BWTRx寄存器各位描述& && & 该寄存器在本章用作写操作时序控制寄存器,需要用到的设置同样是:ACCMOD、DATAST和ADDSET这三个设置。这三个设置的方法同FSMC_BTRx一模一样,只是这里对应的是写操作的时序,ACCMOD设置同FSMC_BTRx一模一样,同样是选择模式A,另外DATAST和ADDSET则对应低电平和高电平持续时间,对ILI9320来说,这两个时间只需要50ns就够了,比读操作快得多。所以我们这里设置DATAST为3,即4个HCLK周期,时间约为55ns。同样由于CS切换延时的存在,我们可以设置ADDSET为0,即1个HCLK周期。& && & 至此,我们对STM32的FSMC介绍就差不多了,通过以上两个小节的了解,我们可以开始写LCD的驱动代码了。不过,这里还要给大家做下科普,在MDK的寄存器定义里面,并没有定义FSMC_BCRx、FSMC_BTRx、FSMC_BWTRx等这个单独的寄存器,而是将他们进行了一些组合。& && & FSMC_BCRx和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 FSMC_BWTRx则组合成BWTR[7],他们的对应关系如下:BWTR[0]对应FSMC_BWTR1,BWTR[2]对应FSMC_BWTR2,BWTR[4]对应FSMC_BWTR3,BWTR[6]对应FSMC_BWTR4,BWTR[1]、BWTR[3]和BWTR[5]保留,没有用到。
18.2 硬件设计 本实验用到的硬件资源有:1)&&指示灯DS0 2)&&TFTLCD模块 TFTLCD模块的电路见图18.1.1.2,这里我们介绍TFTLCD模块与ALIETEK 战舰STM32开发板的连接,战舰STM32开发板底板的LCD接口和ALIENTEK TFTLCD模块直接可以对插,连接关系如图18.2.1所示:
图18.2.1 TFTLCD与开发板连接示意图图18.2.1中圈出来的部分就是连接TFTLCD模块的接口,板上的接口比液晶模块的插针要多2个口,液晶模块在这里是靠右插的。多出的2个口是给OLED用的,所以OLED模块在接这里的时候,是靠左插的,这个请大家注意一下。在硬件上,TFTLCD模块与战舰STM32开发板的IO口对应关系如下:& && & LCD_BL(背光控制)对应PB0;& && & LCD_CS对应PG12即FSMC_NE4;& && & LCD _RS对应PG0即FSMC_A10;& && & LCD _WR对应PD5即FSMC_NWE;& && & LCD _RD对应PD4即FSMC_NOE;& && & LCD _D[15:0]则直接连接在FSMC_D15~FSMC_D0;这些线的连接,战舰STM32开发板的内部已经连接好了,我们只需要将TFTLCD模块插上去就好了。实物连接如图18.2.2所示:图18.2.2 TFTLCD与开发板连接实物图18.3 软件设计 软件设计我们依旧在之前的工程上面增加,首先在HARDWARE文件夹下新建一个LCD的文件夹。然后打开USER文件夹下的工程,新建一个ILI93xx.c的文件和lcd.h的头文件,保存在LCD文件夹下,并将LCD文件夹加入头文件包含路径。在ILI93xx.c里面要输入的代码比较多,我们这里就不贴出来了,只针对几个重要的函数进行讲解。完整版的代码见光盘à4,程序源码à标准例程à实验13 TFTLCD显示实验的ILI93xx.c文件。本实验,我们用到FSMC驱动LCD,通过前面的介绍,我们知道TFTLCD的RS接在FSMC的A10上面,CS接在FSMC_NE4上,并且是16位数据总线。即我们使用的是FSMC存储器1的第4区,我们定义如下LCD操作结构体(在lcd.h里面定义)://LCD操作结构体typedef struct{& && & u16 LCD_REG;& && & u16 LCD_RAM;} LCD_TypeD//使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11 A10作为数据命令区分线//注意16位数据总线时,STM32内部地址会右移一位对齐!& && &&&#define LCD_BASE& && &&&((u32)(0x6C000000 | 0x000007FE))#define LCD& && && && & ((LCD_TypeDef *) LCD_BASE)其中LCD_BASE,必须根据我们外部电路的连接来确定,我们使用Bank1.sector4就是从地址0X6C000000开始,而0X000007FE,则是A10的偏移量。我们将这个地址强制转换为LCD_TypeDef结构体地址,那么可以得到LCD-&LCD_REG的地址就是0X6C00,07FE,对应A10的状态为0(即RS=0),而LCD-& LCD_RAM的地址就是0X6C00,0800(结构体地址自增),对应A10的状态为1(即RS=1)。所以,有了这个定义,当我们要往LCD写命令/数据的时候,可以这样写:LCD-&LCD_REG=CMD;&&//写命令LCD-&LCD_RAM=DATA; //写数据而读的时候反过来操作就可以了,如下所示:CMD= LCD-&LCD_REG;//读LCD寄存器DATA = LCD-&LCD_RAM;//读LCD数据这其中,CS、WR、RD和IO口方向都是由FSMC控制,不需要我们手动设置了。接下来,我们先介绍一下lcd.h里面的另一个重要结构体://LCD重要参数集typedef struct {& && && && && && && && && && && && && && && && && && && && && && && && && && & u16& && && && && && &&&//LCD 宽度& && & u16& && && && && && & //LCD 高度& && & u16& && && && && && && && & //LCD ID& && & u8&&& && && && && && && &&&//横屏还是竖屏控制:0,竖屏;1,横屏。& &&&& && & u8& && && && && & //开始写gram指令& && & u8&&& && && && && & //设置x坐标指令& && & u8&&& && && && && & //设置y坐标指令&&}_lcd_//LCD参数extern _lcd_ //管理LCD重要参数该结构体用于保存一些LCD重要参数信息,比如LCD的长宽、LCD ID(驱动IC型号)、LCD横竖屏状态等,这个结构体虽然占用了10个字节的内存,但是却可以让我们的驱动函数支持不同尺寸的LCD,同时可以实现LCD横竖屏切换等重要功能,所以还是利大于弊的。有了以上了解,下面我们开始介绍ILI93xx.c里面的一些重要函数。先看6个简单,但是很重要的函数://写寄存器函数//regval:寄存器值void LCD_WR_REG(u16 regval){ & && & LCD-&LCD_REG=//写入要写的寄存器序号& &}//写LCD数据//data:要写入的值void LCD_WR_DATA(u16 data){& && && && && && && && && && && && && && && && && && && && && && && && && && && & & && & LCD-&LCD_RAM=& && && && &&&}//读LCD数据//返回值:读到的值u16 LCD_RD_DATA(void){& && && && && && && && && && && && && && && && && && && && && && && && && && && & & && & return LCD-&LCD_RAM;& && && && &}& && && && && && && && && && && && &//写寄存器//LCD_Reg:寄存器地址//LCD_RegValue:要写入的数据void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue){& &&&& && & LCD-&LCD_REG = LCD_R& && && && &//写入要写的寄存器序号& &&&& && & LCD-&LCD_RAM = LCD_RegV//写入数据& && && && && && &&&}& && &&&//读寄存器//LCD_Reg:寄存器地址//返回值:读到的数据u16 LCD_ReadReg(u8 LCD_Reg){& && && && && && && && && && && && && && && && && && && && && && && &&&& && & LCD_WR_REG(LCD_Reg);& && && &//写入要读的寄存器序号& && & delay_us(5);& && && && && && & return LCD_RD_DATA();& && && && &//返回读到的值}& &//开始写GRAMvoid LCD_WriteRAM_Prepare(void){& && &LCD-&LCD_REG=lcddev.& && &}& &&&因为FSMC自动控制了WR/RD/CS等这些信号,所以这6个函数实现起来都非常简单,我们就不多说,实现功能见函数前面的备注,通过这几个简单函数的组合,我们就可以对LCD进行各种操作了。第七个要介绍的函数是坐标设置函数,该函数代码如下://设置光标位置//Xpos:横坐标//Ypos:纵坐标void LCD_SetCursor(u16 Xpos, u16 Ypos){& &&&& && &if(lcddev.id==0X9341)& && & {& && && && && && && && && &&&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.dir==1)Xpos=lcddev.width-1-X//横屏其实就是调转x,y坐标& && && && &&&LCD_WriteReg(lcddev.setxcmd, Xpos);& && && && &&&LCD_WriteReg(lcddev.setycmd, Ypos);& && & }& &&&}该函数实现将LCD的当前操作点设置到指定坐标(x,y)。因为9341的设置同其他屏有些不太一样,所以单独对9341进行了设置。
本帖子中包含更多资源
才可以下载或查看,没有帐号?
我的STM32开发板店铺:
我的技术论坛论坛:
主题帖子积分
高级技术员, 积分 614, 距离下一级还需 386 积分
高级技术员, 积分 614, 距离下一级还需 386 积分
主题帖子积分
专家等级:结帖率:100%
主题帖子积分
高级技术员, 积分 614, 距离下一级还需 386 积分
高级技术员, 积分 614, 距离下一级还需 386 积分
接下来我们介绍第八个函数:画点函数。该函数实现代码如下://画点//x,y:坐标//POINT_COLOR:此点的颜色void LCD_DrawPoint(u16 x,u16 y){& && & LCD_SetCursor(x,y);& && && && &//设置光标位置 & && & LCD_WriteRAM_Prepare();&&//开始写入GRAM& && & LCD-&LCD_RAM=POINT_COLOR;}该函数实现比较简单,就是先设置坐标,然后往坐标写颜色。其中POINT_COLOR是我们定义的一个全局变量,用于存放画笔颜色,顺带介绍一下另外一个全局变量:BACK_COLOR,该变量代表LCD的背景色。LCD_DrawPoint函数虽然简单,但是至关重要,其他几乎所有上层函数,都是通过调用这个函数实现的。有了画点,当然还需要有读点的函数,第九个介绍的函数就是读点函数,用于读取LCD的GRAM,这里说明一下,为什么OLED模块没做读GRAM的函数,而这里做了。因为OLED模块是单色的,所需要全部GRAM也就1K个字节,而TFTLCD模块为彩色的,点数也比OLED模块多很多,以16位色计算,一款320×240的液晶,需要320×240×2个字节来存储颜色值,也就是也需要150K字节,这对任何一款单片机来说,都不是一个小数目了。而且我们在图形叠加的时候,可以先读回原来的值,然后写入新的值,在完成叠加后,我们又恢复原来的值。这样在做一些简单菜单的时候,是很有用的。这里我们读取TFTLCD模块数据的函数为LCD_ReadPoint,该函数直接返回读到的GRAM值。该函数使用之前要先设置读取的GRAM地址,通过LCD_SetCursor函数来实现。LCD_ReadPoint的代码如下://读取个某点的颜色值&&//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)LCD_WR_REG(0X2E);& && && & //9341 发送读GRAM指令& && & else LCD_WR_REG(R34);& && && && && && && && && && && &//其他IC发送读GRAM指令& && &if(lcddev.id==0X9320)opt_delay(2);& && && && && && && && & //FOR 9320,延时2us& && && && && & if(LCD-&LCD_RAM)r=0;& && && && && && && && && && && && && & //dummy Read& && && & & && & opt_delay(2);& & & && &r=LCD-&LCD_RAM;& && && && && && && && && && && && && && &&&//实际坐标颜色& && &if(lcddev.id==0X9341)//9341要分2次读出& && &{& && && && &&&opt_delay(2);& & & && && && &&&b=LCD-&LCD_RAM;& && && && &&&g=r&0XFF;//对于9341,第一次读取的是RG的值,R在前,G在后,各占8位& && && && &&&g&&=8;& && & }//这几种IC直接返回颜色值if(lcddev.id==0X9325||lcddev.id==0X4535||lcddev.id==0X4531||lcddev.id==0X8989||lcddev.id==0XB505)& && &else if(lcddev.id==0X9341)return (((r&&11)&&11)|((g&&10)&&5)|(b&&11));& &//ILI9341需要公式转换一下else return LCD_BGR2RGB(r);& && &&&//其他IC}在LCD_ReadPoint函数中,因为我们的代码不止支持一种LCD驱动器,所以,我们根据不同的LCD驱动器((lcddev.id)型号,执行不同的操作,以实现对各个驱动器兼容,提高函数的通用性。 第十个要介绍的是字符显示函数LCD_ShowChar,该函数同前面OLED模块的字符显示函数差不多,但是这里的字符显示函数多了1个功能,就是可以以叠加方式显示,或者以非叠加方式显示。叠加方式显示多用于在显示的图片上再显示字符。非叠加方式一般用于普通的显示。该函数实现代码如下://在指定位置显示一个字符//x,y:起始坐标//num:要显示的字符:& &---&&~&//size:字体大小 12/16//mode:叠加方式(1)还是非叠加方式(0)void LCD_ShowChar(u16 x,u16 y,u8 num,u8 size,u8 mode){& && && && && && && && && && && && && && && && && & u8 temp,t1,t;& && & u16 y0=y;& && & u16 colortemp=POINT_COLOR;& && && && && && && && && && & & && & //设置窗口& && && && && && && & num=num-' ';//得到偏移后的值& && & if(!mode) //非叠加方式& && & {& && && &&&for(t=0;t&t++)& && && &&&{& && && && && && && && &if(size==12)temp=asc2_1206[num][t];&&//调用1206字体& && && && && && && &else temp=asc2_1608[num][t];& && && && & //调用1608字体& && && && && && && && && && && & & && && && && &for(t1=0;t1&8;t1++)& && && && && && && &{& && && && && && && &&&& && && && && && && & if(temp&0x80)POINT_COLOR=& && && && && && && && && & else POINT_COLOR=BACK_COLOR;& && && && && && && && && & LCD_DrawPoint(x,y);& && && && && && && && && && & temp&&=1;& && && && && && && && && & y++;& && && && && && && && && & if(x&=lcddev.height) {POINT_COLOR=}//超区域了& && && && && && && && && & if((y-y0)==size)& && && && && && && && && & {& && && && && && && && && && && &&&y=y0;& && && && && && && && && && && &&&x++;& && && && && && && && && && && &&&if(x&=lcddev.width) {POINT_COLOR=}//超区域了& && && && && && && && && && && &&&& && && && && && && && && & }& && && && && && && &}& &&&& && && &&&}& & & && & }else//叠加方式& && & {& && && &&&for(t=0;t&t++)& && && &&&{& && && && && && && && &if(size==12)temp=asc2_1206[num][t];&&//调用1206字体& && && && && && && &else temp=asc2_1608[num][t];& && && && & //调用1608字体& && && && && && && && && && && & & && && && && &for(t1=0;t1&8;t1++)& && && && && && && &{& && && && && && && &&&& && && && && && && & if(temp&0x80)LCD_DrawPoint(x,y); & && && && && && && && && & temp&&=1;& && && && && && && && && & y++;& && && && && && && && && & if(x&=lcddev.height) {POINT_COLOR=}//超区域了& && && && && && && && && & if((y-y0)==size)& && && && && && && && && & {& && && && && && && && && && && &&&y=y0;& && && && && && && && && && && &&&x++;& && && && && && && && && && && &&&if(x&=lcddev.width) {POINT_COLOR=}//超区域了& && && && && && && && && && && &&&& && && && && && && && && & }& && && && && && && &}& &&&& && && &&&}& & & && & }& && & POINT_COLOR=& && && && && && && && & }&&在LCD_ShowChar函数里面,我们采用画点函数来显示字符,虽然速度不如开辟窗口的方式,但是这样写可以有更好的兼容性,方便在不同LCD之间移植。该代码中我们用到了两个字符集点阵数据数组asc2_1206和asc2_1608,这两个字符集的点阵数据的提取方式,同十七章介绍的提取方法是一模一样的。详细请参考第十七章。 最后,我们再介绍一下TFTLCD模块的初始化函数LCD_Init,该函数先初始化STM32与TFTLCD连接的IO口,并配置FSMC控制器,然后读取LCD控制器的型号,根据控制IC的型号执行不同的初始化代码,其简化代码如下: //初始化lcd//该初始化函数可以初始化各种ILI93XX液晶,但是其他函数是基于ILI9320的!!!//在其他型号的驱动芯片上没有测试! void LCD_Init(void){& && && && && && && && && && && && && && && && && && && && && && && & & && & RCC-&AHBENR|=1&&8;& && & //使能FSMC时钟& &&&& && &RCC-&APB2ENR|=1&&3;& && &//使能PORTB时钟& && & RCC-&APB2ENR|=1&&5;& && &//使能PORTD时钟& && & RCC-&APB2ENR|=1&&6;& && &//使能PORTE时钟& && &RCC-&APB2ENR|=1&&8;& && &//使能PORTG时钟& && & RCC-&APB2ENR|=1&&0;& && &//使能AFIO时钟& & & && & GPIOB-&CRL&=0XFFFFFFF0;//PB0推挽输出 背光& && & GPIOB-&CRL|=0X;& && && & & && & //PORTD复用推挽输出& && & & && & GPIOD-&CRH&=0X00FFF000;& && & GPIOD-&CRH|=0XBB000BBB;& && & GPIOD-&CRL&=0XFF00FF00;& && & GPIOD-&CRL|=0X00BB00BB;& && && & & && & //PORTE复用推挽输出& && & & && & GPIOE-&CRH&=0X;& && & GPIOE-&CRH|=0XBBBBBBBB;& && & GPIOE-&CRL&=0X0FFFFFFF;& && & GPIOE-&CRL|=0XB0000000;& && && && && && && && && && && && && && && && && && && && && && && && && && &&&& && & //PORTG12复用推挽输出 A0& && && && && && && && && && && && && && && && && && && && && && && && && && && & & && & GPIOG-&CRH&=0XFFF0FFFF;& && & GPIOG-&CRH|=0X000B0000;& && & GPIOG-&CRL&=0XFFFFFFF0;//PG0-&RS& && & GPIOG-&CRL|=0X0000000B;& && & //寄存器清零& && & //bank1有NE1~4,每一个有一个BCR+TCR,所以总共八个寄存器。& && & //这里我们使用NE4 ,也就对应BTCR[6],[7]。& && && && && && && && && && && && & FSMC_Bank1-&BTCR[6]=0X;& && & FSMC_Bank1-&BTCR[7]=0X;& && & FSMC_Bank1E-&BWTR[6]=0X;& && & //操作BCR寄存器& && & 使用异步模式& && & FSMC_Bank1-&BTCR[6]|=1&&12;& && && && &&&//存储器写使能& && & FSMC_Bank1-&BTCR[6]|=1&&14;& && && && &&&//读写使用不同的时序& && & FSMC_Bank1-&BTCR[6]|=1&&4;& && && && &&&//存储器数据宽度为16bit& && & & && & //操作BTR寄存器 & && & //读时序控制寄存器& && && && && && && && && && && && && && && && &&&& && & FSMC_Bank1-&BTCR[7]|=0&&28;& && & //模式A& && && && && && && && && && && && && && && && && && && && && && && & FSMC_Bank1-&BTCR[7]|=1&&0;& && & //地址建立时间(ADDSET)为2个HCLK & && & //因为液晶驱动IC的读数据的时候,速度不能太快,尤其对1289这个IC。& && & FSMC_Bank1-&BTCR[7]|=0XF&&8;&&//数据保存时间为16个HCLK& && && & & && & //写时序控制寄存器&&& && & FSMC_Bank1E-&BWTR[6]|=0&&28;&&//模式A& && && && && && && && && && && && && && && && && && && && && && & FSMC_Bank1E-&BWTR[6]|=0&&0;& &&&//地址建立时间(ADDSET)为1个HCLK //4个HCLK(HCLK=72M)因为液晶驱动IC的写信号脉宽,//最少也得50ns。72M/4=24M=55ns& && && & & && & FSMC_Bank1E-&BWTR[6]|=3&&8;& & //数据保存时间为4个HCLK& && && && & //使能BANK1,区域4& && & FSMC_Bank1-&BTCR[6]|=1&&0;& && && &//使能BANK1,区域4& && && && && && && && & & && & delay_ms(50); // delay 50 ms & && & LCD_WriteReg(0x1);& && & delay_ms(50); // delay 50 ms & && &lcddev.id = LCD_ReadReg(0x0000);& && && &if(lcddev.id &0XFF||lcddev.id==0XFFFF)//读到ID不正确& && & {& &&&& && && && &&&//尝试9341的ID读取&&& && && && &&&LCD_WR_REG(0XD3);& && && && && && && && && && & & && && && &&&LCD_RD_DATA();& && && && && && &&&//dummy read& && &&&& && && && & LCD_RD_DATA();& && && && && &&&//读到0X00& && && && & lcddev.id=LCD_RD_DATA();& &&&//读取93& && && && && && && && && && && && && && && && && &&&& && && && & lcddev.id&&=8;& && && && &&&lcddev.id|=LCD_RD_DATA();& &&&//读取41& && && && && && && && && &&&& && &}& && &printf(& LCD ID:%x\r\n&,lcddev.id);& &&&//打印LCD ID&&& && & if(lcddev.id==0X9341)& && && && && && && &&&//9341初始化& && & { & && && && &&&……//9341初始化代码 & && & }else if(lcddev.id==0x9325)//9325& && & { & && && && &&&……//9325初始化代码 }else if(lcddev.id==0x9328)& && && && && & //ILI9328& &OK&&& && & { & && && && &&&……//9328初始化代码 & && & }else if(lcddev.id==0x9320||lcddev.id==0x9300)//未测试.& && & {& && && && &&&……//9300初始化代码 & && & }else if(lcddev.id==0X9331)& && && && && & & && & { & && && && &&&……//9331初始化代码 & && & }else if(lcddev.id==0x5408)& && & { & && && && &&&……//5408初始化代码 & && & }& &&&& && & else if(lcddev.id==0x1505)//OK& && & { & && && && &&&……//1505初始化代码 & && & }else if(lcddev.id==0xB505)& && & { & && && && &&&……//B505初始化代码& && & & && & }else if(lcddev.id==0xC505)& && & {& && && && &&&……//C505初始化代码& && & & && & }else if(lcddev.id==0x8989)& && & {& && &&&& && && && &&&……//8989初始化代码& && && && &&&& && & }else if(lcddev.id==0x4531)& && & {& && && && &&&……//4531初始化代码 & && & }else if(lcddev.id==0x4535)& && & {& && && && && && && && & & && && && &&&……//4535初始化代码 & && & }& && && && && && & LCD_Display_Dir(0);& && && && && & //默认为竖屏显示& && & LCD_LED=1;& && && && && && && && && &&&//点亮背光& && & LCD_Clear(WHITE);}
我的STM32开发板店铺:
我的技术论坛论坛:
主题帖子积分
高级技术员, 积分 614, 距离下一级还需 386 积分
高级技术员, 积分 614, 距离下一级还需 386 积分
主题帖子积分
专家等级:结帖率:100%
主题帖子积分
高级技术员, 积分 614, 距离下一级还需 386 积分
高级技术员, 积分 614, 距离下一级还需 386 积分
本帖最后由 正点原子 于
18:29 编辑
该函数先对FSMC相关IO进行初始化,然后是FSMC的初始化,这个我们在前面都有介绍,最后根据读到的LCD ID,对不同的驱动器执行不同的初始化代码,从上面的代码可以看出,这个初始化函数可以针对13款不同的驱动IC执行初始化操作,这样大大提高了整个程序的通用性。大家在以后的学习中应该多使用这样的方式,以提高程序的通用性、兼容性。特别注意:本函数使用了printf来打印LCD ID,所以,如果你在主函数里面没有初始化串口,那么将导致程序死在printf里面!!如果不想用printf,那么请注释掉它。保存ILI93xx.c,并将该代码加入到HARDWARE组下。在介绍完了ILI93xx.c的内容之后,然后我们在lcd.h里面输入如下内容:#ifndef __LCD_H#define __LCD_H& && && &#include &sys.h&& &&&#include &stdlib.h& //LCD重要参数集typedef struct {& && && && && && && && && && && && && && && && && && && && && && && && && && & u16& && && && && && &&&//LCD 宽度& && & u16& && && && && && & //LCD 高度& && & u16& && && && && && && && & //LCD ID& && & u8&&& && && && && && && &&&//横屏还是竖屏控制:0,竖屏;1,横屏。& &&&& && & u8& && && && && & //开始写gram指令& && & u8&&& && && &//设置x坐标指令& && & u8&&& && && &//设置y坐标指令&&}_lcd_& && & //LCD参数extern _lcd_ //管理LCD重要参数//LCD的画笔颜色和背景色& & extern u16 POINT_COLOR;//默认红色& & extern u16 BACK_COLOR; //背景颜色.默认为白色//////////////////////////////////////////////////////////////////////////////////&&//-----------------LCD端口定义---------------- #define& & LCD_LED PBout(0) //LCD背光& && && && &&&PB0& && && & //LCD地址结构体typedef struct{& && & u16 LCD_REG;& && & u16 LCD_RAM;} LCD_TypeD//使用NOR/SRAM的 BANK 4,地址位HADDR[27,26]=11 A10作为数据命令区分线 //注意设置时STM32内部会右移一位对其! X3E& && && && && && && && &#define LCD_BASE& && &&&((u32)(0x6C000000 | 0x000007FE))#define LCD& && && && & ((LCD_TypeDef *) LCD_BASE)////////////////////////////////////////////////////////////////////////////////////扫描方向定义#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 LBBLUE& && && &&&0X2B12 //浅棕蓝色(选择条目的反色)& && && & void LCD_Init(void);& && && && && && && && && && && && && && && && && && && && && && &&&/初始化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);& && && && && && && && && && && && && && && &&&//画点u16 LCD_ReadPoint(u16 x,u16 y);& && && && && && && && && && && && && && && &//读点 void 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(u8 LCD_Reg, u16 LCD_RegValue);u16 LCD_ReadReg(u8 LCD_Reg);void LCD_WriteRAM_Prepare(void);void LCD_WriteRAM(u16 RGB_Code);& && && && &&&void LCD_Scan_Dir(u8 dir);& && && && && && && && && && && && && && & //设置屏扫描方向void LCD_Display_Dir(u8 dir);& && && && && && && && && && && && && &//设置屏幕显示方向& && && && &// LCD寄存器&&#define R0& && && && & 0x00……//省略部分#define R229& && && &&&0xE5& && && && && && && && && && && && && && && && && && && &&&#endif这段代码的两个重要结构体定义,我们都在前面有介绍,其他的相对就比较简单了。另外这段代码对颜色和驱动器的寄存器进行了很多宏定义,限于篇幅考虑,我们没有完全贴出来,省略了其中绝大部分。此部分我们就不多说了。接下来,我们在test.c里面修改main函数如下:int main(void){
& && &u8 x=0;& && & u8 lcd_id[12];& && && && && &//存放LCD ID字符串& && &Stm32_Clock_Init(9);& & //系统时钟设置& && & uart_init(72,9600);& && &//串口初始化为9600& && & delay_init(72);& && && && && && &//延时初始化 & && & LED_Init();& && && && && && && &&&//初始化与LED连接的硬件接口& && &LCD_Init();& && & POINT_COLOR=RED;& && & sprintf((char*)lcd_id,&LCD ID:%04X&,lcddev.id);//将LCD ID打印到lcd_id数组& && &&&& && &while(1) & && & {& && && && && && && && &&&switch(x)& && && && &&&{& && && && && && && &case 0:LCD_Clear(WHITE);& && && && && && && &case 1:LCD_Clear(BLACK);& && && && && && && &case 2:LCD_Clear(BLUE);& && && && && && && &case 3:LCD_Clear(RED);& && && && && && && &case 4:LCD_Clear(MAGENTA);& && && && && && && &case 5:LCD_Clear(GREEN);& && && && && && && &case 6:LCD_Clear(CYAN);case 7:LCD_Clear(YELLOW);& && && && && && && &case 8:LCD_Clear(BRRED);& && && && && && && &case 9:LCD_Clear(GRAY);& && && && && && && &case 10:LCD_Clear(LGRAY);& && && && && && && &case 11:LCD_Clear(BROWN);& && && && &&&}& && && && &&&POINT_COLOR=RED;& & & && && && &&&LCD_ShowString(30,50,200,16,16,&WarShip STM32 ^_^&);& &&&& && && && &&&LCD_ShowString(30,70,200,16,16,&TFTLCD TEST&);& && && && && && &&&LCD_ShowString(30,90,200,16,16,&ATOM@ALIENTEK&);& && && && & LCD_ShowString(30,110,200,16,16,lcd_id);& && && && &&&//显示LCD ID& && && && && && && && && && && && && && && && & LCD_ShowString(30,130,200,16,16,&&);& && && & & && && &&&x++;& && && && &&&if(x==12)x=0;& && && && &&&LED0=!LED0;& && && && && && && && && && && &&&& && && && &&&delay_ms(1000);& & & && & } }该部分代码将显示一些固定的字符,同时显示LCD驱动IC的型号,然后不停的切换背景颜色,每1s切换一次。而LED0也会不停的闪烁,指示程序已经在运行了。其中我们用到一个sprintf的函数,该函数用法同printf,只是sprintf把打印内容输出到指定的内存区间上,sprintf的详细用法,请百度。在编译通过之后,我们开始下载验证代码。
18.4 下载验证 将程序下载到战舰STM32后,可以看到DS0不停的闪烁,提示程序已经在运行了。同时可以看到TFTLCD模块的显示如图18.4.1所示:
图18.4.1 TFTLCD显示效果图我们可以看到屏幕的背景是不停切换的,同时DS0不停的闪烁,证明我们的代码被正确的执行了,达到了我们预期的目的。
本帖子中包含更多资源
才可以下载或查看,没有帐号?
我的STM32开发板店铺:
我的技术论坛论坛:
主题帖子积分
高级工程师, 积分 7150, 距离下一级还需 850 积分
高级工程师, 积分 7150, 距离下一级还需 850 积分
主题帖子积分
专家等级:结帖率:13%
主题帖子积分
高级工程师, 积分 7150, 距离下一级还需 850 积分
高级工程师, 积分 7150, 距离下一级还需 850 积分
很不错的开发指南
主题帖子积分
资深工程师, 积分 10265, 距离下一级还需 9735 积分
资深工程师, 积分 10265, 距离下一级还需 9735 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
资深工程师, 积分 10265, 距离下一级还需 9735 积分
资深工程师, 积分 10265, 距离下一级还需 9735 积分
LZ可以整理成一些文档
主题帖子积分
高级技术员, 积分 614, 距离下一级还需 386 积分
高级技术员, 积分 614, 距离下一级还需 386 积分
主题帖子积分
专家等级:结帖率:100%
主题帖子积分
高级技术员, 积分 614, 距离下一级还需 386 积分
高级技术员, 积分 614, 距离下一级还需 386 积分
无冕之王 发表于
LZ可以整理成一些文档
是完整版本的拆分,完整版本&STM32开发指南&
我的STM32开发板店铺:
我的技术论坛论坛:
主题帖子积分
中级技术员, 积分 295, 距离下一级还需 5 积分
中级技术员, 积分 295, 距离下一级还需 5 积分
主题帖子积分
专家等级:结帖率:50%
主题帖子积分
中级技术员, 积分 295, 距离下一级还需 5 积分
中级技术员, 积分 295, 距离下一级还需 5 积分
不要高估自己的能力,不要轻视自己的惰性!
主题帖子积分
实习生, 积分 15, 距离下一级还需 35 积分
实习生, 积分 15, 距离下一级还需 35 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
实习生, 积分 15, 距离下一级还需 35 积分
实习生, 积分 15, 距离下一级还需 35 积分
主题帖子积分
资深技术员, 积分 414, 距离下一级还需 86 积分
资深技术员, 积分 414, 距离下一级还需 86 积分
主题帖子积分
专家等级:结帖率:100%
主题帖子积分
资深技术员, 积分 414, 距离下一级还需 86 积分
资深技术员, 积分 414, 距离下一级还需 86 积分
原子来这开讲了
主题帖子积分
实习生, 积分 6, 距离下一级还需 44 积分
实习生, 积分 6, 距离下一级还需 44 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
实习生, 积分 6, 距离下一级还需 44 积分
实习生, 积分 6, 距离下一级还需 44 积分
这一节学习我有几个问题 我看了ili9431的pdf,主要是指令都看了,发现一些指令手册根本没写,比如 读gram这部分
if(lcddev.id==0X9341||lcddev.id==0X6804)LCD_WR_REG(0X2E);// 发送读GRAM指令
else LCD_WR_REG(R34);& && && && & //其他IC发送读GRAM指令
&&if(lcddev.id==0X9320)opt_delay(2);& & //FOR 9320,延时2us& &&&
if(LCD-&LCD_RAM)r=0;& && & //dummy Read& &
opt_delay(2);& &
&&r=LCD-&LCD_RAM;& && && && &//实际坐标颜色
&&if(lcddev.id==0X9341)//9341要分2次读出
&&opt_delay(2);& &
&&b=LCD-&LCD_RAM;
&&g=r&0XFF;//对于9341,第一次读取的是RG的值,R在前,G在后,各占8位
我看手册只提及一次读取18位,而不是读两次,还有坐标点设定用指令2A 2B,数据2字节,手册我只看到用4字节设定区域范围,怎么看手册好多设定都没提及,厂商初始化时愣是往上写。
主题帖子积分
主题帖子积分
专家等级:结帖率:100%打赏:0.00受赏:6.00
主题帖子积分
QQ:& &可接项目和毕设等
& && && && && && &可以出售各种LED灯,控制类产品和
& && && && && && &控制类方案。
主题帖子积分
高级技术员, 积分 614, 距离下一级还需 386 积分
高级技术员, 积分 614, 距离下一级还需 386 积分
主题帖子积分
专家等级:结帖率:100%
主题帖子积分
高级技术员, 积分 614, 距离下一级还需 386 积分
高级技术员, 积分 614, 距离下一级还需 386 积分
valkyrie1107 发表于
这一节学习我有几个问题 我看了ili9431的pdf,主要是指令都看了,发现一些指令手册根本没写,比如 读gram这 ...
9341的手册问题多多。
我的STM32开发板店铺:
我的技术论坛论坛:
主题帖子积分
实习生, 积分 6, 距离下一级还需 44 积分
实习生, 积分 6, 距离下一级还需 44 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
实习生, 积分 6, 距离下一级还需 44 积分
实习生, 积分 6, 距离下一级还需 44 积分
顶,真不错
主题帖子积分
实习生, 积分 9, 距离下一级还需 41 积分
实习生, 积分 9, 距离下一级还需 41 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
实习生, 积分 9, 距离下一级还需 41 积分
实习生, 积分 9, 距离下一级还需 41 积分
写的好~~
主题帖子积分
初级技术员, 积分 54, 距离下一级还需 46 积分
初级技术员, 积分 54, 距离下一级还需 46 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
初级技术员, 积分 54, 距离下一级还需 46 积分
初级技术员, 积分 54, 距离下一级还需 46 积分
都是FSMC控制的,要是用的片子不带FSMC怎么办
主题帖子积分
实习生, 积分 3, 距离下一级还需 47 积分
实习生, 积分 3, 距离下一级还需 47 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
实习生, 积分 3, 距离下一级还需 47 积分
实习生, 积分 3, 距离下一级还需 47 积分
为什么用此代码能正常清屏就是不能用别的功能,仔细看屏幕只有右上角的一个像素点有反应,谁能告诉我这个怎么搞,是啥原因。万分感谢,控制IC是ili9486的.在此先谢谢大家了!
主题帖子积分
实习生, 积分 20, 距离下一级还需 30 积分
实习生, 积分 20, 距离下一级还需 30 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
实习生, 积分 20, 距离下一级还需 30 积分
实习生, 积分 20, 距离下一级还需 30 积分
不错的教程
主题帖子积分
实习生, 积分 9, 距离下一级还需 41 积分
实习生, 积分 9, 距离下一级还需 41 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
实习生, 积分 9, 距离下一级还需 41 积分
实习生, 积分 9, 距离下一级还需 41 积分
不错,谢谢分享,顶顶
主题帖子积分
实习生, 积分 13, 距离下一级还需 37 积分
实习生, 积分 13, 距离下一级还需 37 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
实习生, 积分 13, 距离下一级还需 37 积分
实习生, 积分 13, 距离下一级还需 37 积分
lz问下你怎么动态显示图片,就是让图片往左移动,求帮助
时间类勋章
技术奇才奖章
人才类勋章
涓涓之细流
发帖类勋章
技术新星奖章
人才类勋章
晶莹之水滴
发帖类勋章
时间类勋章
坚毅之洋流
发帖类勋章
核心会员奖章
等级类勋章}

我要回帖

更多关于 tft lcd显示屏驱动 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信