3.2inch 320x240 Touch LCD (D)教程

1. 硬件资源

1.1 ILI9341

  • ILI9341是一个240x320(RGB)分辨率、262144色的TFT 液晶显示屏的驱动芯片;172820 (240 x 320x 18/8) 字节的RAM。每个像素点深度可以达到18 位。
  • ILI9341有以下几种数据接口模式:

1) i80-system MPU 接口(8-/9-/16-/18-bit bus width)

2) serial data transfer 接口(SPI)

3) RGB 6-/16-/18-bit 接口(DOTCLK, VSYNC, HSYNC, ENABLE, DB[17:0]).

此屏的ILI9341的18位RGB赋值与 LCD GRAM的对应关系如图所示: 
从图中可以看出,ILI9341 在16 位模式下面,GRAM Data有用的是:D17~D13 和 D11~D1, D12和 D0 没有用到,实际上在我们 LCD 模块里面, ILI9341 的 D12 和 D0没有引出,ILI9341 的 D17~D13 和 D11~D1对应 MCU 的 D15~D0。MCU 的 16 位数据,最低 5 位代表蓝色,中间 6 位为绿色,最高 5 位为红色;数值越大,表示该颜色越深。

8080 16位接口时序介绍

  • 寄存器详细介绍请参阅 ILI9341的 datasheet
  • 这里只介绍读写的时序要求

8080接口是由英特尔设计,是一种并行、异步、半双工通信协议,作用是用于外扩RAM、ROM,后面也用于LCD接口。

  • 控制线四根
RD:写使能(将信息写入寄存器)
WR:读使能(从寄存器读出信息)
​DC(RS):数据/命令(1为数据读写,0为命令读写)
​CS:片选
  • 写入命令或者数据的时序图,如下:

  • 读取信息的时序图,如下:

1.2 XPT2046

  • XPT2046 是一款 4 线制电阻式触摸屏控制器,内含 12 位分辨率 125KHz 转换速率逐步逼近型 A/D 转换器。
  • XPT2046 支持从 1.5V 到 5.25V 的低电压 I/O 接口。
  • XPT2046 能通过执行两次 A/D 转换查出被按的屏幕位置,除此之外,还可以测量加在触摸屏上的压力。内部自带 2.5V 参考电压,可以作为辅助输入、温度测量和电池监测之用,电池监测的电压范围可以从 0V 到 5V。
  • XPT2046 片内集成有一个温度传感器。在 2.7V 的典型工作状态下,关闭参考电压,功耗可小于 0.75mW。XPT2046 采用微小的封装形式:TSSOP-16,QFN-16 和 VFBGA-48。 工作温度范围为-40℃~+85℃。与 ADS7846、TSC2046、AK4182A 完全兼容。

2. 硬件说明

引脚号标识描述功能
15V5V电源当5V供电时(1,2脚接5V电源),3.3V端(33,34脚输出3.3V电压)
2GND接地GND
3D0数据线D0-D15
4D1
5D2
6D3
7D4
8D5
9D6
10D7
11D8
12D9
13D10
14D11
15D12
16D13
17D14
18D15
19CSLCD片选信号低电平选择LCD
20RS指令/数据 寄存器选择RS = 0:指令寄存器
RS = 1:数据寄存器
21WR写动作WR = 0,RD = 1
22RD读动作WR = 1,RD = 0
23RESET芯片重启低电平重启芯片
24NC
25BLVCC5V或3.3V背光灯VCC
26BLGND接地背光灯GND
27BLCNT背光灯亮度调节可以使用PWM来控制背光灯亮度
28TP_IRQ触摸面板中断检测到触摸面板有按下则为低电平
29TP_CS触摸面板片选信号低电平选择触摸面板
30TP_SCK触摸面板SPI时钟信号连接到SPI的SCK
31TP_SI触摸面板SPI数据输入连接到SPI的MOSI
32TP_SO触摸面板SPI数据输出连接到SPI的MISO
333.3V+3.3电源当3.3V供电时(33,34脚输入3.3V) 1,2脚悬空
34GND接地

3. 示例程序

本手册使用主控芯片STM32F103RCT6的开发板说明本款LCD的基本使用方法。用户也可以采用其他类似的开发板进行开发。
3.2inch 320x240 Touch LCD (D)和STM32F103RCT6连接接口图:

程序流程:

源代码解析:

/*下面宏定义的是图像的旋转角度跟设置控制线*/<br />
//#define DISP_ORIENTATION					0
//#define DISP_ORIENTATION					90
//#define DISP_ORIENTATION					180
#define DISP_ORIENTATION					270

#define Set_Cs        GPIOC->BSRR = GPIO_Pin_6	//CS=1
#define Clr_Cs        GPIOC->BRR = GPIO_Pin_6		//CS=0

#define Set_Rs        GPIOC->BSRR = GPIO_Pin_7	//RS=1
#define Clr_Rs        GPIOC->BRR = GPIO_Pin_7		//RS=0

#define Set_nWr       GPIOC->BSRR = GPIO_Pin_1	//WR=1
#define Clr_nWr       GPIOC->BRR = GPIO_Pin_1		//WR=0

#define Set_nRd       GPIOC->BSRR = GPIO_Pin_2	//RD=1
#define Clr_nRd       GPIOC->BRR = GPIO_Pin_2		//RD=0
/* 写命令函数 */
__inline void LCD_WriteIndex(uint16_t index)
{
Clr_Rs;              //RS=0
Set_nRd;             //RD=0
LCD_Delay(0);        //延时
GPIOB->ODR = index; /*写命令 */	
LCD_Delay(0);        //延时
Clr_nWr;             //WR=0  
Set_nWr;             //WR=1
}
/* 写数据函数 */
__inline void ILI9341_LCD_WriteData(uint16_t data)
{
	Clr_Cs;						//CS=1
	Set_Rs;						//RS=1
	LCD_Delay(0);					//delay
	GPIOB->ODR = data;	 	/* GPIO_Write(GPIOB,data); */
	LCD_Delay(0);					//delay
	Clr_nWr;					//WR=0
	Set_nWr;					//WR=1
	Set_Cs;						//CS=1
}
/* 读数据函数 */
__inline uint16_t LCD_ReadData(void)
{
uint16_t value;
Set_Rs;
Set_nWr;
Clr_nRd;
GPIOB->CRH = 0x44444444;   //设置PB0-PB15为输入
GPIOB->CRL = 0x44444444;
value = GPIOB->IDR;         //读取数据
    GPIOB->CRH = 0x33333333;   //设置PB0-PB15为输出
    GPIOB->CRL = 0x33333333;
    Set_nRd;
    return value;
}
/******************************************************************************

指定的地址写入数据,LCD_Reg是地址,LCD_RegValue是写入的值。

******************************************************************************/
__inline void LCD_WriteReg(uint16_t LCD_Reg,uint16_t LCD_RegValue)
{ 
Clr_Cs;
LCD_WriteIndex(LCD_Reg);        //写指令;即要写入数据的地址;     
LCD_WriteData(LCD_RegValue);    //数据写入;
Set_Cs;
}

/******************************************************************************

从指定的地址读取数据,LCD_Reg是地址,函数返回读取出来的值。
<pre>
******************************************************************************/
__inline uint16_t LCD_ReadReg(uint16_t LCD_Reg)
{
uint16_t LCD_RAM;
Clr_Cs;
LCD_WriteIndex(LCD_Reg);     //写指令;即要读出数据的地址;
LCD_RAM = LCD_ReadData();  //数据读出;	
Set_Cs;
return LCD_RAM;
}
//以上是最基本的读写函数;IO模拟操作,如果想STM32的FSMC来控制的,参考另外一个例程LCD + TouchPanel(8080 FSMC)
/****************************************************************************** 
LCD寄存器的初始化,以下寄存器的初始化值由LCD原厂家提供,按照如下配置就可以正常显示,寄存器请参考芯片手册。
******************************************************************************/
void LCD_Initializtion(void)
{
uint16_t DeviceCode;
LCD_Configuration();                  //管脚初始化
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE);//改变指定管脚的映射
GPIO_ResetBits(GPIOC, GPIO_Pin_0);   /* LCD复位*/	
delay_ms(100);
GPIO_SetBits(GPIOC, GPIO_Pin_0);
GPIO_SetBits(GPIOA, GPIO_Pin_3);     /*使能背光 */
DeviceCode = LCD_ReadReg(0x0000);    /* 读取ID	*/
if(DeviceCode == 0 || DeviceCode == 0xffff)
{		
   ILI9341_LCD_WriteReg(0XD3);
   Clr_Cs;
   DeviceCode = LCD_ReadData();
   DeviceCode = LCD_ReadData();
   DeviceCode = LCD_ReadData();
   DeviceCode <<= 8;
   DeviceCode |= LCD_ReadData();
   Set_Cs;
}
if(DeviceCode == 0x9341)
{
	LCD_Code = ILI9341;	
	ILI9341_LCD_WriteReg(0x3A);   
	ILI9341_LCD_WriteData(0x55);
		
	ILI9341_LCD_WriteReg(0xB5);   
	ILI9341_LCD_WriteData(0X04);
	ILI9341_LCD_WriteData(0X04);
	ILI9341_LCD_WriteData(0X0A);
	ILI9341_LCD_WriteData(0x14);
		
	ILI9341_LCD_WriteReg(0x35);   
	ILI9341_LCD_WriteData(0x00);
	
	ILI9341_LCD_WriteReg(0xCF);  
	ILI9341_LCD_WriteData(0x00); 
	ILI9341_LCD_WriteData(0xEA); 
	ILI9341_LCD_WriteData(0XF0);
		
	ILI9341_LCD_WriteReg(0xED);  
	ILI9341_LCD_WriteData(0x64); 
	ILI9341_LCD_WriteData(0x03); 
	ILI9341_LCD_WriteData(0X12); 
	ILI9341_LCD_WriteData(0X81);
		
	ILI9341_LCD_WriteReg(0xE8);  
	ILI9341_LCD_WriteData(0x85); 
	ILI9341_LCD_WriteData(0x10); 
	ILI9341_LCD_WriteData(0x78); 
	
	ILI9341_LCD_WriteReg(0xCB);  
	ILI9341_LCD_WriteData(0x39); 
	ILI9341_LCD_WriteData(0x2C); 
	ILI9341_LCD_WriteData(0x00); 
	ILI9341_LCD_WriteData(0x33); 
	ILI9341_LCD_WriteData(0x06);
		
	ILI9341_LCD_WriteReg(0xF7);  
	ILI9341_LCD_WriteData(0x20); 
		
	ILI9341_LCD_WriteReg(0xEA);  
	ILI9341_LCD_WriteData(0x00); 
	ILI9341_LCD_WriteData(0x00); 
		
	ILI9341_LCD_WriteReg(0xC0);    //Power control 
	ILI9341_LCD_WriteData(0x21);   //VRH[5:0] 
		
	ILI9341_LCD_WriteReg(0xC1);    //Power control 
	ILI9341_LCD_WriteData(0x10);   //SAP[2:0];BT[3:0] 
		
	ILI9341_LCD_WriteReg(0xC5);    //VCM control 
	ILI9341_LCD_WriteData(0x4F); 	 //3F
	ILI9341_LCD_WriteData(0x38); 	 //3C
		
	ILI9341_LCD_WriteReg(0xC7);    //VCM control2 
	ILI9341_LCD_WriteData(0XB7); 
		
	ILI9341_LCD_WriteReg(0x36);    // Memory Access Control 
	if (DISP_ORIENTATION == 0)
		ILI9341_LCD_WriteData(0x08 | 0x00); 
	else if (DISP_ORIENTATION == 90)
		ILI9341_LCD_WriteData(0x08 | 0xa0); 
	else if(DISP_ORIENTATION == 180)
		ILI9341_LCD_WriteData(0x08 | 0xc0); 
	else
		ILI9341_LCD_WriteData(0x08 | 0x60); 
		
		
	ILI9341_LCD_WriteReg(0xB1);   
	ILI9341_LCD_WriteData(0x00);   
	ILI9341_LCD_WriteData(0x13);
		
	ILI9341_LCD_WriteReg(0xB6);    // Display Function Control 
	ILI9341_LCD_WriteData(0x0A); 
	ILI9341_LCD_WriteData(0xA2); 
		
	ILI9341_LCD_WriteReg(0xF2);    // 3Gamma Function Disable 
	ILI9341_LCD_WriteData(0x02); 
		
	ILI9341_LCD_WriteReg(0x26);    //Gamma curve selected 
	ILI9341_LCD_WriteData(0x01);
		
	ILI9341_LCD_WriteReg(0xE0);    //Set Gamma 
	ILI9341_LCD_WriteData(0x0F);
	ILI9341_LCD_WriteData(0x27);
	ILI9341_LCD_WriteData(0x24);
	ILI9341_LCD_WriteData(0x0C);
	ILI9341_LCD_WriteData(0x10);
	ILI9341_LCD_WriteData(0x08);
	ILI9341_LCD_WriteData(0x55);
	ILI9341_LCD_WriteData(0X87);
	ILI9341_LCD_WriteData(0x45);
	ILI9341_LCD_WriteData(0x08);
	ILI9341_LCD_WriteData(0x14);
	ILI9341_LCD_WriteData(0x07);
	ILI9341_LCD_WriteData(0x13);
	ILI9341_LCD_WriteData(0x08);
	ILI9341_LCD_WriteData(0x00);
		
	ILI9341_LCD_WriteReg(0XE1);    //Set Gamma 
	ILI9341_LCD_WriteData(0x00);
	ILI9341_LCD_WriteData(0x0F);
	ILI9341_LCD_WriteData(0x12);
	ILI9341_LCD_WriteData(0x05);
	ILI9341_LCD_WriteData(0x11);
	ILI9341_LCD_WriteData(0x06);
	ILI9341_LCD_WriteData(0x25);
	ILI9341_LCD_WriteData(0x34);
	ILI9341_LCD_WriteData(0x37);
	ILI9341_LCD_WriteData(0x01);
	ILI9341_LCD_WriteData(0x08);
	ILI9341_LCD_WriteData(0x07);
	ILI9341_LCD_WriteData(0x2B);
	ILI9341_LCD_WriteData(0x34);
	ILI9341_LCD_WriteData(0x0F);
		
	ILI9341_LCD_WriteReg(0x11); //Exit Sleep
	delay_ms(120);
	ILI9341_LCD_WriteReg(0x29); //display on			
}
delay_ms(50);  	
}
/******************************************************************************
设置显示窗口的位置X、Y;
*****************************************************************************/
void LCD_Address_Set(u16 x1,u16 y1,u16 x2,u16 y2)
{
	ILI9341_LCD_WriteReg(0x2a);//Column address setting 列地址设置
	ILI9341_LCD_WriteData(x1>>8);
	ILI9341_LCD_WriteData(x1&0xff);
	ILI9341_LCD_WriteData(x2>>8);
	ILI9341_LCD_WriteData(x2&0xff);
	
	ILI9341_LCD_WriteReg(0x2b);//Line address Setting 行地址设置
	ILI9341_LCD_WriteData(y1>>8);
	ILI9341_LCD_WriteData(y1&0xff);
	ILI9341_LCD_WriteData(y2>>8);
	ILI9341_LCD_WriteData(y2&0xff);
	
	ILI9341_LCD_WriteReg(0x2c);//Write in memory	 写入内存
}

static void LCD_SetCursor( uint16_t Xpos, uint16_t Ypos )
{
	uint16_t temp;
	#if (DISP_ORIENTATION == 0)
	#elif (DISP_ORIENTATION == 90)
	temp = Xpos;
	Xpos =Ypos;  
	Ypos = MAX_X - 1 - temp;
	#elif (DISP_ORIENTATION == 180)
	Xpos = MAX_X - 1 - Xpos; 
	Ypos = MAX_Y - 1 - Ypos; 
	#elif (DISP_ORIENTATION == 270)
	temp = Ypos;
	Ypos = Xpos;
	Xpos = MAX_Y - 1 - temp;
	#endif

	ILI9341_LCD_WriteReg(0x2a);	//Column address setting 列地址设置
	ILI9341_LCD_WriteData(Xpos>>8);
	ILI9341_LCD_WriteData(Xpos&0xff);
		
	ILI9341_LCD_WriteReg(0x2b);	//Line address Setting	行地址设置
	ILI9341_LCD_WriteData(Ypos>>8);
	ILI9341_LCD_WriteData(Ypos&0xff);	
}
/******************************************************************************
清屏函数,作用是让整个屏显示某一种颜色,
*****************************************************************************/
void LCD_Clear(uint16_t Color)
{
uint32_t index=0;

LCD_Address_Set(0,0,MAX_X-1,MAX_Y-1);//Set Display range Set the display range 	设置显示范围
for( index = 0; index < MAX_X * MAX_Y; index++ )
{
   ILI9341_LCD_WriteData(Color);
}

}

int main(void)
{
//延时和初始化系统
  LCD_Initializtion();      //LCD初始化
//LCD触摸板初始化
  LCD_Clear(Red);        //清屏为红色
//您可以编写函数来校准屏幕。
  /* Infinite loop */
  while (1)	
  {
//您可以编写函数,把触摸点坐标显示在 LCD 上
  }
}