day27:ILI9341绘图初始化

和GPIO初始化不同,GPIO是公用的初始化函数,这个绘图初始化要在这个GPIO基础上建立新东西

bsp_usart.c、bsp_usart.h这两个文件和day26一样

bsp_ili9341_lcd.h

#ifndef __BSP_ILI9341_LCD_H__
#define __BSP_ILI9341_LCD_H__

#include "stm32f10x.h"

/* ------------------------------- 变量宏定义 ------------------------------ */
// CS(NSS)引脚 片选选普通GPIO即可
#define			ILI9341_CS_CLK			RCC_APB2Periph_GPIOC   
#define			ILI9341_CS_PORT			GPIOC
#define			ILI9341_CS_PIN			GPIO_Pin_4

// RD引脚 片选选普通GPIO即可
#define			ILI9341_RD_CLK			RCC_APB2Periph_GPIOC   
#define			ILI9341_RD_PORT			GPIOC
#define			ILI9341_RD_PIN			GPIO_Pin_5

// WE引脚 片选选普通GPIO即可
#define			ILI9341_WE_CLK			RCC_APB2Periph_GPIOC   
#define			ILI9341_WE_PORT			GPIOC
#define			ILI9341_WE_PIN			GPIO_Pin_6

// DC引脚 片选选普通GPIO即可
#define			ILI9341_DC_CLK			RCC_APB2Periph_GPIOC   
#define			ILI9341_DC_PORT			GPIOC
#define			ILI9341_DC_PIN			GPIO_Pin_7

// BK引脚 片选选普通GPIO即可
#define			ILI9341_BK_CLK			RCC_APB2Periph_GPIOD  
#define			ILI9341_BK_PORT			GPIOD
#define			ILI9341_BK_PIN			GPIO_Pin_2

// D0-D15引脚 片选选普通GPIO即可(数据引脚)
#define			ILI9341_DATA_CLK		RCC_APB2Periph_GPIOB   
#define			ILI9341_DATA_PORT       GPIOB
#define			ILI9341_DATA_PIN        GPIO_Pin_All

/******************************* 定义 ILI934 常用命令 ********************************/
#define      	CMD_SetCoordinateX		0x2A	     //设置X坐标
#define      	CMD_SetCoordinateY		0x2B	     //设置Y坐标
#define      	CMD_SetPixel		 	0x2C	     //填充像素

#define 		ILI9341_LESS_PIXEL	  	240			//液晶屏较短方向的像素宽度
#define 		ILI9341_MORE_PIXEL	 	320			//液晶屏较长方向的像素宽度


/* ------------------------------- 函数宏定义 ------------------------------ */
// BK:背光引脚的GPIO打开或关闭
#define			LCD_BK_ON()     		GPIO_ResetBits(ILI9341_BK_PORT, ILI9341_BK_PIN)
#define			LCD_BK_OFF()     		GPIO_SetBits(ILI9341_BK_PORT, ILI9341_BK_PIN)

// CS
#define			LCD_CS_HIGH()     		GPIO_SetBits(ILI9341_CS_PORT, ILI9341_CS_PIN)
#define			LCD_CS_LOW()     		GPIO_ResetBits(ILI9341_CS_PORT, ILI9341_CS_PIN)

// RD
#define			LCD_RD_HIGH()     		GPIO_SetBits(ILI9341_RD_PORT, ILI9341_RD_PIN)
#define			LCD_RD_LOW()     		GPIO_ResetBits(ILI9341_RD_PORT, ILI9341_RD_PIN)

// WE
#define			LCD_WE_HIGH()     		GPIO_SetBits(ILI9341_WE_PORT, ILI9341_WE_PIN)
#define			LCD_WE_LOW()     		GPIO_ResetBits(ILI9341_WE_PORT, ILI9341_WE_PIN)

// DC
#define			LCD_DC_HIGH()     		GPIO_SetBits(ILI9341_DC_PORT, ILI9341_DC_PIN)
#define			LCD_DC_LOW()     		GPIO_ResetBits(ILI9341_DC_PORT, ILI9341_DC_PIN)

// D0-D15
#define			LCD_DATA_OUT(data)		GPIO_Write(ILI9341_DATA_PORT, data)		// ILI9341_DATA_PORT->ODR = data	
#define			LCD_DATA_IN()			GPIO_ReadInputData(ILI9341_DATA_PORT)	

/* 初始化delay */
#define      DEBUG_DELAY()       ILI9341_Delay(0xFFFF)

/* ------------------------------- 函数 ------------------------------ */
/* ILI9341初始化 */
void ILI9341_GPIO_Init(void);

/* ILI9341绘制图形初始化 */
void ILI9341_Init(void);

/* 写命令 */
void ILI9341_Write_Cmd(uint16_t cmd);

/* 写数据 */
void ILI9341_Write_Data(uint16_t data);

/* 读数据 */
uint16_t ILI9341_Read_Data(void);

/* 读取ID */
uint16_t ILI9341_Read_ID(void);


#endif		/* __BSP_ILI9341_LCD_H__ */

bsp_ili9341_lcd.c

/*
1.初始化跟液晶控制相关的引脚
  初始化时要确认配置GPIOB使用的PB3/PB4引脚,
	需要重定义才能用作普通GPIO
	
2.模拟8080时序
  写命令
	写数据
	读数据
	
3.通过读取ILI9341的ID测试函数
4.初始化液晶屏及配置扫描方向
5.往LCD坐标x,y写一个特定颜色像素点
*/

#include "./lcd/bsp_ili9341_lcd.h"

/*
根据液晶扫描方向而变化的XY像素宽度
调用ILI9341_GramScan函数设置方向时会自动更改
*/
uint16_t LCD_X_LENGTH = ILI9341_LESS_PIXEL;
uint16_t LCD_Y_LENGTH = ILI9341_MORE_PIXEL;

/*
液晶屏扫描模式,本变量主要用于方便选择触摸屏的计算参数
参数可选值为0-7
调用ILI9341_GramScan函数设置方向时会自动更改
LCD刚初始化完成时会使用本默认值
*/
uint8_t LCD_SCAN_MODE = 6;

// 这里定义一个宏,目的是不用大幅度修改代码,方便程序维护
#define ILI9341_DELAY()		ILI9341_Delay(10)

static void ILI9341_Delay(__IO uint32_t nCount)
{
	for(; nCount!=0; nCount--);
}

/* ILI9341初始化 */
void ILI9341_GPIO_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	/*
	把PB3,PB4引脚用作普通GPIO
	因为PB3和PB4引脚和JTAG功能引脚共用,所以要把JTAG功能禁用,让PB3和PB4引脚可以使用
	*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);		// 使能复用时钟AFIO
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
	
	/* 使能引脚相关的时钟 */
 	RCC_APB2PeriphClockCmd(ILI9341_CS_CLK|
							ILI9341_RD_CLK|
							ILI9341_WE_CLK|
							ILI9341_DC_CLK|
							ILI9341_BK_CLK|
							ILI9341_DATA_CLK, ENABLE);
	
	/* 默认全配置成输出模式 */
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	
	// CS
	GPIO_InitStructure.GPIO_Pin = ILI9341_CS_PIN;
	GPIO_Init(ILI9341_CS_PORT, &GPIO_InitStructure);	
	
	// RD
	GPIO_InitStructure.GPIO_Pin = ILI9341_RD_PIN;
	GPIO_Init(ILI9341_RD_PORT, &GPIO_InitStructure);
	
	// WE
	GPIO_InitStructure.GPIO_Pin = ILI9341_WE_PIN;
	GPIO_Init(ILI9341_DC_PORT, &GPIO_InitStructure);
	
	// DC
	GPIO_InitStructure.GPIO_Pin = ILI9341_DC_PIN;
	GPIO_Init(ILI9341_WE_PORT, &GPIO_InitStructure);
	
	// BK
	GPIO_InitStructure.GPIO_Pin = ILI9341_BK_PIN;
	GPIO_Init(ILI9341_BK_PORT, &GPIO_InitStructure);
	
	// D0-D15
	GPIO_InitStructure.GPIO_Pin = ILI9341_DATA_PIN;
	GPIO_Init(ILI9341_DATA_PORT, &GPIO_InitStructure);
	
	// 默认点亮背光
	LCD_BK_ON();
}

/* 写命令:根据时序写 */
void ILI9341_Write_Cmd(uint16_t cmd)
{
	LCD_CS_LOW();
	ILI9341_DELAY();
	
	LCD_DC_LOW();
	ILI9341_DELAY();
	
	LCD_RD_HIGH();
	ILI9341_DELAY();
	
	LCD_DATA_OUT(cmd);
	ILI9341_DELAY();
	
	LCD_WE_LOW();
	ILI9341_DELAY();
	
	LCD_WE_HIGH();
	ILI9341_DELAY();
	
	LCD_CS_HIGH();
}

/* 写数据:根据时序写 */
void ILI9341_Write_Data(uint16_t data)
{
	LCD_CS_LOW();
	ILI9341_DELAY();
	
	LCD_DC_HIGH();	 		/* 和写命令的区别,这里DC为高电平 */
	ILI9341_DELAY(); 
	
	LCD_RD_HIGH();
	ILI9341_DELAY();
	
	LCD_DATA_OUT(data);	
	ILI9341_DELAY();
	
	LCD_WE_LOW();	
	ILI9341_DELAY();
	
	LCD_WE_HIGH();	
	ILI9341_DELAY();
	
	LCD_CS_HIGH();	
}

/* 读数据:根据时序写 */
uint16_t ILI9341_Read_Data()
{
	uint16_t data = 0;
	
	// 切换data端口为输入模式【因为输出模式常用,输入不常用,所以默认定义成输出模式】
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = ILI9341_DATA_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init(ILI9341_DATA_PORT, &GPIO_InitStructure);
	
	/* 根据时序写 */
	LCD_CS_LOW();
	ILI9341_DELAY();
	
	LCD_DC_HIGH();
	ILI9341_DELAY();
	
	LCD_WE_HIGH();	
	ILI9341_DELAY();	
	
	LCD_RD_LOW();
	ILI9341_DELAY();	
	
	data = LCD_DATA_IN();		/* 读取到的数据 */
	ILI9341_DELAY();
		
	LCD_RD_HIGH();
	ILI9341_DELAY();	

	LCD_CS_HIGH();
	
	/* 切换data端口为输出模式,方便其他方法使用 */
	GPIO_InitStructure.GPIO_Pin = ILI9341_DATA_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(ILI9341_DATA_PORT, &GPIO_InitStructure);
	
	// 返回数据
	return data;
}

/* 读取ID */
uint16_t ILI9341_Read_ID()
{
	uint16_t temp = 0 ;
	
	// 发送读取ID的命令:0XD3
	ILI9341_Write_Cmd(0xD3);
	
	// 读取前面两个用不到的字节
	ILI9341_Read_Data();
	ILI9341_Read_Data();
	
	// 开始正式的读取数据
	temp = ILI9341_Read_Data();
	// 将读取到的数据向左移动8位,腾出位置
	temp <<= 8;
	// 继续读取数据放到temp变量中
	temp |= ILI9341_Read_Data();
	
	// 返回读取到的ID数据
	return temp;
}

/**
 * @brief  初始化ILI9341寄存器
 * @param  无
 * @retval 无
 */
void ILI9341_REG_Config ( void )
{	
	/*  Power control B (CFh)  */
	DEBUG_DELAY();
	ILI9341_Write_Cmd ( 0xCF  );
	ILI9341_Write_Data ( 0x00  );
	ILI9341_Write_Data ( 0x81  );
	ILI9341_Write_Data ( 0x30  );
	
	/*  Power on sequence control (EDh) */
	DEBUG_DELAY ();
	ILI9341_Write_Cmd ( 0xED );
	ILI9341_Write_Data ( 0x64 );
	ILI9341_Write_Data ( 0x03 );
	ILI9341_Write_Data ( 0x12 );
	ILI9341_Write_Data ( 0x81 );
	
	/*  Driver timing control A (E8h) */
	DEBUG_DELAY ();
	ILI9341_Write_Cmd ( 0xE8 );
	ILI9341_Write_Data ( 0x85 );
	ILI9341_Write_Data ( 0x10 );
	ILI9341_Write_Data ( 0x78 );
	
	/*  Power control A (CBh) */
	DEBUG_DELAY ();
	ILI9341_Write_Cmd ( 0xCB );
	ILI9341_Write_Data ( 0x39 );
	ILI9341_Write_Data ( 0x2C );
	ILI9341_Write_Data ( 0x00 );
	ILI9341_Write_Data ( 0x34 );
	ILI9341_Write_Data ( 0x02 );
	
	/* Pump ratio control (F7h) */
	DEBUG_DELAY ();
	ILI9341_Write_Cmd ( 0xF7 );
	ILI9341_Write_Data ( 0x20 );
	
	/* Driver timing control B */
	DEBUG_DELAY ();
	ILI9341_Write_Cmd ( 0xEA );
	ILI9341_Write_Data ( 0x00 );
	ILI9341_Write_Data ( 0x00 );
	
	/* Frame Rate Control (In Normal Mode/Full Colors) (B1h) */
	DEBUG_DELAY ();
	ILI9341_Write_Cmd ( 0xB1 );
	ILI9341_Write_Data ( 0x00 );
	ILI9341_Write_Data ( 0x1B );
	
	/*  Display Function Control (B6h) */
	DEBUG_DELAY ();
	ILI9341_Write_Cmd ( 0xB6 );
	ILI9341_Write_Data ( 0x0A );
	ILI9341_Write_Data ( 0xA2 );
	
	/* Power Control 1 (C0h) */
	DEBUG_DELAY ();
	ILI9341_Write_Cmd ( 0xC0 );
	ILI9341_Write_Data ( 0x35 );
	
	/* Power Control 2 (C1h) */
	DEBUG_DELAY ();
	ILI9341_Write_Cmd ( 0xC1 );
	ILI9341_Write_Data ( 0x11 );
	
	/* VCOM Control 1 (C5h) */
	ILI9341_Write_Cmd ( 0xC5 );
	ILI9341_Write_Data ( 0x45 );
	ILI9341_Write_Data ( 0x45 );
	
	/*  VCOM Control 2 (C7h)  */
	ILI9341_Write_Cmd ( 0xC7 );
	ILI9341_Write_Data ( 0xA2 );
	
	/* Enable 3G (F2h) */
	ILI9341_Write_Cmd ( 0xF2 );
	ILI9341_Write_Data ( 0x00 );
	
	/* Gamma Set (26h) */
	ILI9341_Write_Cmd ( 0x26 );
	ILI9341_Write_Data ( 0x01 );
	DEBUG_DELAY ();
	
	/* Positive Gamma Correction */
	ILI9341_Write_Cmd ( 0xE0 ); //Set Gamma
	ILI9341_Write_Data ( 0x0F );
	ILI9341_Write_Data ( 0x26 );
	ILI9341_Write_Data ( 0x24 );
	ILI9341_Write_Data ( 0x0B );
	ILI9341_Write_Data ( 0x0E );
	ILI9341_Write_Data ( 0x09 );
	ILI9341_Write_Data ( 0x54 );
	ILI9341_Write_Data ( 0xA8 );
	ILI9341_Write_Data ( 0x46 );
	ILI9341_Write_Data ( 0x0C );
	ILI9341_Write_Data ( 0x17 );
	ILI9341_Write_Data ( 0x09 );
	ILI9341_Write_Data ( 0x0F );
	ILI9341_Write_Data ( 0x07 );
	ILI9341_Write_Data ( 0x00 );
	
	/* Negative Gamma Correction (E1h) */
	ILI9341_Write_Cmd ( 0XE1 ); //Set Gamma
	ILI9341_Write_Data ( 0x00 );
	ILI9341_Write_Data ( 0x19 );
	ILI9341_Write_Data ( 0x1B );
	ILI9341_Write_Data ( 0x04 );
	ILI9341_Write_Data ( 0x10 );
	ILI9341_Write_Data ( 0x07 );
	ILI9341_Write_Data ( 0x2A );
	ILI9341_Write_Data ( 0x47 );
	ILI9341_Write_Data ( 0x39 );
	ILI9341_Write_Data ( 0x03 );
	ILI9341_Write_Data ( 0x06 );
	ILI9341_Write_Data ( 0x06 );
	ILI9341_Write_Data ( 0x30 );
	ILI9341_Write_Data ( 0x38 );
	ILI9341_Write_Data ( 0x0F );
	
	/* memory access control set */
	DEBUG_DELAY ();
	ILI9341_Write_Cmd ( 0x36 ); 	
	ILI9341_Write_Data ( 0xC8 );    /*竖屏  左上角到 (起点)到右下角 (终点)扫描方式*/
	DEBUG_DELAY ();
	
	/* column address control set */
	ILI9341_Write_Cmd ( CMD_SetCoordinateX ); 
	ILI9341_Write_Data ( 0x00 );
	ILI9341_Write_Data ( 0x00 );
	ILI9341_Write_Data ( 0x00 );
	ILI9341_Write_Data ( 0xEF );
	
	/* page address control set */
	DEBUG_DELAY ();
	ILI9341_Write_Cmd ( CMD_SetCoordinateY ); 
	ILI9341_Write_Data ( 0x00 );
	ILI9341_Write_Data ( 0x00 );
	ILI9341_Write_Data ( 0x01 );
	ILI9341_Write_Data ( 0x3F );
	
	/*  Pixel Format Set (3Ah)  */
	DEBUG_DELAY ();
	ILI9341_Write_Cmd ( 0x3a ); 
	ILI9341_Write_Data ( 0x55 );
	
	/* Sleep Out (11h)  */
	ILI9341_Write_Cmd ( 0x11 );	
	ILI9341_Delay ( 0xAFFf<<2 );
	DEBUG_DELAY ();
	
	/* Display ON (29h) */
	ILI9341_Write_Cmd ( 0x29 ); 
		
}

/**
 * @brief  设置ILI9341的GRAM的扫描方向 
 * @param  ucOption :选择GRAM的扫描方向 
 *     @arg 0-7 :参数可选值为0-7这八个方向
 *
 *	!!!其中0、3、5、6 模式适合从左至右显示文字,
 *				不推荐使用其它模式显示文字	其它模式显示文字会有镜像效果			
 *		
 *	其中0、2、4、6 模式的X方向像素为240,Y方向像素为320
 *	其中1、3、5、7 模式下X方向像素为320,Y方向像素为240
 *
 *	其中 6 模式为大部分液晶例程的默认显示方向
 *	其中 3 模式为摄像头例程使用的方向
 *	其中 0 模式为BMP图片显示例程使用的方向
 *
 * @retval 无
 * @note  坐标图例:A表示向上,V表示向下,<表示向左,>表示向右
					X表示X轴,Y表示Y轴

------------------------------------------------------------
模式0:				.		模式1:		.	模式2:			.	模式3:					
					A		.					A		.		A					.		A									
					|		.					|		.		|					.		|							
					Y		.					X		.		Y					.		X					
					0		.					1		.		2					.		3					
	<--- X0 o		.	<----Y1	o		.		o 2X--->  .		o 3Y--->	
------------------------------------------------------------	
模式4:				.	模式5:			.	模式6:			.	模式7:					
	<--- X4 o		.	<--- Y5 o		.		o 6X--->  .		o 7Y--->	
					4		.					5		.		6					.		7	
					Y		.					X		.		Y					.		X						
					|		.					|		.		|					.		|							
					V		.					V		.		V					.		V		
---------------------------------------------------------				
											 LCD屏示例
								|-----------------|
								|			秉火Logo		|
								|									|
								|									|
								|									|
								|									|
								|									|
								|									|
								|									|
								|									|
								|-----------------|
								屏幕正面(宽240,高320)

 *******************************************************/
void ILI9341_GramScan ( uint8_t ucOption )
{	
	//参数检查,只可输入0-7
	if(ucOption >7 )
		return;
	
	//根据模式更新LCD_SCAN_MODE的值,主要用于触摸屏选择计算参数
	LCD_SCAN_MODE = ucOption;
	
	//根据模式更新XY方向的像素宽度
	if(ucOption%2 == 0)	
	{
		//0 2 4 6模式下X方向像素宽度为240,Y方向为320
		LCD_X_LENGTH = ILI9341_LESS_PIXEL;
		LCD_Y_LENGTH =	ILI9341_MORE_PIXEL;
	}
	else				
	{
		//1 3 5 7模式下X方向像素宽度为320,Y方向为240
		LCD_X_LENGTH = ILI9341_MORE_PIXEL;
		LCD_Y_LENGTH =	ILI9341_LESS_PIXEL; 
	}

	//0x36命令参数的高3位可用于设置GRAM扫描方向	
	ILI9341_Write_Cmd ( 0x36 ); 
	ILI9341_Write_Data ( 0x08 |(ucOption<<5));//根据ucOption的值设置LCD参数,共0-7种模式
	ILI9341_Write_Cmd ( CMD_SetCoordinateX ); 
	ILI9341_Write_Data ( 0x00 );		/* x 起始坐标高8位 */
	ILI9341_Write_Data ( 0x00 );		/* x 起始坐标低8位 */
	ILI9341_Write_Data ( ((LCD_X_LENGTH-1)>>8)&0xFF ); /* x 结束坐标高8位 */	
	ILI9341_Write_Data ( (LCD_X_LENGTH-1)&0xFF );				/* x 结束坐标低8位 */

	ILI9341_Write_Cmd ( CMD_SetCoordinateY ); 
	ILI9341_Write_Data ( 0x00 );		/* y 起始坐标高8位 */
	ILI9341_Write_Data ( 0x00 );		/* y 起始坐标低8位 */
	ILI9341_Write_Data ( ((LCD_Y_LENGTH-1)>>8)&0xFF );	/* y 结束坐标高8位 */	 
	ILI9341_Write_Data ( (LCD_Y_LENGTH-1)&0xFF );				/* y 结束坐标低8位 */

	/* write gram start */
	ILI9341_Write_Cmd ( CMD_SetPixel );	
}

/* ILI9341绘制图形初始化 */
void ILI9341_Init()
{
	// ILI9341的GPIO初始化
	ILI9341_GPIO_Init();
	
	// ILI9341寄存器初始化
	ILI9341_REG_Config();
	
	// 设置ILI9341的GRAM的扫描方向 
	ILI9341_GramScan(6);
}

main.c

 

#include "stm32f10x.h"
#include "./usart/bsp_usart.h"
#include "./led/bsp_led.h" 
#include "./lcd/bsp_ili9341_lcd.h"

int main(void)
{	
	/* LED引脚初始化 */	
	//LED_GPIO_Config();
	
	/* USART串口初始化 */
	DEBUG_USART_Config();
	
	printf("这是一个LCD实验\r\n");
	
	/* ILI9341初始化 */
	ILI9341_GPIO_Init();
	
	// 读取ID
	printf("读取到的ID = %x\r\n\r\n", ILI9341_Read_ID());
	
	// 绘图初始化
	ILI9341_Init();
	
	while(1);	
}

 编译没有错误,下一节进行绘图

 

posted @ 2018-07-28 09:03  半生戎马,共话桑麻、  阅读(1277)  评论(0)    收藏  举报
levels of contents