3、TFTLCD Demo(STM32F407)

TFTLCD屏采用驱动IC的是ILI9341,16位的8080并口协议

LCD_CS:LCD片选信号

LCD_WR:LCD写信号

LCD_RD:LCD读信号

DB[17:1]:16位双向数据线

LCD_RST:硬复位LCD信号

LCD_RS:命令/数据标志(0:命令,1:数据)

BL_CTR:背光控制信号

T_MISO/T_MOSI/T_PEN/T_CS/T_CLK,触摸屏接口信号

3、TFTLCD Demo(STM32F407)_第1张图片

驱动流程:

3、TFTLCD Demo(STM32F407)_第2张图片

模块对外接口采用16位并口,颜色深度为16位,格式为RGB565,关系如下图:

 ILI9341所有的指令都是8位的(高8位无效),且参数除了读写GRAM的时候是16位,其他操作参数,都是8位的。

ILI9341的指令很多,这里不一一介绍,仅介绍几个重要的指令,他们是:0XD3,0X36,0X2A,0X2B,0X2C,0X2E等6条指令。

0XD3指令

该指令为读ID4指令,用于读取LCD控制器的ID 。因此,同一个代码,可以根据ID的不同,执行不同的LCD驱动初始化,以兼容不同的LCD屏幕。

3、TFTLCD Demo(STM32F407)_第3张图片

 0X36指令

该指令为存储访问控制指令,可以控制ILI9341存储器的读写方向,简单的说,就是在连续写GRAM的时候,可以控制GRAM指针的增长方向,从而控制显示方式(读GRAM也是一样)。

3、TFTLCD Demo(STM32F407)_第4张图片

 3、TFTLCD Demo(STM32F407)_第5张图片

 0X2A指令

该指令是列地址设置指令,在从左到右,从上到下的扫描方式(默认)下面,该指令用于设置横坐标(x坐标)

3、TFTLCD Demo(STM32F407)_第6张图片

 在默认扫描方式时,该指令用于设置x坐标,该指令带有4个参数,实际上是2个坐标值:SC和EC,即列地址的起始值和结束值,SC必须小于等于EC,且0≤SC/EC≤239。一般在设置x坐标的时候,我们只需要带2个参数即可,也就是设置SC即可,因为如果EC没有变化,我们只需要设置一次即可(在初始化ILI9341的时候设置),从而提高速度。

0X2B指令

该指令是页地址设置指令,在从左到右,从上到下的扫描方式(默认)下面,该指令用于设置纵坐标(y坐标)

3、TFTLCD Demo(STM32F407)_第7张图片

 在默认扫描方式时,该指令用于设置y坐标,该指令带有4个参数,实际上是2个坐标值:SP和EP,即页地址的起始值和结束值,SP必须小于等于EP,且0≤SP/EP≤319。一般在设置y坐标的时候,我们只需要带2个参数即可,也就是设置SP即可,因为如果EP没有变化,我们只需要设置一次即可(在初始化ILI9341的时候设置),从而提高速度。

0X2C指令

该指令是写GRAM指令,在发送该指令之后,我们便可以往LCD的GRAM里面写入颜色数据了,该指令支持连续写 (地址自动递增)

3、TFTLCD Demo(STM32F407)_第8张图片

 在收到指令0X2C之后,数据有效位宽变为16位,我们可以连续写入LCD GRAM值,而GRAM的地址将根据MY/MX/MV设置的扫描方向进行自增。例如:假设设置的是从左到右,从上到下的扫描方式,那么设置好起始坐标(通过SC,SP设置)后,每写入一个颜色值,GRAM地址将会自动自增1(SC++),如果碰到EC,则回到SC,同时SP++,一直到坐标:EC,EP结束,其间无需再次设置的坐标,从而大大提高写入速度。

0X2E指令

该指令是读GRAM指令,用于读取ILI9341的显存(GRAM),同0X2C指令,该指令支持连续读 (地址自动递增)

3、TFTLCD Demo(STM32F407)_第9张图片

 ILI9341在收到该指令后,第一次输出的是dummy数据(无效),第二次开始,读取到的才是有效的GRAM数据(从坐标:SC,SP开始),输出规律为:每个颜色分量占8个位,一次输出2个颜色分量。比如:第一次输出是R1G1,随后的规律为:B1R2G2B2R3G3B3R4G4B4R5G5... 以此类推。

FSMC介绍

FSMC,即灵活的静态存储控制器,能够与同步或异步存储器和16位PC存储器卡连接,STM32的FSMC接口支持包括SRAM、NAND FLASH、NOR FLASH和PSRAM等存储器。FSMC的框图如下图所示:

3、TFTLCD Demo(STM32F407)_第10张图片

 FSMC驱动外部SRAM时,外部SRAM的控制一般有:地址线(如A0~A25)、数据线(如D0~D15)、写信号(WE,即WR)、读信号(OE,即RD)、片选信号(CS),如果SRAM支持字节控制,那么还有UB/LB信号。

而TFTLCD的信号我们在前面介绍过,包括:RS、D0~D15、WR、RD、CS、RST和BL等,其中真正在操作LCD的时候需要用到的就只有:RS、D0~D15、WR、RD和CS。其操作时序和SRAM的控制完全类似,唯一不同就是TFTLCD有RS信号,但是没有地址信号。

TFTLCD通过RS信号来决定传送的数据是数据还是命令,本质上可以理解为一个地址信号,比如我们把RS接在A0上面,那么当FSMC控制器写地址0的时候,会使得A0变为0,对TFTLCD来说,就是写命令。而FSMC写地址1的时候,A0将会变为1,对TFTLCD来说,就是写数据了。这样,就把数据和命令区分开了,他们其实就是对应SRAM操作的两个连续地址。当然RS也可以接在其他地址线上,战舰V3和精英板开发板都是把RS连接在A10上面,而探索者STM32F4把RS接在A6上面。

因此,可以把TFTLCD当成一个SRAM来用,只不过这个SRAM有2个地址,这就是FSMC可以驱动LCD的原理。

STM32的FSMC支持8/16/32位数据宽度,我们这里用到的LCD是16位宽度的,所以在设置的时候,选择16位宽就OK了。FSMC的外部设备地址映像,STM32的FSMC将外部存储器划分为固定大小为256M字节的四个存储块。

3、TFTLCD Demo(STM32F407)_第11张图片

 STM32的FSMC存储块1(Bank1)用于驱动NOR FLASH/SRAM/PSRAM,被分为4个区,每个区管理64M字节空间,每个区都有独立的寄存器对所连接的存储器进行配置。Bank1的256M字节空间由28根地址线(HADDR[27:0])寻址。

这里HADDR,是内部AHB地址总线,其中,HADDR[25:0]来自外部存储器地址FSMC_A[25:0],而HADDR[26:27]对4个区进行寻址。如下表所示:

3、TFTLCD Demo(STM32F407)_第12张图片

 当Bank1接的是16位宽度存储器的时候:HADDR[25:1] FSMC_A[24:0]

当Bank1接的是8位宽度存储器的时候:HADDR[25:0] FSMC_A[25:0]

不论外部接8位/16位宽设备,FSMC_A[0]永远接在外部设备地址A[0]

STM32的FSMC存储块1 支持的异步突发访问模式包括:模式1、模式A~D等多种时序模型,驱动SRAM时一般使用模式1或者模式 A,这里我们使用模式A来驱动LCD(当SRAM用),模式A支持读写时序分开设置。

对于NOR FLASH/PSRAM控制器(存储块1),通过FSMC_BCRx、FSMC_BTRx和FSMC_BWTRx寄存器设置(其中x=1~4,对应4个区)。通过这3个寄存器,可以设置FSMC访问外部存储器的时序参数,拓宽了可选用的外部存储器的速度范围。

SRAM/NOR闪存片选控制寄存器(FSMC_BCRx)

 EXTMOD:扩展模式使能位,控制是否允许读写不同的时序,需设置为1

WREN:写使能位。我们需要向TFTLCD写数据,故该位必须设置为1

MWID[1:0]:存储器数据总线宽度。00,表示8位数据模式;01表示16位数据模式;10和11保留。我们的TFTLCD是16位数据线,所以设置WMID[1:0]=01。

MTYP[1:0]:存储器类型。00表示SRAM、ROM;01表示PSRAM;10表示NOR FLASH;11保留。我们把LCD当成SRAM用,所以需要设置MTYP[1:0]=00。

MBKEN:存储块使能位。需设置为1

SRAM/NOR闪存片选时序寄存器(FSMC_BTRx)

 ACCMOD[1:0]:访问模式。00:模式A;01:模式B;10:模式C;11:模式D。 DATAST[7:0]:数据保持时间,等于: DATAST(+1)个HCLK时钟周期,DATAST最大为255。对ILI9341来说,其实就是RD低电平持续时间,最大为355ns。对STM32F1,一个HCLK=13.8ns (1/72M),设置为15;对STM32F4,一个HCLK=6ns(1/168M) ,设置为60。

ADDSET[3:0]:地址建立时间。表示:ADDSET (+1)个HCLK周期,ADDSET最大为15。对ILI9341来说,这里相当于RD高电平持续时间,为90ns。STM32F1的FSMC性能存在问题,即便设置为0,RD也有190ns的高电平,我们这里设置为1。而对STM32F4,则设置为15。

如果未设置EXTMOD位,则读写共用这个时序寄存器!

SRAM/NOR闪存写时序寄存器(FSMC_BWTRx)

 ACCMOD[1:0]:访问模式。00:模式A;01:模式B;10:模式C;11:模式D。 DATAST[7:0]:数据保持时间,等于: DATAST(+1)个HCLK时钟周期,DATAST最大为255。对ILI9341来说,其实就是WR低电平持续时间,为15ns,不过ILI9320等则需要50ns。考虑兼容性,对STM32F1,一个HCLK=13.8ns (1/72M),设置为3;对STM32F4,一个HCLK=6ns(1/168M) ,设置为9。

ADDSET[3:0]:地址建立时间。表示:ADDSET+1个HCLK周期,ADDSET最大为15。对ILI9341来说,这里相当于WR高电平持续时间,为15ns。同样考虑兼容ILI9320,对STM32F1,这里即便设置为1,WR也有100ns的高电平,我们这里设置为1。而对STM32F4,则设置为8。

寄存器组合说明

在ST官方库提供的的寄存器定义里面,并没有定义FSMC_BCRx、FSMC_BTRx、FSMC_BWTRx等这个单独的寄存器,而是将他们进行了一些组合。规律如下:     

FSMC_BCRx和FSMC_BTRx,组合成BTCR[8]寄存器组,他们的对应关系如下:

BTCR[0]对应FSMC_BCR1,BTCR[1]对应FSMC_BTR1

BTCR[2]对应FSMC_BCR2,BTCR[3]对应FSMC_BTR2 BTCR

[4]对应FSMC_BCR3,BTCR[5]对应FSMC_BTR3 BTCR

[6]对应FSMC_BCR4,BTCR[7]对应FSMC_BTR4

FSMC_BWTRx则组合成BWTR[7],他们的对应关系如下:

BWTR[0]对应FSMC_BWTR1,BWTR[2]对应FSMC_BWTR2

BWTR[4]对应FSMC_BWTR3,BWTR[6]对应FSMC_BWTR4

BWTR[1]、BWTR[3]和BWTR[5]保留,没有用到

源码部分(正点原子实验13)

lcd.h

#ifndef __LCD_H
#define __LCD_H		
#include "sys.h"	 
#include "stdlib.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的画笔颜色和背景色	   
extern u16  POINT_COLOR;//默认红色    
extern u16  BACK_COLOR; //背景颜色.默认为白色


//	 
//-----------------LCD端口定义---------------- 
#define	LCD_LED PBout(15)  		//LCD背光    		 PB15 	    
//LCD地址结构体
typedef struct
{
	vu16 LCD_REG;
	vu16 LCD_RAM;
} LCD_TypeDef;
//使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11 A6作为数据命令区分线 
//注意设置时STM32内部会右移一位对其! 111 1110=0X7E			    
#define LCD_BASE        ((u32)(0x6C000000 | 0x0000007E))
#define LCD             ((LCD_TypeDef *) LCD_BASE)//指向LCD地址的指针
//
	 
//扫描方向定义
#define L2R_U2D  0 //从左到右,从上到下
#define L2R_D2U  1 //从左到右,从下到上
#define R2L_U2D  2 //从右到左,从上到下
#define R2L_D2U  3 //从右到左,从下到上

#define U2D_L2R  4 //从上到下,从左到右
#define U2D_R2L  5 //从上到下,从右到左
#define D2U_L2R  6 //从下到上,从左到右
#define D2U_R2L  7 //从下到上,从右到左	 

#define DFT_SCAN_DIR  L2R_U2D  //默认的扫描方向

//画笔颜色
#define WHITE         	 0xFFFF
#define BLACK         	 0x0000	  
#define BLUE         	 0x001F  
#define BRED             0XF81F
#define GRED 			 0XFFE0
#define GBLUE			 0X07FF
#define RED           	 0xF800
#define MAGENTA       	 0xF81F
#define GREEN         	 0x07E0
#define CYAN          	 0x7FFF
#define YELLOW        	 0xFFE0
#define BROWN 			 0XBC40 //棕色
#define BRRED 			 0XFC07 //棕红色
#define GRAY  			 0X8430 //灰色
//GUI颜色

#define DARKBLUE      	 0X01CF	//深蓝色
#define LIGHTBLUE      	 0X7D7C	//浅蓝色  
#define GRAYBLUE       	 0X5458 //灰蓝色
//以上三色为PANEL的颜色 
 
#define LIGHTGREEN     	 0X841F //浅绿色
//#define LIGHTGRAY        0XEF5B //浅灰色(PANNEL)
#define LGRAY 			 0XC618 //浅灰色(PANNEL),窗体背景色

#define LGRAYBLUE        0XA651 //浅灰蓝色(中间层颜色)
#define LBBLUE           0X2B12 //浅棕蓝色(选择条目的反色)
	    															  
void LCD_Init(void);													   	//初始化
void LCD_DisplayOn(void);													//开显示
void LCD_DisplayOff(void);													//关显示
void LCD_Clear(u16 Color);	 												//清屏
void LCD_SetCursor(u16 Xpos, u16 Ypos);										//设置光标
void LCD_DrawPoint(u16 x,u16 y);											//画点
void LCD_Fast_DrawPoint(u16 x,u16 y,u16 color);								//快速画点
u16  LCD_ReadPoint(u16 x,u16 y); 											//读点 
void LCD_Draw_Circle(u16 x0,u16 y0,u8 r);						 			//画圆
void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2);							//画线
void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2);		   				//画矩形
void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color);		   				//填充单色
void LCD_Color_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color);				//填充指定颜色
void LCD_ShowChar(u16 x,u16 y,u8 num,u8 size,u8 mode);						//显示一个字符
void LCD_ShowNum(u16 x,u16 y,u32 num,u8 len,u8 size);  						//显示一个数字
void LCD_ShowxNum(u16 x,u16 y,u32 num,u8 len,u8 size,u8 mode);				//显示 数字
void LCD_ShowString(u16 x,u16 y,u16 width,u16 height,u8 size,u8 *p);		//显示一个字符串,12/16字体

void LCD_WriteReg(u16 LCD_Reg, u16 LCD_RegValue);
u16 LCD_ReadReg(u16 LCD_Reg);
void LCD_WriteRAM_Prepare(void);
void LCD_WriteRAM(u16 RGB_Code);
void LCD_SSD_BackLightSet(u8 pwm);							//SSD1963 背光控制
void LCD_Scan_Dir(u8 dir);									//设置屏扫描方向
void LCD_Display_Dir(u8 dir);								//设置屏幕显示方向
void LCD_Set_Window(u16 sx,u16 sy,u16 width,u16 height);	//设置窗口					   						   																			 
//LCD分辨率设置
#define SSD_HOR_RESOLUTION		800		//LCD水平分辨率
#define SSD_VER_RESOLUTION		480		//LCD垂直分辨率
//LCD驱动参数设置
#define SSD_HOR_PULSE_WIDTH		1		//水平脉宽
#define SSD_HOR_BACK_PORCH		46		//水平前廊
#define SSD_HOR_FRONT_PORCH		210		//水平后廊

#define SSD_VER_PULSE_WIDTH		1		//垂直脉宽
#define SSD_VER_BACK_PORCH		23		//垂直前廊
#define SSD_VER_FRONT_PORCH		22		//垂直前廊
//如下几个参数,自动计算
#define SSD_HT	(SSD_HOR_RESOLUTION+SSD_HOR_BACK_PORCH+SSD_HOR_FRONT_PORCH)
#define SSD_HPS	(SSD_HOR_BACK_PORCH)
#define SSD_VT 	(SSD_VER_RESOLUTION+SSD_VER_BACK_PORCH+SSD_VER_FRONT_PORCH)
#define SSD_VPS (SSD_VER_BACK_PORCH)

#endif

lcd.c

略(正点原子实验13)

main.c

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"

//ALIENTEK 探索者STM32F407开发板 实验13
//LCD显示实验-库函数版本
//技术支持:www.openedv.com
//淘宝店铺:http://eboard.taobao.com  
//广州市星翼电子科技有限公司  
//作者:正点原子 @ALIENTEK

int main(void)
{ 
 	u8 x=0;
	u8 lcd_id[12];				//存放LCD ID字符串
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	delay_init(168);      //初始化延时函数
	uart_init(115200);		//初始化串口波特率为115200
	
	LED_Init();					  //初始化LED
 	LCD_Init();           //初始化LCD FSMC接口
	POINT_COLOR=RED;      //画笔颜色:红色
	sprintf((char*)lcd_id,"LCD ID:%04X",lcddev.id);//将LCD ID打印到lcd_id数组。				 	
  	while(1) 
	{		 
		switch(x)
		{
			case 0:LCD_Clear(WHITE);break;
			case 1:LCD_Clear(BLACK);break;
			case 2:LCD_Clear(BLUE);break;
			case 3:LCD_Clear(RED);break;
			case 4:LCD_Clear(MAGENTA);break;
			case 5:LCD_Clear(GREEN);break;
			case 6:LCD_Clear(CYAN);break; 
			case 7:LCD_Clear(YELLOW);break;
			case 8:LCD_Clear(BRRED);break;
			case 9:LCD_Clear(GRAY);break;
			case 10:LCD_Clear(LGRAY);break;
			case 11:LCD_Clear(BROWN);break;
		}
		POINT_COLOR=BLACK;	  
		LCD_ShowString(30,40,210,24,24,"Explorer STM32F4");	
		LCD_ShowString(30,70,200,16,16,"TFTLCD TEST");
		LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
 		LCD_ShowString(30,110,200,16,16,lcd_id);		//显示LCD ID	      					 
		//LCD_ShowString(30,130,200,12,12,"2014/5/4");
        LCD_ShowString(30,130,200,12,12,"2023/11/29");

	    x++;
		if(x==12)x=0;
		LED0=!LED0;	 
		delay_ms(1000);	
	} 
}

效果视频

TFT屏效果

你可能感兴趣的:(单片机充电记录,stm32,嵌入式硬件,单片机)