#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 >= 1; Xaddress++; //水平坐标自加 if( (Xaddress - x)==width ) //如果水平坐标达到了字符宽度,则退出当前循环 { //进入下一行的绘制 Xaddress = x; y++; break; } } pImage++; } } }