FMC驱动8位并口TFT

FMC驱动8位并口TFT

主控:STM32L476VET6
屏幕:8位并口 ILI9163S 128*160
Stm32cube配置如下
1.FMC配置
在这里插入图片描述
extended mode(读写使用不同的时序)关闭
AddressSetupTime
此参数用于设置地址建立时间,单位FMC时钟周期个数,范围0 -15
DataSetupTime
此参数用于设置数据建立时间,单位FMC时钟周期个数,范围1 -255。
BusTurnAroundDuration
此参数用于设置总线TurnAround(总线周转阶段)持续时间,单位FMC时钟周期个数,范围0 -15。

2.GPIO配置
配置LCD的RST和LED背光控制引脚
LCD的RST
3.屏幕电路
在这里插入图片描述
FSMC 读写GRAM函数
不同的地址线要计算地址偏移量

/* 当选择NE1 连接 LCD时, 地址范围: 0x60000000~0x63FFFFFF 
 * 当选用FSMC_A16地址线时
 * 16位数据时: 16bits => FSMC[24:0]== HADDR[25:1]
	 8位数据时 : 8bits  => FSMC[25:0]== HADDR[25:0]
 * register base address: 0x60000000
 * 16位数据时RAM base address: 0x60020000 = 0x60000000 + 2^16 * 2 = 0x60020000
 * 8 位数据时RAM base address: 0x60010000 = 0x60000000 + 2^16     = 0x60010000
 * 选用不同的地址线要重新计算偏移地址
 8位并口屏,A16地址线,所以数据地址起始为0x60010000
*/
#define Bank1_LCD_DATA 		((uint32_t)0x60010000)	/* display data address */
#define Bank1_LCD_REG		((uint32_t)0x60000000)	/* display register address */

/* LCD write data and register */
#define LCD_WR_DATA(value)	((*(__IO uint8_t*)(Bank1_LCD_DATA)) = ((uint8_t)(value)))     //写数据寄存器
#define LCD_WR_REG(index)	((*(__IO uint8_t*)(Bank1_LCD_REG)) = ((uint8_t)index))					//写命令寄存器

屏幕初始化

//ILI9163初始化
void ILI9163_Init(void)
{
	HAL_GPIO_WritePin(GPIOB, LCD_RST_Pin,GPIO_PIN_SET);
	delayms(1);
	HAL_GPIO_WritePin(GPIOB, LCD_RST_Pin,GPIO_PIN_RESET);
	delayms(10);	
	HAL_GPIO_WritePin(GPIOB, LCD_RST_Pin,GPIO_PIN_SET);	
	delayms(100);	
	
	LCD_WR_REG(0x11); //退出睡眠模式
	HAL_Delay(120);
	LCD_WR_REG(0x26); //设置伽玛曲线
	LCD_WR_DATA(0x04);
	LCD_WR_REG(0xB1);//设置帧速率
	LCD_WR_DATA(0x08);
	LCD_WR_DATA(0x14);
	LCD_WR_REG(0xB8);  //背光控制(灰度)
	LCD_WR_DATA(0x01);
	LCD_WR_REG(0xC0); //功耗设置 

	LCD_WR_DATA(0x08);
	LCD_WR_DATA(0x02);  
	LCD_WR_REG(0xC1); //功耗设置2

	LCD_WR_DATA(0x05);
	LCD_WR_REG(0xC5); //设置VCOMH/VCOML 电压


	LCD_WR_DATA(0x3A);   //0X46
	LCD_WR_DATA(0x32);   //0X40
	LCD_WR_REG(0xC7);		// Set VMF
	LCD_WR_DATA(0xbe);   // 0XC0
	LCD_WR_REG(0x3a); 	//16bit/像素
	LCD_WR_DATA(0x05);
	LCD_WR_REG(0x2A); //设置X范围
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x7F);
	LCD_WR_REG(0x2B); //设置Y范围
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x9F);
	LCD_WR_REG(0xB4); //显示反转控制
	LCD_WR_DATA(0x00);
	LCD_WR_REG(0xB7);  //入口模式
	LCD_WR_DATA(0x01);
	LCD_WR_REG(0xB8);  //背光控制
	LCD_WR_DATA(0x00);
	LCD_WR_REG(0xf2); //使能3伽玛控制
	LCD_WR_DATA(0x01);
	LCD_WR_REG(0x36);  //设置扫描方向
	LCD_WR_DATA(0xC0);
	LCD_WR_REG(0xE0);   //正极校验伽玛
	LCD_WR_DATA(0x3F);//p1
	LCD_WR_DATA(0x26);//p2
	LCD_WR_DATA(0x23);//p3
	LCD_WR_DATA(0x30);//p4
	LCD_WR_DATA(0x28);//p5
	LCD_WR_DATA(0x10);//p6
	LCD_WR_DATA(0x55);//p7
	LCD_WR_DATA(0xB7);//p8
	LCD_WR_DATA(0x40);//p9
	LCD_WR_DATA(0x19);//p10
	LCD_WR_DATA(0x10);//p11
	LCD_WR_DATA(0x1E);//p12
	LCD_WR_DATA(0x02);//p13
	LCD_WR_DATA(0x01);//p14
	LCD_WR_DATA(0x00);//p15
	LCD_WR_REG(0xE1);   //负极校验伽玛
	LCD_WR_DATA(0x00);//p1
	LCD_WR_DATA(0x19);//p2
	LCD_WR_DATA(0x1C);//p3
	LCD_WR_DATA(0x0F);//p4
	LCD_WR_DATA(0x14);//p5
	LCD_WR_DATA(0x0F);//p6
	LCD_WR_DATA(0x2A);//p7
	LCD_WR_DATA(0x48);//p8
	LCD_WR_DATA(0x3F);//p9
	LCD_WR_DATA(0x06);//p10
	LCD_WR_DATA(0x1D);//p11
	LCD_WR_DATA(0x21);//p12
	LCD_WR_DATA(0x3d);//p13
	LCD_WR_DATA(0x3e);//p14
	LCD_WR_DATA(0x3f);//p15
	LCD_WR_REG(0x29); // 开启显示
}

设置窗口范围

//设置窗口范围
//X,Y 为起点坐标;width,height为窗口长宽
static void LCD_OpenWindow(uint16_t x, uint16_t y, uint16_t width, uint16_t height)
{
	LCD_WR_REG(0x2A);  //设置X范围坐标

	LCD_WR_DATA(x>>8);								//起始点高8位
	LCD_WR_DATA(x&0x00FF);						//起始点低8位

	LCD_WR_DATA((x+width-1)>>8);  		//结束点高8位
	LCD_WR_DATA((x+width-1)&0x00FF);	//结束点低8位

	LCD_WR_REG(0X2B); 	//设置Y范围坐标

	LCD_WR_DATA(y>>8);									//起始点高8位
	LCD_WR_DATA(y&0x00FF);							//起始点低8位
	/* pate end */
	LCD_WR_DATA((y+height-1)>>8);				//结束点高8位
	LCD_WR_DATA((y+height-1)&0x00FF);		//结束点低8位
	
	LCD_WR_REG(0x2C);   	//开始写入GRAM
}

画图函数

//画一个点
void LCD_DrawPoint(uint16_t x, uint16_t y, uint16_t color)
{
	LCD_OpenWindow(y, x, 1, 1);   //设置坐标
	LCD_WR_DATA(color>>8);      	//颜色高8位
	LCD_WR_DATA(color&0xFF);			//颜色低8位
}

//画一条线
void LCD_DrawLine(uint16_t start_x, uint16_t start_y, uint16_t end_x, uint16_t end_y, uint16_t color)
{
	uint16_t x = 0, y = 0, k = 0;
	
	if((start_x == end_x) && (start_y == end_y))  //如果是一个点
	{
		LCD_DrawPoint(start_x, start_y, color);
	}
	else if(abs(end_y - start_y) > abs(end_x - start_x))
	{
		if(start_y > end_y)
		{
			k = start_y;
			start_y = end_y;
			end_y = k;
			
			k = start_x;
			start_x = end_x;
			end_x = k;
		}
		for(y = start_y; y < end_y; ++y)
		{
			x = (uint16_t)(y - start_y)*(end_x - start_x) / (end_y - start_y) + start_x;
			LCD_DrawPoint(x, y, color);
		}
	}
	else
	{
		if(start_x > end_x)
		{
			k = start_y;
			start_y = end_y;
			end_y = k;
			
			k = start_x;
			start_x = end_x;
			end_x = k;
		}
		for(x = start_x; x < end_x; ++x)
		{
			y = (uint16_t)(x - start_x)*(end_y - start_y)/ (end_x - start_x) + start_y;
			LCD_DrawPoint(x, y, color);
		}
	}
}

//画矩形
void LCD_DrawRectangle(uint16_t start_x, uint16_t start_y, uint16_t end_x, uint16_t end_y, uint16_t color)
{
	/*
	top-left coordinate(start_x, start_y), bottom-right coordinate(end_x, end_y) 
	 '----------------'
	 '                '
	 '                '
	 '                '
	 '                '
	 '----------------'
	*/
	LCD_DrawLine(start_x, start_y, start_x, end_y, color);
	LCD_DrawLine(start_x, start_y, end_x, start_y, color);
	LCD_DrawLine(end_x, start_y, end_x, end_y, color);
	LCD_DrawLine(start_x, end_y, end_x, end_y, color);
}

//画圆,圆心,半径,颜色
void LCD_DrawCircle(uint16_t x, uint16_t y, uint16_t radius, uint16_t color)
{
	uint16_t a,b;
	int16_t di;
	a = 0;
	b = radius;          
	di = 3 - (radius << 1); 
	while(a <= b)
	{
		LCD_DrawPoint(x - b, y - a, color);             //3           
		LCD_DrawPoint(x + b, y - a, color);             //0           
		LCD_DrawPoint(x - a, y + b, color);             //1              
		LCD_DrawPoint(x - a, y - b, color);             //2             
		LCD_DrawPoint(x + b, y + a, color);             //4               
		LCD_DrawPoint(x + a, y - b, color);             //5
		LCD_DrawPoint(x + a, y + b, color);             //6 
		LCD_DrawPoint(x - b, y + a, color);             
		a++;
		/* Bresenham algorithm */ 
		if(di < 0)
		{
			di += 4*a + 6;   
		}			
		else
		{
			di += 10 + 4 * (a - b);   
			b--;
		} 
		LCD_DrawPoint(x + a, y + b, color);
	}
}




//填充整个屏幕
void LCD_FillScreen(uint16_t color)
{
	LCD_FillRectangle(0, 0, 160, 128, color);
}

//画一个ASCII字符:坐标,字符编号,字符颜色,背景色,字符大小
void LCD_DispASCIICharacter(uint16_t x, uint16_t y, uint8_t character, uint16_t fColor, uint16_t bColor, uint8_t font)
{

	uint32_t i = 0, j = 0, k = 0;
	
	for(k = 0; k < sizeof(codeASCII_24) / sizeof(codeASCII_24[0]); ++k) //按编码搜索字符
	{
		if(codeASCII_24[k].Index == character)
		{
			for(i = 0; i < 16; ++i) 	
			{
				uint8_t m = codeASCII_24[k].Msk[i];
				for(j = 0; j < 8; j++)
				{
					if(m & 0x80)
					{
						LCD_DrawPoint(x+j,y+i,fColor); 
					}
					else 
					{
						LCD_DrawPoint(x+j,y+i,bColor);
					}
					m <<= 1;
				}
			}
		}
	}
}

//画一个汉字:坐标,字符编号,字符颜色,背景色,字符大小
void LCD_DispHZCharacter(uint16_t x, uint16_t y, uint8_t index[2], uint16_t fColor, uint16_t bColor, uint8_t font)
{
	uint16_t width = 0, height = 0;
	uint32_t i = 0, j = 0, k = 0;
	uint8_t m ;
	uint8_t a=0 ;
	width = GetFontWidth(font, HZ_CHARACTER);
	height = GetFontHeight(font, HZ_CHARACTER);
	LCD_OpenWindow(x, y, width, height);
	switch(font)
	{
		case FONT_SIZE_24:
			for(k = 0; k < sizeof(codeHZ_24) / sizeof(codeHZ_24[0]); ++k)
			{
				if((codeHZ_24[k].Index[0] == index[0]) && (codeHZ_24[k].Index[1] == index[1]))
				{
					for(i = 0; i < 72; ++i)					
					{
						m= codeHZ_24[k].Msk[i];
							if((i%3==0)&&(i!=0))
							{
								y++;
								a=0;
							}						
							
						for(j = 0; j < 8; ++j)
						{

							if(m & 0x80)
							{
//								LCD_DrawPoint(x+a+j,y,fColor);
								LCD_WR_DATA(fColor>>8);      	//颜色高8位
								LCD_WR_DATA(fColor&0xFF);			//颜色低8位
							}
							else
							{
//								LCD_DrawPoint(x+a+j,y,bColor);
								LCD_WR_DATA(bColor>>8);      	//颜色高8位
								LCD_WR_DATA(bColor&0xFF);			//颜色低8位
							}
							m <<= 1;
						}
													a=a+8;
					}
					break;
				}
			}
			break;
		default:
			break;
	}
}

//显示图片1
//width,height 图片长宽
void LCD_DispPicture1(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint8_t* str)
{
	LCD_OpenWindow(y, x,height, width);

	uint32_t i,j;
	j = (width )*(height);
	
	for(i=0;i<j;i++)
	{
		LCD_WR_DATA(str[2*i+1]);
		LCD_WR_DATA(str[2*i]);
	}
}

写数据后地址会自动+1,不用再设置坐标。窗口范围要设置正确,否则会出现乱码

0X36可以设置扫描方向

这是存储访问控制指令,可以控制 ILI9341 存储器的读写方向,简单的说,就是在连续写 GRAM 的时候,可以控制 GRAM 指针的增长方向,从而控制显示方式。(读 GRAM 也是一样)。该指令如表:
在这里插入图片描述

0X36 指令后面,紧跟一个参数,主要关注: MY、 MX、 MV 这三个位,通过这三个位的设置,可以控制整个 ILI9341 的全部扫描方向。
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值