STM32F429/GD32F450液晶RGBLCD驱动代码

使用这段代码还需要使用SDRAM模块

工程代码可以参考正点原子的例程
例程下载

LCD.h

#ifndef __LCD_H
#define __LCD_H		
#include "sys.h"	 
#include "stdlib.h"  
#include "delay.h"

//LCD重要参数集
typedef struct  
{		 	 
	uint16_t width;			//LCD 宽度
	uint16_t height;			//LCD 高度
	uint16_t id;				//LCD ID
	uint8_t  dir;			//横屏还是竖屏控制:0,竖屏;1,横屏。	
	uint16_t	wramcmd;		//开始写gram指令
	uint16_t setxcmd;		//设置x坐标指令
	uint16_t setycmd;		//设置y坐标指令 
}_lcd_dev; 	  

//LCD参数
extern _lcd_dev lcddev;	//管理LCD重要参数
//LCD的画笔颜色和背景色	   
#define DEFAULT_POINT_COLOR   YELLOW;   //默认画笔颜色
#define DEFAULT_BACK_COLOR    BLACK;    //默认背景颜色
extern uint32_t  PointColor;//画笔颜色,默认黄色    
extern uint32_t  BackColor; //背景颜色,默认为黑色

//	  	    
//LCD地址结构体
typedef struct
{
	vuint16_t LCD_REG;
	vuint16_t LCD_RAM;
} LCD_TypeDef;
//使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11 A18作为数据命令区分线 
//注意设置时STM32内部会右移一位对其!  			    
#define LCD_BASE        ((uint32_t)(0x60000000 | 0x0007FFFE))
#define LCD             ((LCD_TypeDef *) LCD_BASE)
//
	 
//扫描方向定义
#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         	 0x0000FFFF //白色
#define BLACK         	 0x00000000	//黑色
#define BLUE         	 0x0000001F //蓝色 
#define RED           	 0x0000F800 //红色
#define GREEN         	 0x000007E0 //绿色
#define YELLOW        	 0x0000FFE0 //黄色
#define BROWN 			 0X0000BC40 //棕色
#define BRRED 			 0X0000FC07 //棕红色
#define GRAY  			 0X00008430 //灰色

//左右屏
#define LEFT      0
#define RIGHT     1
	    															  
void LCD_Init(void);													   	//初始化
void LCD_DisplayOn(void);													//开显示
void LCD_DisplayOff(void);													//关显示
void LCD_BlackLightOn(void);                        						//点亮背光
void LCD_BlackLightOff(void);                       					    //熄灭背光
void LCD_Clear(uint32_t Color);	 												//清屏
void LCD_DrawPoint(uint16_t x,uint16_t y);											//画点
void LCD_Fast_DrawPoint(uint16_t x,uint16_t y,uint32_t color);								//快速画点
uint32_t  LCD_ReadPoint(uint16_t x,uint16_t y); 											//读点 
void LCD_Draw_Circle(uint16_t x0,uint16_t y0,uint8_t r);						 			//画圆
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);							//画线
void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);		   				//画矩形
void LCD_DrawCheckBox(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2);     //画矩形复选框
void LCD_FillCheckBox(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint32_t color); //填充复选框
void LCD_DrawTriangle(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint16_t x,uint16_t y);  //画三角形
void LCD_DrawTriangleRE(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint16_t x,uint16_t y);//画反向三角形
void LCD_DrawHistogram(uint16_t x,uint16_t y,uint16_t w);                                  //画柱形图
void LCD_FillHistogram(uint16_t x,uint16_t y,uint16_t w,uint16_t value,uint16_t range);              //填充柱形图
void LCD_DrawHistogramLimit(uint16_t x,uint16_t y,uint16_t w,uint16_t limit,uint16_t range);         //画柱状图上限值线
void LCD_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint32_t color);		   				//填充单色
void LCD_Color_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t *color);				//填充指定颜色
void LCD_ShowChar(uint16_t x,uint16_t y,char num,uint8_t size,uint8_t mode);					//显示一个字符
void LCD_ShowString(uint16_t x,uint16_t y,uint16_t width,uint16_t height,uint8_t size,volatile char *p);		//显示一个字符串,12/16字体
void Show_Font(uint16_t x,uint16_t y,uint8_t size,const volatile char *p, uint8_t mode);                 //显示一个汉字
void LCD_ShowPicture(uint16_t x,uint16_t y,uint16_t width,uint16_t heigth, const uint8_t *data,uint8_t mode);   //显示一个单色位图
void LCD_ShowText(uint16_t x,uint16_t y,uint16_t width,uint16_t height,volatile char*str,uint8_t size,uint8_t mode); //显示文本(带汉字)
char* FloatAsc2Right(float value, uint8_t dot);  							      //把浮点数转换成字符串(右对齐)  
char* FloatAsc2Left(float value, uint8_t dot);                                     //把浮点数转换成字符串(左对齐) 
void LCD_WriteReg(uint16_t LCD_Reg, uint16_t LCD_RegValue);
uint16_t  LCD_ReadReg(uint16_t LCD_Reg);
void LCD_WriteRAM_Prepare(void);
void LCD_WriteRAM(uint16_t RGB_Code);
void LCD_Display_Dir(uint8_t dir);								//设置屏幕显示方向
void LCD_Set_Window(uint16_t sx,uint16_t sy,uint16_t width,uint16_t height);	//设置窗口					   						   																			 
//LCD分辨率设置
#define LCD_HOR_RESOLUTION		640		//LCD水平分辨率
#define LCD_VER_RESOLUTION		480		//LCD垂直分辨率
//LCD驱动参数设置
#define LCD_HOR_PULSE_WIDTH		1		//水平脉宽
#define LCD_HOR_BACK_PORCH		144		//水平后廊
#define LCD_HOR_FRONT_PORCH		16		//水平前廊

#define LCD_VER_PULSE_WIDTH		1		//垂直脉宽
#define LCD_VER_BACK_PORCH		35		//垂直后廊
#define LCD_VER_FRONT_PORCH		10		//垂直前廊
//如下几个参数,自动计算
#define LCD_HT	(LCD_HOR_RESOLUTION+LCD_HOR_BACK_PORCH+LCD_HOR_FRONT_PORCH)
#define LCD_HPS	(LCD_HOR_BACK_PORCH)
#define LCD_VT 	(LCD_VER_RESOLUTION+LCD_VER_BACK_PORCH+LCD_VER_FRONT_PORCH)
#define LCD_VPS (LCD_VER_BACK_PORCH)

#endif  

LCD.c

#include "lcd.h"
#include "stdlib.h"
#include "font.h" 
#include "usart.h"	 
#include "delay.h"	 
#include "ltdc.h"

/** \addtogroup lcd_group 液晶显示模块 */

/*@{*/

//LCD的画笔颜色和背景色	   
uint32_t PointColor=DEFAULT_POINT_COLOR;	 //画笔颜色
uint32_t BackColor =DEFAULT_BACK_COLOR;   //背景色 
//管理LCD重要参数
//默认为竖屏
_lcd_dev lcddev;
/**
* \brief      函数功能:写寄存器函数
*             
* \param[in]  regval:寄存器值
*             
* \return   
*            
*/	 
void LCD_WR_REG(vuint16_t regval)
{   
	regval=regval;		//使用-O2优化的时候,必须插入的延时
	LCD->LCD_REG=regval;//写入要写的寄存器序号	 
}
/**
* \brief      函数功能:写LCD数据
*             
* \param[in]  data:要写入的值
*             
* \return   
*            
*/
void LCD_WR_DATA(vuint16_t data)
{	  
	data=data;			//使用-O2优化的时候,必须插入的延时
	LCD->LCD_RAM=data;		 
}
/**
* \brief      函数功能:读LCD数据
*             
* \param[in]  
*             
* \return     读到的值
*            
*/
uint16_t LCD_RD_DATA(void)
{
	vuint16_t ram;			//防止被优化
	ram=LCD->LCD_RAM;	
	return ram;	 
}	
/**
* \brief      函数功能:写寄存器
*             
* \param[in]  LCD_Reg:寄存器地址
*             LCD_RegValue:要写入的数据
* \return   
*            
*/
void LCD_WriteReg(uint16_t LCD_Reg,uint16_t LCD_RegValue)
{	
	LCD->LCD_REG = LCD_Reg;		//写入要写的寄存器序号	 
	LCD->LCD_RAM = LCD_RegValue;//写入数据	    		 
}	   
/**
* \brief      函数功能:读寄存器
*             
* \param[in]  LCD_Reg:寄存器地址
*             
* \return   读到的数据
*            
*/
uint16_t LCD_ReadReg(uint16_t LCD_Reg)
{										   
	LCD_WR_REG(LCD_Reg);		//写入要读的寄存器序号
	delay_us(5);		  
	return LCD_RD_DATA();		//返回读到的值
}   
/**
* \brief      函数功能:开始写GRAM
*             
* \param[in]  
*             
* \return   
*            
*/
void LCD_WriteRAM_Prepare(void)
{
 	LCD->LCD_REG=lcddev.wramcmd;	  
}	
/**
* \brief      函数功能:LCD写GRAM
*             
* \param[in]  RGB_Code:颜色值
*             
* \return   
*            
*/
void LCD_WriteRAM(uint16_t RGB_Code)
{							    
	LCD->LCD_RAM = RGB_Code;//写十六位GRAM
}
/**
* \brief      函数功能:当mdk -O1时间优化时需要设置
*             
* \param[in]  i:延时
*             
* \return   
*            
*/
void opt_delay(uint8_t i)
{
	while(i--);
}
/**
* \brief      函数功能:读取个某点的颜色值
*             
* \param[in]  x,y:坐标
*             
* \return     此点的颜色
*            
*/
uint32_t LCD_ReadPoint(uint16_t x,uint16_t y)
{
	if(x>=lcddev.width||y>=lcddev.height)return 0;	//超过了范围,直接返回
	
	return LTDC_Read_Point(x,y);
}	
/**
* \brief      函数功能:LCD开启显示
*             
* \param[in]  
*             
* \return   
*            
*/
void LCD_DisplayOn(void)
{					   
	LTDC_Switch(1);//开启LCD
}	
/**
* \brief      函数功能:LCD关闭显示
*             
* \param[in]  
*             
* \return   
*            
*/
void LCD_DisplayOff(void)
{	   
	LTDC_Switch(0);//关闭LCD
} 
/**
* \brief      函数功能:点亮LCD背光
*             
* \param[in]  
*             
* \return   
*            
*/
void LCD_BlackLightOn(void)
{
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_SET);
}	
/**
* \brief      函数功能:熄灭LCD背光
*             
* \param[in]  
*             
* \return   
*            
*/
void LCD_BlackLightOff(void)
{
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_RESET);
}
/**
* \brief      函数功能:画点
*             
* \param[in]  x,y:坐标
*             PointColor:此点的颜色
* \return     
*            
*/
void LCD_DrawPoint(uint16_t x,uint16_t y)
{
		LTDC_Draw_Point(x,y,PointColor);
}
/**
* \brief      函数功能:快速画点
*             
* \param[in]  x,y:坐标
*             color:颜色
* \return   
*            
*/
void LCD_Fast_DrawPoint(uint16_t x,uint16_t y,uint32_t color)
{	   
		LTDC_Draw_Point(x,y,color);
		return;
}	 
/**
* \brief      函数功能:设置LCD显示方向
*             
* \param[in]  dir:0,竖屏;1,横屏
*             
* \return   
*            
*/
void LCD_Display_Dir(uint8_t dir)
{
		LTDC_Display_Dir(dir);
		return;
}	 
/**
* \brief      函数功能:初始化lcd
*
* \param[in]  
*             
* \return   
*            
*/       
void LCD_Init(void)
{ 	  
	LTDC_Init();			    //初始化LTDC
}  
/**
* \brief      函数功能:清屏函数
*             
* \param[in]  color:要清屏的填充色
*             
* \return   
*            
*/
void LCD_Clear(uint32_t color)
{
	LTDC_Clear(color);
	delay_ms(5);  //清屏以后不延时会导致LCD刷新次数多以后显示不全
}  
/**
* \brief      函数功能:在指定区域内填充单个颜色
*             
* \param[in]  (sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1) 
*             color:要填充的颜色
* \return   
*            
*/
void LCD_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint32_t color)
{          
	LTDC_Fill(sx,sy,ex,ey,color);
	delay_ms(5);  //填充以后不延时会导致LCD刷新次数多以后显示不全
}  
/**
* \brief      函数功能:在指定区域内填充指定颜色块
*             
* \param[in]  (sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
*             color:要填充的颜色
* \return   
*            
*/
void LCD_Color_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t *color)
{  
		LTDC_Color_Fill(sx,sy,ex,ey,color);
}  
/**
* \brief      函数功能:画线
*             
* \param[in]  x1,y1:起点坐标
*             x2,y2:终点坐标 
* \return   
*            
*/
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
	uint16_t t; 
	int xerr=0,yerr=0,delta_x,delta_y,distance; 
	int incx,incy,uRow,uCol; 
	delta_x=x2-x1; //计算坐标增量 
	delta_y=y2-y1; 
	uRow=x1; 
	uCol=y1; 
	if(delta_x>0)incx=1; //设置单步方向 
	else if(delta_x==0)incx=0;//垂直线 
	else {incx=-1;delta_x=-delta_x;} 
	if(delta_y>0)incy=1; 
	else if(delta_y==0)incy=0;//水平线 
	else{incy=-1;delta_y=-delta_y;} 
	if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 
	else distance=delta_y; 
	for(t=0;t<=distance+1;t++ )//画线输出 
	{  
		LCD_DrawPoint(uRow,uCol);//画点 
		xerr+=delta_x ; 
		yerr+=delta_y ; 
		if(xerr>distance) 
		{ 
			xerr-=distance; 
			uRow+=incx; 
		} 
		if(yerr>distance) 
		{ 
			yerr-=distance; 
			uCol+=incy; 
		} 
	}  
}  
/**
* \brief      函数功能:画矩形
*             
* \param[in]  (x1,y1),(x2,y2):矩形的对角坐标
*             
* \return   
*            
*/
void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
	LCD_DrawLine(x1,y1,x2,y1);
	LCD_DrawLine(x1,y1,x1,y2);
	LCD_DrawLine(x1,y2,x2,y2);
	LCD_DrawLine(x2,y1,x2,y2);
}

/**
* \brief 函数功能 : 画矩形复选框
*        
* \param[in] (x1,y1),(x2,y2):复选框的对角坐标
*
* \return    无
*/
void LCD_DrawCheckBox(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
{
	LCD_DrawRectangle(x1,y1,x2,y2);
	LCD_DrawRectangle(x1+1,y1+1,x2-1,y2-1);
}

/**
* \brief 函数功能 : 填充矩形复选框
*        
* \param[in] (x1,y1),(x2,y2):复选框的对角坐标
*
* \return    无
*/
void LCD_FillCheckBox(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint32_t color)
{
	LCD_Fill(x1+2,y1+2,x2-2,y2-2,color);	
	PointColor = DEFAULT_POINT_COLOR;//恢复默认画笔颜色
}
/**
* \brief 函数功能 : 画实心三角形
*        
* \param[in] (x1,y1),(x2,y2):填充区域
*             x,y           :三角形坐标
*
* \return    无
*/
void LCD_DrawTriangle(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint16_t x,uint16_t y)
{
	LCD_Fill(x1,y1,x2,y2,BackColor);
	
	LCD_DrawLine(x,   y-10,x  , y+10);
	LCD_DrawLine(x+1, y-9, x+1, y+9);
	LCD_DrawLine(x+2, y-8, x+2, y+8);
	LCD_DrawLine(x+3, y-7, x+3, y+7);
	LCD_DrawLine(x+4, y-6, x+4, y+6);
	LCD_DrawLine(x+5, y-5, x+5, y+5);
	LCD_DrawLine(x+6, y-4, x+6, y+4);
	LCD_DrawLine(x+7, y-3, x+7, y+3);
	LCD_DrawLine(x+8, y-2, x+8, y+2);
	LCD_DrawLine(x+9, y-1, x+9, y+1);
	LCD_DrawLine(x+10,y  , x+10,y  );
}
/**
* \brief 函数功能 : 画反向实心三角形
*        
* \param[in] (x1,y1),(x2,y2):填充区域
*             x,y           :三角形坐标
*
* \return    无
*/
void LCD_DrawTriangleRE(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint16_t x,uint16_t y)
{
	LCD_Fill(x1,y1,x2,y2,BackColor);
	
	LCD_DrawLine(x,   y-10,x  , y+10);
	LCD_DrawLine(x-1, y-9, x-1, y+9);
	LCD_DrawLine(x-2, y-8, x-2, y+8);
	LCD_DrawLine(x-3, y-7, x-3, y+7);
	LCD_DrawLine(x-4, y-6, x-4, y+6);
	LCD_DrawLine(x-5, y-5, x-5, y+5);
	LCD_DrawLine(x-6, y-4, x-6, y+4);
	LCD_DrawLine(x-7, y-3, x-7, y+3);
	LCD_DrawLine(x-8, y-2, x-8, y+2);
	LCD_DrawLine(x-9, y-1, x-9, y+1);
	LCD_DrawLine(x-10,y  , x-10,y  );
}
/**
* \brief 函数功能 : 画柱状图
*        这个柱状图高度为固定的280像素,8个刻度,刻度没有数值标识
* \param[in] x,y        柱状图坐标,这个坐标是柱状图矩形方框左上角的坐标
*            w          柱状图宽度
*
* \return    无
*/
void LCD_DrawHistogram(uint16_t x,uint16_t y,uint16_t w)
{
	LCD_DrawLine(x,y,x+w,y);
	LCD_DrawLine(x,y,x,y+280);
	LCD_DrawLine(x+w,y,x+w,y+280);
	LCD_DrawLine(x,y+280,x+w,y+280);
	
	LCD_DrawLine(x-10,y,x-2,y);
	LCD_DrawLine(x-6 ,y+35,x-2,y+35);
	LCD_DrawLine(x-10,y+70,x-2,y+70);
	LCD_DrawLine(x-6,y+105,x-2,y+105);
	LCD_DrawLine(x-10,y+140,x-2,y+140);
	LCD_DrawLine(x-6,y+175,x-2,y+175);
	LCD_DrawLine(x-10,y+210,x-2,y+210);
	LCD_DrawLine(x-6,y+245,x-2,y+245);
	LCD_DrawLine(x-10,y+280,x-2,y+280);
	
	LCD_DrawLine(x-2,y,x-2,y+280);
}

/**
* \brief 函数功能 : 填充柱状图
*        这个柱状图高度为固定的280像素
* \param[in] x,y        柱状图坐标,这个坐标是柱状图矩形方框左上角的坐标
*            w          柱状图宽度
*            value      柱状图显示数值
*            range      柱状图量程
*
* \return    无
*/
void LCD_FillHistogram(uint16_t x,uint16_t y,uint16_t w,uint16_t value,uint16_t range)
{
	LCD_Fill(x+1,y+1,x+w-1,y-1+((range-value)*279)/range,BLACK);
	LCD_Fill(x+1,y+((range-value)*279)/range,x+w-1,y+279,YELLOW);
}

/**
* \brief 函数功能 : 画柱状图上限
*        这个柱状图高度为固定的280像素
* \param[in] x,y        柱状图坐标,这个坐标是柱状图矩形方框左上角的坐标
*            w          柱状图宽度
*            limit      柱状图上限值
*            range      柱状图量程
*
* \return    无
*/
void LCD_DrawHistogramLimit(uint16_t x,uint16_t y,uint16_t w,uint16_t limit,uint16_t range)
{
	LCD_Fill(x+w+2,y,x+w+2,y-1+((range-limit)*279)/range,RED);
	LCD_Fill(x+w+2,y+((range-limit)*279)/range,x+w+2,y+279,BLACK);
}
/**
* \brief      函数功能:在指定位置画一个指定大小的圆
*             
* \param[in]  (x,y):中心点
*             r    :半径
* \return   
*            
*/
void LCD_Draw_Circle(uint16_t x0,uint16_t y0,uint8_t r)
{
	int a,b;
	int di;
	a=0;b=r;	  
	di=3-(r<<1);             //判断下个点位置的标志
	while(a<=b)
	{
		LCD_DrawPoint(x0+a,y0-b);             //5
 		LCD_DrawPoint(x0+b,y0-a);             //0           
		LCD_DrawPoint(x0+b,y0+a);             //4               
		LCD_DrawPoint(x0+a,y0+b);             //6 
		LCD_DrawPoint(x0-a,y0+b);             //1       
 		LCD_DrawPoint(x0-b,y0+a);             
		LCD_DrawPoint(x0-a,y0-b);             //2             
		LCD_DrawPoint(x0-b,y0-a);             //7     	         
		a++;
		//使用Bresenham算法画圆     
		if(di<0)di +=4*a+6;	  
		else
		{
			di+=10+4*(a-b);   
			b--;
		} 						    
	}
} 
/**
* \brief      函数功能:在指定位置显示一个字符
*             
* \param[in]  x,y:起始坐标
*             num:要显示的字符:" "--->"~"
*             size:字体大小 12/16/24/32
*             mode:叠加方式(1)还是非叠加方式(0)
* \return   
*            
*/
void LCD_ShowChar(uint16_t x,uint16_t y,char num,uint8_t size,uint8_t mode)
{  							  
    uint8_t temp,t1,t;
	uint16_t y0=y;
	uint8_t csize=(size/8+((size%8)?1:0))*(size/2);		//得到字体一个字符对应点阵集所占的字节数	
 	num=num-' ';//得到偏移后的值(ASCII字库是从空格开始取模,所以-' '就是对应字符的字库)
	for(t=0;t<csize;t++)
	{   
		if(size==12)temp=asc2_1206[num][t]; 	 	//调用1206字体
		else if(size==16)temp=asc2_1608[num][t];	//调用1608字体
		else if(size==24)temp=asc2_2412[num][t];	//调用2412字体
		else if(size==32)temp=asc2_3216[num][t];	//调用3216字体
		else return;								//没有的字库
		for(t1=0;t1<8;t1++)
		{			    
			if(temp&0x80)LCD_Fast_DrawPoint(x,y,PointColor);
			else if(mode==0)LCD_Fast_DrawPoint(x,y,BackColor);
			temp<<=1;
			y++;
			if(y>=lcddev.height)return;		//超区域了
			if((y-y0)==size)
			{
				y=y0;
				x++;
				if(x>=lcddev.width)return;	//超区域了
				break;
			}
		}  	 
	}  	    	   	 	  
}   
/**
* \brief 浮点数转换至ASC2(右对齐)
*        把浮点数值转化为ASC2码,小数点后最多2位,转换后数值长度为8,没有数值的部分是空格
*        超过部分将被忽略,数值字符为ASCII字符。
*        转换后的字符为右对齐
*
* \param[in]  value 需要转化的数值   转换数值0~99999
* \param[in]  dot 小数点后位数       小数点最大为2
* \return     转换后的字符串指针
*/
char* FloatAsc2Right(float value, uint8_t dot)
{
    float temp_val, compensate;
    uint16_t n, int_num, int_temp;
    uint8_t i,j,k;
    static char temp_char[9] = {0};
	temp_char[8] = 0;  //字符串结尾,字符串输出函数需要检测字符串结尾,如果没有这个会导致字符串输出的时候多一位
    i = 2 - dot;   //根据小数点数移位
    compensate = 0.51;
		
    for(j = 0;j < 8;j++)  //初始化字符串数组,static变量如果不赋值就会保留原来的值
    {
		temp_char[j] = ' ';
	}
	
    for(k = 0; k < dot; k++)              //根据小数点位数加数值起到四舍五入的作用
    {
        compensate = compensate / 10;
    }
    
    temp_val = value + compensate;       //由于浮点数运算问题需要加个数
    int_num  = (uint16_t)temp_val;
    int_temp = int_num;   

	if(dot == 0)
	{
		i++;
	}
	
    n = 10000;
	if(int_num == 0)
	{
		i = i+4;
	}else
	{
		while(n > 0)
		{
			if(int_num >= n)
			{
				temp_char[i] = (char)(int_temp / n) + 48;
				int_temp = int_temp % n; 		        
			}
			i += 1;		
			n /= 10;
		}
	}

    if(temp_val < 1)
    {
        temp_char[i] = 48;
        i +=1;
    }

    int_temp = (uint16_t)((temp_val - int_num) * 10000);

    if(dot > 0)
    {
        temp_char[i] = 46;
        i += 1;
        temp_char[i] = (char)(int_temp / 1000) + 48;
        i += 1;
    }

    if(dot > 1)
    {
        int_temp = int_temp % 1000;
        temp_char[i] = (char)(int_temp / 100) + 48;
        i += 1;
    }
	
	return temp_char;
}

/**
* \brief 浮点数转换至ASC2(左对齐)
*        把浮点数值转化为ASC2码,小数点后最多2位
*        超过部分将被忽略,数值字符为ASCII字符。
*        转换后的字符为右对齐
*
* \param[in]  value 需要转化的数值   转换数值0~99999
* \param[in]  dot 小数点后位数       小数点最大为2
* \return     转换后的字符串指针
*/
char* FloatAsc2Left(float value, uint8_t dot)
{
    float temp_val, compensate;
    uint16_t n, int_num, int_temp;
    uint8_t i,j,k;
    static char temp_char[8] = {0};
	i = 0;
    compensate = 0.51;
		
    for(j = 0;j < 8;j++)  //初始化字符串数组,static变量如果不赋值就会保留原来的值
    {
		temp_char[j] = 0;
	}
	
    for(k = 0; k < dot; k++)              //根据小数点位数加数值起到四舍五入的作用
    {
        compensate = compensate / 10;
    }
    
    temp_val = value + compensate;       //由于浮点数运算问题需要加个数
    int_num  = (uint16_t)temp_val;
    int_temp = int_num;   

    n = 10000;
	while(n > 0)
	{
		if(int_num >= n)
		{
			temp_char[i] = (char)(int_temp / n) + 48;
			int_temp = int_temp % n; 	
			i += 1;
		}					
		n /= 10;
	}

    if(temp_val < 1)
    {
        temp_char[i] = 48;
        i +=1;
    }

    int_temp = (uint16_t)((temp_val - int_num) * 10000);

    if(dot > 0)
    {
        temp_char[i] = 46;
        i += 1;
        temp_char[i] = (char)(int_temp / 1000) + 48;
        i += 1;
    }

    if(dot > 1)
    {
        int_temp = int_temp % 1000;
        temp_char[i] = (char)(int_temp / 100) + 48;
        i += 1;
    }
	
	return temp_char;
}
/**
* \brief      函数功能:显示字符串
*             
* \param[in]  x,y:起点坐标
*             width,height:区域大小  
*             size:字体大小
*             *p:字符串起始地址	
* \return   
*            
*/  
void LCD_ShowString(uint16_t x,uint16_t y,uint16_t width,uint16_t height,uint8_t size,volatile char *p)
{         
	uint8_t x0=x;
	width+=x;
	height+=y;
    while((*p<='~')&&(*p>=' '))//判断是不是非法字符!
    {       
        if(x>=width){x=x0;y+=size;}
        if(y>=height)break;//退出
        LCD_ShowChar(x,y,*p,size,0);
        x+=size/2;
        p++;
    }  
}
/**
* \brief      函数功能:显示一个指定大小的汉字
*             显示24x24汉字,字体采用横向取模方式(即从左到右然后从上到下)
* \param[in]  x,y :汉字的坐标
*             size:字体大小
*             mode:0,正常显示,1,叠加显示
* \return   
*            
*/								   
void LCD_ShowFont(uint16_t x,uint16_t y,uint8_t size,const volatile char *p,uint8_t mode)
{
	uint16_t i=0,j=0,k=0;
	uint16_t num_font;
	uint16_t x0=x;
    if(size == 24)
	{
		num_font = sizeof(GB24_Code) / sizeof(typFNT_GB24);  //计算字库中汉字个数		
	
		for(i=0;i<num_font;i++)//在所有的汉字结构体数组中查找
		{
			if((*p==GB24_Code[i].Index[0]) && (*(p+1)==GB24_Code[i].Index[1]))//索引汉字成功
			{ 
				for(j=0;j<MSKNUM24;j++)//写入数据
				{
					unsigned short word=GB24_Code[i].Msk[j];
					for(k=0;k<8;k++)//循环8次移位
					{
						if(word&0x80)LCD_Fast_DrawPoint(x,y,PointColor);
						else if(mode==0)LCD_Fast_DrawPoint(x,y,BackColor);	 		            
						word<<=1;//往前移位
						x++;
						if((x-x0)==size)
						{
							x=x0;
							y++;
							break;
						}		
					}
				}
			}
		}
	}else if(size == 32)
	{
		num_font = sizeof(GB32_Code) / sizeof(typFNT_GB32);  //计算字库中汉字个数		
	
		for(i=0;i<num_font;i++)//在所有的汉字结构体数组中查找
		{
			if((*p==GB32_Code[i].Index[0]) && (*(p+1)==GB32_Code[i].Index[1]))//索引汉字成功
			{ 
				for(j=0;j<MSKNUM32;j++)//写入数据
				{
					unsigned short word=GB32_Code[i].Msk[j];
					for(k=0;k<8;k++)//循环8次移位
					{
						if(word&0x80)LCD_Fast_DrawPoint(x,y,PointColor);
						else if(mode==0)LCD_Fast_DrawPoint(x,y,BackColor);	 		            
						word<<=1;//往前移位
						x++;
						if((x-x0)==size)
						{
							x=x0;
							y++;
							break;
						}		
					}
				}
			}
		}
	}else
	{
		; //字体大小不合法
	}
}
/**
* \brief      函数功能:显示一个单色位位图片
*             
* \param[in]  x,y :图片坐标
*             width,heigth :显示区域
*             data :图片数据
*             mode:0,正常显示,1,叠加显示
* \return   
*            
*/
void LCD_ShowPicture(uint16_t x,uint16_t y,uint16_t width,uint16_t heigth, const uint8_t *data,uint8_t mode)
{
	uint16_t i=0,j=0;
	uint16_t num_font;
	uint16_t x0=x;
    
	num_font = width * heigth / 8;  //计算图片字节数
	
	for(i=0;i<num_font;i++)//在所有的汉字结构体数组中查找,i最大为结构体数组成员的个数
	{
		uint8_t word=data[i];
		for(j=0;j<8;j++)//循环8次移位
		{
			if(word&0x80)LCD_Fast_DrawPoint(x,y,WHITE);
			else if(mode==0)LCD_Fast_DrawPoint(x,y,BackColor);	 		            
			word<<=1;//往前移位
			x++;
			if((x-x0)==width)
			{
				x=x0;
				y++;
				break;
			}		
		}		
	}
}
/**
* \brief      函数功能:在指定位置开始显示一个字符串	
*             支持自动换行
* \param[in]  (x,y):起始坐标
*             width,height:区域
*             str  :字符串
*             size :字体大小
*             mode:0,非叠加方式;1,叠加方式
* \return   
*            
*/    	   		   
void LCD_ShowText(uint16_t x,uint16_t y,uint16_t width,uint16_t height,volatile char*str,uint8_t size,uint8_t mode)
{											  	   	    				    				  	  
    while(*str!=0)//数据未结束
    { 
	        if((uint8_t)*str<0x81)//字符
	        {      
				LCD_ShowChar(x,y,*str,size,mode);//有效部分写入 
				str++; 
		        x+=size/2; //字符,为全字的一半 
	        }
        else//中文 
        {     						     
	        LCD_ShowFont(x,y,size,str,mode); //显示这个汉字,空心显示 
	        str+=2; 
	        x+=size;//下一个汉字偏移	    
        }						 
    }   
}  			 		 

/*@}*/
LTDC.H

```c
#ifndef _LCD_H
#define _LCD_H
#include "sys.h" 

//LCD LTDC重要参数集
typedef struct  
{							 
	uint32_t pwidth;			//LCD面板的宽度,固定参数,不随显示方向改变,如果为0,说明没有任何RGB屏接入
	uint32_t pheight;		//LCD面板的高度,固定参数,不随显示方向改变
	uint16_t hsw;			//水平同步宽度
	uint16_t vsw;			//垂直同步宽度
	uint16_t hbp;			//水平后廊
	uint16_t vbp;			//垂直后廊
	uint16_t hfp;			//水平前廊
	uint16_t vfp;			//垂直前廊 
	uint8_t activelayer;		//当前层编号:0/1	
	uint8_t dir;				//0,竖屏;1,横屏;
	uint16_t width;			//LCD宽度
	uint16_t height;			//LCD高度
	uint32_t pixsize;		//每个像素所占字节数
}_ltdc_dev; 

extern _ltdc_dev lcdltdc;		            //管理LCD LTDC参数
extern LTDC_HandleTypeDef LTDC_Handler;	    //LTDC句柄
extern DMA2D_HandleTypeDef DMA2D_Handler;   //DMA2D句柄

#define LCD_PIXEL_FORMAT_ARGB8888       0X00    
#define LCD_PIXEL_FORMAT_RGB888         0X01    
#define LCD_PIXEL_FORMAT_RGB565         0X02       
#define LCD_PIXEL_FORMAT_ARGB1555       0X03      
#define LCD_PIXEL_FORMAT_ARGB4444       0X04     
#define LCD_PIXEL_FORMAT_L8             0X05     
#define LCD_PIXEL_FORMAT_AL44           0X06     
#define LCD_PIXEL_FORMAT_AL88           0X07      

///
//用户修改配置部分:

//定义颜色像素格式,一般用RGB565
#define LCD_PIXFORMAT				LCD_PIXEL_FORMAT_RGB565	
//定义默认背景层颜色
#define LTDC_BACKLAYERCOLOR			BLACK	
//LCD帧缓冲区首地址,这里定义在SDRAM里面.
#define LCD_FRAME_BUF_ADDR			0XC0000000  

void LTDC_Switch(uint8_t sw);					//LTDC开关
void LTDC_Layer_Switch(uint8_t layerx,uint8_t sw);	//层开关
void LTDC_Select_Layer(uint8_t layerx);			//层选择
void LTDC_Display_Dir(uint8_t dir);				//显示方向控制
void LTDC_Draw_Point(uint16_t x,uint16_t y,uint32_t color);//画点函数
uint32_t LTDC_Read_Point(uint16_t x,uint16_t y);			//读点函数
void LTDC_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint32_t color);			//矩形单色填充函数
void LTDC_Color_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t *color);	//矩形彩色填充函数
void LTDC_Clear(uint32_t color);					//清屏函数
uint8_t LTDC_Clk_Set(uint32_t pllsain,uint32_t pllsair,uint32_t pllsaidivr);//LTDC时钟配置
void LTDC_Layer_Window_Config(uint8_t layerx,uint16_t sx,uint16_t sy,uint16_t width,uint16_t height);//LTDC层窗口设置
void LTDC_Layer_Parameter_Config(uint8_t layerx,uint32_t bufaddr,uint8_t pixformat,uint8_t alpha,uint8_t alpha0,uint8_t bfac1,uint8_t bfac2,uint32_t bkcolor);//LTDC基本参数设置
uint16_t LTDC_PanelID_Read(void);				//LCD ID读取函数
void LTDC_Init(void);						//LTDC初始化函数

LTDC.c

#include "ltdc.h"
#include "lcd.h"

/** \addtogroup ltdc_group ltdc通讯模块 */

/*@{*/

LTDC_HandleTypeDef  LTDC_Handler;	    //LTDC句柄
DMA2D_HandleTypeDef DMA2D_Handler; 	    //DMA2D句柄

//根据不同的颜色格式,定义帧缓存数组
#if LCD_PIXFORMAT==LCD_PIXFORMAT_ARGB8888||LCD_PIXFORMAT==LCD_PIXFORMAT_RGB888
	uint32_t ltdc_lcd_framebuf[1280][800] __attribute__((at(LCD_FRAME_BUF_ADDR)));	//定义最大屏分辨率时,LCD所需的帧缓存数组大小
#else
	uint16_t ltdc_lcd_framebuf[1280][800] __attribute__((at(LCD_FRAME_BUF_ADDR)));	//定义最大屏分辨率时,LCD所需的帧缓存数组大小
#endif

uint32_t *ltdc_framebuf[2];					//LTDC LCD帧缓存数组指针,必须指向对应大小的内存区域
_ltdc_dev lcdltdc;						//管理LCD LTDC的重要参数
/**
* \brief      函数功能:打开LCD开关
*
* \param[in]  sw:1 打开,0,关闭
* \return   
*            
*/
void LTDC_Switch(uint8_t sw)
{
	if(sw==1) __HAL_LTDC_ENABLE(&LTDC_Handler);
	else if(sw==0)__HAL_LTDC_DISABLE(&LTDC_Handler);
}
/**
* \brief      函数功能:开关指定层
*
* \param[in]  layerx:层号,0,第一层; 1,第二层
*             sw:1 打开;0关闭
* \return   
*            
*/
void LTDC_Layer_Switch(uint8_t layerx,uint8_t sw)
{
	if(sw==1) __HAL_LTDC_LAYER_ENABLE(&LTDC_Handler,layerx);
	else if(sw==0) __HAL_LTDC_LAYER_DISABLE(&LTDC_Handler,layerx);
	__HAL_LTDC_RELOAD_CONFIG(&LTDC_Handler);
}
/**
* \brief      函数功能:选择层
*
* \param[in]  layerx:层号;0,第一层;1,第二层;
* \return   
*            
*/
void LTDC_Select_Layer(uint8_t layerx)
{
	lcdltdc.activelayer=layerx;
}
/**
* \brief      函数功能:设置LCD显示方向
*
* \param[in]  dir:0,竖屏;1,横屏
* \return   
*            
*/
void LTDC_Display_Dir(uint8_t dir)
{
    lcdltdc.dir=dir; 	//显示方向
	if(dir==0)			//竖屏
	{
		lcdltdc.width=lcdltdc.pheight;
		lcdltdc.height=lcdltdc.pwidth;	
	}else if(dir==1)	//横屏
	{
		lcdltdc.width=lcdltdc.pwidth;
		lcdltdc.height=lcdltdc.pheight;
	}
}
/**
* \brief      函数功能:画点函数
*
* \param[in]  x,y:写入坐标
*             color:颜色值
* \return   
*            
*/
void LTDC_Draw_Point(uint16_t x,uint16_t y,uint32_t color)
{ 
#if LCD_PIXFORMAT==LCD_PIXFORMAT_ARGB8888||LCD_PIXFORMAT==LCD_PIXFORMAT_RGB888
	if(lcdltdc.dir)	//横屏
	{
        *(uint32_t*)((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*y+x))=color;
	}else 			//竖屏
	{
        *(uint32_t*)((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*(lcdltdc.pheight-x)+y))=color; 
	}
#else
	if(lcdltdc.dir)	//横屏
	{
        *(uint16_t*)((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*y+x))=color;
	}else 			//竖屏
	{
        *(uint16_t*)((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*(lcdltdc.pheight-x-1)+y))=color; 
	}
#endif
}
/**
* \brief      函数功能:读点函数
*
* \param[in]  x,y:读取点的坐标
*             返回值:颜色值
* \return   
*            
*/
uint32_t LTDC_Read_Point(uint16_t x,uint16_t y)
{ 
#if LCD_PIXFORMAT==LCD_PIXFORMAT_ARGB8888||LCD_PIXFORMAT==LCD_PIXFORMAT_RGB888
	if(lcdltdc.dir)	//横屏
	{
		return *(uint32_t*)((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*y+x));
	}else 			//竖屏
	{
		return *(uint32_t*)((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*(lcdltdc.pheight-x)+y)); 
	}
#else
	if(lcdltdc.dir)	//横屏
	{
		return *(uint16_t*)((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*y+x));
	}else 			//竖屏
	{
		return *(uint16_t*)((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*(lcdltdc.pheight-x-1)+y)); 
	}
#endif 
}
/**
* \brief      函数功能:LTDC填充矩形,DMA2D填充
*             有时候需要频繁的调用填充函数,所以为了速度,填充函数采用寄存器版本
* \param[in]  (sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
*             color:要填充的颜色
* \return   
*            
*/
void LTDC_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint32_t color)
{ 
	uint32_t psx,psy,pex,pey;	//以LCD面板为基准的坐标系,不随横竖屏变化而变化
	uint32_t timeout=0; 
	uint16_t offline;
	uint32_t addr; 
	//坐标系转换
	if(lcdltdc.dir)	//横屏
	{
		psx=sx;psy=sy;
		pex=ex;pey=ey;
	}else			//竖屏
	{
		psx=sy;psy=lcdltdc.pheight-ex-1;
		pex=ey;pey=lcdltdc.pheight-sx-1;
	}
	offline=lcdltdc.pwidth-(pex-psx+1);
	addr=((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*psy+psx));
	__HAL_RCC_DMA2D_CLK_ENABLE();	//使能DM2D时钟
	DMA2D->CR&=~(DMA2D_CR_START);	//先停止DMA2D
	DMA2D->CR=DMA2D_R2M;			//寄存器到存储器模式
	DMA2D->OPFCCR=LCD_PIXFORMAT;	//设置颜色格式
	DMA2D->OOR=offline;				//设置行偏移 

	DMA2D->OMAR=addr;				//输出存储器地址
	DMA2D->NLR=(pey-psy+1)|((pex-psx+1)<<16);	//设定行数寄存器
	DMA2D->OCOLR=color;						//设定输出颜色寄存器 
	DMA2D->CR|=DMA2D_CR_START;				//启动DMA2D
	while((DMA2D->ISR&(DMA2D_FLAG_TC))==0)	//等待传输完成
	{
		timeout++;
		if(timeout>0X1FFFFF)break;	//超时退出
	} 
	DMA2D->IFCR|=DMA2D_FLAG_TC;		//清除传输完成标志 		
}
/**
* \brief      函数功能:在指定区域内填充指定颜色块,DMA2D填充	
*             此函数仅支持uint16_t,RGB565格式的颜色数组填充.
* \param[in]  sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
*                 注意:sx,ex,不能大于lcddev.width-1;sy,ey,不能大于lcddev.height-1!!!
*             color:要填充的颜色数组首地址
* \return   
*            
*/
void LTDC_Color_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t *color)
{
	uint32_t psx,psy,pex,pey;	//以LCD面板为基准的坐标系,不随横竖屏变化而变化
	uint32_t timeout=0; 
	uint16_t offline;
	uint32_t addr; 
	//坐标系转换
	if(lcdltdc.dir)	//横屏
	{
		psx=sx;psy=sy;
		pex=ex;pey=ey;
	}else			//竖屏
	{
		psx=sy;psy=lcdltdc.pheight-ex-1;
		pex=ey;pey=lcdltdc.pheight-sx-1;
	}
	offline=lcdltdc.pwidth-(pex-psx+1);
	addr=((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*psy+psx));
	__HAL_RCC_DMA2D_CLK_ENABLE();	//使能DM2D时钟
	DMA2D->CR&=~(DMA2D_CR_START);	//先停止DMA2D
	DMA2D->CR=DMA2D_M2M;			//存储器到存储器模式
	DMA2D->FGPFCCR=LCD_PIXFORMAT;	//设置颜色格式
	DMA2D->FGOR=0;					//前景层行偏移为0
	DMA2D->OOR=offline;				//设置行偏移 

	DMA2D->FGMAR=(uint32_t)color;		//源地址
	DMA2D->OMAR=addr;				//输出存储器地址
	DMA2D->NLR=(pey-psy+1)|((pex-psx+1)<<16);	//设定行数寄存器 
	DMA2D->CR|=DMA2D_CR_START;					//启动DMA2D
	while((DMA2D->ISR&(DMA2D_FLAG_TC))==0)		//等待传输完成
	{
		timeout++;
		if(timeout>0X1FFFFF)break;	//超时退出
	} 
	DMA2D->IFCR|=DMA2D_FLAG_TC;				//清除传输完成标志  	
}  
/**
* \brief      函数功能:LCD清屏
*
* \param[in]  color:颜色值
* \return   
*            
*/
void LTDC_Clear(uint32_t color)
{
	LTDC_Fill(0,0,lcdltdc.width-1,lcdltdc.height-1,color);
}
/**
* \brief      函数功能:LTDC时钟(Fdclk)设置函数
*             Fvco=Fin*pllsain; 
*             Fdclk=Fvco/pllsair/2*2^pllsaidivr=Fin*pllsain/pllsair/2*2^pllsaidivr;
*             假设:外部晶振为25M,pllm=25的时候,Fin=1Mhz.
*             例如:要得到20M的LTDC时钟,则可以设置:pllsain=400,pllsair=5,pllsaidivr=RCC_PLLSAIDIVR_4
*             Fdclk=1*400/5/4=400/20=20Mhz
*
* \param[in]  Fvco:VCO频率
*             Fin:输入时钟频率一般为1Mhz(来自系统时钟PLLM分频后的时钟,见时钟树图)
*             pllsain:SAI时钟倍频系数N,取值范围:50~432.  
*             pllsair:SAI时钟的分频系数R,取值范围:2~7
*             pllsaidivr:LCD时钟分频系数,取值范围:RCC_PLLSAIDIVR_2/4/8/16,对应分频2~16 
* \return     0,成功;1,失败。
*            
*/
uint8_t LTDC_Clk_Set(uint32_t pllsain,uint32_t pllsair,uint32_t pllsaidivr)
{
	RCC_PeriphCLKInitTypeDef PeriphClkIniture;
	
	//LTDC输出像素时钟,需要根据自己所使用的LCD数据手册来配置!
    PeriphClkIniture.PeriphClockSelection=RCC_PERIPHCLK_LTDC;	//LTDC时钟 	
	PeriphClkIniture.PLLSAI.PLLSAIN=pllsain;    
	PeriphClkIniture.PLLSAI.PLLSAIR=pllsair;  
	PeriphClkIniture.PLLSAIDivR=pllsaidivr;
	if(HAL_RCCEx_PeriphCLKConfig(&PeriphClkIniture)==HAL_OK)    //配置像素时钟
    {
        return 0;   //成功
    }
    else return 1;  //失败    
}
/**
* \brief      函数功能:LTDC,层颜窗口设置,窗口以LCD面板坐标系为基准
*             注意:此函数必须在LTDC_Layer_Parameter_Config之后再设置.
* \param[in]  layerx:层值,0/1.
*             sx,sy:起始坐标
*             width,height:宽度和高度
* \return   
*            
*/
void LTDC_Layer_Window_Config(uint8_t layerx,uint16_t sx,uint16_t sy,uint16_t width,uint16_t height)
{
    HAL_LTDC_SetWindowPosition(&LTDC_Handler,sx,sy,layerx);  //设置窗口的位置
    HAL_LTDC_SetWindowSize(&LTDC_Handler,width,height,layerx);//设置窗口大小    
}
/**
* \brief      函数功能:LTDC,基本参数设置.
*             注意:此函数,必须在LTDC_Layer_Window_Config之前设置.
* \param[in]  layerx:层值,0/1.
*             bufaddr:层颜色帧缓存起始地址
*             pixformat:颜色格式.0,ARGB8888;1,RGB888;2,RGB565;3,ARGB1555;4,ARGB4444;5,L8;6;AL44;7;AL88
*             alpha:层颜色Alpha值,0,全透明;255,不透明
*             alpha0:默认颜色Alpha值,0,全透明;255,不透明
*             bfac1:混合系数1,4(100),恒定的Alpha;6(101),像素Alpha*恒定Alpha
*             bfac2:混合系数2,5(101),恒定的Alpha;7(111),像素Alpha*恒定Alpha
*             bkcolor:层默认颜色,32位,低24位有效,RGB888格式
* \return   
*            
*/
void LTDC_Layer_Parameter_Config(uint8_t layerx,uint32_t bufaddr,uint8_t pixformat,uint8_t alpha,uint8_t alpha0,uint8_t bfac1,uint8_t bfac2,uint32_t bkcolor)
{
	LTDC_LayerCfgTypeDef pLayerCfg;
	
	pLayerCfg.WindowX0=0;                       //窗口起始X坐标
	pLayerCfg.WindowY0=0;                       //窗口起始Y坐标
	pLayerCfg.WindowX1=lcdltdc.pwidth;          //窗口终止X坐标
	pLayerCfg.WindowY1=lcdltdc.pheight;         //窗口终止Y坐标
	pLayerCfg.PixelFormat=pixformat;		    //像素格式
	pLayerCfg.Alpha=alpha;				        //Alpha值设置,0~255,255为完全不透明
	pLayerCfg.Alpha0=alpha0;			        //默认Alpha值
	pLayerCfg.BlendingFactor1=(uint32_t)bfac1<<8;    //设置层混合系数
	pLayerCfg.BlendingFactor2=(uint32_t)bfac2<<8;	//设置层混合系数
	pLayerCfg.FBStartAdress=bufaddr;	        //设置层颜色帧缓存起始地址
	pLayerCfg.ImageWidth=lcdltdc.pwidth;        //设置颜色帧缓冲区的宽度    
	pLayerCfg.ImageHeight=lcdltdc.pheight;      //设置颜色帧缓冲区的高度
	pLayerCfg.Backcolor.Red=(uint8_t)(bkcolor&0X00FF0000)>>16;   //背景颜色红色部分
	pLayerCfg.Backcolor.Green=(uint8_t)(bkcolor&0X0000FF00)>>8;  //背景颜色绿色部分
	pLayerCfg.Backcolor.Blue=(uint8_t)bkcolor&0X000000FF;        //背景颜色蓝色部分
	HAL_LTDC_ConfigLayer(&LTDC_Handler,&pLayerCfg,layerx);   //设置所选中的层
}  
/**
* \brief      函数功能:LCD初始化函数
*             
* \param[in]  
*             
* \return   
*            
*/
void LTDC_Init(void)
{   	
	lcdltdc.pwidth=LCD_HOR_RESOLUTION;			    //面板宽度,单位:像素
	lcdltdc.pheight=LCD_VER_RESOLUTION;		        //面板高度,单位:像素
	lcdltdc.hsw=LCD_HOR_PULSE_WIDTH;			    //水平同步宽度
	lcdltdc.vsw=LCD_VER_PULSE_WIDTH;			    //垂直同步宽度
	lcdltdc.hbp=LCD_HOR_BACK_PORCH;				    //水平后廊
	lcdltdc.vbp=LCD_VER_BACK_PORCH;				    //垂直后廊
	lcdltdc.hfp=LCD_HOR_FRONT_PORCH;			    //水平前廊
    lcdltdc.vfp=LCD_VER_FRONT_PORCH;			    //垂直前廊
    LTDC_Clk_Set(400,4,RCC_PLLSAIDIVR_4);           //设置像素时钟 25Mhz 
		//其他参数待定.

	lcddev.width=lcdltdc.pwidth;
	lcddev.height=lcdltdc.pheight;
    
#if LCD_PIXFORMAT==LCD_PIXFORMAT_ARGB8888||LCD_PIXFORMAT==LCD_PIXFORMAT_RGB888 
	ltdc_framebuf[0]=(uint32_t*)&ltdc_lcd_framebuf;
	lcdltdc.pixsize=4;				//每个像素占4个字节
#else 
    lcdltdc.pixsize=2;				//每个像素占2个字节
	ltdc_framebuf[0]=(uint32_t*)&ltdc_lcd_framebuf;
#endif 	
    //LTDC配置
    LTDC_Handler.Instance=LTDC;
    LTDC_Handler.Init.HSPolarity=LTDC_HSPOLARITY_AL;         //水平同步极性
    LTDC_Handler.Init.VSPolarity=LTDC_VSPOLARITY_AL;         //垂直同步极性
    LTDC_Handler.Init.DEPolarity=LTDC_DEPOLARITY_AL;         //数据使能极性
    LTDC_Handler.Init.PCPolarity=LTDC_PCPOLARITY_IPC;   	//像素时钟极性
    LTDC_Handler.Init.HorizontalSync=lcdltdc.hsw-1;          //水平同步宽度
    LTDC_Handler.Init.VerticalSync=lcdltdc.vsw-1;            //垂直同步宽度
    LTDC_Handler.Init.AccumulatedHBP=lcdltdc.hsw+lcdltdc.hbp-1; //水平同步后沿宽度
    LTDC_Handler.Init.AccumulatedVBP=lcdltdc.vsw+lcdltdc.vbp-1; //垂直同步后沿高度
    LTDC_Handler.Init.AccumulatedActiveW=lcdltdc.hsw+lcdltdc.hbp+lcdltdc.pwidth-1;//有效宽度
    LTDC_Handler.Init.AccumulatedActiveH=lcdltdc.vsw+lcdltdc.vbp+lcdltdc.pheight-1;//有效高度
    LTDC_Handler.Init.TotalWidth=lcdltdc.hsw+lcdltdc.hbp+lcdltdc.pwidth+lcdltdc.hfp-1;   //总宽度
    LTDC_Handler.Init.TotalHeigh=lcdltdc.vsw+lcdltdc.vbp+lcdltdc.pheight+lcdltdc.vfp-1;  //总高度
    LTDC_Handler.Init.Backcolor.Red=0XFF;           //屏幕背景层红色部分
    LTDC_Handler.Init.Backcolor.Green=0XFF;         //屏幕背景层绿色部分
    LTDC_Handler.Init.Backcolor.Blue=0XFF;          //屏幕背景色蓝色部分
    HAL_LTDC_Init(&LTDC_Handler);
 	
	//层配置
	LTDC_Layer_Parameter_Config(0,(uint32_t)ltdc_framebuf[0],LCD_PIXFORMAT,255,0,6,7,0X000000);//层参数配置
	LTDC_Layer_Window_Config(0,0,0,lcdltdc.pwidth,lcdltdc.pheight);	//层窗口配置,以LCD面板坐标系为基准,不要随便修改!
	
 	LTDC_Display_Dir(1);			//默认横屏
	LTDC_Select_Layer(0); 			//选择第1层
    LCD_BlackLightOn();         		        //点亮背光
    LTDC_Clear(BLACK);			//清屏
}
/**
* \brief      函数功能:LTDC底层IO初始化和时钟使能
*             此函数会被HAL_LTDC_Init()调用
* \param[in]  hltdc:LTDC句柄
* \return   
*            
*/
void HAL_LTDC_MspInit(LTDC_HandleTypeDef* hltdc)
{
    GPIO_InitTypeDef GPIO_Initure;
    
    __HAL_RCC_LTDC_CLK_ENABLE();                //使能LTDC时钟
    __HAL_RCC_DMA2D_CLK_ENABLE();               //使能DMA2D时钟
  //  __HAL_RCC_GPIOB_CLK_ENABLE();               //使能GPIOB时钟
    __HAL_RCC_GPIOF_CLK_ENABLE();               //使能GPIOF时钟
    __HAL_RCC_GPIOG_CLK_ENABLE();               //使能GPIOG时钟
    __HAL_RCC_GPIOH_CLK_ENABLE();               //使能GPIOH时钟
    __HAL_RCC_GPIOI_CLK_ENABLE();               //使能GPIOI时钟
	
/* 背光在硬件上连了,不用软件控制 
    //初始化PB15,背光引脚
    GPIO_Initure.Pin=GPIO_PIN_15;               //PB15推挽输出,控制背光
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;      //推挽输出
    GPIO_Initure.Pull=GPIO_PULLUP;              //上拉        
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;         //高速
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);
*/    
    //初始化PF10
    GPIO_Initure.Pin=GPIO_PIN_10; 
    GPIO_Initure.Mode=GPIO_MODE_AF_PP;          //复用
    GPIO_Initure.Pull=GPIO_NOPULL;              
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;         //高速
    GPIO_Initure.Alternate=GPIO_AF14_LTDC;      //复用为LTDC
    HAL_GPIO_Init(GPIOF,&GPIO_Initure);
  
 
    //初始化PG6,7,11
    GPIO_Initure.Pin=GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_11;
    HAL_GPIO_Init(GPIOG,&GPIO_Initure);
    
    //初始化PH9,10,11,12,13,14,15
    GPIO_Initure.Pin=GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|\
                     GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
    HAL_GPIO_Init(GPIOH,&GPIO_Initure);
    
    //初始化PI0,1,2,4,5,6,7,9,10
    GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|\
                     GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_9|GPIO_PIN_10;
    HAL_GPIO_Init(GPIOI,&GPIO_Initure); 
}

``

  • 4
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
STM32GD32都是基于ARM Cortex-M内核的微控制器。因此,我们可以通过移植的方式将STM32的应用程序移植到GD32F450上运行。 移植的过程主要包括以下几个步骤: 1. 硬件兼容性的评估:首先需要评估STM32GD32F450之间的硬件兼容性。包括引脚定义和功能,外设接口,时钟配置等。确保GD32F450能够满足STM32应用程序的硬件需求。 2. 代码移植:将STM32的应用程序代码移植到GD32F450上。这需要根据GD32F450的器件文档和引脚定义对代码进行修改。例如,将与引脚相关的代码进行调整,确保外设的初始化和配置正确。 3. 外设适配:GD32F450STM32之间可能存在一些外设差异。在移植过程中,需要对外设进行适配,确保GD32F450上的外设能够与STM32的应用程序正确交互。 4. 系统时钟配置:根据GD32F450的时钟配置要求,对应用程序的系统时钟进行调整。确保系统时钟的稳定性和准确性。 5. 编译和调试:对移植后的代码进行编译和调试。根据GD32F450的开发工具和环境,对代码进行编译和烧录,然后通过调试工具对程序进行调试。 在移植过程中,需要对应用程序的硬件相关代码进行修改,以适配GD32F450的硬件和外设。同时还需注意时钟配置和系统初始化的差异,以确保移植后的应用程序能够在GD32F450上正常运行。 综上所述,将STM32的应用程序移植到GD32F450主要涉及硬件兼容性评估、代码移植、外设适配、系统时钟配置和编译调试等步骤。通过仔细的修改和调试,我们可以成功地将STM32应用程序移植到GD32F450上运行。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

予叶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值