TFT-LCD屏幕填充颜色(FSMC)

TFT-LCD屏幕填充颜色

手上的TFT-LCD屏幕为2.8寸屏, 驱动IC为ILI9341

TFT-LCD屏幕显示内容前要设置一个显示窗口,窗口的参数有X坐标,Y坐标,宽度,高度,设置一个正方形或者长方形窗口,就可在窗口内显示内容,如果要显示一个点,则X、Y坐标也要设置,只不过宽度和高度都为1

TFT-LCD驱动流程

在这里插入图片描述

CubeMX配置

打开CubeMX软件,点击Connectivity下的FSMC

在这里插入图片描述

在模式中可以看到有多种选择,前四个对应了NOR Flash的四个区,因为硬件的LCD_CS引脚接到了FSMC_NE1,所以用第1个区

在这里插入图片描述

LCD的片选引脚CS接到了NE1,所以选择NE1

在这里插入图片描述

内存类型选择LCD接口,其实就是TFT_LCD驱动芯片里的GRAM,与SRAM差不多,只不过FSMC常用于LCD,所以就有这个LCD的接口选择

在这里插入图片描述

LCD的数据/命令选择线D/CX线接到了FSMC_A0,所以这里的LCD Register Select选择A0

在这里插入图片描述

数据位选择16位,这要看屏幕,有些屏幕数据8位的就选8位

在这里插入图片描述

配置按默认值即可,时钟周期可按下面的来配置

在这里插入图片描述

最后LCD屏幕的背光引脚初始化为推挽输出,默认低电平即可

程序

TFT_LCD.h
#ifndef __TFT_LCD_H_
#define __TFT_LCD_H_

/* Includes ------------------------------------------------------------------*/
#include "MyApplication.h"

//屏幕背光控制
#define TFT_LCD_BL_ON    HAL_GPIO_WritePin(TFT_LCD_BL_GPIO_Port,TFT_LCD_BL_Pin,GPIO_PIN_SET)
#define TFT_LCD_BL_OFF   HAL_GPIO_WritePin(TFT_LCD_BL_GPIO_Port,TFT_LCD_BL_Pin,GPIO_PIN_RESET)

/******************************************************************************
NOR/PSRAM存储区地址:
64MB:FSMC_Bank1_NORSRAM1:0x6000 0000 ~ 0x63FF FFFF
64MB:FSMC_Bank1_NORSRAM2:0x6400 0000 ~ 0x67FF FFFF
64MB:FSMC_Bank1_NORSRAM3:0x6800 0000 ~ 0x6BFF FFFF
64MB:FSMC_Bank1_NORSRAM4:0x6C00 0000 ~ 0x6FFF FFFF

选择BANK1-BORSRAM1 连接 TFT,地址范围为0x6000 0000 ~ 0x63FF FFFF
实验板选择 FSMC_A0 接LCD的D/CX(命令/数据选择)脚
命令地址 = 0x6000 0000		相当于A0 = 0,此时是发送命令
数据地址 = 0x6000 0002 = 0x6000 0000+(1<<(0+1))	 想让A0 = 1,本来是0x6000 0001的,但数据要左移一位,才是HADDR[25:1]的地址
如果电路设计时选择不同的地址线时,地址要重新计算        
eg:选择A10,则数据基地址 = 0x6000 0000+(1<<(10+1)) = 0x6000 0800
*******************************************************************************/
#define FSMC_LCD_CMD_ADDR   ((uint32_t)0x60000000)      //FSMC_Bank1_NORSRAM1用于LCD命令操作的地址
#define FSMC_LCD_DATA_ADDR  ((uint32_t)0x60000002)      //FSMC_Bank1_NORSRAM1用于LCD数据操作的地址

//LCD读写函数宏定义
//先把地址强制类型转换为指针,再解引用,就得到数据,然后把命令或数据直接赋值过去就行
#define LCD_WRITE_CMD(CMD)      *((__IO uint16_t*)FSMC_LCD_CMD_ADDR) = (uint16_t)CMD
#define LCD_WRITE_DATA(DATA)    *((__IO uint16_t*)FSMC_LCD_DATA_ADDR) = (uint16_t)DATA
#define LCD_READ_DATA(DATA)     *((__IO uint16_t*)FSMC_LCD_DATA_ADDR)

//显示方向选择,共有4个方向
#define LCD_DIRECTION       1   //竖屏,原点在屏幕左上角 X*Y = 240*320
//#define LCD_DIRECTION       2   //横屏,原点在屏幕右上角 X*Y = 320*240
//#define LCD_DIRECTION       3   //竖屏,原点在屏幕右下角 X*Y = 240*320
// #define LCD_DIRECTION       4   //横屏,原点在屏幕左下角 X*Y = 320*240

//LCD屏幕的长度与宽度,根据显示方向来定
#if  (LCD_DIRECTION==1)||(LCD_DIRECTION==3)
    #define LCD_WIGHT               240     //X轴长度
    #define LCD_HIGHT               320     //Y轴长度
#else
    #define LCD_WIGHT               320     //X轴长度
    #define LCD_HIGHT               240     //Y轴长度
#endif

//LCD命令
#define LCD_CMD_SET_X_ORGIN     0x2A			//设置X轴坐标,也就是列地址
#define LCD_CMD_SET_Y_ORGIN     0x2B			//设置Y轴坐标,也就是行地址
#define LCD_CMD_WRGRAM          0x2C			//写GRAM命令
#define LCD_CMD_REGRAM          0x2E			//读GRAM命令

//定义颜色枚举类型
typedef enum
{
    Color_BLACK     = 0x0000,       //黑色
    Color_WHITE     = 0xFFFF,       //白色
    Color_RED       = 0xF800,       //红色
    Color_GREEN     = 0x07E0,       //绿色
    Color_BLUE      = 0x001F,       //蓝色
    Color_YELLOW    = 0xFFE0,       //黄色
    Color_GRAY      = 0x8430,       //灰色
}LCD_Color_t;

//定义结构体类型
typedef struct
{
    uint32_t ID;            //屏幕ID
    void (*Init)(void);     //屏幕初始化
    void (*LCD_FillColor)(uint16_t,uint16_t,uint16_t,uint16_t,LCD_Color_t);     //屏幕填充颜色
}TFT_LCD_t;

/* extern variables-----------------------------------------------------------*/
extern TFT_LCD_t TFT_LCD;
/* extern function prototypes-------------------------------------------------*/ 

#endif
/********************************************************
  End Of File
********************************************************/

头文件中主要对LCD写命令、写数据和读数据的操作用宏定义来说明,因为屏幕是接到FSMC的引脚上的,FSMC已经将通信时序做好,代码中就只需要操作数据或命令的地址就行

TFT_LCD.c

读取屏幕的ID,命令为0xD3,返回值为0x009341

/**
 * @name   LCD_ReadID
 * @brief  读取LCD屏幕的ID号
 * @param  None
 * @retval 返回屏幕ID号 
 */
static uint32_t LCD_ReadID(void)
{
    uint32_t LCD_ID = 0;
    uint32_t buf[4];

    LCD_WRITE_CMD(0xD3);                    //发送读取ID号的指令
    buf[0] = LCD_READ_DATA();               //第一个读取数据无效
    buf[1] = LCD_READ_DATA()&0x00FF;        //只有低8位的数据才有效
    buf[2] = LCD_READ_DATA()&0x00FF;        //只有低8位的数据才有效
    buf[3] = LCD_READ_DATA()&0x00FF;        //只有低8位的数据才有效
    
    LCD_ID = (buf[1]<<16)+(buf[2]<<8)+buf[3];       //组合成ID号
    return LCD_ID;									//0x009341
}

在这里插入图片描述

屏幕初始化函数

该函数内容一般厂商会给,可以直接拿来用,有些初始化硬照着数据手册来看都不是很懂,也可以对某些命令进行修改,比如初始化一般会设置固定的显示方向,这里可以改为用自己写的控制LCD显示方向的函数,可以随意更改不同方向;最后记得打开显示以及背光

/**
 * @name   LCD_Init
 * @brief  TFT_LCD屏幕初始化
 * @param  None
 * @retval None  
 */
static void LCD_Init(void)
{
    TFT_LCD.ID = LCD_ReadID();
    printf("The ID of LCD is 0x%.6X\r\n",TFT_LCD.ID);

    //2.8inch ILI9341初始化
	LCD_WRITE_CMD(0xCF); 	//电源控制
	LCD_WRITE_DATA(0x00); 
	LCD_WRITE_DATA(0xC9);   //C1 
	LCD_WRITE_DATA(0x30); 
	LCD_WRITE_CMD(0xED);  	//通电顺序控制
	LCD_WRITE_DATA(0x64); 
	LCD_WRITE_DATA(0x03); 
	LCD_WRITE_DATA(0X12); 
	LCD_WRITE_DATA(0X81); 
	LCD_WRITE_CMD(0xE8);  	//驱动时基控制
	LCD_WRITE_DATA(0x85); 
	LCD_WRITE_DATA(0x10); 
	LCD_WRITE_DATA(0x7A); 
	LCD_WRITE_CMD(0xCB);  	//电源(功率)控制
	LCD_WRITE_DATA(0x39); 
	LCD_WRITE_DATA(0x2C); 
	LCD_WRITE_DATA(0x00); 
	LCD_WRITE_DATA(0x34); 
	LCD_WRITE_DATA(0x02); 
	LCD_WRITE_CMD(0xF7);  	
	LCD_WRITE_DATA(0x20); 
	LCD_WRITE_CMD(0xEA);  
	LCD_WRITE_DATA(0x00); 
	LCD_WRITE_DATA(0x00); 
	LCD_WRITE_CMD(0xC0);    //Power control 
	LCD_WRITE_DATA(0x1B);   //VRH[5:0] 
	LCD_WRITE_CMD(0xC1);    //Power control 
	LCD_WRITE_DATA(0x00);   //SAP[2:0];BT[3:0] 01 
	LCD_WRITE_CMD(0xC5);    //VCM control 
	LCD_WRITE_DATA(0x30); 	//3F
	LCD_WRITE_DATA(0x30); 	//3C
	LCD_WRITE_CMD(0xC7);    //VCM control2 
	LCD_WRITE_DATA(0XB7); 

	//LCD_WRITE_CMD(0x36);   // Memory Access Control  不用固定的显示方式,改为自己写的设置显示方向函数
	//LCD_WRITE_DATA(0x08); 
	LCD_Disp_Direction();   //设置LCD显示方向

	LCD_WRITE_CMD(0x3A);   	//像素格式设置
	LCD_WRITE_DATA(0x55); 
	LCD_WRITE_CMD(0xB1);   	//帧速率控制
	LCD_WRITE_DATA(0x00);   
	LCD_WRITE_DATA(0x1A); 
	LCD_WRITE_CMD(0xB6);    // Display Function Control 
	LCD_WRITE_DATA(0x0A); 
	LCD_WRITE_DATA(0xA2); 
	LCD_WRITE_CMD(0xF2);    // 3Gamma Function Disable 
	LCD_WRITE_DATA(0x00); 
	LCD_WRITE_CMD(0x26);    //Gamma curve selected 
	LCD_WRITE_DATA(0x01); 
	LCD_WRITE_CMD(0xE0);    //Set Gamma 
	LCD_WRITE_DATA(0x0F); 
	LCD_WRITE_DATA(0x2A); 
	LCD_WRITE_DATA(0x28); 
	LCD_WRITE_DATA(0x08); 
	LCD_WRITE_DATA(0x0E); 
	LCD_WRITE_DATA(0x08); 
	LCD_WRITE_DATA(0x54); 
	LCD_WRITE_DATA(0XA9); 
	LCD_WRITE_DATA(0x43); 
	LCD_WRITE_DATA(0x0A); 
	LCD_WRITE_DATA(0x0F); 
	LCD_WRITE_DATA(0x00); 
	LCD_WRITE_DATA(0x00); 
	LCD_WRITE_DATA(0x00); 
	LCD_WRITE_DATA(0x00); 		 
	LCD_WRITE_CMD(0XE1);    //Set Gamma 
	LCD_WRITE_DATA(0x00); 
	LCD_WRITE_DATA(0x15); 
	LCD_WRITE_DATA(0x17); 
	LCD_WRITE_DATA(0x07); 
	LCD_WRITE_DATA(0x11); 
	LCD_WRITE_DATA(0x06); 
	LCD_WRITE_DATA(0x2B); 
	LCD_WRITE_DATA(0x56); 
	LCD_WRITE_DATA(0x3C); 
	LCD_WRITE_DATA(0x05); 
	LCD_WRITE_DATA(0x10); 
	LCD_WRITE_DATA(0x0F); 
	LCD_WRITE_DATA(0x3F); 
	LCD_WRITE_DATA(0x3F); 
	LCD_WRITE_DATA(0x0F);

    //自己添加的初始化代码
	LCD_WRITE_CMD(0x2B);    //设置Y轴
	LCD_WRITE_DATA(0x00);
	LCD_WRITE_DATA(0x00);
	LCD_WRITE_DATA(0x01);
	LCD_WRITE_DATA(0x3f);
	LCD_WRITE_CMD(0x2A);    //设置X轴
	LCD_WRITE_DATA(0x00);
	LCD_WRITE_DATA(0x00);
	LCD_WRITE_DATA(0x00);
	LCD_WRITE_DATA(0xef);	 
	LCD_WRITE_CMD(0x11); 	//Exit Sleep
	HAL_Delay(120);
	LCD_WRITE_CMD(0x29); 	//display on

    TFT_LCD_BL_ON;      	//打开背光
}

控制LCD显示方向

根据头文件中的宏定义LCD_DIRECTION来设置不同的方向,需要根据屏幕手册来设置,后面有显示方向实物图

BGR位要始终设置为1,不然根据RGB565数据格式设置的颜色数据会不正确,例如想显示红色的却显示了蓝色

注意:屏幕显示部分面向自己,插针朝上,此时屏幕为竖屏1,而竖屏2就是屏幕旋转180度来看

/**
 * @name   LCD_Disp_Direction
 * @brief  LCD显示方向
 * @param  None
 * @retval None  
 */
static void LCD_Disp_Direction(void)
{
	switch (LCD_DIRECTION)
	{
		//竖屏1
		case 1:	LCD_WRITE_CMD(0x36); LCD_WRITE_DATA(1<<3); break;				//BGR=1
		//横屏1
		case 2:	LCD_WRITE_CMD(0x36); LCD_WRITE_DATA((1<<3)|(1<<5)|(1<<6)); break;	//BGR=1,MV=1,MX=1
		//竖屏2
		case 3:	LCD_WRITE_CMD(0x36); LCD_WRITE_DATA((1<<3)|(1<<7)|(1<<6)); break;	//BGR=1,MY=1,MX=1
		//横屏2
		case 4:	LCD_WRITE_CMD(0x36); LCD_WRITE_DATA((1<<3)|(1<<7)|(1<<5)); break;	//BGR=1,MY=1,MV=1
		default:LCD_WRITE_CMD(0x36); LCD_WRITE_DATA(1<<3); break;
	}
}

在这里插入图片描述

设置LCD显示窗口

显示任何内容前,都要先绘制一个显示窗口,主要是设置X轴坐标(列地址),Y轴坐标(行地址),窗口宽度,窗口高度;

要显示一个点则X轴坐标和Y轴坐标也要设置,只不过宽度和高度都为1

/**
 * @name   LCD_SetWindows
 * @brief  设置LCD显示窗口
 * @param  xStar:窗口起点x轴坐标
 * 			yStar:窗口起点y轴坐标
 * 			xWidth:窗口宽度
 * 			yHeight:窗口高度
 * @retval None  
 */
static void LCD_SetWindows(uint16_t xStar,uint16_t yStar,uint16_t xWidth,uint16_t yHeight)
{
	LCD_WRITE_CMD(LCD_CMD_SET_X_ORGIN);		//发送设置X轴坐标的命令0x2A
	//参数SC[15:0]	->	设置起始列地址,也就是设置X轴起始坐标
	LCD_WRITE_DATA(xStar>>8);				//先写高8位
	LCD_WRITE_DATA(xStar&0x00FF);			//再写低8位
	//参数EC[15:0]	->	设置窗口X轴结束的列地址,因为参数xWidth是窗口长度,所以要转为列地址再发送
	LCD_WRITE_DATA((xStar+xWidth-1)>>8);				//先写高8位
	LCD_WRITE_DATA((xStar+xWidth-1)&0x00FF);			//再写低8位

	LCD_WRITE_CMD(LCD_CMD_SET_Y_ORGIN);		//发送设置Y轴坐标的命令0x2B
	//参数SP[15:0]	->	设置起始行地址,也就是设置Y轴起始坐标
	LCD_WRITE_DATA(yStar>>8);				//先写高8位
	LCD_WRITE_DATA(yStar&0x00FF);			//再写低8位
	//参数EP[15:0]	->	设置窗口Y轴结束的列地址,因为参数yHeight是窗口高度,所以要转为行地址再发送
	LCD_WRITE_DATA((yStar+yHeight-1)>>8);				//先写高8位
	LCD_WRITE_DATA((yStar+yHeight-1)&0x00FF);			//再写低8位

	LCD_WRITE_CMD(LCD_CMD_WRGRAM);			//开始往GRAM里写数据,写GRAM的指令为0x2C
}

设置列地址指令0x2A

起始列地址就由16位的SC确定,停止列地址由16位的EC确定,EC减去SC就是窗口的宽度

SC <= EC 0<=SC EC<=239

在这里插入图片描述

设置行地址的指令0x2B

起始行地址由16位的SP来确定,停止行地址由16位的EP来确定

SP <= EP 0<=SP EP<=319

在这里插入图片描述

LCD屏幕填充颜色

要先设置显示窗口,然后窗口就相当于二维数组,用两个for循环往窗口内写入颜色数据,颜色数据为头文件定义的颜色枚举类型

可以用一个for循环来进行延时,动态观看屏幕显示颜色的过程

/**
 * @name   LCD_FillColor
 * @brief  LCD屏幕填充颜色
 * @param  xStar:窗口起点x轴坐标
 * 			yStar:窗口起点y轴坐标
 * 			xWidth:窗口宽度
 * 			yHeight:窗口高度
 * 			FillColor:填充的颜色
 * @retval None  
 */
static void LCD_FillColor(uint16_t xStar,uint16_t yStar,uint16_t xWidth,uint16_t yHeight,LCD_Color_t FillColor)
{
	uint16_t i,j;
	uint16_t k;
	LCD_SetWindows(xStar,yStar,xWidth,yHeight);			//设置显示窗口

	for(i=xStar;i<(xStar+xWidth);i++)
	{
		for(j=0;j<(yStar+yHeight);j++)
		{
			LCD_WRITE_DATA(FillColor);
			//延时一会,动态观看屏幕显示过程
			for(k=0;k<20000;k++);
		}
	}
}

屏幕显示方向

在这里插入图片描述

竖屏1

首先屏幕有插针的一边朝上,屏幕对自己,这样看就是竖屏,上图中的显示效果就始终以这个方向为基准

屏幕颜色填充方向:从原点开始,从左到右,从上到下

在这里插入图片描述

/*
* @name   Run
* @brief  系统运行
* @param  None
* @retval None   
*/
static void Run()
{
	TFT_LCD.LCD_FillColor(0,0,LCD_WIGHT,LCD_HIGHT,Color_RED);		//显示红色
	HAL_Delay(1000);
}

在主函数中调用填充屏幕颜色的函数,X坐标为0,Y坐标为0,即从原点开始,LCD_WIGHT为240,LCD_HIGHT为320,即窗口为整个屏幕,下载到实验板后可以看到屏幕逐渐显示红色以及其显示过程

在这里插入图片描述

在这里插入图片描述

横屏1

不旋转屏幕,则颜色填充方向:从上到下,从右到左

在这里插入图片描述

旋转屏幕,则颜色填充方向:从左到右,从上到下

在这里插入图片描述

TFT_LCD.LCD_FillColor(0,0,LCD_WIGHT,LCD_HIGHT,Color_GREEN);		//显示绿色

此时LCD_WIGHT宽度就是320,LCD_HIGHT高度就是240

在这里插入图片描述

在这里插入图片描述

竖屏2

不旋转屏幕,则颜色填充方向:从右到左,从下到上

在这里插入图片描述

旋转屏幕,则颜色填充方向:从原点开始,从左到右,从上到下

在这里插入图片描述

TFT_LCD.LCD_FillColor(0,0,LCD_WIGHT,LCD_HIGHT,Color_BLUE);		//显示蓝色

在这里插入图片描述

横屏2

不旋转屏幕,则颜色填充方向:从下到上,从左到右

在这里插入图片描述

旋转屏幕,则颜色填充方向:从原点开始,从左到右,从上到下

在这里插入图片描述

TFT_LCD.LCD_FillColor(0,0,LCD_WIGHT,LCD_HIGHT,Color_YELLOW);		//显示黄色

在这里插入图片描述

读GRAM颜色数据

ILI9341手册不详细,下图中指令说明更清晰

在这里插入图片描述

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值