嵌入式单片机基础篇(二十一)之TFTLCD 显示

TFTLCD 显示详解

1、在硬件上,TFTLCD 模块与 STM32F103 的 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;
2、程序:
用 FSMC 驱动 LCD,TFTLCD 的RS接在 FSMC 的 A10上面,CS 接在 FSMC_NE4 上,并且是16 位数据总线。即使用的是 FSMC 存储器1的第 4 区,定义如下 LCD 操作结构体:

//LCD 操作结构体
typedef struct
{
    vu16 LCD_REG;
vu16 LCD_RAM;
} LCD_TypeDef;
//使用 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 重要参数集
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 横竖屏状态等,这个结构体虽然占用了 10 个字节的内存,但是却可以让驱动函数支持不同尺寸的 LCD,同时可以实现 LCD 横竖屏切换等重要功能。
一些重要函数:

//写寄存器函数
//regval:寄存器值
void LCD_WR_REG(u16 regval)
{
    
LCD->LCD_REG=regval; //写入要写的寄存器序号
}
//写 LCD 数据
//data:要写入的值
void LCD_WR_DATA(u16 data)
{
   
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(); //返回读到的值
} 
//开始写 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 优化的时候会出问题。
坐标设置函数,该函数代码如下:

/设置光标位置
//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)
  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值