STM32学习之ILI9341控制显示屏输出(三)

对于LCD显示屏的控制,简单的讲就是通过向芯片ILI9341发送指定的命令和参数,就可以直接控制。FSMC连接好外部存储器并连接好后,可以直接通过访问地址进行读写数据。使用FSMC外接存储器时,起存储单元是映射到STM32内部存储空间的,在程序中,定义一个指向这些地址的指针,然后就可以通过指针直接修改该存储单元的内容,FSMC外设会自动完成数据访问过程,读写命令之类的操作不需要程序控制。如本实验中:

#define CMD_BASE ((u32)(0x6C000000 | 0x00001FFE))
#define DATA_BASE ((u32)(0x6C000000 | 0x00002000))

#define LCD_CMD (*(u16*)CMD_BASE)
#define LCD_DATA (*(u16*)DATA_BASE)


/*如果需要发送指令,直接像下面这样发送指令:

LCD_CMD = 0xCF   //用于控制芯片供电
 

发送数据可以像下面这样发送:
LCD_DATA = 0xFF;
*/

本实验中会用到如下几个命令(ILI9341专用命令):

0xD3:9341读取ID的命令;

0x2A:设置X坐标;

0x2B:设置Y坐标;

0x2C:存储器写命令;

步骤:

在屏幕上写英语字母的一般步骤为:读取设备ID(确认设备)、初始化、定显示区域、设置更新屏幕方向、设置背景颜色、定鼠标位置、绘制单个像素点、根据库绘制字母。

 

1、读取设备ID:

u16 ILI9341_Read_id(void)
{
 	 u16 id;
	
	 LCD_CMD=0xD3;	//9341读ID命令   
	 id=LCD_DATA;	 
	 id=LCD_DATA; 	//0x00
	 id=LCD_DATA;   //0x93								   
	 id<<=8;
	 id|=LCD_DATA;  //0x41 
	
	 return id;
}

2、初始化:

//初始化lcd
void LCD_Init(void)
{ 	
	 LCD_FSMC_Config();  //配置好FSMC就可以驱动液晶屏

   lcd_id=ILI9341_Read_id(); //先读看看所接屏幕是不是9341驱动
		
	 if(lcd_id!=0x9341)		//如果不是9341,读看看是不是1963驱动	 
		{
			LCD_CMD=(0xA1);   //1963读ID命令  
			lcd_id=LCD_DATA;
			lcd_id=LCD_DATA;	//0x57
			lcd_id<<=8;	 
			lcd_id|=LCD_DATA;	//0x61	
			if(lcd_id==0x5761)
				 lcd_id=0x1963;  //SSD1963实际读出的ID是0x5761,为了直观,这边设置为1963
		}

  if(lcd_id==0X9341) //此驱动,设置写时序为最快
	{	 							    
		FSMC_Bank1E->BWTR[6]&=~(0XF<<0); //地址建立时间清零 	 
		FSMC_Bank1E->BWTR[6]&=~(0XF<<8); //数据保存时间清零
		FSMC_Bank1E->BWTR[6]|=3<<0;		   //地址建立时间为3个HCLK =18ns  	 
		FSMC_Bank1E->BWTR[6]|=2<<8;    	 //数据保存时间为6ns*3个HCLK=18ns
	}

	if(lcd_id==0X9341)	//9341初始化
	{	 
		LCD_CMD=0xCF;//电源控制命令  
		LCD_DATA=0x00;
		LCD_DATA=0xC1; 
		LCD_DATA=0X30; 
		LCD_CMD=0xED;//系列功率控制  
		LCD_DATA=0x64; 
		LCD_DATA=0x03; 
		LCD_DATA=0X12; 
		LCD_DATA=0X81; 
		LCD_CMD=0xE8;//驱动器时序控制  
		LCD_DATA=0x85; 
		LCD_DATA=0x10; 
		LCD_DATA=0x7A; 
		LCD_CMD=0xCB;  
		LCD_DATA=0x39; 
		LCD_DATA=0x2C; 
		LCD_DATA=0x00; 
		LCD_DATA=0x34; 
		LCD_DATA=0x02; 
		LCD_CMD=0xF7;  
		LCD_DATA=0x20; 
		LCD_CMD=0xEA;  
		LCD_DATA=0x00; 
		LCD_DATA=0x00; 
		LCD_CMD=0xC0;    
		LCD_DATA=0x1B;    
		LCD_CMD=0xC1;    
		LCD_DATA=0x01;    
		LCD_CMD=0xC5;     
		LCD_DATA=0x30; 	  
		LCD_DATA=0x30; 	  
		LCD_CMD=0xC7;      
		LCD_DATA=0XB7; 
		LCD_CMD=0x36;      
		LCD_DATA=0x48; 
		LCD_CMD=0x3A;   
		LCD_DATA=0x55; 
		LCD_CMD=0xB1;   
		LCD_DATA=0x00;   
		LCD_DATA=0x1A; 
		LCD_CMD=0xB6;     
		LCD_DATA=0x0A; 
		LCD_DATA=0xA2; 
		LCD_CMD=0xF2;      
		LCD_DATA=0x00; 
		LCD_CMD=0x26;      
		LCD_DATA=0x01; 
		LCD_CMD=0xE0;      
		LCD_DATA=0x0F; 
		LCD_DATA=0x2A; 
		LCD_DATA=0x28; 
		LCD_DATA=0x08; 
		LCD_DATA=0x0E; 
		LCD_DATA=0x08; 
		LCD_DATA=0x54; 
		LCD_DATA=0XA9; 
		LCD_DATA=0x43; 
		LCD_DATA=0x0A; 
		LCD_DATA=0x0F; 
		LCD_DATA=0x00; 
		LCD_DATA=0x00; 
		LCD_DATA=0x00; 
		LCD_DATA=0x00; 		 
		LCD_CMD=0XE1;     
		LCD_DATA=0x00; 
		LCD_DATA=0x15; 
		LCD_DATA=0x17; 
		LCD_DATA=0x07; 
		LCD_DATA=0x11; 
		LCD_DATA=0x06; 
		LCD_DATA=0x2B; 
		LCD_DATA=0x56; 
		LCD_DATA=0x3C; 
		LCD_DATA=0x05; 
		LCD_DATA=0x10; 
		LCD_DATA=0x0F; 
		LCD_DATA=0x3F; 
		LCD_DATA=0x3F; 
		LCD_DATA=0x0F; 
		LCD_CMD=0x2B; 
		LCD_DATA=0x00;
		LCD_DATA=0x00;
		LCD_DATA=0x01;
		LCD_DATA=0x3f;
		LCD_CMD=0x2A; 
		LCD_DATA=0x00;
		LCD_DATA=0x00;
		LCD_DATA=0x00;
		LCD_DATA=0xef;	 
		LCD_CMD=0x11;  
		delay_ms(120);
		LCD_CMD=0x29; 
		
		LCD_BACK=1;	  //点亮背光
	}
	else if(lcd_id==0X1963)
	{
		LCD_CMD=0xE2;		
		LCD_DATA=0x1D;		
		LCD_DATA=0x02;		
		LCD_DATA=0x04;		
		delay_us(100);
		
		LCD_CMD=0xE0;		
		LCD_DATA=0x01;		
		delay_ms(10);
		
		LCD_CMD=0xE0;		
		LCD_DATA=0x03;		
		delay_ms(12); 
		
		LCD_CMD=0x01;		//软复位
		delay_ms(10);

		LCD_CMD=0xE6;		
		LCD_DATA=0x2F;
		LCD_DATA=0xFF;
		LCD_DATA=0xFF;

		LCD_CMD=0xB0;		  
		LCD_DATA=0x20;		 
		LCD_DATA=0x00;		
	
		LCD_DATA=(800-1)>>8; //LCD水平像素设置
		LCD_DATA=800-1;		 
		LCD_DATA=(480-1)>>8; //LCD垂直像素设置
		LCD_DATA=480-1;		 
		LCD_DATA=0x00;		   //RGB序列 
		
		LCD_CMD=0xB4;	
		LCD_DATA=(800+46+210-1)>>8;
		LCD_DATA=800+46+210-1;
		LCD_DATA=46>>8;
		LCD_DATA=46;
		LCD_DATA=0;
		LCD_DATA=0x00;
		LCD_DATA=0x00;
		LCD_DATA=0x00;
		
		LCD_CMD=0xB6;		 
		LCD_DATA=(480+23+22-1)>>8;
		LCD_DATA=480+23+22-1;
		LCD_DATA=23>>8;
		LCD_DATA=23;
		LCD_DATA=21;
		LCD_DATA=0x00;
		LCD_DATA=0x00;
		
		LCD_CMD=0xF0;	 
		LCD_DATA=0x03;	//SSD1963与MCU的接口为16bit  

		LCD_CMD=0x29;	//开启显示
		LCD_CMD=0xD0;	//设置自动白平衡DBC
		LCD_DATA=0x00;	
	
		LCD_CMD=0xBE;	  //PWM输出
		LCD_DATA=0x05;	//PWM频率
		LCD_DATA=0xFE;	//PWM占空比
		LCD_DATA=0x01;	
		LCD_DATA=0x00;	
		LCD_DATA=0x00;	
		LCD_DATA=0x00;	
		
		LCD_CMD=0xB8;	 
		LCD_DATA=0x03;	 
		LCD_DATA=0x01;	 
		LCD_CMD=0xBA;
		LCD_DATA=0X01;	//控制LCD方向

		Ssd1963_Set_BackLight(255);//背光设置
	}
	Set_Display_Mode(0);		 //初始化为竖屏		
	LCD_Clear(WHITE);        //清屏白色
} 

定显示区域:

void LCD_Open_Window(u16 X0,u16 Y0,u16 width,u16 height)
{   
	width=X0+width-1;    //算出右下角坐标
	height=Y0+height-1;
  
	if(dir_flag==0&&lcd_id==0X1963)  //1963竖屏处理
		{
			X0=lcd_width-width-X0; 
			height=Y0+height-1; 
			LCD_CMD=setxcmd; 
			LCD_DATA=X0>>8; 
			LCD_DATA=X0&0XFF;	 
			LCD_DATA=(X0+width-1)>>8; 
			LCD_DATA=(X0+width-1)&0XFF;  
			LCD_CMD=setycmd; 
			LCD_DATA=Y0>>8; 
			LCD_DATA=Y0&0XFF; 
			LCD_DATA=height>>8; 
			LCD_DATA=height&0XFF; 		
		}
	else
		{
			LCD_CMD=setxcmd; 
			LCD_DATA=X0>>8; 
			LCD_DATA=X0&0XFF;	 
			LCD_DATA=width>>8; 
			LCD_DATA=width&0XFF;  
			LCD_CMD=setycmd; 
			LCD_DATA=Y0>>8; 
			LCD_DATA=Y0&0XFF; 
			LCD_DATA=height>>8; 
			LCD_DATA=height&0XFF; 
		}
} 

设置更新屏幕方向:

void Set_Scan_Direction(u8 direction)
{
	u16 skhda=0;
	u16 diomf=0;
	    //9341横屏和1963竖屏时需要转化下
	if( (dir_flag==1&&lcd_id==0X9341)||(dir_flag==0&&lcd_id==0X1963)) 
	  {			   
			switch(direction)//方向转换
				{
					case 0:direction=6;break;
					case 1:direction=7;break;
					case 2:direction=4;break;
					case 3:direction=5;break;
					case 4:direction=1;break;
					case 5:direction=0;break;
					case 6:direction=3;break;
					case 7:direction=2;break;	     
				}
    }	
		
		switch(direction)
		{
			case L2R_U2D:   //从左到右,从上到下
				skhda|=(0<<7)|(0<<6)|(0<<5); 
				break;
			case L2R_D2U:   //从左到右,从下到上
				skhda|=(1<<7)|(0<<6)|(0<<5); 
				break;
			case R2L_U2D:   //从右到左,从上到下
				skhda|=(0<<7)|(1<<6)|(0<<5); 
				break;
			case R2L_D2U:   //从右到左,从下到上
				skhda|=(1<<7)|(1<<6)|(0<<5); 
				break;	 
			case U2D_L2R:   //从上到下,从左到右
				skhda|=(0<<7)|(0<<6)|(1<<5); 
				break;
			case U2D_R2L:   //从上到下,从右到左
				skhda|=(0<<7)|(1<<6)|(1<<5); 
				break;
			case D2U_L2R:   //从下到上,从左到右
				skhda|=(1<<7)|(0<<6)|(1<<5); 
				break;
			case D2U_R2L:   //从下到上,从右到左
				skhda|=(1<<7)|(1<<6)|(1<<5); 
				break;	 
		}
	  diomf=0X36;
	  if(lcd_id==0X9341)		
			 skhda|=0X08;		
	  LCD_WriteReg(diomf,skhda);		
	  LCD_Open_Window(0,0,lcd_width,lcd_height);  //设置完扫描方向后,开显示区域为全屏窗口
}

设置背景颜色:

//初始化LCD的画笔颜色和背景色	   
u16 BRUSH_COLOR=BLACK;	//画笔颜色
u16 BACK_COLOR=WHITE;   //背景色 

定鼠标位置

void LCD_SetCursor(u16 Xaddr, u16 Yaddr)
{	 
	if(lcd_id==0X9341)
		{		    
			LCD_CMD=setxcmd; 
			LCD_DATA=(Xaddr>>8); 
			LCD_DATA=(Xaddr&0XFF);	 
			LCD_CMD=setycmd; 
			LCD_DATA=(Yaddr>>8); 
			LCD_DATA=(Yaddr&0XFF);
		}
	else if(lcd_id==0X1963)
		{  			 		
			if(dir_flag==0) 
			{
				Xaddr=lcd_width-1-Xaddr;
				LCD_CMD=setxcmd; 
				LCD_DATA=0;
				LCD_DATA=0; 		
				LCD_DATA=Xaddr>>8;
				LCD_DATA=Xaddr&0XFF;		 	 
			}else
			{
				LCD_CMD=setxcmd; 
				LCD_DATA=Xaddr>>8;
				LCD_DATA=Xaddr&0XFF; 		
				LCD_DATA=(lcd_width-1)>>8;
				LCD_DATA=(lcd_width-1)&0XFF;		 	 			
			}	
			LCD_CMD=setycmd; 
			LCD_DATA=Yaddr>>8;
			LCD_DATA=Yaddr&0XFF; 		
			LCD_DATA=(lcd_height-1)>>8;
			LCD_DATA=(lcd_height-1)&0XFF; 			 		
			
		}
} 

绘制单个像素点

void LCD_DrawPoint(u16 x,u16 y)
{
    LCD_SetCursor(x,y);            //设置光标位置 
    LCD_WriteGRAM();            //开始写入GRAM
    LCD_DATA=BRUSH_COLOR; 
}

 

根据库绘制字母

void LCD_DisplayChar(u16 x,u16 y,u8 word,u8 size)
{  							  
  u8  bytenum,bytedata, a,b;
	
	u16 xmid=x;   //存储初始X值(位置)			     
	 
	if(size==12) bytenum=12;        //从字库数组中可知道每种字体单个字符所占的字节数
	else if(size==16) bytenum=16;
	else if(size==24) bytenum=48;
	else return;    //其他字体退出
	                
	word=word-' ';  //字库数组是按ASCII表排列
  //cfont.h中字库是从空格开始的 空格就是第一个元素 其他字符的ASCII码减去空格后就得到在数组中的偏移值(位置) 
	    for(b=0;b>=1;    //低位判断完 依次往高位判断
						x++;	           //显示完一位 往下一位显示 
						if((x-xmid)==size/2)  //x方向超出字体大小 如:16字体 实际是 08*16的点阵  故这边 size/2
						{
							x=xmid;  //从初始X位置在写下一行
							y++;     //上一行写完 从下一行再写
							break;   //跳出for(a=0;a<8;a++)循环
						}
		      }   	 
	    }       	 	  
}   

以上代码是参照网上的,经过测试是可以直接使用的:我自己写的代码如下链接中

你可能感兴趣的:(STM32学习)