STM32H750XB_RT-THREAD/26-27-LTDC—液晶显示/1-LTDC—液晶显示英文(字库在内部FLASH)/User/lcd/bsp_lcd.c
2025-07-21 14:34:29 +08:00

1520 lines
44 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
******************************************************************************
* @file bsp_lcd.c
* @author fire
* @version V1.0
* @date 2016-xx-xx
* @brief LCD应用函数接口支持ARGB888/RGB888/RGB565/ARGB4444/ARGB1555 (不含中文显示)
******************************************************************************
* @attention
*
* 实验平台:野火 STM32 H750 开发板
* 论坛 :http://www.firebbs.cn
* 淘宝 :http://firestm32.taobao.com
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "./lcd/bsp_lcd.h"
#include "./fonts//font24.c"
#include "./fonts//font20.c"
#include "./fonts//font16.c"
#include "./fonts//font12.c"
#include "./fonts//font8.c"
#define POLY_X(Z) ((int32_t)((Points + Z)->X))
#define POLY_Y(Z) ((int32_t)((Points + Z)->Y))
#define ABS(X) ((X) > 0 ? (X) : -(X))
static LTDC_HandleTypeDef Ltdc_Handler;
static DMA2D_HandleTypeDef Dma2d_Handler;
/* Default LCD configuration with LCD Layer 1 */
static uint32_t ActiveLayer = 0;
static LCD_DrawPropTypeDef DrawProp[MAX_LAYER_NUMBER];
/**
* @brief Initializes the LCD.
* @param None
* @retval None
*/
/* 不同液晶屏的参数 */
const LCD_PARAM_TypeDef lcd_param[LCD_TYPE_NUM]={
/* 5寸屏参数 */
{
/*根据液晶数据手册的参数配置*/
.hbp = 46, //HSYNC后的无效像素
.vbp = 23, //VSYNC后的无效行数
.hsw = 1, //HSYNC宽度
.vsw = 3, //VSYNC宽度
.hfp = 40, //HSYNC前的无效像素
.vfp = 13, //VSYNC前的无效行数
.comment_clock_2byte = 33, //rgb565/argb4444等双字节像素时推荐使用的液晶时钟频率
.comment_clock_4byte = 21, //Argb8888等四字节像素时推荐使用的液晶时钟频率
.lcd_pixel_width = ((uint16_t)800),//液晶分辨率,宽
.lcd_pixel_height = ((uint16_t)480),//液晶分辨率,高
.m_palette_btn_width = 90,//触摸画板按键的宽度
.m_palette_btn_height = 50,//触摸画板按键的高度
},
/* 7寸屏参数与5寸一样 */
{
/*根据液晶数据手册的参数配置*/
.hbp = 46, //HSYNC后的无效像素
.vbp = 23, //VSYNC后的无效行数
.hsw = 1, //HSYNC宽度
.vsw = 1, //VSYNC宽度
.hfp = 22, //HSYNC前的无效像素
.vfp = 22, //VSYNC前的无效行数
.comment_clock_2byte = 33, //rgb565/argb4444等双字节像素时推荐使用的液晶时钟频率
.comment_clock_4byte = 21, //Argb8888等四字节像素时推荐使用的液晶时钟频率
.lcd_pixel_width = ((uint16_t)800),//液晶分辨率,宽
.lcd_pixel_height = ((uint16_t)480),//液晶分辨率,高
.m_palette_btn_width = 90,//触摸画板按键的宽度
.m_palette_btn_height = 50,//触摸画板按键的高度
},
/* 4.3寸屏参数 */
{
/*根据液晶数据手册的参数配置*/
.hbp = 8, //HSYNC后的无效像素
.vbp = 2, //VSYNC后的无效行数
.hsw = 41, //HSYNC宽度
.vsw = 10, //VSYNC宽度
.hfp = 4, //HSYNC前的无效像素
.vfp = 4, //VSYNC前的无效行数
.comment_clock_2byte = 15, //rgb565/argb4444等双字节像素时推荐使用的液晶时钟频率
.comment_clock_4byte = 15, //Argb8888等四字节像素时推荐使用的液晶时钟频率
.lcd_pixel_width = 480,//液晶分辨率,宽
.lcd_pixel_height = 272,//液晶分辨率,高
.m_palette_btn_width = 50,//触摸画板按键的宽度
.m_palette_btn_height = 30,//触摸画板按键的高度
}
};
LCD_TypeDef cur_lcd = INCH_5;
static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c);
static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3);
static void LL_FillBuffer(uint32_t LayerIndex, void *pDst, uint32_t xSize, uint32_t ySize, uint32_t OffLine, uint32_t ColorIndex);
static void LL_ConvertLineToARGB8888(void * pSrc, void *pDst, uint32_t xSize, uint32_t ColorMode);
/**
* @brief 初始化控制LCD的IO
* @param 无
* @retval 无
*/
static void LCD_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* 使能LCD使用到的引脚时钟 */
//红色数据线
LTDC_R0_GPIO_CLK_ENABLE();LTDC_R1_GPIO_CLK_ENABLE();LTDC_R2_GPIO_CLK_ENABLE();\
LTDC_R3_GPIO_CLK_ENABLE();LTDC_R4_GPIO_CLK_ENABLE();LTDC_R5_GPIO_CLK_ENABLE();\
LTDC_R6_GPIO_CLK_ENABLE();LTDC_R7_GPIO_CLK_ENABLE();LTDC_G0_GPIO_CLK_ENABLE();\
LTDC_G1_GPIO_CLK_ENABLE();LTDC_G2_GPIO_CLK_ENABLE();LTDC_G3_GPIO_CLK_ENABLE();\
LTDC_G3_GPIO_CLK_ENABLE();LTDC_G5_GPIO_CLK_ENABLE();LTDC_G6_GPIO_CLK_ENABLE();\
LTDC_G7_GPIO_CLK_ENABLE();LTDC_B0_GPIO_CLK_ENABLE();LTDC_B1_GPIO_CLK_ENABLE();\
LTDC_B2_GPIO_CLK_ENABLE();LTDC_B3_GPIO_CLK_ENABLE();LTDC_B4_GPIO_CLK_ENABLE();\
LTDC_B5_GPIO_CLK_ENABLE();LTDC_B6_GPIO_CLK_ENABLE();LTDC_B7_GPIO_CLK_ENABLE();\
LTDC_CLK_GPIO_CLK_ENABLE();LTDC_HSYNC_GPIO_CLK_ENABLE();LTDC_VSYNC_GPIO_CLK_ENABLE();\
LTDC_DE_GPIO_CLK_ENABLE();LTDC_BL_GPIO_CLK_ENABLE();
/* GPIO配置 */
/* 红色数据线 */
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Pin = LTDC_R0_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_R0_AF;
HAL_GPIO_Init(LTDC_R0_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_R1_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_R1_AF;
HAL_GPIO_Init(LTDC_R1_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_R2_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_R2_AF;
HAL_GPIO_Init(LTDC_R2_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_R3_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_R3_AF;
HAL_GPIO_Init(LTDC_R3_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_R4_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_R4_AF;
HAL_GPIO_Init(LTDC_R4_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_R5_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_R5_AF;
HAL_GPIO_Init(LTDC_R5_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_R6_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_R6_AF;
HAL_GPIO_Init(LTDC_R6_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_R7_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_R7_AF;
HAL_GPIO_Init(LTDC_R7_GPIO_PORT, &GPIO_InitStruct);
//绿色数据线
GPIO_InitStruct.Pin = LTDC_G0_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_G0_AF;
HAL_GPIO_Init(LTDC_G0_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_G1_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_G1_AF;
HAL_GPIO_Init(LTDC_G1_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_G2_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_G2_AF;
HAL_GPIO_Init(LTDC_G2_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_G3_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_G3_AF;
HAL_GPIO_Init(LTDC_G3_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_G4_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_G4_AF;
HAL_GPIO_Init(LTDC_G4_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_G5_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_G5_AF;
HAL_GPIO_Init(LTDC_G5_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_G6_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_G6_AF;
HAL_GPIO_Init(LTDC_G6_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_G7_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_G7_AF;
HAL_GPIO_Init(LTDC_G7_GPIO_PORT, &GPIO_InitStruct);
//蓝色数据线
GPIO_InitStruct.Pin = LTDC_B0_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_B0_AF;
HAL_GPIO_Init(LTDC_B0_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_B1_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_B1_AF;
HAL_GPIO_Init(LTDC_B1_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_B2_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_B2_AF;
HAL_GPIO_Init(LTDC_B2_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_B3_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_B3_AF;
HAL_GPIO_Init(LTDC_B3_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_B4_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_B4_AF;
HAL_GPIO_Init(LTDC_B4_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_B5_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_B5_AF;
HAL_GPIO_Init(LTDC_B5_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_B6_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_B6_AF;
HAL_GPIO_Init(LTDC_B6_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_B7_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_B7_AF;
HAL_GPIO_Init(LTDC_B7_GPIO_PORT, &GPIO_InitStruct);
//控制信号线
GPIO_InitStruct.Pin = LTDC_CLK_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_CLK_AF;
HAL_GPIO_Init(LTDC_CLK_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_HSYNC_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_HSYNC_AF;
HAL_GPIO_Init(LTDC_HSYNC_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_VSYNC_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_VSYNC_AF;
HAL_GPIO_Init(LTDC_VSYNC_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LTDC_DE_GPIO_PIN;
GPIO_InitStruct.Alternate = LTDC_DE_AF;
HAL_GPIO_Init(LTDC_DE_GPIO_PORT, &GPIO_InitStruct);
//背光BL
GPIO_InitStruct.Pin = LTDC_BL_GPIO_PIN;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(LTDC_BL_GPIO_PORT, &GPIO_InitStruct);
}
/**
* @brief 时钟配置
* @retval 无
*/
void LCD_ClockConfig(void)
{
static RCC_PeriphCLKInitTypeDef periph_clk_init_struct;
/* 液晶屏时钟配置 */
/* 5寸屏的典型PCLK为27 MHz因此PLL3R配置为提供此时钟 */
/* AMPIRE640480 LCD clock configuration */
/* PLL3_VCO Input = HSE_VALUE/PLL3M = 1 Mhz */
/* PLL3_VCO Output = PLL3_VCO Input * PLL3N = 270 Mhz */
/* PLLLCDCLK = PLL3_VCO Output/PLL3R = 270/10 = 27Mhz */
/* LTDC clock frequency = PLLLCDCLK = 27 Mhz */
periph_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
periph_clk_init_struct.PLL3.PLL3M = 25;
periph_clk_init_struct.PLL3.PLL3N = 270;
periph_clk_init_struct.PLL3.PLL3P = 2;
periph_clk_init_struct.PLL3.PLL3Q = 2;
periph_clk_init_struct.PLL3.PLL3R = 10;
HAL_RCCEx_PeriphCLKConfig(&periph_clk_init_struct);
}
void LCD_Init(void)
{
/* 使能LTDC时钟 */
__HAL_RCC_LTDC_CLK_ENABLE();
/* 使能DMA2D时钟 */
__HAL_RCC_DMA2D_CLK_ENABLE();
/* 液晶屏时钟配置 */
LCD_ClockConfig();
/* 初始化LCD引脚 */
LCD_GPIO_Config();
/* 初始化SDRAM 用作LCD 显存*/
SDRAM_Init();
/* 配置LTDC参数 */
Ltdc_Handler.Instance = LTDC;
/* 配置行同步信号宽度(HSW-1) */
Ltdc_Handler.Init.HorizontalSync =HSW-1;
/* 配置垂直同步信号宽度(VSW-1) */
Ltdc_Handler.Init.VerticalSync = VSW-1;
/* 配置(HSW+HBP-1) */
Ltdc_Handler.Init.AccumulatedHBP = HSW+HBP-1;
/* 配置(VSW+VBP-1) */
Ltdc_Handler.Init.AccumulatedVBP = VSW+VBP-1;
/* 配置(HSW+HBP+有效像素宽度-1) */
Ltdc_Handler.Init.AccumulatedActiveW = HSW+HBP+LCD_PIXEL_WIDTH-1;
/* 配置(VSW+VBP+有效像素高度-1) */
Ltdc_Handler.Init.AccumulatedActiveH = VSW+VBP+LCD_PIXEL_HEIGHT-1;
/* 配置总宽度(HSW+HBP+有效像素宽度+HFP-1) */
Ltdc_Handler.Init.TotalWidth =HSW+ HBP+LCD_PIXEL_WIDTH + HFP-1;
/* 配置总高度(VSW+VBP+有效像素高度+VFP-1) */
Ltdc_Handler.Init.TotalHeigh =VSW+ VBP+LCD_PIXEL_HEIGHT + VFP-1;
/* 初始化LCD的像素宽度和高度 */
Ltdc_Handler.LayerCfg->ImageWidth = LCD_PIXEL_WIDTH;
Ltdc_Handler.LayerCfg->ImageHeight = LCD_PIXEL_HEIGHT;
/* 设置LCD背景层的颜色默认黑色 */
Ltdc_Handler.Init.Backcolor.Red = 0;
Ltdc_Handler.Init.Backcolor.Green = 0;
Ltdc_Handler.Init.Backcolor.Blue = 0;
/* 极性配置 */
/* 初始化行同步极性,低电平有效 */
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;
HAL_LTDC_Init(&Ltdc_Handler);
/* 初始化字体 */
LCD_SetFont(&LCD_DEFAULT_FONT);
}
/**
* @brief 获取LCD当前有效层X轴的大小
* @retval X轴的大小
*/
uint32_t LCD_GetXSize(void)
{
return Ltdc_Handler.LayerCfg[ActiveLayer].ImageWidth;
}
/**
* @brief 获取LCD当前有效层Y轴的大小
* @retval Y轴的大小
*/
uint32_t LCD_GetYSize(void)
{
return Ltdc_Handler.LayerCfg[ActiveLayer].ImageHeight;
}
/**
* @brief 设置LCD当前有效层Y轴的大小
* @param imageWidthPixels图像宽度像素个数
* @retval 无
*/
void LCD_SetXSize(uint32_t imageWidthPixels)
{
Ltdc_Handler.LayerCfg[ActiveLayer].ImageWidth = imageWidthPixels;
}
/**
* @brief 设置LCD当前有效层Y轴的大小
* @param imageHeightPixels图像高度像素个数
* @retval None
*/
void LCD_SetYSize(uint32_t imageHeightPixels)
{
Ltdc_Handler.LayerCfg[ActiveLayer].ImageHeight = imageHeightPixels;
}
/**
* @brief 初始化LCD层
* @param LayerIndex: 前景层(层1)或者背景层(层0)
* @param FB_Address: 每一层显存的首地址
* @param PixelFormat: 层的像素格式
* @retval 无
*/
void LCD_LayerInit(uint16_t LayerIndex, uint32_t FB_Address,uint32_t PixelFormat)
{
LTDC_LayerCfgTypeDef layer_cfg;
/* 层初始化 */
layer_cfg.WindowX0 = 0; //窗口起始位置X坐标
layer_cfg.WindowX1 = LCD_GetXSize(); //窗口结束位置X坐标
layer_cfg.WindowY0 = 0; //窗口起始位置Y坐标
layer_cfg.WindowY1 = LCD_GetYSize(); //窗口结束位置Y坐标
layer_cfg.PixelFormat = PixelFormat; //像素格式
layer_cfg.FBStartAdress = FB_Address; //层显存首地址
layer_cfg.Alpha = 255; //用于混合的透明度常量范围0—2550为完全透明
layer_cfg.Alpha0 = 0; //默认透明度常量范围0—2550为完全透明
layer_cfg.Backcolor.Blue = 0; //层背景颜色蓝色分量
layer_cfg.Backcolor.Green = 0; //层背景颜色绿色分量
layer_cfg.Backcolor.Red = 0; //层背景颜色红色分量
layer_cfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;//层混合系数1
layer_cfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;//层混合系数2
layer_cfg.ImageWidth = LCD_GetXSize();//设置图像宽度
layer_cfg.ImageHeight = LCD_GetYSize();//设置图像高度
HAL_LTDC_ConfigLayer(&Ltdc_Handler, &layer_cfg, LayerIndex); //设置选中的层参数
DrawProp[LayerIndex].BackColor = LCD_COLOR_WHITE;//设置层的字体颜色
DrawProp[LayerIndex].pFont = &LCD_DEFAULT_FONT;//设置层的字体类型
DrawProp[LayerIndex].TextColor = LCD_COLOR_BLACK; //设置层的字体背景颜色
__HAL_LTDC_RELOAD_CONFIG(&Ltdc_Handler);//重载层的配置参数
}
/**
* @brief 选择LCD层
* @param LayerIndex: 前景层(层1)或者背景层(层0)
* @retval 无
*/
void LCD_SelectLayer(uint32_t LayerIndex)
{
ActiveLayer = LayerIndex;
}
/**
* @brief 设置LCD层的可视化
* @param LayerIndex: 前景层(层1)或者背景层(层0)
* @param State: 禁能或者使能
* @retval 无
*/
void LCD_SetLayerVisible(uint32_t LayerIndex, FunctionalState State)
{
if(State == ENABLE)
{
__HAL_LTDC_LAYER_ENABLE(&Ltdc_Handler, LayerIndex);
}
else
{
__HAL_LTDC_LAYER_DISABLE(&Ltdc_Handler, LayerIndex);
}
__HAL_LTDC_RELOAD_CONFIG(&Ltdc_Handler);
}
/**
* @brief 设置LCD的透明度常量
* @param LayerIndex: 前景层(层1)或者背景层(层0)
* @param Transparency: 透明度范围0—2550为完全透明
* @retval 无
*/
void LCD_SetTransparency(uint32_t LayerIndex, uint8_t Transparency)
{
HAL_LTDC_SetAlpha(&Ltdc_Handler, Transparency, LayerIndex);
}
/**
* @brief 设置LCD缓冲帧的首地址
* @param LayerIndex: 前景层(层1)或者背景层(层0)
* @param Address: LCD缓冲帧的首地址
* @retval 无
*/
void LCD_SetLayerAddress(uint32_t LayerIndex, uint32_t Address)
{
HAL_LTDC_SetAddress(&Ltdc_Handler, Address, LayerIndex);
}
/**
* @brief 设置显示窗口
* @param LayerIndex: 前景层(层1)或者背景层(层0)
* @param Xpos: LCD X轴起始位置
* @param Ypos: LCD Y轴起始位置
* @param Width: LCD 窗口大小
* @param Height: LCD 窗口大小
* @retval None
*/
void LCD_SetLayerWindow(uint16_t LayerIndex, uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height)
{
/* 重新设置窗口大小 */
HAL_LTDC_SetWindowSize(&Ltdc_Handler, Width, Height, LayerIndex);
/* 重新设置窗口的起始位置 */
HAL_LTDC_SetWindowPosition(&Ltdc_Handler, Xpos, Ypos, LayerIndex);
}
/**
* @brief 设置LCD当前层文字颜色
* @param Color: 文字颜色
* @retval 无
*/
void LCD_SetTextColor(uint32_t Color)
{
DrawProp[ActiveLayer].TextColor = Color;
}
/**
* @brief 获取LCD当前层文字颜色
* @retval 文字颜色
*/
uint32_t LCD_GetTextColor(void)
{
return DrawProp[ActiveLayer].TextColor;
}
/**
* @brief 设置LCD当前层的文字背景颜色
* @param Color: 文字背景颜色
* @retval 无
*/
void LCD_SetBackColor(uint32_t Color)
{
DrawProp[ActiveLayer].BackColor = Color;
}
/**
* @brief 获取LCD当前层的文字背景颜色
* @retval 文字背景颜色
*/
uint32_t LCD_GetBackColor(void)
{
return DrawProp[ActiveLayer].BackColor;
}
/**
* @brief 设置LCD文字的颜色和背景的颜色
* @param TextColor: 指定文字颜色
* @param BackColor: 指定背景颜色
* @retval 无
*/
void LCD_SetColors(uint32_t TextColor, uint32_t BackColor)
{
LCD_SetTextColor (TextColor);
LCD_SetBackColor (BackColor);
}
/**
* @brief 设置LCD当前层显示的字体
* @param fonts: 字体类型
* @retval None
*/
void LCD_SetFont(sFONT *fonts)
{
DrawProp[ActiveLayer].pFont = fonts;
}
/**
* @brief 获取LCD当前层显示的字体
* @retval 字体类型
*/
sFONT *LCD_GetFont(void)
{
return DrawProp[ActiveLayer].pFont;
}
/**
* @brief 读LCD的像素值
* @param Xpos: X 轴坐标位置
* @param Ypos: Y 轴坐标位置
* @retval RGB像素值
*/
uint32_t LCD_ReadPixel(uint16_t Xpos, uint16_t Ypos)
{
uint32_t ret = 0;
if(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888)
{
/* 从SDRAM显存中读取颜色数据 */
ret = *(__IO uint32_t*) (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*LCD_GetXSize() + Xpos)));
}
else if(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB888)
{
/* 从SDRAM显存中读取颜色数据 */
ret = (*(__IO uint8_t*) (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress + (3*(Ypos*LCD_GetXSize() + Xpos))+2) & 0x00FFFFFF);
ret |= (*(__IO uint8_t*) (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress + (3*(Ypos*LCD_GetXSize() + Xpos))+1) & 0x00FFFFFF);
ret |= (*(__IO uint8_t*) (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress + (3*(Ypos*LCD_GetXSize() + Xpos))) & 0x00FFFFFF);
}
else if((Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) || \
(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB4444) || \
(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_AL88))
{
/* 从SDRAM显存中读取颜色数据 */
ret = *(__IO uint16_t*) (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*LCD_GetXSize() + Xpos)));
}
else
{
/* 从SDRAM显存中读取颜色数据 */
ret = *(__IO uint8_t*) (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*LCD_GetXSize() + Xpos)));
}
return ret;
}
/**
* @brief LCD当前层清屏
* @param Color: 背景颜色
* @retval None
*/
void LCD_Clear(uint32_t Color)
{
/* 清屏 */
LL_FillBuffer(ActiveLayer, (uint32_t *)(Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress), LCD_GetXSize(), LCD_GetYSize(), 0, Color);
}
/**
* @brief 清除一行
* @param Line: 行
* @retval None
*/
void LCD_ClearLine(uint32_t Line)
{
uint32_t color_backup = DrawProp[ActiveLayer].TextColor;
DrawProp[ActiveLayer].TextColor = DrawProp[ActiveLayer].BackColor;
/* 画一个跟背景色一致的矩形完成清除 */
LCD_FillRect(0, (Line * DrawProp[ActiveLayer].pFont->Height), LCD_GetXSize(), DrawProp[ActiveLayer].pFont->Height);
DrawProp[ActiveLayer].TextColor = color_backup;
LCD_SetTextColor(DrawProp[ActiveLayer].TextColor);
HAL_Delay(1);
}
/**
* @brief 显示一个字符
* @param Xpos: X轴起始坐标
* @param Ypos: Y轴起始坐标
* @param Ascii: 字符 ascii 码,范围( 0x20 —0x7E
* @retval 无
*/
void LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii)
{
DrawChar(Xpos, Ypos, &DrawProp[ActiveLayer].pFont->table[(Ascii-' ') *\
DrawProp[ActiveLayer].pFont->Height * ((DrawProp[ActiveLayer].pFont->Width + 7) / 8)]);
}
/**
* @brief 显示字符串
* @param Xpos: X轴起始坐标
* @param Ypos: Y轴起始坐标
* @param Text: 字符串指针
* @param Mode: 显示对齐方式可以是CENTER_MODE、RIGHT_MODE、LEFT_MODE
* @retval None
*/
void LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Text_AlignModeTypdef Mode)
{
uint16_t ref_column = 1, i = 0;
uint32_t size = 0, xsize = 0;
uint8_t *ptr = Text;
/* 获取字符串大小 */
while (*ptr++) size ++ ;
/* 每一行可以显示字符的数量 */
xsize = (LCD_GetXSize()/DrawProp[ActiveLayer].pFont->Width);
switch (Mode)
{
case CENTER_MODE:
{
ref_column = Xpos + ((xsize - size)* DrawProp[ActiveLayer].pFont->Width) / 2;
break;
}
case LEFT_MODE:
{
ref_column = Xpos;
break;
}
case RIGHT_MODE:
{
ref_column = - Xpos + ((xsize - size)*DrawProp[ActiveLayer].pFont->Width);
break;
}
default:
{
ref_column = Xpos;
break;
}
}
/*检查起始行是否在显示范围内 */
if ((ref_column < 1) || (ref_column >= 0x8000))
{
ref_column = 1;
}
/* 使用字符显示函数显示每一个字符*/
while ((*Text != 0) & (((LCD_GetXSize() - (i*DrawProp[ActiveLayer].pFont->Width)) & 0xFFFF)\
>= DrawProp[ActiveLayer].pFont->Width))
{
/* 显示一个字符 */
LCD_DisplayChar(ref_column, Ypos, *Text);
/* 根据字体大小计算下一个偏移位置 */
ref_column += DrawProp[ActiveLayer].pFont->Width;
/* 指针指向下一个字符 */
Text++;
i++;
}
}
/**
* @brief 在指定行显示字符串(最多60个)
* @param Line: 显示的行
* @param ptr: 字符串指针
* @retval 无
*/
void LCD_DisplayStringLine(uint16_t Line, uint8_t *ptr)
{
LCD_DisplayStringAt(0, LINE(Line), ptr, LEFT_MODE);
}
/**
* @brief 绘制水平线
* @param Xpos: X轴起始坐标
* @param Ypos: Y轴起始坐标
* @param Length: 线的长度
* @retval 无
*/
void LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length)
{
uint32_t Xaddress = 0;
if(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888)
{
Xaddress = (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress) + 4*(LCD_GetXSize()*Ypos + Xpos);
}
else if(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB888)
{
Xaddress = (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress) + 3*(LCD_GetXSize()*Ypos + Xpos);
}
else if((Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) || \
(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB4444) || \
(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_AL88))
{
Xaddress = (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress) + 2*(LCD_GetXSize()*Ypos + Xpos);
}
else
{
Xaddress = (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress) + 2*(LCD_GetXSize()*Ypos + Xpos);
}
/* 填充数据 */
LL_FillBuffer(ActiveLayer, (uint32_t *)Xaddress, Length, 1, 0, DrawProp[ActiveLayer].TextColor);
}
/**
* @brief 绘制垂直线
* @param Xpos: X轴起始坐标
* @param Ypos: Y轴起始坐标
* @param Length: 线的长度
* @retval 无
*/
void LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length)
{
uint32_t Xaddress = 0;
if(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888)
{
Xaddress = (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress) + 4*(LCD_GetXSize()*Ypos + Xpos);
}
else if(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB888)
{
Xaddress = (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress) + 3*(LCD_GetXSize()*Ypos + Xpos);
}
else if((Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) || \
(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB4444) || \
(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_AL88))
{
Xaddress = (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress) + 2*(LCD_GetXSize()*Ypos + Xpos);
}
else
{
Xaddress = (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress) + 2*(LCD_GetXSize()*Ypos + Xpos);
}
/* 填充数据 */
LL_FillBuffer(ActiveLayer, (uint32_t *)Xaddress, 1, Length, (LCD_GetXSize() - 1), DrawProp[ActiveLayer].TextColor);
}
/**
* @brief 指定两点画一条线
* @param x1: 第一点X轴坐标
* @param y1: 第一点Y轴坐标
* @param x2: 第二点X轴坐标
* @param y2: 第二点Y轴坐标
* @retval 无
*/
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0,
yinc1 = 0, yinc2 = 0, den = 0, num = 0, num_add = 0, num_pixels = 0,
curpixel = 0;
deltax = ABS(x2 - x1); /* 求x轴的绝对值 */
deltay = ABS(y2 - y1); /* 求y轴的绝对值 */
x = x1; /* 第一个像素的x坐标起始值 */
y = y1; /* 第一个像素的y坐标起始值 */
if (x2 >= x1) /* x坐标值为递增 */
{
xinc1 = 1;
xinc2 = 1;
}
else /* x坐标值为递减 */
{
xinc1 = -1;
xinc2 = -1;
}
if (y2 >= y1) /* y坐标值为递增 */
{
yinc1 = 1;
yinc2 = 1;
}
else /* y坐标值为递减 */
{
yinc1 = -1;
yinc2 = -1;
}
if (deltax >= deltay) /* 每个 y 坐标值至少有一个x坐标值*/
{
xinc1 = 0; /* 当分子大于或等于分母时不要改变 x */
yinc2 = 0; /* 不要为每次迭代更改 y */
den = deltax;
num = deltax / 2;
num_add = deltay;
num_pixels = deltax; /* x比y多的值 */
}
else /* 每个 x 坐标值至少有一个y坐标值 */
{
xinc2 = 0; /* 不要为每次迭代更改 x */
yinc1 = 0; /* 当分子大于或等于分母时不要改变 y */
den = deltay;
num = deltay / 2;
num_add = deltax;
num_pixels = deltay; /* y比x多的值 */
}
for (curpixel = 0; curpixel <= num_pixels; curpixel++)
{
LCD_DrawPixel(x, y, DrawProp[ActiveLayer].TextColor); /* 绘制当前像素点 */
num += num_add; /* 在分数的基础上增加分子 */
if (num >= den) /* 检查分子大于或等于分母 */
{
num -= den; /* 计算新的分子值 */
x += xinc1; /* x值递增 */
y += yinc1; /* y值递增 */
}
x += xinc2; /* y值递增 */
y += yinc2; /* y值递增 */
}
}
/**
* @brief 绘制一个矩形
* @param Xpos: X轴坐标
* @param Ypos: Y轴坐标
* @param Width: 矩形宽度
* @param Height: 矩形高度
* @retval 无
*/
void LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height)
{
/* 绘制水平线 */
LCD_DrawHLine(Xpos, Ypos, Width);
LCD_DrawHLine(Xpos, (Ypos+ Height), Width);
/* 绘制垂直线 */
LCD_DrawVLine(Xpos, Ypos, Height);
LCD_DrawVLine((Xpos + Width), Ypos, Height);
}
/**
* @brief 绘制一个圆形
* @param Xpos: X轴坐标
* @param Ypos: Y轴坐标
* @param Radius: 圆的半径
* @retval 无
*/
void LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius)
{
int32_t decision; /* 决策变量 */
uint32_t current_x; /* 当前x坐标值 */
uint32_t current_y; /* 当前y坐标值 */
decision = 3 - (Radius << 1);
current_x = 0;
current_y = Radius;
while (current_x <= current_y)
{
LCD_DrawPixel((Xpos + current_x), (Ypos - current_y), DrawProp[ActiveLayer].TextColor);
LCD_DrawPixel((Xpos - current_x), (Ypos - current_y), DrawProp[ActiveLayer].TextColor);
LCD_DrawPixel((Xpos + current_y), (Ypos - current_x), DrawProp[ActiveLayer].TextColor);
LCD_DrawPixel((Xpos - current_y), (Ypos - current_x), DrawProp[ActiveLayer].TextColor);
LCD_DrawPixel((Xpos + current_x), (Ypos + current_y), DrawProp[ActiveLayer].TextColor);
LCD_DrawPixel((Xpos - current_x), (Ypos + current_y), DrawProp[ActiveLayer].TextColor);
LCD_DrawPixel((Xpos + current_y), (Ypos + current_x), DrawProp[ActiveLayer].TextColor);
LCD_DrawPixel((Xpos - current_y), (Ypos + current_x), DrawProp[ActiveLayer].TextColor);
if (decision < 0)
{
decision += (current_x << 2) + 6;
}
else
{
decision += ((current_x - current_y) << 2) + 10;
current_y--;
}
current_x++;
}
}
/**
* @brief 绘制一条折线
* @param Points: 指向点数组的指针
* @param PointCount: 点数
* @retval 无
*/
void LCD_DrawPolygon(pPoint Points, uint16_t PointCount)
{
int16_t x = 0, y = 0;
if(PointCount < 2)
{
return;
}
LCD_DrawLine(Points->X, Points->Y, (Points+PointCount-1)->X, (Points+PointCount-1)->Y);
while(--PointCount)
{
x = Points->X;
y = Points->Y;
Points++;
LCD_DrawLine(x, y, Points->X, Points->Y);
}
}
/**
* @brief 绘制一个椭圆
* @param Xpos: X轴坐标
* @param Ypos: Y轴坐标
* @param XRadius: 椭圆X轴半径
* @param YRadius: 椭圆Y轴半径
* @retval 无
*/
void LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius)
{
int x = 0, y = -YRadius, err = 2-2*XRadius, e2;
float k = 0, rad1 = 0, rad2 = 0;
rad1 = XRadius;
rad2 = YRadius;
k = (float)(rad2/rad1);
do {
LCD_DrawPixel((Xpos-(uint16_t)(x/k)), (Ypos+y), DrawProp[ActiveLayer].TextColor);
LCD_DrawPixel((Xpos+(uint16_t)(x/k)), (Ypos+y), DrawProp[ActiveLayer].TextColor);
LCD_DrawPixel((Xpos+(uint16_t)(x/k)), (Ypos-y), DrawProp[ActiveLayer].TextColor);
LCD_DrawPixel((Xpos-(uint16_t)(x/k)), (Ypos-y), DrawProp[ActiveLayer].TextColor);
e2 = err;
if (e2 <= x) {
err += ++x*2+1;
if (-y == x && e2 <= y) e2 = 0;
}
if (e2 > y) err += ++y*2+1;
}
while (y <= 0);
}
/**
* @brief 绘制一个点
* @param Xpos: X轴坐标
* @param Ypos: Y轴坐标
* @param RGB_Code: 像素颜色值
* @retval 无
*/
void LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint32_t RGB_Code)
{
if(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888)
{
*(__IO uint32_t*) (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*LCD_GetXSize() + Xpos))) = RGB_Code;
}
else if(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB888)
{
*(__IO uint8_t*) (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress + (3*(Ypos*LCD_GetXSize() + Xpos))+2) = 0xFF&(RGB_Code>>16);
*(__IO uint8_t*) (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress + (3*(Ypos*LCD_GetXSize() + Xpos))+1) = 0xFF&(RGB_Code>>8);
*(__IO uint8_t*) (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress + (3*(Ypos*LCD_GetXSize() + Xpos))) = 0xFF&RGB_Code;
}
else if((Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) || \
(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB4444) || \
(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_AL88))
{
*(__IO uint16_t*) (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*LCD_GetXSize() + Xpos))) = (uint16_t)RGB_Code;
}
else
{
*(__IO uint16_t*) (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*LCD_GetXSize() + Xpos))) = (uint16_t)RGB_Code;
}
}
/**
* @brief 绘制一幅从内部flash加载的ARGB888(32 bits per pixel)格式的图片
* @param Xpos: Bmp在液晶上X 轴坐标
* @param Ypos: Bmp在液晶上Y 轴坐标
* @param pbmp: 指针指向存在内部flash的Bmp图片的首地址
* @retval 无
*/
void LCD_DrawBitmap(uint32_t Xpos, uint32_t Ypos, uint8_t *pbmp)
{
uint32_t index = 0, width = 0, height = 0, bit_pixel = 0;
uint32_t address;
uint32_t input_color_mode = 0;
/* 获取位图数据的基地址 */
index = *(__IO uint16_t *) (pbmp + 10);
index |= (*(__IO uint16_t *) (pbmp + 12)) << 16;
/* 获取位图宽度 */
width = *(uint16_t *) (pbmp + 18);
width |= (*(uint16_t *) (pbmp + 20)) << 16;
/* 获取位图高度 */
height = *(uint16_t *) (pbmp + 22);
height |= (*(uint16_t *) (pbmp + 24)) << 16;
/* 获取像素个数 */
bit_pixel = *(uint16_t *) (pbmp + 28);
/* 设定地址 */
address = Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress + (((LCD_GetXSize()*Ypos) + Xpos)*(4));
/*判断层输入像素格式 */
if ((bit_pixel/8) == 4)
{
input_color_mode = DMA2D_INPUT_ARGB8888;
}
else if ((bit_pixel/8) == 2)
{
input_color_mode = DMA2D_INPUT_RGB565;
}
else
{
input_color_mode = DMA2D_INPUT_RGB888;
}
/* 绕过位图的帧头 */
pbmp += (index + (width * (height - 1) * (bit_pixel/8)));
/* 将图片转换为 ARGB8888 像素格式 */
for(index=0; index < height; index++)
{
/* 像素格式转换 */
LL_ConvertLineToARGB8888((uint32_t *)pbmp, (uint32_t *)address, width,input_color_mode);
/* 递增源和目标缓冲区 */
address+= (LCD_GetXSize()*4);
pbmp -= width*(bit_pixel/8);
}
}
/**
* @brief 填充一个实心矩形
* @param Xpos: X坐标值
* @param Ypos: Y坐标值
* @param Width: 矩形宽度
* @param Height: 矩形高度
* @retval 无
*/
void LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height)
{
uint32_t x_address = 0;
/* 设置文字颜色 */
LCD_SetTextColor(DrawProp[ActiveLayer].TextColor);
/* 设置矩形开始地址 */
if(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888)
{
x_address = (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress) + 4*(LCD_GetXSize()*Ypos + Xpos);
}
else if(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB888)
{
x_address = (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress) + 3*(LCD_GetXSize()*Ypos + Xpos);
}
else if((Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) || \
(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB4444) || \
(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_AL88))
{
x_address = (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress) + 2*(LCD_GetXSize()*Ypos + Xpos);
}
else
{
x_address = (Ltdc_Handler.LayerCfg[ActiveLayer].FBStartAdress) + 2*(LCD_GetXSize()*Ypos + Xpos);
}
/* 填充矩形 */
LL_FillBuffer(ActiveLayer, (uint32_t *)x_address, Width, Height, (LCD_GetXSize() - Width), DrawProp[ActiveLayer].TextColor);
}
/**
* @brief 填充一个实心圆
* @param Xpos: X坐标值
* @param Ypos: Y坐标值
* @param Radius: 圆的半径
* @retval 无
*/
void LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius)
{
int32_t decision; /* 决策变量 */
uint32_t current_x; /* 当前x坐标值 */
uint32_t current_y; /* 当前y坐标值 */
decision = 3 - (Radius << 1);
current_x = 0;
current_y = Radius;
LCD_SetTextColor(DrawProp[ActiveLayer].TextColor);
while (current_x <= current_y)
{
if(current_y > 0)
{
LCD_DrawHLine(Xpos - current_y, Ypos + current_x, 2*current_y);
LCD_DrawHLine(Xpos - current_y, Ypos - current_x, 2*current_y);
}
if(current_x > 0)
{
LCD_DrawHLine(Xpos - current_x, Ypos - current_y, 2*current_x);
LCD_DrawHLine(Xpos - current_x, Ypos + current_y, 2*current_x);
}
if (decision < 0)
{
decision += (current_x << 2) + 6;
}
else
{
decision += ((current_x - current_y) << 2) + 10;
current_y--;
}
current_x++;
}
LCD_SetTextColor(DrawProp[ActiveLayer].TextColor);
LCD_DrawCircle(Xpos, Ypos, Radius);
}
/**
* @brief 绘制多边形
* @param Points: 指向点数组的指针
* @param PointCount: 点数
* @retval 无
*/
void LCD_FillPolygon(pPoint Points, uint16_t PointCount)
{
int16_t X = 0, Y = 0, X2 = 0, Y2 = 0, X_center = 0, Y_center = 0, X_first = 0, Y_first = 0, pixelX = 0, pixelY = 0, counter = 0;
uint16_t image_left = 0, image_right = 0, image_top = 0, image_bottom = 0;
image_left = image_right = Points->X;
image_top= image_bottom = Points->Y;
for(counter = 1; counter < PointCount; counter++)
{
pixelX = POLY_X(counter);
if(pixelX < image_left)
{
image_left = pixelX;
}
if(pixelX > image_right)
{
image_right = pixelX;
}
pixelY = POLY_Y(counter);
if(pixelY < image_top)
{
image_top = pixelY;
}
if(pixelY > image_bottom)
{
image_bottom = pixelY;
}
}
if(PointCount < 2)
{
return;
}
X_center = (image_left + image_right)/2;
Y_center = (image_bottom + image_top)/2;
X_first = Points->X;
Y_first = Points->Y;
while(--PointCount)
{
X = Points->X;
Y = Points->Y;
Points++;
X2 = Points->X;
Y2 = Points->Y;
FillTriangle(X, X2, X_center, Y, Y2, Y_center);
FillTriangle(X, X_center, X2, Y, Y_center, Y2);
FillTriangle(X_center, X2, X, Y_center, Y2, Y);
}
FillTriangle(X_first, X2, X_center, Y_first, Y2, Y_center);
FillTriangle(X_first, X_center, X2, Y_first, Y_center, Y2);
FillTriangle(X_center, X2, X_first, Y_center, Y2, Y_first);
}
/**
* @brief 填充一个实心椭圆
* @param Xpos: X轴坐标
* @param Ypos: Y轴坐标
* @param XRadius: 椭圆X轴半径
* @param YRadius: 椭圆Y轴半径
* @retval 无
*/
void LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius)
{
int x = 0, y = -YRadius, err = 2-2*XRadius, e2;
float k = 0, rad1 = 0, rad2 = 0;
rad1 = XRadius;
rad2 = YRadius;
k = (float)(rad2/rad1);
do
{
LCD_DrawHLine((Xpos-(uint16_t)(x/k)), (Ypos+y), (2*(uint16_t)(x/k) + 1));
LCD_DrawHLine((Xpos-(uint16_t)(x/k)), (Ypos-y), (2*(uint16_t)(x/k) + 1));
e2 = err;
if (e2 <= x)
{
err += ++x*2+1;
if (-y == x && e2 <= y) e2 = 0;
}
if (e2 > y) err += ++y*2+1;
}
while (y <= 0);
}
/**
* @brief 使能显示
* @retval 无
*/
void LCD_DisplayOn(void)
{
/* 开显示 */
__HAL_LTDC_ENABLE(&Ltdc_Handler);
HAL_GPIO_WritePin(LTDC_BL_GPIO_PORT, LTDC_BL_GPIO_PIN, GPIO_PIN_SET); /* 开背光*/
}
/**
* @brief 禁能显示
* @retval 无
*/
void LCD_DisplayOff(void)
{
/* 关显示 */
__HAL_LTDC_DISABLE(&Ltdc_Handler);
HAL_GPIO_WritePin(LTDC_BL_GPIO_PORT, LTDC_BL_GPIO_PIN, GPIO_PIN_RESET);/*关背光*/
}
/*******************************************************************************
局部函数
*******************************************************************************/
/**
* @brief 显示一个字符
* @param Xpos: 显示字符的行位置
* @param Ypos: 列起始位置
* @param c: 指向字体数据的指针
* @retval 无
*/
static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c)
{
uint32_t i = 0, j = 0;
uint16_t height, width;
uint8_t offset;
uint8_t *pchar;
uint32_t line;
height = DrawProp[ActiveLayer].pFont->Height;//获取正在使用字体高度
width = DrawProp[ActiveLayer].pFont->Width; //获取正在使用字体宽度
offset = 8 *((width + 7)/8) - width ;//计算字符的每一行像素的偏移值,实际存储大小-字体宽度
for(i = 0; i < height; i++)//遍历字体高度绘点
{
pchar = ((uint8_t *)c + (width + 7)/8 * i);//计算字符的每一行像素的偏移地址
switch(((width + 7)/8))//根据字体宽度来提取不同字体的实际像素值
{
case 1:
line = pchar[0]; //提取字体宽度小于8的字符的像素值
break;
case 2:
line = (pchar[0]<< 8) | pchar[1]; //提取字体宽度大于8小于16的字符的像素值
break;
case 3:
default:
line = (pchar[0]<< 16) | (pchar[1]<< 8) | pchar[2]; //提取字体宽度大于16小于24的字符的像素值
break;
}
for (j = 0; j < width; j++)//遍历字体宽度绘点
{
if(line & (1 << (width- j + offset- 1))) //根据每一行的像素值及偏移位置按照当前字体颜色进行绘点
{
LCD_DrawPixel((Xpos + j), Ypos, DrawProp[ActiveLayer].TextColor);
}
else//如果这一行没有字体像素则按照背景颜色绘点
{
LCD_DrawPixel((Xpos + j), Ypos, DrawProp[ActiveLayer].BackColor);
}
}
Ypos++;
}
}
/**
* @brief 填充三角形(基于三点)
* @param x1: 第一点的X坐标值
* @param y1: 第一点的Y坐标值
* @param x2: 第二点的X坐标值
* @param y2: 第二点的Y坐标值
* @param x3: 第三点的X坐标值
* @param y3: 第三点的Y坐标值
* @retval 无
*/
static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3)
{
int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0,
yinc1 = 0, yinc2 = 0, den = 0, num = 0, num_add = 0, num_pixels = 0,
curpixel = 0;
deltax = ABS(x2 - x1); /* 求x轴的绝对值 */
deltay = ABS(y2 - y1); /* 求y轴的绝对值 */
x = x1; /* 第一个像素的x坐标起始值 */
y = y1; /* 第一个像素的y坐标起始值 */
if (x2 >= x1) /* x坐标值为递增*/
{
xinc1 = 1;
xinc2 = 1;
}
else /* x坐标值为递减 */
{
xinc1 = -1;
xinc2 = -1;
}
if (y2 >= y1) /* y坐标值为递增*/
{
yinc1 = 1;
yinc2 = 1;
}
else /* y坐标值为递减 */
{
yinc1 = -1;
yinc2 = -1;
}
if (deltax >= deltay) /* 每个 y 坐标值至少有一个x坐标值*/
{
xinc1 = 0; /* 当分子大于或等于分母时不要改变 x */
yinc2 = 0; /* 不要为每次迭代更改 y */
den = deltax;
num = deltax / 2;
num_add = deltay;
num_pixels = deltax; /* x比y多的值 */
}
else /* 每个 x 坐标值至少有一个y坐标值 */
{
xinc2 = 0; /* 不要为每次迭代更改 x */
yinc1 = 0; /* 当分子大于或等于分母时不要改变 y */
den = deltay;
num = deltay / 2;
num_add = deltax;
num_pixels = deltay; /* y比x多的值 */
}
for (curpixel = 0; curpixel <= num_pixels; curpixel++)
{
LCD_DrawLine(x, y, x3, y3);
num += num_add; /* 在分数的基础上增加分子 */
if (num >= den) /* 判断分子是否大于或等于分母 */
{
num -= den; /* 计算新的分子值 */
x += xinc1; /* x值递增 */
y += yinc1; /* y值递增 */
}
x += xinc2; /* x值递增 */
y += yinc2; /* y值递增 */
}
}
/**
* @brief 填充一个缓冲区
* @param LayerIndex: 当前层
* @param pDst: 指向目标缓冲区指针
* @param xSize: 缓冲区宽度
* @param ySize: 缓冲区高度
* @param OffLine: 偏移量
* @param ColorIndex: 当前颜色
* @retval None
*/
static void LL_FillBuffer(uint32_t LayerIndex, void *pDst, uint32_t xSize, uint32_t ySize, uint32_t OffLine, uint32_t ColorIndex)
{
Dma2d_Handler.Init.Mode = DMA2D_R2M;
if(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565)
{
Dma2d_Handler.Init.ColorMode = DMA2D_OUTPUT_RGB565;
}
else if(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888)
{
Dma2d_Handler.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
}
else if(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB888)
{
Dma2d_Handler.Init.ColorMode = DMA2D_OUTPUT_RGB888;
}
else if(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB1555)
{
Dma2d_Handler.Init.ColorMode = DMA2D_OUTPUT_ARGB1555;
}
else if(Ltdc_Handler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB4444)
{
Dma2d_Handler.Init.ColorMode = DMA2D_OUTPUT_ARGB4444;
}
Dma2d_Handler.Init.OutputOffset = OffLine;
Dma2d_Handler.Instance = DMA2D;
/* DMA2D 初始化 */
if(HAL_DMA2D_Init(&Dma2d_Handler) == HAL_OK)
{
if(HAL_DMA2D_ConfigLayer(&Dma2d_Handler, LayerIndex) == HAL_OK)
{
if (HAL_DMA2D_Start(&Dma2d_Handler, ColorIndex, (uint32_t)pDst, xSize, ySize) == HAL_OK)
{
/* DMA轮询传输 */
HAL_DMA2D_PollForTransfer(&Dma2d_Handler, 10);
}
}
}
}
/**
* @brief 转换一行为ARGB8888像素格式
* @param pSrc: 指向源缓冲区的指针
* @param pDst: 输出颜色
* @param xSize: 缓冲区宽度
* @param ColorMode: 输入颜色模式
* @retval 无
*/
static void LL_ConvertLineToARGB8888(void *pSrc, void *pDst, uint32_t xSize, uint32_t ColorMode)
{
/* 配置DMA2D模式,颜色模式和输出偏移 */
Dma2d_Handler.Init.Mode = DMA2D_M2M_PFC;
Dma2d_Handler.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
Dma2d_Handler.Init.OutputOffset = 0;
/* Foreground Configuration */
Dma2d_Handler.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;
Dma2d_Handler.LayerCfg[1].InputAlpha = 0xFF;
Dma2d_Handler.LayerCfg[1].InputColorMode = ColorMode;
Dma2d_Handler.LayerCfg[1].InputOffset = 0;
Dma2d_Handler.Instance = DMA2D;
/* DMA2D 初始化 */
if(HAL_DMA2D_Init(&Dma2d_Handler) == HAL_OK)
{
if(HAL_DMA2D_ConfigLayer(&Dma2d_Handler, 1) == HAL_OK)
{
if (HAL_DMA2D_Start(&Dma2d_Handler, (uint32_t)pSrc, (uint32_t)pDst, xSize, 1) == HAL_OK)
{
/* DMA轮询传输*/
HAL_DMA2D_PollForTransfer(&Dma2d_Handler, 10);
}
}
}
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/