LCD的一般使用步骤
其中硬复位和初始化序列只需要执行一次
显示需要相关设置步骤
- 设置 STM32 与 TFTLCD 模块相连接的 IO
将TFTLCD 模块相连的 IO 口进行初始化,以便驱动 LCD - 初始化 TFTLCD 模块
初始化序列,就是向 LCD 控制器写入一系列的设置值(比如伽马校准),
这些初始化序列一般 LCD 供应商会提供给客户,我们直接使用这些序列即可,不需要深入研究 - 通过函数将字符和数字显示到 TFTLCD 模块上
重要的函数
结构体_lcd_dev
用于设置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;
使用时,定义了一个外部变量(extern )的用于保存设置LCD的重要参数结构体 lcddev
extern _lcd_dev lcddev; //管理 LCD 重要参数
!)LCD_Display_Dir 函数赋值该结构体参数
LCD_WR_REG
写寄存器函数
//data:寄存器值
void LCD_WR_REG(u16 data)
{
LCD_RS_CLR;//写地址
LCD_CS_CLR;
DATAOUT(data);
LCD_WR_CLR;
LCD_WR_SET;
LCD_CS_SET;
}
LCD_WR_DATA
写数据函数
#define LCD_WR_DATA(data){\
LCD_RS_SET;\
LCD_CS_CLR;\
DATAOUT(data);\
LCD_WR_CLR;\
LCD_WR_SET;\
LCD_CS_SET;
因为其使用频率最高,采用宏定义的方式,以提高速度
LCD_RD_DATA
读 LCD 寄存器数据
//返回值:读到的值
u16 LCD_RD_DATA(void)
{
u16 t;
GPIOB->CRL=0X88888888; //PB0-7 上拉输入
GPIOB->CRH=0X88888888; //PB8-15 上拉输入
GPIOB->ODR=0X0000; //全部输出 0
LCD_RS_SET;
LCD_CS_CLR;
LCD_RD_CLR; //读取数据(读寄存器时,并不需要读 2 次)
if(lcddev.id==0X8989)delay_us(2);//FOR 8989,延时 2us
t=DATAIN;
LCD_RD_SET;
LCD_CS_SET;
GPIOB->CRL=0X33333333; //PB0-7 上拉输出
GPIOB->CRH=0X33333333; //PB8-15 上拉输出
GPIOB->ODR=0XFFFF; //全部输出高
return t;
}
LCD_WriteReg 与 LCD_ReadReg
写寄存器
//LCD_Reg:寄存器编号
//LCD_RegValue:要写入的值
void LCD_WriteReg(u16 LCD_Reg,u16 LCD_RegValue)
{
LCD_WR_REG(LCD_Reg);
LCD_WR_DATA(LCD_RegValue);
}
读寄存器
//LCD_Reg:寄存器编号
//返回值:读到的值
u16 LCD_ReadReg(u16 LCD_Reg)
{
LCD_WR_REG(LCD_Reg); //写入要读的寄存器号
return LCD_RD_DATA();
}
LCD_WriteReg 用于向 LCD 指定寄存器写入指定数据
LCD_ReadReg 则用于读取指定寄存器的数据
但只带一个参数/返回值,所以,在有多个参数操作(读取/写入)的时候,就不适合用这两个函数
init函数
void LCD_Init(void)
{
初始化GPIO
读取LCD_ID
printf(" LCD ID:%x\r\n",lcddev.id); //打印 LCD ID
/*打印LCD_ID时用到了串口1,所以必须初始化串口1,否则会黑屏*/
根据不同ID执行不同LCD初始化代码
LCD_Display_Dir(0); //默认为竖屏显示
LCD_LED=1; //点亮背光
LCD_Clear(WHITE);//清屏
}
坐标设置函数
设置光标位置
//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);
LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);
}else
{
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);
LCD_WR_DATA((lcddev.width-1)>>8);LCD_WR_DATA((lcddev.width-1)&0XFF);
}
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF);
LCD_WR_DATA((lcddev.height-1)>>8);LCD_WR_DATA((lcddev.height-1)&0XFF);
}else if(lcddev.id==0X5510)
{
LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(Xpos>>8);
LCD_WR_REG(lcddev.setxcmd+1);LCD_WR_DATA(Xpos&0XFF);
LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(Ypos>>8);
LCD_WR_REG(lcddev.setycmd+1);LCD_WR_DATA(Ypos&0XFF);
}else
{
if(lcddev.dir==1)Xpos=lcddev.width-1-Xpos;//横屏其实就是调转x,y坐标
LCD_WriteReg(lcddev.setxcmd, Xpos);
LCD_WriteReg(lcddev.setycmd, Ypos);
}
}
该函数将 LCD 的当前操作点设置到指定坐标(x,y),因为不同 LCD 的设置方式不一定完全一样,所以代码里面有好几个判断,对不同的驱动 IC 进行不同的设置
画点函数与读点函数
画点
//x,y:坐标
//POINT_COLOR:此点的颜色
void LCD_DrawPoint(u16 x,u16 y)
{
LCD_SetCursor(x,y); //设置光标位置
LCD_WriteRAM_Prepare(); //开始写入 GRAM
LCD_WR_DATA(POINT_COLOR);
}
该函数先设置坐标,然后往坐标写颜色
读点
u16 LCD_ReadPoint(u16 x,u16 y)
{略}
如何使用
在main.c中
int main(void)
{
u8 lcd_id[12]; //存放LCD ID字符串
delay_init(); //延时函数初始化
uart_init(9600); //串口初始化为9600
LED_Init(); //初始化与LED连接的硬件接口
LCD_Init();
POINT_COLOR=RED;
sprintf((char*)lcd_id,"LCD ID:%04X",lcddev.id);//将LCD ID打印到lcd_id数组。
/*准备步骤👆*/
while(1)
{
/*循环内的是显示的内容*/
u8 x=0,y=0;
LCD_Clear(WHITE);
POINT_COLOR=BLACK;
while(1)
{
x++;
y++;
LCD_Fast_DrawPoint(x,y,BLACK);
delay_ms(20);
}
}
}