You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
905 lines
28 KiB
905 lines
28 KiB
#include "bsp_lcd.h"
|
|
#include "elog.h"
|
|
|
|
LCD_TypeDef cur_lcd = INCH_4_3;
|
|
LCD_DrawPropTypeDef DrawProp[2];
|
|
|
|
MY_LCD_TypeDef my_lcd = {
|
|
|
|
0, 0, // 宽度 高度
|
|
|
|
0, 4, // 横屏还是竖屏控制:0,竖屏;1,横屏,像素大小。
|
|
|
|
LTDC_PIXEL_FORMAT_ARGB8888, // PIXEL Format
|
|
LCD_COLOR_WHITE, // color
|
|
LCD_COLOR_BLACK, // back_color
|
|
NULL, // LCD_DrawPropTypeDef draw_prop[2];
|
|
0, // show_num_mode
|
|
|
|
0, //active layer
|
|
{LCD_BUF_ADDRESS,LCD_BUF_ADDRESS}, // Layer0 Addr
|
|
};
|
|
|
|
// static void LCD_Draw_Point(uint16_t x, uint16_t y, uint32_t color);
|
|
// static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c);
|
|
extern void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c);
|
|
|
|
void LCD_Init()
|
|
{
|
|
|
|
LTDC_Init();
|
|
// TODO my_lcd 调用LTDC画点,无需考虑坐标切换
|
|
LCD_DisplayDirection(1);
|
|
|
|
#if LCD_PIXFORMAT == LTDC_PIXEL_FORMAT_ARGB8888 || LCD_PIXFORMAT == LTDC_PIXEL_FORMAT_RGB888
|
|
my_lcd.pixelsize = 4; // 每个像素占4个字节
|
|
#else
|
|
my_lcd.pixelsize = 2; // 每个像素占2个字节
|
|
#endif
|
|
my_lcd.layeraddr[0] = LCD_BUF_ADDRESS;
|
|
my_lcd.layeraddr[1] = LCD_BUF_ADDRESS + my_lcd.width * my_lcd.height * my_lcd.pixelsize;
|
|
|
|
LCD_SetLayer(0, my_lcd.layeraddr[0] , my_lcd.color_format, LCD_COLOR_GREEN,255);
|
|
LCD_SetLayer(1, my_lcd.layeraddr[1], my_lcd.color_format, LCD_COLOR_GREEN,0);
|
|
LCD_Set_Active_layer(0);
|
|
LCD_Clear(LTDC_COLOR_GREEN); //清屏
|
|
LTDC_DISP_ON();
|
|
// LTDC_Display_Dir(1);
|
|
// my_lcd.width = my_ltdc.width;
|
|
// my_lcd.height = my_ltdc.height;
|
|
// my_lcd.activelayer = my_ltdc.activelayer;
|
|
|
|
// TODO 添加 DrawProp[2] 定义
|
|
my_lcd.draw_prop[0].BackColor = LCD_COLOR_WHITE; // 设置层的字体颜色
|
|
my_lcd.draw_prop[0].pFont = &Font16; // 设置层的字体类型
|
|
my_lcd.draw_prop[0].pCnFont = &CH_Font16; // 设置层的字体类型
|
|
my_lcd.draw_prop[0].TextColor = LCD_COLOR_BLACK; // 设置层的字体背景颜色
|
|
my_lcd.draw_prop[1].BackColor = LCD_COLOR_WHITE; // 设置层的字体颜色
|
|
my_lcd.draw_prop[1].pFont = &Font16; // 设置层的字体类型
|
|
my_lcd.draw_prop[1].pCnFont = &CH_Font16; // 设置层的字体类型
|
|
my_lcd.draw_prop[1].TextColor = LCD_COLOR_BLACK; // 设置层的字体背景颜色
|
|
}
|
|
|
|
void LCD_DisplayDirection(uint8_t dir){
|
|
my_lcd.dir = dir;
|
|
// my_ltdc.dir = dir; // 显示方向
|
|
|
|
if(dir==0) //竖屏
|
|
{
|
|
my_lcd.width=my_ltdc.pixel_height;
|
|
my_lcd.height=my_ltdc.pixel_width;
|
|
}else if(dir==1) //横屏
|
|
{
|
|
my_lcd.width=my_ltdc.pixel_width;
|
|
my_lcd.height=my_ltdc.pixel_height;
|
|
}
|
|
}
|
|
|
|
void LCD_Set_Active_layer( uint8_t layer_no )
|
|
{
|
|
my_lcd.activelayer = layer_no;
|
|
my_ltdc.activelayer = layer_no;
|
|
}
|
|
|
|
void LCD_SetLayer( uint8_t layer,uint32_t buf_addr, uint32_t layer_color_format,
|
|
uint32_t layer_back_color,uint8_t alpha )
|
|
{
|
|
|
|
LTDC_Layer_Parameter_Config( layer,buf_addr,my_lcd.color_format,alpha,
|
|
0,6,7,LCD_COLOR_GREEN);//层参数配置
|
|
LTDC_Layer_Window_Config(layer,0,0,my_ltdc.pixel_width,my_ltdc.pixel_height); //层窗口配置,以LCD面板坐标系为基准,不要随便修改!
|
|
}
|
|
|
|
/**
|
|
* @brief 设置LCD当前层文字颜色
|
|
* @param Color: 文字颜色
|
|
* @retval 无
|
|
*/
|
|
void LCD_SetTextColor(uint32_t Color)
|
|
{
|
|
my_lcd.draw_prop[my_lcd.activelayer].TextColor = Color;
|
|
}
|
|
|
|
/**
|
|
* @brief 获取LCD当前层文字颜色
|
|
* @retval 文字颜色
|
|
*/
|
|
uint32_t LCD_GetTextColor(void)
|
|
{
|
|
return my_lcd.draw_prop[my_lcd.activelayer].TextColor;
|
|
}
|
|
|
|
/**
|
|
* @brief 设置LCD当前层的文字背景颜色
|
|
* @param Color: 文字背景颜色
|
|
* @retval 无
|
|
*/
|
|
void LCD_SetBackColor(uint32_t Color)
|
|
{
|
|
my_lcd.draw_prop[my_lcd.activelayer].BackColor = Color;
|
|
}
|
|
|
|
/**
|
|
* @brief 获取LCD当前层的文字背景颜色
|
|
* @retval 文字背景颜色
|
|
*/
|
|
uint32_t LCD_GetBackColor(void)
|
|
{
|
|
return my_lcd.draw_prop[my_lcd.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)
|
|
{
|
|
my_lcd.draw_prop[my_lcd.activelayer].pFont = fonts;
|
|
}
|
|
|
|
/**
|
|
* @brief 获取LCD当前层显示的字体
|
|
* @retval 字体类型
|
|
*/
|
|
sFONT *LCD_GetFont(void)
|
|
{
|
|
return my_lcd.draw_prop[my_lcd.activelayer].pFont;
|
|
}
|
|
/*******************************************************************************
|
|
局部函数
|
|
*******************************************************************************/
|
|
// static void LCD_Draw_Point(uint16_t x, uint16_t y, uint32_t color)
|
|
// {
|
|
// LTDC_Draw_Point(x, y, color);
|
|
// }
|
|
|
|
//画点函数
|
|
//x,y:写入坐标
|
|
//color:颜色值
|
|
void LCD_Draw_Point(uint16_t x,uint16_t y,uint32_t color)
|
|
{
|
|
|
|
if(my_lcd.dir) //横屏
|
|
{
|
|
*(uint32_t*)((uint32_t)my_lcd.layeraddr[my_lcd.activelayer]+my_lcd.pixelsize*(my_lcd.width*y+x))=color;
|
|
}else //竖屏
|
|
{
|
|
*(uint32_t*)((uint32_t)my_lcd.layeraddr[my_lcd.activelayer]+my_lcd.pixelsize*(my_lcd.height*(my_lcd.width-x)+y))=color;
|
|
// *(uint32_t*)((uint32_t)my_lcd.layeraddr[my_lcd.activelayer]+my_lcd.pixelsize*(my_ltdc.pixel_width*(my_ltdc.pixel_height-x)+y))=color;
|
|
}
|
|
|
|
}
|
|
|
|
//读点函数
|
|
//x,y:读取点的坐标
|
|
//返回值:颜色值
|
|
uint32_t LCD_Read_Point(uint16_t x,uint16_t y)
|
|
{
|
|
// return *(uint32_t*)((uint32_t)my_lcd.layeraddr[my_lcd.activelayer]+my_ltdc.pixelsize*(my_ltdc.pixel_width*y+x));
|
|
if(my_lcd.dir) //横屏
|
|
{
|
|
return *(uint32_t*)((uint32_t)my_lcd.layeraddr[my_lcd.activelayer]+my_lcd.pixelsize*(my_lcd.width*y+x));
|
|
}else //竖屏
|
|
{
|
|
return *(uint32_t*)((uint32_t)my_lcd.layeraddr[my_lcd.activelayer]+my_lcd.pixelsize*(my_lcd.height*(my_lcd.width-x)+y));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* @brief 显示一个字符
|
|
* @param Xpos: 显示字符的行位置
|
|
* @param Ypos: 列起始位置
|
|
* @param c: 指向字体数据的指针
|
|
* @retval 无
|
|
*/
|
|
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;
|
|
uint8_t tempchar;
|
|
uint32_t line;
|
|
uint8_t t,t1;
|
|
uint8_t y0 = Ypos;
|
|
|
|
height = my_lcd.draw_prop[my_lcd.activelayer].pFont->Height;//获取正在使用字体高度
|
|
width = my_lcd.draw_prop[my_lcd.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_Draw_Point((Xpos + j), Ypos, my_lcd.draw_prop[my_lcd.activelayer].TextColor);
|
|
}
|
|
else //如果这一行没有字体像素则按照背景颜色绘点
|
|
{
|
|
LCD_Draw_Point((Xpos + j), Ypos, my_lcd.draw_prop[my_lcd.activelayer].BackColor);
|
|
}
|
|
}
|
|
Ypos++;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************************************************
|
|
* 函 数 名: LCD_DisplayChar
|
|
*
|
|
* 入口参数: x - 起始水平坐标,取值范围0~799
|
|
* y - 起始垂直坐标,取值范围0~479
|
|
* c - ASCII字符
|
|
*
|
|
* 函数功能: 在指定坐标显示指定的字符
|
|
*
|
|
* 说 明: 1. 可设置要显示的字体,例如使用 LCD_SetFont(&Font24) 设置为 2412的ASCII字体
|
|
* 2. 可设置要显示的颜色,例如使用 LCD_SetColor(0xff0000FF) 设置为蓝色
|
|
* 3. 可设置对应的背景色,例如使用 LCD_SetBackColor(0xff000000) 设置为黑色的背景色
|
|
* 4. 使用示例 LCD_DisplayChar( 10, 10, 'a') ,在坐标(10,10)显示字符 'a'
|
|
*
|
|
***************************************************************************************************************/
|
|
|
|
/**
|
|
* @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)]);
|
|
|
|
DrawChar(Xpos, Ypos, &my_lcd.draw_prop[my_lcd.activelayer].pFont->table[(Ascii-' ') * \
|
|
my_lcd.draw_prop[my_lcd.activelayer].pFont->Height * \
|
|
((my_lcd.draw_prop[my_lcd.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 = (my_lcd.width/my_lcd.draw_prop[my_lcd.activelayer].pFont->Width);
|
|
|
|
switch (Mode)
|
|
{
|
|
case CENTER_MODE:
|
|
{
|
|
ref_column = Xpos + ((xsize - size)* my_lcd.draw_prop[my_lcd.activelayer].pFont->Width) / 2;
|
|
break;
|
|
}
|
|
case LEFT_MODE:
|
|
{
|
|
ref_column = Xpos;
|
|
break;
|
|
}
|
|
case RIGHT_MODE:
|
|
{
|
|
ref_column = - Xpos + ((xsize - size)*my_lcd.draw_prop[my_lcd.activelayer].pFont->Width);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
ref_column = Xpos;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*检查起始行是否在显示范围内 */
|
|
if ((ref_column < 1) || (ref_column >= 0x8000))
|
|
{
|
|
ref_column = 1;
|
|
}
|
|
|
|
/* 使用字符显示函数显示每一个字符*/
|
|
while ( (*Text != 0) & (((my_lcd.width - (i*my_lcd.draw_prop[my_lcd.activelayer].pFont->Width)) & 0xFFFF) \
|
|
>= my_lcd.draw_prop[my_lcd.activelayer].pFont->Width) )
|
|
{
|
|
/* 显示一个字符 */
|
|
LCD_DisplayChar( ref_column, Ypos, *Text );
|
|
/* 根据字体大小计算下一个偏移位置 */
|
|
ref_column += my_lcd.draw_prop[my_lcd.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);
|
|
}
|
|
|
|
|
|
void LCD_DisplayNumber( uint16_t Line, int32_t number, uint8_t len)
|
|
{
|
|
char Number_Buffer[15]; // 用于存储转换后的字符串
|
|
// if( LCD.ShowNum_Mode == Fill_Zero) // 多余位补0
|
|
if( my_lcd.show_num_mode ==0) // 多余位补0
|
|
{
|
|
sprintf( Number_Buffer , "%0.*d",len, number ); // 将 number 转换成字符串,便于显示
|
|
}
|
|
else // 多余位补空格
|
|
{
|
|
sprintf( Number_Buffer , "%*d",len, number ); // 将 number 转换成字符串,便于显示
|
|
}
|
|
LCD_DisplayStringAt(0, LINE(Line), (char *)Number_Buffer , LEFT_MODE) ; // 将转换得到的字符串显示出来
|
|
}
|
|
|
|
/***************************************************************************************************************************************
|
|
* 函 数 名: LCD_DisplayDecimals
|
|
*
|
|
* 入口参数: x - 起始水平坐标,取值范围0~799
|
|
* y - 起始垂直坐标,取值范围0~479
|
|
* decimals - 要显示的数字, double型取值1.7 x 10^(-308)~ 1.7 x 10^(+308),但是能确保准确的有效位数为15~16位
|
|
*
|
|
* len - 整个变量的总位数(包括小数点和负号),若实际的总位数超过了指定的总位数,将按实际的总长度位输出,
|
|
* 示例1:小数 -123.123 ,指定 len <=8 的话,则实际照常输出 -123.123
|
|
* 示例2:小数 -123.123 ,指定 len =10 的话,则实际输出 -123.123(负号前面会有两个空格位)
|
|
* 示例3:小数 -123.123 ,指定 len =10 的话,当调用函数 LCD_ShowNumMode() 设置为填充0模式时,实际输出 -00123.123
|
|
*
|
|
* decs - 要保留的小数位数,若小数的实际位数超过了指定的小数位,则按指定的宽度四舍五入输出
|
|
* 示例:1.12345 ,指定 decs 为4位的话,则输出结果为1.1235
|
|
*
|
|
* 函数功能: 在指定坐标显示指定的变量,包括小数
|
|
*
|
|
* 说 明: 1. 可设置要显示的字体,例如使用 LCD_SetTextFont(&CH_Font24) 设置为 2424的中文字体以及2412的ASCII字符字体
|
|
* 2. 可设置要显示的颜色,例如使用 LCD_SetColor(0xff0000FF) 设置为蓝色
|
|
* 3. 可设置对应的背景色,例如使用 LCD_SetBackColor(0xff000000) 设置为黑色的背景色
|
|
* 4. 使用示例 LCD_DisplayDecimals( 10, 10, a, 5, 3) ,在坐标(10,10)显示字变量a,总长度为5位,其中保留3位小数
|
|
*
|
|
*****************************************************************************************************************************************/
|
|
|
|
void LCD_DisplayDecimals( uint16_t Line, double decimals, uint8_t len, uint8_t decs)
|
|
{
|
|
char Number_Buffer[20]; // 用于存储转换后的字符串
|
|
|
|
// if( LCD.ShowNum_Mode == Fill_Zero) // 多余位填充0模式
|
|
if( my_lcd.show_num_mode ==0) // 多余位补0
|
|
{
|
|
sprintf( Number_Buffer , "%0*.*lf",len,decs, decimals ); // 将 number 转换成字符串,便于显示
|
|
}
|
|
else // 多余位填充空格
|
|
{
|
|
sprintf( Number_Buffer , "%*.*lf",len,decs, decimals ); // 将 number 转换成字符串,便于显示
|
|
}
|
|
|
|
LCD_DisplayStringAt(0, LINE(Line), (char *)Number_Buffer, LEFT_MODE) ; // 将转换得到的字符串显示出来
|
|
}
|
|
|
|
/**
|
|
* @brief 在显示器上显示一个中文字符
|
|
* @param usX :在特定扫描方向下字符的起始X坐标
|
|
* @param usY :在特定扫描方向下字符的起始Y坐标
|
|
* @param usChar :要显示的中文字符(国标码)
|
|
* @retval 无
|
|
*/
|
|
void LCD_DispChar_CH (uint16_t Xpos, uint16_t Ypos, uint16_t Text)
|
|
{
|
|
uint32_t i = 0, j = 0;
|
|
uint16_t height, width;
|
|
uint8_t offset;
|
|
uint8_t *pchar;
|
|
// uint8_t Buffer[HEIGHT_CH_CHAR*3];
|
|
uint8_t Buffer[HEIGHT_CH_CHAR*3];
|
|
uint32_t line;
|
|
|
|
GetGBKCode (Buffer, Text ); // TODO 获得Buffer
|
|
|
|
// height = HEIGHT_CH_CHAR;//取字模数据//获取正在使用字体高度
|
|
// width = WIDTH_CH_CHAR; //获取正在使用字体宽度
|
|
height = my_lcd.draw_prop[my_lcd.activelayer].pCnFont->Height;//获取正在使用字体高度
|
|
width = my_lcd.draw_prop[my_lcd.activelayer].pCnFont->Width; //获取正在使用字体宽度
|
|
|
|
offset = 8 *((width + 7)/8) - width ;//计算字符的每一行像素的偏移值,实际存储大小-字体宽度
|
|
|
|
for(i = 0; i < height; i++)//遍历字体高度绘点
|
|
{
|
|
pchar = ((uint8_t *)Buffer + (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_Draw_Point((Xpos + j), Ypos, DrawProp[ActiveLayer].TextColor);
|
|
}
|
|
else//如果这一行没有字体像素则按照背景颜色绘点
|
|
{
|
|
LCD_Draw_Point((Xpos + j), Ypos, DrawProp[ActiveLayer].BackColor);
|
|
}
|
|
}
|
|
Ypos++;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief 显示一行字符,若超出液晶宽度,不自动换行。
|
|
中英混显时,请把英文字体设置为Font24格式
|
|
* @param Line: 要显示的行编号LINE(0) - LINE(N)
|
|
* @param *ptr: 要显示的字符串指针
|
|
* @retval None
|
|
*/
|
|
void LCD_DisplayStringLine_EN_CH(uint16_t Line, uint8_t *ptr)
|
|
{
|
|
uint16_t refcolumn = 0;
|
|
/* 判断显示位置不能超出液晶的边界 */
|
|
while ((refcolumn < LCD_PIXEL_WIDTH) && ((*ptr != 0) & (((refcolumn + DrawProp[ActiveLayer].pFont->Width) & 0xFFFF) >= DrawProp[ActiveLayer].pFont->Width)))
|
|
{
|
|
/* 使用LCD显示一个字符 */
|
|
if ( * ptr <= 126 ) //英文字符
|
|
{
|
|
|
|
LCD_DisplayChar(refcolumn, LINE(Line), *ptr);
|
|
/* 根据字体偏移显示的位置 */
|
|
refcolumn += DrawProp[ActiveLayer].pFont->Width;
|
|
/* 指向字符串中的下一个字符 */
|
|
ptr++;
|
|
}
|
|
|
|
else //汉字字符
|
|
{
|
|
uint16_t usCh;
|
|
|
|
/*一个汉字两字节*/
|
|
usCh = * ( uint16_t * ) ptr;
|
|
/*交换编码顺序*/
|
|
usCh = ( usCh << 8 ) + ( usCh >> 8 );
|
|
|
|
/*显示汉字*/
|
|
LCD_DispChar_CH ( refcolumn,LINE(Line) , usCh );
|
|
/*显示位置偏移*/
|
|
refcolumn += WIDTH_CH_CHAR;
|
|
/* 指向字符串中的下一个字符 */
|
|
ptr += 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
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_Draw_Point(x, y, DrawProp[my_ltdc.activelayer].TextColor); /* 绘制当前像素点 */
|
|
num += num_add; /* 在分数的基础上增加分子 */
|
|
if (num >= den) /* 检查分子大于或等于分母 */
|
|
{
|
|
num -= den; /* 计算新的分子值 */
|
|
x += xinc1; /* x值递增 */
|
|
y += yinc1; /* y值递增 */
|
|
}
|
|
x += xinc2; /* y值递增 */
|
|
y += yinc2; /* y值递增 */
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief 填充三角形(基于三点)
|
|
* @param x1: 第一点的X坐标值
|
|
* @param y1: 第一点的Y坐标值
|
|
* @param x2: 第二点的X坐标值
|
|
* @param y2: 第二点的Y坐标值
|
|
* @param x3: 第三点的X坐标值
|
|
* @param y3: 第三点的Y坐标值
|
|
* @retval 无
|
|
*/
|
|
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值递增 */
|
|
}
|
|
}
|
|
|
|
// 画矩形
|
|
//(x1,y1),(x2,y2):矩形的对角坐标
|
|
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);
|
|
}
|
|
|
|
// 在指定位置画一个指定大小的圆
|
|
//(x,y):中心点
|
|
// r :半径
|
|
void LCD_DrawCircle(uint16_t x, uint16_t y, uint16_t r)
|
|
{
|
|
int Xadd = -r, Yadd = 0, err = 2-2*r, e2;
|
|
do {
|
|
|
|
LCD_Draw_Point(x-Xadd,y+Yadd,my_lcd.color);
|
|
LCD_Draw_Point(x+Xadd,y+Yadd,my_lcd.color);
|
|
LCD_Draw_Point(x+Xadd,y-Yadd,my_lcd.color);
|
|
LCD_Draw_Point(x-Xadd,y-Yadd,my_lcd.color);
|
|
|
|
e2 = err;
|
|
if (e2 <= Yadd) {
|
|
err += ++Yadd*2+1;
|
|
if (-Xadd == Yadd && e2 <= Xadd) e2 = 0;
|
|
}
|
|
if (e2 > Xadd) err += ++Xadd*2+1;
|
|
}
|
|
while (Xadd <= 0);
|
|
|
|
}
|
|
|
|
|
|
// 在指定区域内填充单个颜色
|
|
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
|
|
// color:要填充的颜色
|
|
void LCD_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t color)
|
|
{
|
|
// TODO: 未测试正确
|
|
uint32_t offline;
|
|
uint32_t address;
|
|
offline = my_lcd.width - (ex-sx+1);
|
|
address = my_lcd.layeraddr[my_lcd.activelayer] + my_lcd.pixelsize*(sy*my_lcd.width +sx);
|
|
|
|
// DMA2D->CR = 0x00030000UL; // 配置为寄存器到储存器模式
|
|
// DMA2D->OCOLR = color; // 设置填充使用的颜色,格式应该与设置的颜色格式相同
|
|
// DMA2D->OMAR = (uint32_t)address; // 填充区域的起始内存地址
|
|
// DMA2D->OOR = offline; // 行偏移,即跳过的像素,注意是以像素为单位
|
|
// DMA2D->OPFCCR = my_lcd.color_format; // 设置颜色格式
|
|
// DMA2D->NLR = (uint32_t)( (ex-sx+1) << 16) | (uint16_t)(ey-sy+1); // 设置填充区域的宽和高,单位是像素
|
|
|
|
// // 传输中断
|
|
// // DMA2D->CR |= DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE;
|
|
// // DMA2D->CR |= DMA2D_CR_START;
|
|
|
|
// // 启动传输 阻塞 -- 阻塞一般用于清屏,R2M 模式
|
|
// DMA2D->CR |= DMA2D_CR_START;
|
|
// while (DMA2D->CR & DMA2D_CR_START) {}
|
|
|
|
DMA2D_Fill(address, (ex-sx+1), (ey-sy+1), offline, my_lcd.color_format, color);
|
|
}
|
|
|
|
// 在指定区域内填充指定颜色块
|
|
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
|
|
// color:要填充的颜色
|
|
// 注意两个地址的offline
|
|
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);
|
|
uint32_t offline;
|
|
offline = my_lcd.width - (ex-sx+1);
|
|
DMA2D_MemCopy(my_lcd.color_format,
|
|
color, (uint32_t)my_lcd.layeraddr[my_lcd.activelayer],
|
|
(ex-sx+1), (ey-sy+1), offline, offline );
|
|
}
|
|
|
|
void LCD_Clear( uint32_t color)
|
|
{
|
|
LCD_Fill( 0, 0, my_lcd.width, my_lcd.height, color );
|
|
}
|
|
|
|
/***************************************************************************************************************************************
|
|
* 函 数 名: LCD_FillRect
|
|
*
|
|
* 入口参数: x - 水平坐标,取值范围 0~799
|
|
* y - 垂直坐标,取值范围 0~479
|
|
* width - 图片的水平宽度,最大取值800
|
|
* height - 图片的垂直宽度,最大取值480
|
|
*
|
|
* 函数功能: 在坐标 (x,y) 填充指定长宽的实心矩形
|
|
*
|
|
* 说 明: 1. 使用DMA2D实现
|
|
* 2. 要绘制的区域不能超过屏幕的显示区域
|
|
*
|
|
*****************************************************************************************************************************************/
|
|
|
|
void LCD_FillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height)
|
|
{
|
|
DMA2D->CR &= ~(DMA2D_CR_START); // 停止DMA2D
|
|
DMA2D->CR = DMA2D_R2M; // 寄存器到SDRAM
|
|
DMA2D->OPFCCR = my_lcd.color_format; // 设置颜色格式
|
|
DMA2D->OCOLR = my_lcd.color; // 颜色
|
|
|
|
// if(my_lcd.dir == 1) //横屏填充
|
|
// {
|
|
// DMA2D->OOR = my_lcd.width - width; // 设置行偏移
|
|
// DMA2D->OMAR = my_ltdc.layeraddr[my_ltdc.activelayer] + LCD.BytesPerPixel*(my_lcd.width * y + x); // 地址;
|
|
// DMA2D->NLR = (width<<16)|(height); // 设定长度和宽度
|
|
// }
|
|
// else //竖屏填充
|
|
// {
|
|
// DMA2D->OOR = my_lcd.width - height; // 设置行偏移
|
|
// DMA2D->OMAR = my_ltdc.layeraddr[my_ltdc.activelayer] + LCD.BytesPerPixel*((my_lcd.height - x - 1 - width)*LCD_Width + y); // 地址
|
|
// DMA2D->NLR = (width)|(height<<16); // 设定长度和宽度
|
|
// }
|
|
|
|
DMA2D->OOR = my_lcd.width - width; // 设置行偏移
|
|
DMA2D->OMAR = my_lcd.layeraddr[my_lcd.activelayer] + my_lcd.pixelsize*(my_lcd.width * y + x); // 地址;
|
|
DMA2D->NLR = (width<<16)|(height); // 设定长度和宽度
|
|
DMA2D->CR |= DMA2D_CR_START; // 启动DMA2D
|
|
|
|
while (DMA2D->CR & DMA2D_CR_START) ; // 等待传输完成
|
|
}
|
|
|
|
/***************************************************************************************************************************************
|
|
* 函 数 名: LCD_FillCircle
|
|
*
|
|
* 入口参数: x - 圆心 水平坐标,取值范围 0~799
|
|
* y - 圆心 垂直坐标,取值范围 0~479
|
|
* r - 半径
|
|
*
|
|
* 函数功能: 在坐标 (x,y) 填充半径为 r 的圆形区域
|
|
*
|
|
* 说 明: 1. 该函数移植于ST官方评估板的例程
|
|
* 2. 要绘制的区域不能超过屏幕的显示区域
|
|
*
|
|
*****************************************************************************************************************************************/
|
|
|
|
void LCD_FillCircle(uint16_t x, uint16_t y, uint16_t r)
|
|
{
|
|
int32_t D; /* Decision Variable */
|
|
uint32_t CurX;/* Current X Value */
|
|
uint32_t CurY;/* Current Y Value */
|
|
|
|
D = 3 - (r << 1);
|
|
|
|
CurX = 0;
|
|
CurY = r;
|
|
|
|
while (CurX <= CurY)
|
|
{
|
|
if(CurY > 0)
|
|
{
|
|
LCD_DrawLine(x - CurX, y - CurY,x - CurX,y - CurY + 2*CurY);
|
|
LCD_DrawLine(x + CurX, y - CurY,x + CurX,y - CurY + 2*CurY);
|
|
}
|
|
|
|
if(CurX > 0)
|
|
{
|
|
LCD_DrawLine(x - CurY, y - CurX,x - CurY,y - CurX + 2*CurX);
|
|
LCD_DrawLine(x + CurY, y - CurX,x + CurY,y - CurX + 2*CurX);
|
|
}
|
|
if (D < 0)
|
|
{
|
|
D += (CurX << 2) + 6;
|
|
}
|
|
else
|
|
{
|
|
D += ((CurX - CurY) << 2) + 10;
|
|
CurY--;
|
|
}
|
|
CurX++;
|
|
}
|
|
|
|
LCD_DrawCircle(x, y, r);
|
|
}
|
|
|
|
|
|
/***************************************************************************************************************************************
|
|
* 函 数 名: LCD_DrawImage
|
|
*
|
|
* 入口参数: x - 水平坐标,取值范围 0~799
|
|
* y - 垂直坐标,取值范围 0~479
|
|
* width - 图片的水平宽度,最大取值800
|
|
* height - 图片的垂直宽度,最大取值480
|
|
* *pImage - 图片数据存储区的首地址
|
|
*
|
|
* 函数功能: 在指定坐标处显示图片
|
|
*
|
|
* 说 明: 要显示的图片需要事先进行取模,且只能显示一种颜色,使用 LCD_SetColor() 函数设置画笔色
|
|
*
|
|
*****************************************************************************************************************************************/
|
|
|
|
void LCD_DrawImage(uint16_t x,uint16_t y,uint16_t width,uint16_t height,const uint8_t *pImage)
|
|
{
|
|
uint8_t disChar; //字模的值
|
|
uint16_t Xaddress = x; //水平坐标
|
|
uint16_t i=0,j=0,m=0;
|
|
|
|
for(i = 0; i <height; i++)
|
|
{
|
|
for(j = 0; j <(float)width/8; j++)
|
|
{
|
|
disChar = *pImage;
|
|
|
|
for(m = 0; m < 8; m++)
|
|
{
|
|
if(disChar & 0x01)
|
|
{
|
|
LCD_Draw_Point(Xaddress,y,my_lcd.color); //当前模值不为0时,使用画笔色绘点
|
|
}
|
|
else
|
|
{
|
|
LCD_Draw_Point(Xaddress,y,my_lcd.color); //否则使用背景色绘制点
|
|
}
|
|
disChar >>= 1;
|
|
Xaddress++; //水平坐标自加
|
|
|
|
if( (Xaddress - x)==width ) //如果水平坐标达到了字符宽度,则退出当前循环
|
|
{ //进入下一行的绘制
|
|
Xaddress = x;
|
|
y++;
|
|
break;
|
|
}
|
|
}
|
|
pImage++;
|
|
}
|
|
}
|
|
} |