STM32f4————TFTLCD显示实验代码(01)
/*******************************************************/
本实验,我们用到FSMC驱动 LCD,通过前面的介绍,我们知道TFTLCD 的RS接在FSMC的 A6上面,CS 接在 FSMC_NE4 上,并且是16位数据总线。即我们使用的是FSMC 存储器1的第 4区,我们定义如下LCD 操作结构体(在lcd.h 里面定义):
//LCD 操作结构体
typedef struct
{
vu16 LCD_REG;
vu16 LCD_RAM;
} LCD_TypeDef;
//使用NOR/SRAM的 Bank1.sector4,地址位 HADDR[27,26]=11 A6作为数据命令区分线
//注意16位数据总线时,STM32内部地址会右移一位对齐!
#define LCD_BASE ((u32)(0x6C000000 | 0x0000007E))
#define LCD ((LCD_TypeDef *) LCD_BASE)
其中 LCD_BASE,必须根据我们外部电路的连接来确定,我们使用 Bank1.sector4 就是从地址 0X6C000000开始,而 0X0000007E,则是A6的偏移量,这里很多朋友不理解这个偏移量的概念,简单说明下:以 A6 为例,7E 转换成二进制就是:1111110,而 16 位数据时,地址右移一位对齐,那么实际对应到地址引脚的时候,就是:A6:A0=0111111,此时 A6 是0,但是如果16位地址再加1(注意:对应到8 位地址是加2,即 7E+0X02), 那 么 :A6:A0=1000000,此时 A6 就是1了,即实现了对RS的 0和1的控制。
我们将这个地址强制转换为LCD_TypeDef结构体地址,那么可以得到LCD->LCD_REG 的地址就是 0X6C00,007E,对应 A6 的状态为 0(即 RS=0),而 LCD-> LCD_RAM 的地址就是0X6C00,0080(结构体地址自增),对应A6的状态为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 width; //LCD 宽度
u16 height; //LCD 高度
u16 id; //LCD ID
u8 dir; //横屏还是竖屏控制:0,竖屏;1,横屏。
u16 wramcmd; //开始写 gram指令
u16 setxcmd; //设置 x坐标指令
u16 setycmd; //设置 y坐标指令
}_lcd_dev;
//LCD 参数
extern _lcd_dev lcddev; //管理LCD 重要参数
该结构体用于保存一些 LCD 重要参数信息,比如LCD 的长宽、LCD ID(驱动IC 型号)、LCD 横竖屏状态等,这个结构体虽然占用了十几个字节的内存,但是却可以让我们的驱动函数支持不同尺寸的 LCD,同时可以实现 LCD 横竖屏切换等重要功能,所以还是利大于弊的。有了以上了解,下面我们开始介绍 lcd.c里面的一些重要函数。
先看 7个简单,但是很重要的函数:
//写寄存器函数
//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(vu16 LCD_Reg, vu16 LCD_RegValue)
{ LCD->LCD_REG = LCD_Reg; //写入要写的寄存器序号
LCD->LCD_RAM = LCD_RegValue; //写入数据
}
//读寄存器
//LCD_Reg:寄存器地址
//返回值:读到的数据
u16 LCD_ReadReg(vu16 LCD_Reg)
{ LCD_WR_REG(LCD_Reg); //写入要读的寄存器序号
delay_us(5);
return LCD_RD_DATA(); //返回读到的值
}
//开始写GRAM
void 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
}
因为FSMC 自动控制了WR/RD/CS 等这些信号,所以这7个函数实现起来都非常简单,我们就不多说,注意,上面有几个函数,我们添加了一些对MDK –O2优化的支持,去掉的话,在-O2 优化的时候会出问题。这些函数实现功能见函数前面的备注,通过这几个简单函数的组合,我们就可以对 LCD进行各种操作了。
/*******************************************************/
|