IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 清洁机器人--屏幕显示LCD方案之MCU GD32F470及其液晶RGB接口的LCD驱动代码 -> 正文阅读

[嵌入式]清洁机器人--屏幕显示LCD方案之MCU GD32F470及其液晶RGB接口的LCD驱动代码

  • 1.MCU GD32F470及其液晶RGB接口
    STM32F429 支持LCD RGB硬件接口,但是其存在供货 价格问题,暂时不选,选择国产替代方案。

国产MCU中支持LCD RGB 硬件接口的有GD32F450 GD32F470.根据GD FAE最新消息450不在新推客户,推GD32F470.
2.不同的分辨率涉及不同RAM需求,如内置RAM不足,需要外扩。
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初始化函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
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); 
}

参考:https://blog.csdn.net/weixin_48375064/article/details/120009393
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-04-29 12:18:17  更:2022-04-29 12:18:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 3:46:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码