简介
1、为什么可以把 TFTLCD 当成 SRAM 设备用
- 首先我们了解下外部 SRAM的连接,外部 SRAM 的控制一般有:地址线(如 A0~ A18)、数据线(如 D0~D15)、写信号(WE)、读信号(OE)、片选信号(CS),如果 SRAM 支持字节控制,那么还有 UB/LB 信号
- 而 TFTLCD的信号包括:RS(选择发送命令或者数据)、D0~ D15、WR(写)、RD(读)、CS(片选)、RST(复位) 和 BL 等
- 其中真正在操作 LCD 的时候需要用到的就只有:RS、D0~D15、WR、RD 和 CS。
- 其操作时序和 SRAM的控制完全类似,唯一不同就是 TFTLCD 有 RS 信号,但是没有地址信号。
2、具体数据线的改变,导致能够使用
- TFTLCD 通过 RS 信号来决定传送的数据是数据还是命令,本质上可以理解为一个地址信号,比如我们把 RS 接在 A0 上面,那么当 FSMC 控制器写地址 0 的时候,会使得 A0 变为 0, 对 TFTLCD 来说,就是写命令。而FSMC 写地址 1 的时候,A0 将会变为 1,对 TFTLCD 来说,就是写数据了。这样,就把数据和命令区分开了,他们其实就是对应 SRAM 操作的两个连续地址。
- 当然 RS 也可以接在其他地址线上,探索者 STM32F4 开发板是把 RS 连接在 A6 上面的。
使用
1、任何 LCD,使用流程都可以简单的用以上流程图表示。其中硬复位和初始化序列,只需要执行一次即可。而画点流程就是:设置坐标→写 GRAM 指令→写入颜色数据,然后在 LCD 上面,我们就可以看到对应的点显示我们写入的颜色了。读点流程为:设置坐标→读 GRAM 指令→读取颜色数据,这样就可以获取到对应点的颜色数据了。
2、实际操作
- 首先在HAL库进行配置:选择片选信号为NE4,选择控制类型为LCD控制,此时就可以选将数据和命令控制线 映射到A6,然后设置DATA为16bit(因为使用了RGB565),最后设置好时序,和背光IO为PB15就可以了
- 如何在使用过程中发送命令或者数据呢:直接在使A6变为1或者0的内存地址上写就可以了
- 发送初始化命令啥的
各种屏幕介绍
视频
1、显示器介绍
- 常见的显示器有CRT显示器
- LCD(Liquid Crystal Display):液晶显示器,所有像素点共用一个背光灯
- LED点阵显示器
- OLED(Organic Light Emitting Diode):有机发光二极管显示器
2、LCD屏幕介绍
- 液晶分子不能完全遮住光,因此不能显示纯黑
- 液晶在温度低的时候相应会变慢,这也就是LCD的手机在冬天温度低的时候滑动手机会有拖影的现象
- LCD更厚一点,OLED是有机物容易老化所以使用寿命是小于LCD的,容易烧屏
- DC调光,直接控制电压控制那个大的灯的亮度,电压高灯就亮,没有频闪伤眼。
- 由于背光的波长相当大一部分属于蓝光,蓝光伤眼
3、OLED
- 对比度更好
- OLED是有机物容易老化,使用寿命小于LCD的,容易烧屏
- 由于没有背光层啥的,屏幕可以更薄
- PWM调节控制亮度,频率低了容易造成频闪
显示器控制
1、显示器基本参数
- 像素:成像最小的点,一个显示单元;三个构成一个像素,如下图所示
- 分辨率:1920×1080(前面是行,后面是列)
- 色彩深度:一个像素用多少位表示;常见的有色深16bit(RGB565,红色通道用5位表示这样,一共可以显示2的16次方种颜色)和24bit(RGB888);还有RGB8888,其中有一位代表了透明度,即2的32次方
- 显示器尺寸:用对角线的尺寸表示,用英寸(1英寸就是2.54cm)表示
- 点距:两个相邻像素点之间的距离
2、显示器的接口技术
- 使用信号转接板可以使用这四种,但是一般不这样,不划算。DP,HDMI;DVI,VGA这两个比较老,现在的笔记本基本都没了
- 单片机常用的接口模式:MCU模式,RGB模式,SPI,串口
产品
简介
1、用的是正点原子提供的3.5寸TFTLCD驱动芯片用的是NT35310,电阻触摸屏。分辨率480×320,集成的触摸屏接口是SPI的;采用 RGB565 格式存储颜色数据,即16位颜色深度(我感觉16位数据并口,意思就是16位颜色)
2、16位8080并口(通过FSMC模拟实现),数据线:
- CS:TFTLCD 片选信号,;对应就是FSMC_NE4 做片选
- WR:向 TFTLCD 写入数据
- RD:从 TFTLCD 读取数据
- D[15:0]:16 位双向数据线
- RST:硬复位 TFTLCD(RST 信号线是直接接到 STM32F4 的复位脚上,并不由软件控制,这样可以省下来一个
IO 口。) - RS:命令/数据标志(0,读写命令;1,读写数据)
- 还需要一个IO口作为背光控制线
使用简介
- 使用基本就是先发送初始化信息进行初始化
- 然后发送要写坐标的命令 之后发送坐标信息 (设置坐标)
- 然后发送写值命令 然后写值也就是这个点的颜色
配置
HAL库配置
STM32F4 的 FSMC 支持 8/16/32 位数据宽度,我们这里用到的 LCD 是 16 位宽度的,所以在设置的时候,选择 16 位宽就 OK 了
配置背光PB15 上电默认输出高电平
基本参数与寄存器
//LCD重要参数集
typedef struct
{
uint16_t width; //LCD 宽度
uint16_t height; //LCD 高度d
uint16_t id; //LCD ID
uint8_t dir; //横屏还是竖屏控制:0,竖屏;1,横屏。
uint16_t wramcmd; //开始写gram指令
uint16_t setxcmd; //设置x坐标指令
uint16_t setycmd; //设置y坐标指令
}LcdDevArg;
/************************ 基本参数与寄存器 *************************************/
//管理LCD重要参数
//默认为竖屏 就宽度和高度设置的不同
LcdDevArg lcddev={
//参数
.dir=0, //竖屏/横屏
.width=320,
.height=480,
//命令
.wramcmd=0X2C,//开始写gram指令
.setxcmd=0X2A,//设置x坐标指令
.setycmd=0X2B,//y坐标命令
};
关键函数(读写函数)
//读写函数
void LCD_WR_REG(volatile uint16_t regval);//写命令
uint16_t LCD_RD_DATA(void); //读数据
void LCD_WR_DATA(volatile uint16_t data); //写数据
void LCD_WriteReg(uint16_t LCD_Reg,uint16_t LCD_RegValue);//先写寄存器再写值
数据命令操作原理
- 1、 用的是第4块,地址范围为0x6800 0000——6BFF FFFF
- 2、我们把FSMC的A6地址线与 数据/命令 相连接 当A6为高电平时,数据线[15:0]被理解为数据
反正当A6为低电平时 被理解为命令 - 3、因此当我们需要写数据时,则使第6位地址为1;写命令时为0
- 4、7E:0111 1110 此时第六位为1数据,但是由于STM32内部会右移一位对齐,则右移后第六位为0
- 5、因此原地址为0 加1后就为数据了
//LCD地址结构体
typedef struct
{
volatile uint16_t LCD_REG;//0 命令
volatile uint16_t LCD_RAM;//1 数据
} LCD_TypeDef;
/*
1、 用的是第4块,地址范围为0x6800 0000——6BFF FFFF
2、我们把FSMC的A6地址线与 数据/命令 相连接 当A6为高电平时,数据线[15:0]被理解为数据
反正当A6为低电平时 被理解为命令
3、因此当我们需要写数据时,则使第6位地址为1;写命令时为0
4、7E:0111 1110 此时第六位为1数据,但是由于STM32内部会右移一位对齐,则右移后第六位为0
5、因此原地址为0 加1后就为数据了
*/
#define LCD_BASE ((uint32_t)(0x6C000000 | 0x0000007E))
#define LCD ((LCD_TypeDef *) LCD_BASE)
实际操作:
- 当我们在LCD->LCD_REG地址写入数据的时候,STM32会自动在数据线[15:0],输出相应数据。但此时LCD会将这段数据识别成命令
- 当我们在LCD->LCD_RAM地址写入数据时,STM32会自动在数据线[15:0],输出相应数据。但此时LCD会将这段数据识别成数据。
- 同理读数据也是相同的,当我们在ram=LCD->LCD_RAM这段内存读数据时,STM32就会将从数据线[15:0]读到的数据读出。此时就是可以看成是LCD发送过来的数据。
//写寄存器
//regval:寄存器值
void LCD_WR_REG(volatile uint16_t regval)
{
regval=regval; //使用-O2优化的时候,必须插入的延时
LCD->LCD_REG=regval;//写入要写的寄存器序号
}
//读LCD数据
//返回值:读到的值 通常用在发送完寄存器 后读取返回的值,他返回的值是需要我们读的
uint16_t LCD_RD_DATA(void)
{
volatile uint16_t ram; //防止被优化
ram=LCD->LCD_RAM; //这里相当于 读一个内存地址(可以看成读一个变量 自动会生成读时序)
return ram;
}
//写LCD数据
//data:要写入的值
void LCD_WR_DATA(volatile uint16_t data)
{
data=data; //使用-O2优化的时候,必须插入的延时
LCD->LCD_RAM=data;
}
//写寄存器 针对某个寄存器写值,先写寄存器序号,然后写入数据
//LCD_Reg:寄存器地址
//LCD_RegValue:要写入的数据
void LCD_WriteReg(uint16_t LCD_Reg,uint16_t LCD_RegValue)
{
LCD->LCD_REG = LCD_Reg; //写入要写的寄存器序号
LCD->LCD_RAM = LCD_RegValue;//写入数据
}
读写点函数
void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos);//设置光标位置 用于读点
void opt_delay(uint8_t i);
//实际操作函数
void LCD_Fast_DrawPoint(uint16_t x,uint16_t y,uint32_t color);//快速画点
uint32_t LCD_ReadPoint(uint16_t x,uint16_t y);//读点
/************************ 读点与画点函数 *************************************/
//快速画点
//x,y:坐标
//color:颜色
void LCD_Fast_DrawPoint(uint16_t x,uint16_t y,uint32_t color)
{
//设置坐标
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA(x>>8);LCD_WR_DATA(x&0XFF);
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA(y>>8);LCD_WR_DATA(y&0XFF);
//写点颜色
LCD->LCD_REG=lcddev.wramcmd;
LCD->LCD_RAM=color;
}
//当mdk -O1时间优化时需要设置
//延时i
void opt_delay(uint8_t i)
{
while(i--);
}
//设置光标位置(对RGB屏无效)
//Xpos:横坐标
//Ypos:纵坐标
void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
{
LCD_WR_REG(lcddev.setxcmd); //发送设置x坐标命令
LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF); //先发送高8位 后发送低8位
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF);
}
//读取个某点的颜色值
//x,y:坐标
//返回值:此点的颜色
uint32_t LCD_ReadPoint(uint16_t x,uint16_t y)
{
uint16_t r=0,g=0,b=0