2026-08-26 07:26:58 +08:00
|
|
|
|
#include "includes.h"
|
|
|
|
|
|
#include "Drv_ILI9341_Lcd_EnglishFont.h"
|
|
|
|
|
|
#include "Drv_ILI9341_Lcd_ChineseFont.h"
|
|
|
|
|
|
#include "w25q128.h"
|
|
|
|
|
|
#define PIC_BATCH_SIZE 1024
|
|
|
|
|
|
|
2026-08-28 11:24:06 +08:00
|
|
|
|
static uint8_t LCD_CnFontMetrics(uint8_t sizey, uint8_t *sizex, uint16_t *typeface_num)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (sizey)
|
|
|
|
|
|
{
|
|
|
|
|
|
case 8: *sizex = 8; *typeface_num = 8; return 1;
|
|
|
|
|
|
case 11: *sizex = 11; *typeface_num = 22; return 1;
|
|
|
|
|
|
case 12: *sizex = 12; *typeface_num = 24; return 1;
|
|
|
|
|
|
case 13: *sizex = 13; *typeface_num = 26; return 1;
|
|
|
|
|
|
case 15: *sizex = 15; *typeface_num = 30; return 1;
|
|
|
|
|
|
case 16: *sizex = 16; *typeface_num = 32; return 1;
|
|
|
|
|
|
case 24: *sizex = 24; *typeface_num = 72; return 1;
|
|
|
|
|
|
case 28: *sizex = 28; *typeface_num = 112; return 1;
|
|
|
|
|
|
default: return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint8_t LCD_GetCnFontByte(uint8_t sizey, uint8_t index, uint16_t i)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (sizey)
|
|
|
|
|
|
{
|
|
|
|
|
|
case 8: return Chinese_font_8[index][i];
|
|
|
|
|
|
case 11: return Chinese_font_11[index][i];
|
|
|
|
|
|
case 12: return Chinese_font_12[index][i];
|
|
|
|
|
|
case 13: return Chinese_font_13[index][i];
|
|
|
|
|
|
case 15: return Chinese_font_15[index][i];
|
|
|
|
|
|
case 16: return Chinese_font_16[index][i];
|
|
|
|
|
|
case 24: return Chinese_font_24[index][i];
|
|
|
|
|
|
case 28: return Chinese_font_28[index][i];
|
|
|
|
|
|
default: return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint8_t LCD_GetAsciiFontByte(uint8_t sizey, uint8_t num, uint16_t i)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (sizey)
|
|
|
|
|
|
{
|
|
|
|
|
|
case 8: return ascii_84[num][i];
|
|
|
|
|
|
case 11: return ascii_115[num][i];
|
|
|
|
|
|
case 12: return ascii_126[num][i];
|
|
|
|
|
|
case 13: return ascii_1306[num][i];
|
|
|
|
|
|
case 15: return ascii_157[num][i];
|
|
|
|
|
|
case 16: return ascii_1608[num][i];
|
|
|
|
|
|
case 24: return ascii_2412[num][i];
|
|
|
|
|
|
case 28: return ascii_2814[num][i];
|
|
|
|
|
|
default: return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const char (*LCD_GetChsTable(uint8_t sizey))[2]
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (sizey)
|
|
|
|
|
|
{
|
|
|
|
|
|
case 8: return CHS8Table;
|
|
|
|
|
|
case 11: return CHS11Table;
|
|
|
|
|
|
case 12: return CHS12Table;
|
|
|
|
|
|
case 13: return CHS13Table;
|
|
|
|
|
|
case 15: return CHS15Table;
|
|
|
|
|
|
case 16: return CHS16Table;
|
|
|
|
|
|
case 24: return CHS24Table;
|
|
|
|
|
|
case 28: return CHS24Table;
|
|
|
|
|
|
default: return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint16_t LCD_GetChsTableSize(uint8_t sizey)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (sizey)
|
|
|
|
|
|
{
|
|
|
|
|
|
case 8: return (uint16_t)(sizeof(CHS8Table) / 2);
|
|
|
|
|
|
case 11: return (uint16_t)(sizeof(CHS11Table) / 2);
|
|
|
|
|
|
case 12: return (uint16_t)(sizeof(CHS12Table) / 2);
|
|
|
|
|
|
case 13: return (uint16_t)(sizeof(CHS13Table) / 2);
|
|
|
|
|
|
case 15: return (uint16_t)(sizeof(CHS15Table) / 2);
|
|
|
|
|
|
case 16: return (uint16_t)(sizeof(CHS16Table) / 2);
|
|
|
|
|
|
case 24: return (uint16_t)(sizeof(CHS24Table) / 2);
|
|
|
|
|
|
case 28: return (uint16_t)(sizeof(CHS24Table) / 2);
|
|
|
|
|
|
default: return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint8_t LCD_GetAsciiMetrics(uint8_t size, uint8_t *char_width, uint8_t *char_height)
|
|
|
|
|
|
{
|
|
|
|
|
|
*char_height = size;
|
|
|
|
|
|
switch (size)
|
|
|
|
|
|
{
|
|
|
|
|
|
case 8: *char_width = 4; return 1;
|
|
|
|
|
|
case 11: *char_width = 5; return 1;
|
|
|
|
|
|
case 12: *char_width = 6; return 1;
|
|
|
|
|
|
case 13: *char_width = 6; return 1;
|
|
|
|
|
|
case 15: *char_width = 7; return 1;
|
|
|
|
|
|
case 16: *char_width = 8; return 1;
|
|
|
|
|
|
case 24: *char_width = 12; return 1;
|
|
|
|
|
|
case 28: *char_width = 14; return 1;
|
|
|
|
|
|
default: return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
|
|
|
|
|
//r:0-31 g:0-63 b:0-31
|
|
|
|
|
|
uint16_t RGB(int r,int g,int b)
|
|
|
|
|
|
{
|
|
|
|
|
|
return r << 11 | g << 5 | b;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// SPI轮询批量发送(无DMA开销,适合10~100字节的小批量数据)
|
|
|
|
|
|
void LCD_SPI_Write(const uint8_t *data, uint32_t len)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint32_t tmp = len;
|
|
|
|
|
|
while (tmp--) {
|
|
|
|
|
|
while (!(SPI2->sts & SPI_I2S_TDBE_FLAG));
|
|
|
|
|
|
SPI2->dt = *(data++);
|
|
|
|
|
|
}
|
|
|
|
|
|
while (SPI2->sts & SPI_I2S_BF_FLAG);
|
|
|
|
|
|
}
|
|
|
|
|
|
static uint8_t pic_batch_buf[PIC_BATCH_SIZE];
|
|
|
|
|
|
// 在指定位置显示图片
|
|
|
|
|
|
void LCD_WR_PIC(uint16_t x, uint16_t y, uint16_t length, uint16_t width, const uint8_t data[])
|
|
|
|
|
|
{
|
|
|
|
|
|
// 1. 计算总像素数和总字节数(每个像素2字节RGB565)
|
|
|
|
|
|
uint32_t total_pixels = (uint32_t)length * width;
|
|
|
|
|
|
uint32_t total_bytes = total_pixels * 2;
|
|
|
|
|
|
if (total_bytes == 0) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 设置显示区域
|
|
|
|
|
|
LCD_SetWindow(x, y, x + length - 1, y + width - 1);
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 手动设置DC为数据模式(批量传输期间保持)
|
|
|
|
|
|
LCD_DC_Set();
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 批量DMA传输数据(直接从源地址发送,无需中间拷贝)
|
|
|
|
|
|
// 注意:data 指向 Flash 中的 const 数组,STM32F1 DMA 可直接从 Flash 读取
|
|
|
|
|
|
uint32_t remaining_bytes = total_bytes;
|
|
|
|
|
|
uint32_t pic_offset = 0;
|
|
|
|
|
|
|
|
|
|
|
|
while (remaining_bytes > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint32_t transmit_bytes = (remaining_bytes >= PIC_BATCH_SIZE) ? PIC_BATCH_SIZE : remaining_bytes;
|
|
|
|
|
|
|
|
|
|
|
|
/* DMA 直接从源数据地址发送(无中间拷贝) */
|
|
|
|
|
|
LCD_SPI_DMA_Send(data + pic_offset, transmit_bytes);
|
|
|
|
|
|
|
|
|
|
|
|
pic_offset += transmit_bytes;
|
|
|
|
|
|
remaining_bytes -= transmit_bytes;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-31 06:10:13 +08:00
|
|
|
|
/* 跳过 key_color 像素,用于图标透明底(常见 key=BLACK) */
|
|
|
|
|
|
void LCD_WR_PIC_Trans(uint16_t x, uint16_t y, uint16_t length, uint16_t width,
|
|
|
|
|
|
const uint8_t data[], uint16_t key_color)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint32_t total_pixels = (uint32_t)length * width;
|
|
|
|
|
|
uint8_t key_h = (uint8_t)(key_color >> 8);
|
|
|
|
|
|
uint8_t key_l = (uint8_t)(key_color & 0xFF);
|
|
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
|
|
|
|
if (total_pixels == 0)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < total_pixels; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t hi = data[i * 2];
|
|
|
|
|
|
uint8_t lo = data[i * 2 + 1];
|
|
|
|
|
|
if (hi == key_h && lo == key_l)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
LCD_DrawPoint((uint16_t)(x + (i % length)),
|
|
|
|
|
|
(uint16_t)(y + (i / length)),
|
|
|
|
|
|
(uint16_t)((hi << 8) | lo));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-26 07:26:58 +08:00
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:从W25Q128外部Flash读取图片数据并显示
|
|
|
|
|
|
入口数据:x,y 显示起始坐标
|
|
|
|
|
|
length 图片宽度(像素)
|
|
|
|
|
|
width 图片高度(像素)
|
|
|
|
|
|
flash_addr W25Q128中的起始地址
|
|
|
|
|
|
返回值: 无
|
|
|
|
|
|
注意: 图片数据格式为RGB565,每像素2字节
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
void LCD_WR_PIC_FROM_FLASH(uint16_t x, uint16_t y, uint16_t length, uint16_t width, uint32_t flash_addr)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 1. 计算总像素数和总字节数
|
|
|
|
|
|
uint32_t total_pixels = (uint32_t)length * width;
|
|
|
|
|
|
uint32_t total_bytes = total_pixels * 2;
|
|
|
|
|
|
if (total_bytes == 0) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 设置显示区域
|
|
|
|
|
|
LCD_SetWindow(x, y, x + length - 1, y + width - 1);
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 手动设置DC为数据模式(批量传输期间保持)
|
|
|
|
|
|
LCD_DC_Set();
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 分批从W25Q128读取并发送到LCD
|
|
|
|
|
|
uint32_t remaining_bytes = total_bytes;
|
|
|
|
|
|
uint32_t flash_offset = 0;
|
|
|
|
|
|
|
|
|
|
|
|
while (remaining_bytes > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint32_t batch_size = (remaining_bytes >= PIC_BATCH_SIZE) ? PIC_BATCH_SIZE : remaining_bytes;
|
|
|
|
|
|
|
|
|
|
|
|
// 从W25Q128读取一批数据到内存缓冲区(SPI1阻塞读)
|
|
|
|
|
|
W25Q128_Read(pic_batch_buf, flash_addr + flash_offset, (uint16_t)batch_size);
|
|
|
|
|
|
|
|
|
|
|
|
// 通过SPI2 DMA发送到LCD(内部等待完成)
|
|
|
|
|
|
LCD_SPI_DMA_Send(pic_batch_buf, batch_size);
|
|
|
|
|
|
|
|
|
|
|
|
flash_offset += batch_size;
|
|
|
|
|
|
remaining_bytes -= batch_size;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:在指定区域填充颜色
|
|
|
|
|
|
入口数据:xsta,ysta 起始坐标
|
|
|
|
|
|
xend,yend 终止坐标
|
|
|
|
|
|
color 要填充的颜色
|
|
|
|
|
|
返回值: 无
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
//void LCD_FillByColor(uint16_t xsta,uint16_t ysta,uint16_t xend,uint16_t yend,uint16_t color)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// uint16_t i,j,fill;
|
|
|
|
|
|
// uint8_t u8ColorTmp[960];
|
|
|
|
|
|
//
|
|
|
|
|
|
// LCD_SetWindow(xsta,ysta,xend-1,yend-1);//设置显示范围
|
|
|
|
|
|
//
|
|
|
|
|
|
// for(i=ysta;i<yend;i++)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// for(j=xsta;j<xend;j++)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// LCD_WR_DATA16(color);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// return ;
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////// 把缓冲区改为全局/静态(避免栈溢出)
|
|
|
|
|
|
uint8_t lcd_fill_buf[2048]; // 1024字节 = 512个像素,减少DMA批次
|
|
|
|
|
|
////
|
|
|
|
|
|
void LCD_FillByColor(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend, uint16_t color)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(xsta >= xend || ysta >= yend)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
uint32_t total_pixel;
|
|
|
|
|
|
int i;
|
|
|
|
|
|
// 颜色拆分:16位RGB565拆分为高低8位
|
|
|
|
|
|
uint8_t ch = (color >> 8) & 0xFF;
|
|
|
|
|
|
uint8_t cl = color & 0xFF;
|
|
|
|
|
|
|
|
|
|
|
|
int buf_pixels = sizeof(lcd_fill_buf) / 2; // 1024个像素(2048字节)
|
|
|
|
|
|
|
|
|
|
|
|
// 预填充颜色缓冲区:每个像素2字节(高8位+低8位)
|
|
|
|
|
|
for (i = 0; i < buf_pixels; i++) {
|
|
|
|
|
|
lcd_fill_buf[i * 2] = ch;
|
|
|
|
|
|
lcd_fill_buf[i * 2 + 1] = cl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置屏幕填充窗口(告诉屏幕要填充的区域)
|
|
|
|
|
|
LCD_SetWindow(xsta, ysta, xend - 1, yend - 1);
|
|
|
|
|
|
|
|
|
|
|
|
// 切换到数据模式(DC=1,屏幕接收像素数据)
|
|
|
|
|
|
LCD_DC_Set();
|
|
|
|
|
|
|
|
|
|
|
|
// 计算总像素数
|
|
|
|
|
|
total_pixel = (uint32_t)(xend - xsta) * (yend - ysta);
|
|
|
|
|
|
|
|
|
|
|
|
// 批量DMA发送像素数据
|
|
|
|
|
|
while (total_pixel > 0) {
|
|
|
|
|
|
int send_pixels = (total_pixel > buf_pixels) ? buf_pixels : total_pixel;
|
|
|
|
|
|
int send_bytes = send_pixels * 2;
|
|
|
|
|
|
|
|
|
|
|
|
/* DMA 发送(内部等待完成) */
|
|
|
|
|
|
LCD_SPI_DMA_Send(lcd_fill_buf, send_bytes);
|
|
|
|
|
|
|
|
|
|
|
|
total_pixel -= send_pixels;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 恢复DC为指令模式(避免后续指令被当数据处理)
|
|
|
|
|
|
LCD_DC_Clr();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:垂直渐变填充矩形区域(顶部颜色 → 底部颜色)
|
|
|
|
|
|
入口数据:xsta,ysta 起始坐标
|
|
|
|
|
|
xend,yend 终止坐标
|
|
|
|
|
|
color_top 顶部颜色(RGB565)
|
|
|
|
|
|
color_bottom 底部颜色(RGB565)
|
|
|
|
|
|
实现: 逐行插值 R/G/B 分量,复用 lcd_fill_buf 批量发送
|
|
|
|
|
|
注意: 当前测试颜色:深灰(0x5AEB) → 黑(0x0000)
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
void LCD_FillGradient(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend,
|
|
|
|
|
|
uint16_t color_top, uint16_t color_bottom)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (xsta >= xend || ysta >= yend) return;
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t height = yend - ysta;
|
|
|
|
|
|
uint16_t width = xend - xsta;
|
|
|
|
|
|
if (width == 0 || height == 0) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 拆分解顶底颜色的 R/G/B 分量(RGB565)
|
|
|
|
|
|
uint16_t r_top = (color_top >> 11) & 0x1F;
|
|
|
|
|
|
uint16_t g_top = (color_top >> 5) & 0x3F;
|
|
|
|
|
|
uint16_t b_top = color_top & 0x1F;
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t r_bot = (color_bottom >> 11) & 0x1F;
|
|
|
|
|
|
uint16_t g_bot = (color_bottom >> 5) & 0x3F;
|
|
|
|
|
|
uint16_t b_bot = color_bottom & 0x1F;
|
|
|
|
|
|
|
|
|
|
|
|
// 只用 SetWindow 设一次整个区域,GRAM 地址自动递增
|
|
|
|
|
|
LCD_SetWindow(xsta, ysta, xend - 1, yend - 1);
|
|
|
|
|
|
LCD_DC_Set();
|
|
|
|
|
|
|
|
|
|
|
|
// 用 lcd_fill_buf 逐行发送,一行 240 像素 = 480 字节 < 700,不会溢出
|
|
|
|
|
|
int row_bytes = width * 2;
|
|
|
|
|
|
|
|
|
|
|
|
// 高度为1时直接填顶部颜色,防止除零
|
|
|
|
|
|
if (height <= 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t ch = (color_top >> 8) & 0xFF;
|
|
|
|
|
|
uint8_t cl = color_top & 0xFF;
|
|
|
|
|
|
for (int i = 0; i < width; i++) {
|
|
|
|
|
|
lcd_fill_buf[i * 2] = ch;
|
|
|
|
|
|
lcd_fill_buf[i * 2 + 1] = cl;
|
|
|
|
|
|
}
|
|
|
|
|
|
LCD_SPI_Write(lcd_fill_buf, row_bytes);
|
|
|
|
|
|
LCD_DC_Clr();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 逐行填充:纯整数运算 val = top + (bot - top) * row / (height - 1)
|
|
|
|
|
|
for (uint16_t row = 0; row < height; row++)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint16_t r = r_top + (r_bot - r_top) * row / (height - 1);
|
|
|
|
|
|
uint16_t g = g_top + (g_bot - g_top) * row / (height - 1);
|
|
|
|
|
|
uint16_t b = b_top + (b_bot - b_top) * row / (height - 1);
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t color = (r << 11) | (g << 5) | b;
|
|
|
|
|
|
uint8_t ch = (color >> 8) & 0xFF;
|
|
|
|
|
|
uint8_t cl = color & 0xFF;
|
|
|
|
|
|
|
|
|
|
|
|
// 填充行缓冲
|
|
|
|
|
|
for (int i = 0; i < width; i++) {
|
|
|
|
|
|
lcd_fill_buf[i * 2] = ch;
|
|
|
|
|
|
lcd_fill_buf[i * 2 + 1] = cl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 发送该行(SPI 轮询)
|
|
|
|
|
|
LCD_SPI_Write(lcd_fill_buf, row_bytes);
|
|
|
|
|
|
}
|
|
|
|
|
|
LCD_DC_Clr();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
入口数据:x,y 画点坐标
|
|
|
|
|
|
color 点的颜色
|
|
|
|
|
|
返回值: 无
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
void LCD_DrawPoint(uint16_t x,uint16_t y,uint16_t color)
|
|
|
|
|
|
{
|
|
|
|
|
|
LCD_SetWindow(x, y, x, y);//设置光标位置
|
|
|
|
|
|
LCD_WR_DATA16(color);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:画线
|
|
|
|
|
|
入口数据:x1,y1 起始坐标
|
|
|
|
|
|
x2,y2 终止坐标
|
|
|
|
|
|
color 线的颜色
|
|
|
|
|
|
返回值: 无
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
|
|
|
|
|
|
{
|
|
|
|
|
|
// ===== 水平/垂直线快速通道(用批量填充代替逐点画) =====
|
|
|
|
|
|
if (y1 == y2)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (x1 > x2) { uint16_t tmp = x1; x1 = x2; x2 = tmp; }
|
|
|
|
|
|
LCD_FillByColor(x1, y1, x2 + 1, y1 + 1, color);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (x1 == x2)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (y1 > y2) { uint16_t tmp = y1; y1 = y2; y2 = tmp; }
|
|
|
|
|
|
LCD_FillByColor(x1, y1, x1 + 1, y2 + 1, color);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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, color);//画点
|
|
|
|
|
|
xerr += delta_x;
|
|
|
|
|
|
yerr += delta_y;
|
|
|
|
|
|
|
|
|
|
|
|
if(xerr > distance)
|
|
|
|
|
|
{
|
|
|
|
|
|
xerr -= distance;
|
|
|
|
|
|
uRow += incx;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(yerr > distance)
|
|
|
|
|
|
{
|
|
|
|
|
|
yerr -= distance;
|
|
|
|
|
|
uCol += incy;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// for(uint16_t x = x1;x <= x2;x++)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// LCD_DrawPoint(x,y1,color);
|
|
|
|
|
|
// }
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:画矩形
|
|
|
|
|
|
入口数据:x1,y1 起始坐标
|
|
|
|
|
|
x2,y2 终止坐标
|
|
|
|
|
|
color 矩形的颜色
|
|
|
|
|
|
返回值: 无
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2,uint16_t color)
|
|
|
|
|
|
{
|
|
|
|
|
|
LCD_DrawLine(x1, y1, x2, y1, color);
|
|
|
|
|
|
LCD_DrawLine(x1, y1, x1, y2, color);
|
|
|
|
|
|
LCD_DrawLine(x1, y2, x2, y2, color);
|
|
|
|
|
|
LCD_DrawLine(x2, y1, x2, y2, color);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:画圆
|
|
|
|
|
|
入口数据:x0,y0 圆心坐标
|
|
|
|
|
|
r 半径
|
|
|
|
|
|
color 圆的颜色
|
|
|
|
|
|
返回值: 无
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
void LCD_DrawCircle(uint16_t x0, uint16_t y0, uint8_t r, uint16_t color)
|
|
|
|
|
|
{
|
|
|
|
|
|
int a = 0, b = r;
|
|
|
|
|
|
|
|
|
|
|
|
while (a <= b)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 画 8 个对称点(逐点绘制,保证左右两侧正确显示)
|
|
|
|
|
|
LCD_DrawPoint(x0 + b, y0 - a, color);
|
|
|
|
|
|
LCD_DrawPoint(x0 + b, y0 + a, color);
|
|
|
|
|
|
LCD_DrawPoint(x0 - b, y0 - a, color);
|
|
|
|
|
|
LCD_DrawPoint(x0 - b, y0 + a, color);
|
|
|
|
|
|
LCD_DrawPoint(x0 + a, y0 - b, color);
|
|
|
|
|
|
LCD_DrawPoint(x0 + a, y0 + b, color);
|
|
|
|
|
|
LCD_DrawPoint(x0 - a, y0 - b, color);
|
|
|
|
|
|
LCD_DrawPoint(x0 - a, y0 + b, color);
|
|
|
|
|
|
a++;
|
|
|
|
|
|
|
|
|
|
|
|
if ((a * a + b * b) > (r * r))
|
|
|
|
|
|
b--;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:显示单个字符
|
|
|
|
|
|
入口数据:x,y显示坐标
|
|
|
|
|
|
num 要显示的字符
|
|
|
|
|
|
fc 字的颜色
|
|
|
|
|
|
bc 字的背景色
|
|
|
|
|
|
sizey 字号
|
|
|
|
|
|
mode: 0非叠加模式 1叠加模式
|
|
|
|
|
|
返回值: 无
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
void LCD_ShowChar(uint16_t x, uint16_t y, uint8_t num, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t sizex;
|
|
|
|
|
|
uint16_t i, TypefaceNum;
|
|
|
|
|
|
uint16_t x0 = x;
|
|
|
|
|
|
|
2026-08-28 11:24:06 +08:00
|
|
|
|
uint8_t char_h;
|
|
|
|
|
|
|
2026-08-26 07:26:58 +08:00
|
|
|
|
num = num - ' ';
|
2026-08-28 11:24:06 +08:00
|
|
|
|
if (!LCD_GetAsciiMetrics(sizey, &sizex, &char_h))
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
TypefaceNum = (sizex / 8 + ((sizex % 8) ? 1 : 0)) * sizey;
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 一次性设置窗口(LCD地址自动递增,无需每像素都设)
|
|
|
|
|
|
LCD_SetWindow(x, y, x + sizex - 1, y + sizey - 1);
|
|
|
|
|
|
LCD_DC_Set(); // 保持数据模式
|
|
|
|
|
|
|
|
|
|
|
|
if (!mode) // 非叠加模式(全字批量优化路径)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t fc_h = (fc >> 8) & 0xFF, fc_l = fc & 0xFF;
|
|
|
|
|
|
uint8_t bc_h = (bc >> 8) & 0xFF, bc_l = bc & 0xFF;
|
|
|
|
|
|
uint8_t temp;
|
|
|
|
|
|
uint8_t m = 0;
|
|
|
|
|
|
uint16_t buf_idx = 0;
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < TypefaceNum; i++)
|
|
|
|
|
|
{
|
2026-08-28 11:24:06 +08:00
|
|
|
|
temp = LCD_GetAsciiFontByte(sizey, num, i);
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
|
|
|
|
|
for (uint8_t t = 0; t < 8; t++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (temp & (0x01 << t))
|
|
|
|
|
|
{
|
|
|
|
|
|
pic_batch_buf[buf_idx++] = fc_h;
|
|
|
|
|
|
pic_batch_buf[buf_idx++] = fc_l;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
pic_batch_buf[buf_idx++] = bc_h;
|
|
|
|
|
|
pic_batch_buf[buf_idx++] = bc_l;
|
|
|
|
|
|
}
|
|
|
|
|
|
m++;
|
|
|
|
|
|
if (m == sizex) { m = 0; break; }
|
|
|
|
|
|
}
|
|
|
|
|
|
if (buf_idx + 16 > PIC_BATCH_SIZE) {
|
|
|
|
|
|
LCD_SPI_Write(pic_batch_buf, buf_idx);
|
|
|
|
|
|
buf_idx = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (buf_idx > 0)
|
|
|
|
|
|
LCD_SPI_Write(pic_batch_buf, buf_idx);
|
|
|
|
|
|
}
|
|
|
|
|
|
else // 叠加模式(保持逐点画,不改动)
|
|
|
|
|
|
{
|
2026-08-28 11:24:06 +08:00
|
|
|
|
uint8_t temp;
|
2026-08-26 07:26:58 +08:00
|
|
|
|
for (i = 0; i < TypefaceNum; i++)
|
|
|
|
|
|
{
|
2026-08-28 11:24:06 +08:00
|
|
|
|
temp = LCD_GetAsciiFontByte(sizey, num, i);
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
|
|
|
|
|
for (uint8_t t = 0; t < 8; t++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (temp & (0x01 << t))
|
|
|
|
|
|
LCD_DrawPoint(x, y, fc);
|
|
|
|
|
|
x++;
|
|
|
|
|
|
if ((x - x0) == sizex)
|
|
|
|
|
|
{
|
|
|
|
|
|
x = x0;
|
|
|
|
|
|
y++;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
LCD_DC_Clr();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void LCD_ShowChinese(uint16_t x, uint16_t y, uint8_t index, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t sizex;
|
|
|
|
|
|
uint16_t i, TypefaceNum = 0;
|
|
|
|
|
|
uint16_t x0 = x;
|
|
|
|
|
|
|
2026-08-28 11:24:06 +08:00
|
|
|
|
if (!LCD_CnFontMetrics(sizey, &sizex, &TypefaceNum))
|
|
|
|
|
|
return;
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 一次性设置窗口
|
|
|
|
|
|
LCD_SetWindow(x, y, x + sizex - 1, y + sizey - 1);
|
|
|
|
|
|
LCD_DC_Set();
|
|
|
|
|
|
|
|
|
|
|
|
if (!mode) // 非叠加模式(全字批量优化路径)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t fc_h = (fc >> 8) & 0xFF, fc_l = fc & 0xFF;
|
|
|
|
|
|
uint8_t bc_h = (bc >> 8) & 0xFF, bc_l = bc & 0xFF;
|
|
|
|
|
|
uint8_t temp;
|
|
|
|
|
|
uint8_t m = 0;
|
|
|
|
|
|
uint16_t buf_idx = 0;
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < TypefaceNum; i++)
|
|
|
|
|
|
{
|
2026-08-28 11:24:06 +08:00
|
|
|
|
temp = LCD_GetCnFontByte(sizey, index, i);
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
|
|
|
|
|
for (uint8_t t = 0; t < 8; t++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (temp & (0x80 >> t))
|
|
|
|
|
|
{
|
|
|
|
|
|
pic_batch_buf[buf_idx++] = fc_h;
|
|
|
|
|
|
pic_batch_buf[buf_idx++] = fc_l;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
pic_batch_buf[buf_idx++] = bc_h;
|
|
|
|
|
|
pic_batch_buf[buf_idx++] = bc_l;
|
|
|
|
|
|
}
|
|
|
|
|
|
m++;
|
|
|
|
|
|
if (m == sizex) { m = 0; break; }
|
|
|
|
|
|
}
|
|
|
|
|
|
if (buf_idx + 16 > PIC_BATCH_SIZE) {
|
|
|
|
|
|
LCD_SPI_Write(pic_batch_buf, buf_idx);
|
|
|
|
|
|
buf_idx = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (buf_idx > 0)
|
|
|
|
|
|
LCD_SPI_Write(pic_batch_buf, buf_idx);
|
|
|
|
|
|
}
|
|
|
|
|
|
else // 叠加模式(保持逐点画)
|
|
|
|
|
|
{
|
2026-08-28 11:24:06 +08:00
|
|
|
|
uint8_t temp;
|
2026-08-26 07:26:58 +08:00
|
|
|
|
for (i = 0; i < TypefaceNum; i++)
|
|
|
|
|
|
{
|
2026-08-28 11:24:06 +08:00
|
|
|
|
temp = LCD_GetCnFontByte(sizey, index, i);
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
|
|
|
|
|
for (uint8_t t = 0; t < 8; t++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (temp & (0x80 >> t))
|
|
|
|
|
|
LCD_DrawPoint(x, y, fc);
|
|
|
|
|
|
|
|
|
|
|
|
x++;
|
|
|
|
|
|
if ((x - x0) == sizex)
|
|
|
|
|
|
{
|
|
|
|
|
|
x = x0;
|
|
|
|
|
|
y++;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
LCD_DC_Clr();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:带圆角矩形填充
|
|
|
|
|
|
入口数据:x,y 左上角坐标
|
|
|
|
|
|
w,h 宽度、高度
|
|
|
|
|
|
r 圆角半径(建议 5~12 最明显)
|
|
|
|
|
|
color 填充颜色
|
|
|
|
|
|
返回值: 无
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
// 鍦嗚鐭╁舰鍗曡壊濉厖锛堜繚鐣欏師鏈夎皟鐢ㄨ<E990A2>呬笉鍙楀奖鍝嶏級
|
|
|
|
|
|
// 鏃х増瀹炵幇鍦ㄤ笅鏂规敞閲婂尯鍐呬繚鐣欙紝渚垮洖婊?
|
|
|
|
|
|
void LCD_FillRoundRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r, uint16_t color)
|
|
|
|
|
|
{
|
|
|
|
|
|
int16_t x1 = x, y1 = y;
|
|
|
|
|
|
int16_t x2 = x + w - 1, y2 = y + h - 1;
|
|
|
|
|
|
|
|
|
|
|
|
if (r > (w / 2)) r = w / 2;
|
|
|
|
|
|
if (r > (h / 2)) r = h / 2;
|
|
|
|
|
|
|
|
|
|
|
|
LCD_FillByColor(x1 + r, y1, x2 - r + 1, y2 + 1, color);
|
|
|
|
|
|
LCD_FillByColor(x1, y1 + r, x1 + r, y2 - r + 1, color);
|
|
|
|
|
|
LCD_FillByColor(x2 - r + 1, y1 + r, x2 + 1, y2 - r + 1, color);
|
|
|
|
|
|
|
|
|
|
|
|
int16_t cx1 = x1 + r;
|
|
|
|
|
|
int16_t cy1 = y1 + r;
|
|
|
|
|
|
int16_t cx2 = x2 - r;
|
|
|
|
|
|
int16_t cy2 = y2 - r;
|
|
|
|
|
|
|
|
|
|
|
|
int16_t tx, ty, d;
|
|
|
|
|
|
tx = 0;
|
|
|
|
|
|
ty = r;
|
|
|
|
|
|
d = 3 - 2 * r;
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t ch = (color >> 8) & 0xFF;
|
|
|
|
|
|
uint8_t cl = color & 0xFF;
|
|
|
|
|
|
|
|
|
|
|
|
while (tx <= ty)
|
|
|
|
|
|
{
|
|
|
|
|
|
LCD_DrawPoint(cx1 - ty, cy1 - tx, color);
|
|
|
|
|
|
LCD_DrawPoint(cx2 + ty, cy1 - tx, color);
|
|
|
|
|
|
LCD_DrawPoint(cx1 - tx, cy1 - ty, color);
|
|
|
|
|
|
LCD_DrawPoint(cx2 + tx, cy1 - ty, color);
|
|
|
|
|
|
LCD_DrawPoint(cx1 - ty, cy2 + tx, color);
|
|
|
|
|
|
LCD_DrawPoint(cx2 + ty, cy2 + tx, color);
|
|
|
|
|
|
LCD_DrawPoint(cx1 - tx, cy2 + ty, color);
|
|
|
|
|
|
LCD_DrawPoint(cx2 + tx, cy2 + ty, color);
|
|
|
|
|
|
|
|
|
|
|
|
if (d < 0) d += 4 * tx + 6;
|
|
|
|
|
|
else { d += 4 * (tx - ty) + 10; ty--; }
|
|
|
|
|
|
tx++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (ty = 0; ty < r; ty++)
|
|
|
|
|
|
{
|
|
|
|
|
|
int max_tx = -1;
|
|
|
|
|
|
for (tx = 0; tx < r; tx++) { if (tx * tx + ty * ty <= r * r) max_tx = tx; }
|
|
|
|
|
|
if (max_tx < 0) continue;
|
|
|
|
|
|
int row_pixels = max_tx + 1;
|
|
|
|
|
|
uint8_t row_buf[48];
|
|
|
|
|
|
for (tx = 0; tx < row_pixels; tx++) { row_buf[tx * 2] = ch; row_buf[tx * 2 + 1] = cl; }
|
|
|
|
|
|
int row_bytes = row_pixels * 2;
|
|
|
|
|
|
LCD_SetWindow(cx1 - max_tx, cy1 - ty, cx1, cy1 - ty); LCD_DC_Set(); LCD_SPI_Write(row_buf, row_bytes);
|
|
|
|
|
|
LCD_SetWindow(cx2, cy1 - ty, cx2 + max_tx, cy1 - ty); LCD_DC_Set(); LCD_SPI_Write(row_buf, row_bytes);
|
|
|
|
|
|
LCD_SetWindow(cx1 - max_tx, cy2 + ty, cx1, cy2 + ty); LCD_DC_Set(); LCD_SPI_Write(row_buf, row_bytes);
|
|
|
|
|
|
LCD_SetWindow(cx2, cy2 + ty, cx2 + max_tx, cy2 + ty); LCD_DC_Set(); LCD_SPI_Write(row_buf, row_bytes);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// =====================================================================
|
|
|
|
|
|
// 函数名:LCD_FillRoundRectGradient
|
|
|
|
|
|
// 功能:绘制渐变圆角矩形,从上到下垂直渐变填充
|
|
|
|
|
|
//
|
|
|
|
|
|
// 入参说明:
|
|
|
|
|
|
// x, y 矩形左上角坐标
|
|
|
|
|
|
// w, h 矩形宽度、高度
|
|
|
|
|
|
// r 圆角半径
|
|
|
|
|
|
// color_top 顶部起始颜色(RGB565格式)
|
|
|
|
|
|
// color_bottom底部结束颜色(RGB565格式)
|
|
|
|
|
|
//
|
|
|
|
|
|
// 实现逻辑:
|
|
|
|
|
|
// 1. 逐行计算每行对应的渐变中间色值;
|
|
|
|
|
|
// 2. 计算圆角区域有效显示范围,仅渲染可见像素;
|
|
|
|
|
|
// 3. 调用单行填充接口 LCD_FillByColor 逐行绘制;
|
|
|
|
|
|
// 4. 逐行渲染保证垂直渐变过渡平滑无断层。
|
|
|
|
|
|
// =====================================================================
|
|
|
|
|
|
void LCD_FillRoundRectGradient(uint16_t x, uint16_t y, uint16_t w, uint16_t h,
|
|
|
|
|
|
uint16_t r, uint16_t color_top, uint16_t color_bottom)
|
|
|
|
|
|
{
|
|
|
|
|
|
int16_t x1 = x, y1 = y;
|
|
|
|
|
|
int16_t x2 = x + w - 1, y2 = y + h - 1;
|
|
|
|
|
|
|
|
|
|
|
|
// 闄愬埗鍦嗚鏈<EE9D97>ぇ涓嶈秴杩囧崐瀹<E5B490>崐楂?
|
|
|
|
|
|
if (r > (w / 2)) r = w / 2;
|
|
|
|
|
|
if (r > (h / 2)) r = h / 2;
|
|
|
|
|
|
|
|
|
|
|
|
if (h <= 1) { LCD_FillByColor(x, y, x2 + 1, y2 + 1, color_top); return; }
|
|
|
|
|
|
|
|
|
|
|
|
// 鎷嗚В椤跺簳棰滆壊R/G/B鍒嗛噺
|
|
|
|
|
|
uint16_t r_top = (color_top >> 11) & 0x1F;
|
|
|
|
|
|
uint16_t g_top = (color_top >> 5) & 0x3F;
|
|
|
|
|
|
uint16_t b_top = color_top & 0x1F;
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t r_bot = (color_bottom >> 11) & 0x1F;
|
|
|
|
|
|
uint16_t g_bot = (color_bottom >> 5) & 0x3F;
|
|
|
|
|
|
uint16_t b_bot = color_bottom & 0x1F;
|
|
|
|
|
|
|
|
|
|
|
|
// int16_t cx1 = x1 + r;
|
|
|
|
|
|
int16_t cy1 = y1 + r;
|
|
|
|
|
|
// int16_t cx2 = x2 - r;
|
|
|
|
|
|
int16_t cy2 = y2 - r;
|
|
|
|
|
|
|
|
|
|
|
|
// 娓愬彉琛屽~鍏咃細閫犺璁$畻璇ュ瞾棰滆壊鍜屽彲瑙<E5BDB2>寮韫堬紙鑰冭檻鍦嗚锛?
|
|
|
|
|
|
for (int16_t row_y = y1; row_y <= y2; row_y++)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 璁$畻璇ヨ娓愬彉棰滆壊
|
|
|
|
|
|
uint16_t offset = row_y - y1;
|
|
|
|
|
|
uint16_t r_comp = r_top + (r_bot - r_top) * offset / (h - 1);
|
|
|
|
|
|
uint16_t g_comp = g_top + (g_bot - g_top) * offset / (h - 1);
|
|
|
|
|
|
uint16_t b_comp = b_top + (b_bot - b_top) * offset / (h - 1);
|
|
|
|
|
|
uint16_t color = (r_comp << 11) | (g_comp << 5) | b_comp;
|
|
|
|
|
|
|
|
|
|
|
|
// 璁$畻璇ヨ宸﹀彸搴旇烦杩囩殑鍍忕礌鏁帮紙鍦嗚閮ㄥ垎锛?
|
|
|
|
|
|
int16_t left_skip = 0;
|
|
|
|
|
|
int16_t right_skip = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (r > 0 && row_y < cy1)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 椤堕儴鍦嗚
|
|
|
|
|
|
int16_t ty = cy1 - row_y - 1; // 0 ~ r-1
|
|
|
|
|
|
if (ty >= 0 && ty < r)
|
|
|
|
|
|
{
|
|
|
|
|
|
int max_tx = 0;
|
|
|
|
|
|
for (int16_t tx = 0; tx < r; tx++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (tx * tx + ty * ty <= r * r) max_tx = tx;
|
|
|
|
|
|
}
|
|
|
|
|
|
left_skip = r - max_tx - 1;
|
|
|
|
|
|
right_skip = left_skip;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (r > 0 && row_y > cy2)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 搴曢儴鍦嗚
|
|
|
|
|
|
int16_t ty = row_y - cy2 - 1; // 0 ~ r-1
|
|
|
|
|
|
if (ty >= 0 && ty < r)
|
|
|
|
|
|
{
|
|
|
|
|
|
int max_tx = 0;
|
|
|
|
|
|
for (int16_t tx = 0; tx < r; tx++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (tx * tx + ty * ty <= r * r) max_tx = tx;
|
|
|
|
|
|
}
|
|
|
|
|
|
left_skip = r - max_tx - 1;
|
|
|
|
|
|
right_skip = left_skip;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 濉厖璇ヨ鍙閮ㄥ垎
|
|
|
|
|
|
LCD_FillByColor(x1 + left_skip, row_y, x2 - right_skip + 1, row_y + 1, color);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//void LCD_FillRoundRect(uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, uint16_t r, uint16_t color)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// uint16_t x2 = x0 + w - 1;
|
|
|
|
|
|
// uint16_t y2 = y0 + h - 1;
|
|
|
|
|
|
// if(w == 0 || h == 0) return;
|
|
|
|
|
|
// if(r > w/2) r = w/2;
|
|
|
|
|
|
// if(r > h/2) r = w/2;
|
|
|
|
|
|
//
|
|
|
|
|
|
// // 主体填充
|
|
|
|
|
|
// LCD_FillByColor(x0, y0 + r, x2+1, y2 - r + 1, color);
|
|
|
|
|
|
// LCD_FillByColor(x0 + r, y0, x2 - r + 1, y0 + r + 1, color);
|
|
|
|
|
|
// LCD_FillByColor(x0 + r, y2 - r + 1, x2 - r + 1, y2 + 1, color);
|
|
|
|
|
|
//
|
|
|
|
|
|
// // 简易圆角(逐行填充,无复杂算法)
|
|
|
|
|
|
// for(uint16_t y = 0; y < r; y++)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// for(uint16_t x = 0; x < r; x++)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// if(x*x + y*y <= r*r)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// LCD_DrawPoint(x0 + r - x, y0 + r - y, color);
|
|
|
|
|
|
// LCD_DrawPoint(x2 - r + x, y0 + r - y, color);
|
|
|
|
|
|
// LCD_DrawPoint(x0 + r - x, y2 - r + y, color);
|
|
|
|
|
|
// LCD_DrawPoint(x2 - r + x, y2 - r + y, color);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 绘制矩形(填充/空心)
|
|
|
|
|
|
* @param x1/y1: 左上角, x2/y2: 右下角, color: 颜色, fill: 1=填充/0=空心
|
|
|
|
|
|
*/
|
|
|
|
|
|
void LCD_DrawRect(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color, uint8_t fill)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint16_t x, y;
|
|
|
|
|
|
if(fill)
|
|
|
|
|
|
{
|
|
|
|
|
|
for(y=y1; y<=y2; y++)
|
|
|
|
|
|
{
|
|
|
|
|
|
for(x=x1; x<=x2; x++)
|
|
|
|
|
|
{
|
|
|
|
|
|
LCD_DrawPoint(x, y, color);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 画边框
|
|
|
|
|
|
for(x=x1; x<=x2; x++) {LCD_DrawPoint(x, y1, color); LCD_DrawPoint(x, y2, color);}
|
|
|
|
|
|
for(y=y1; y<=y2; y++) {LCD_DrawPoint(x1, y, color); LCD_DrawPoint(x2, y, color);}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:显示字符串
|
|
|
|
|
|
入口数据:x,y显示坐标
|
|
|
|
|
|
*p 要显示的字符串
|
|
|
|
|
|
fc 字的颜色
|
|
|
|
|
|
bc 字的背景色
|
|
|
|
|
|
sizey 字号
|
|
|
|
|
|
mode: 0非叠加模式 1叠加模式
|
|
|
|
|
|
返回值: 无
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
void LCD_ShowString(uint16_t x, uint16_t y, const uint8_t *p, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
|
|
|
|
|
|
{
|
|
|
|
|
|
while(*p != '\0')
|
|
|
|
|
|
{
|
|
|
|
|
|
LCD_ShowChar(x, y, *p, fc, bc, sizey, mode);
|
|
|
|
|
|
x += sizey / 2;
|
|
|
|
|
|
p++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t GetLength(const char* str) {
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
while (*str++) {
|
|
|
|
|
|
i++;
|
|
|
|
|
|
}
|
|
|
|
|
|
return i;
|
|
|
|
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:显示中文串
|
|
|
|
|
|
入口数据:x,y 坐标
|
|
|
|
|
|
str 中文字符串
|
|
|
|
|
|
fc 字体颜色
|
|
|
|
|
|
bc 背景颜色
|
|
|
|
|
|
sizey 字号
|
|
|
|
|
|
mode 0=非叠加 1=叠加
|
|
|
|
|
|
返回值: 无
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
void LCD_ShowChineseString(uint16_t x, uint16_t y, uint8_t *str, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint16_t i;
|
|
|
|
|
|
int slen = GetLength((const char*)str);
|
2026-08-30 19:50:01 +08:00
|
|
|
|
char TmpS[2];
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
2026-08-30 19:50:01 +08:00
|
|
|
|
const char (*codeTab)[2] = NULL;
|
|
|
|
|
|
uint8_t xStep = 0;
|
|
|
|
|
|
uint16_t tabSize;
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
2026-08-30 19:50:01 +08:00
|
|
|
|
codeTab = LCD_GetChsTable(sizey);
|
|
|
|
|
|
if (codeTab == NULL)
|
2026-08-26 07:26:58 +08:00
|
|
|
|
{
|
2026-08-30 19:50:01 +08:00
|
|
|
|
return;
|
2026-08-26 07:26:58 +08:00
|
|
|
|
}
|
2026-08-30 19:50:01 +08:00
|
|
|
|
tabSize = LCD_GetChsTableSize(sizey);
|
|
|
|
|
|
if (!LCD_CnFontMetrics(sizey, &xStep, &i))
|
2026-08-26 07:26:58 +08:00
|
|
|
|
{
|
2026-08-30 19:50:01 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
/* xStep is character cell width (= sizey for square CN glyphs). */
|
|
|
|
|
|
xStep = sizey;
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
2026-08-30 19:50:01 +08:00
|
|
|
|
for (i = 0; i < (uint16_t)slen; )
|
|
|
|
|
|
{
|
|
|
|
|
|
if ((uint8_t)str[0] > 0x80)
|
2026-08-26 07:26:58 +08:00
|
|
|
|
{
|
2026-08-30 19:50:01 +08:00
|
|
|
|
uint16_t j;
|
|
|
|
|
|
uint8_t found = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (i + 1 >= (uint16_t)slen)
|
|
|
|
|
|
{
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
TmpS[0] = (char)str[0];
|
|
|
|
|
|
TmpS[1] = (char)str[1];
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
2026-08-30 19:50:01 +08:00
|
|
|
|
for (j = 0; j < tabSize; j++)
|
2026-08-26 07:26:58 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (TmpS[0] == codeTab[j][0] && TmpS[1] == codeTab[j][1])
|
|
|
|
|
|
{
|
2026-08-30 19:50:01 +08:00
|
|
|
|
LCD_ShowChinese(x, y, j, fc, bc, sizey, mode);
|
|
|
|
|
|
x += xStep;
|
|
|
|
|
|
found = 1;
|
|
|
|
|
|
break;
|
2026-08-26 07:26:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-08-30 19:50:01 +08:00
|
|
|
|
/* Always advance past this GBK character, even if glyph is missing. */
|
|
|
|
|
|
str += 2;
|
|
|
|
|
|
i += 2;
|
|
|
|
|
|
(void)found;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
str += 1;
|
|
|
|
|
|
i += 1;
|
|
|
|
|
|
}
|
2026-08-26 07:26:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:计算中英文混排字符串的像素宽度(静态辅助函数)
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
static uint16_t LCD_GetMixedStringWidth(uint8_t *str, uint8_t sizey)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint16_t width = 0;
|
|
|
|
|
|
uint8_t xStepCn = sizey;
|
|
|
|
|
|
uint8_t xStepAscii = sizey / 2;
|
|
|
|
|
|
|
|
|
|
|
|
while(*str != '\0')
|
|
|
|
|
|
{
|
|
|
|
|
|
if(*str > 0x80)
|
|
|
|
|
|
{
|
|
|
|
|
|
width += xStepCn;
|
|
|
|
|
|
str += 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
width += xStepAscii;
|
|
|
|
|
|
str += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return width;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:显示中英文混合字符串(自动识别ASCII和中文字符)
|
|
|
|
|
|
(支持左/中/右对齐)
|
|
|
|
|
|
入口数据:x1,x2 显示区域的左右边界
|
|
|
|
|
|
y 显示区域的Y坐标
|
|
|
|
|
|
*str 要显示的字符串(ASCII+中文混合,中文GB2312编码)
|
|
|
|
|
|
align 对齐方式:LCD_ALIGN_LEFT / LCD_ALIGN_CENTER / LCD_ALIGN_RIGHT
|
|
|
|
|
|
fc 字的颜色
|
|
|
|
|
|
bc 字的背景色
|
|
|
|
|
|
sizey 字号(12/16/24)
|
|
|
|
|
|
mode 0非叠加模式 1叠加模式
|
|
|
|
|
|
返回值: 字符串结束后的X坐标
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
uint16_t LCD_ShowMixedString(uint16_t x1, uint16_t x2, uint16_t y, uint8_t *str, uint8_t align, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
|
|
|
|
|
|
{
|
|
|
|
|
|
const char (*codeTab)[2] = NULL;
|
|
|
|
|
|
uint8_t xStepCn = sizey;
|
|
|
|
|
|
uint8_t xStepAscii = sizey / 2;
|
|
|
|
|
|
uint16_t draw_x;
|
|
|
|
|
|
|
2026-08-28 11:24:06 +08:00
|
|
|
|
codeTab = LCD_GetChsTable(sizey);
|
|
|
|
|
|
if (codeTab == NULL)
|
|
|
|
|
|
return x1;
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 先计算字符串总像素宽度,再根据对齐方式确定起始X坐标
|
|
|
|
|
|
uint16_t total_width = LCD_GetMixedStringWidth(str, sizey);
|
|
|
|
|
|
uint16_t area_width = (x2 > x1) ? (x2 - x1) : 0;
|
|
|
|
|
|
|
|
|
|
|
|
switch(align)
|
|
|
|
|
|
{
|
|
|
|
|
|
case LCD_ALIGN_LEFT:
|
|
|
|
|
|
default:
|
|
|
|
|
|
draw_x = x1;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case LCD_ALIGN_CENTER:
|
|
|
|
|
|
draw_x = (total_width >= area_width) ? x1 : x1 + (area_width - total_width) / 2;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case LCD_ALIGN_RIGHT:
|
|
|
|
|
|
draw_x = (total_width >= area_width) ? x1 : x2 - total_width;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 记住起始X坐标(对齐后的位置),供返回
|
|
|
|
|
|
uint16_t start_x = draw_x;
|
|
|
|
|
|
|
|
|
|
|
|
// 渲染字符串
|
|
|
|
|
|
while(*str != '\0')
|
|
|
|
|
|
{
|
|
|
|
|
|
if(*str > 0x80)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t ch_high = str[0];
|
|
|
|
|
|
uint8_t ch_low = str[1];
|
|
|
|
|
|
if(ch_low == 0) break;
|
|
|
|
|
|
|
2026-08-28 11:24:06 +08:00
|
|
|
|
uint16_t maxIndex = LCD_GetChsTableSize(sizey);
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
|
|
|
|
|
for(uint16_t j = 0; j < maxIndex; j++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(ch_high == codeTab[j][0] && ch_low == codeTab[j][1])
|
|
|
|
|
|
{
|
|
|
|
|
|
LCD_ShowChinese(draw_x, y, j, fc, bc, sizey, mode);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
draw_x += xStepCn;
|
|
|
|
|
|
str += 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
LCD_ShowChar(draw_x, y, *str, fc, bc, sizey, mode);
|
|
|
|
|
|
draw_x += xStepAscii;
|
|
|
|
|
|
str += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return start_x;
|
|
|
|
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:清除字符串
|
|
|
|
|
|
入口数据:x,y显示坐标
|
|
|
|
|
|
*p 要清除的字符串
|
|
|
|
|
|
fc 字的颜色
|
|
|
|
|
|
bc 字的背景色
|
|
|
|
|
|
sizey 字号
|
|
|
|
|
|
mode: 0非叠加模式 1叠加模式
|
|
|
|
|
|
返回值: 无
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
void LCD_ClearString(uint16_t x, uint16_t y, const uint8_t *p, uint16_t bc, uint8_t sizey, uint8_t mode)
|
|
|
|
|
|
{
|
|
|
|
|
|
while (*p != '\0')
|
|
|
|
|
|
{
|
|
|
|
|
|
// 用背景色bc作为“前景色”,显示空格字符,覆盖原字符
|
|
|
|
|
|
LCD_ShowChar(x, y, ' ', bc, bc, sizey, mode); // 前景色=背景色=bc,相当于清除
|
|
|
|
|
|
x += sizey / 2; // 与原显示函数x步长一致
|
|
|
|
|
|
p++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///******************************************************************************
|
|
|
|
|
|
// 函数说明:自动对齐显示汉字字符串
|
|
|
|
|
|
// 入口数据:
|
|
|
|
|
|
// x 显示x轴起始坐标(水平位置)
|
|
|
|
|
|
// y 显示Y轴起始坐标(垂直位置)
|
|
|
|
|
|
// *p 要显示的字符串(需以'\0'结尾)
|
|
|
|
|
|
// align 对齐模式(LCD_ALIGN_LEFT/LCD_ALIGN_CENTER/LCD_ALIGN_RIGHT)
|
|
|
|
|
|
// fc 字的颜色(前景色)
|
|
|
|
|
|
// bc 字的背景色
|
|
|
|
|
|
// mode 显示模式(0=非叠加,1=叠加)
|
|
|
|
|
|
// 返回值: 无
|
|
|
|
|
|
// 核心参数固定:
|
|
|
|
|
|
// - 字体大小:8*16(字符宽度=8,高度=16)
|
|
|
|
|
|
// - 屏幕X轴范围:0~240(靠右对齐时贴X=240)
|
|
|
|
|
|
// 注意: 1. 字符串必须以'\0'结尾,否则会读取垃圾数据导致显示异常
|
|
|
|
|
|
// 2. 若字符串总宽度超过240,会自动向左溢出(符合常规显示逻辑)
|
|
|
|
|
|
// 3. 完全兼容原LCD_ShowChar函数,显示效果与原逻辑一致
|
|
|
|
|
|
//******************************************************************************/
|
|
|
|
|
|
//void LCD_ShowChinese_AutoAlign(uint8_t x, uint16_t y, const uint8_t *p, uint8_t align,
|
|
|
|
|
|
// uint16_t fc, uint16_t bc, uint8_t mode, uint8_t size)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// uint8_t CHAR_WIDTH = size;
|
|
|
|
|
|
// uint16_t str_total_width = 0;
|
|
|
|
|
|
// uint16_t curr_x = 0;
|
|
|
|
|
|
// const uint8_t *p_tmp = p;
|
|
|
|
|
|
//
|
|
|
|
|
|
// // ==========================
|
|
|
|
|
|
// // 汉字个数 × 宽度
|
|
|
|
|
|
// // ==========================
|
|
|
|
|
|
// while (*p_tmp != '\0')
|
|
|
|
|
|
// {
|
|
|
|
|
|
// if ((uint8_t)*p_tmp > 0x80) // 是汉字
|
|
|
|
|
|
// {
|
|
|
|
|
|
// str_total_width += CHAR_WIDTH; // 一个汉字占 size 宽度
|
|
|
|
|
|
// p_tmp += 2; // 汉字2字节
|
|
|
|
|
|
// }
|
|
|
|
|
|
// else
|
|
|
|
|
|
// {
|
|
|
|
|
|
// p_tmp++; // 非汉字跳过
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
//
|
|
|
|
|
|
// switch (align)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// case LCD_ALIGN_CENTER:
|
|
|
|
|
|
// curr_x = (x - str_total_width) / 2;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
//
|
|
|
|
|
|
// case LCD_ALIGN_RIGHT:
|
|
|
|
|
|
// curr_x = x - str_total_width;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
//
|
|
|
|
|
|
// case LCD_ALIGN_LEFT:
|
|
|
|
|
|
// default:
|
|
|
|
|
|
// curr_x = 0;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// }
|
|
|
|
|
|
//
|
|
|
|
|
|
// // ==========================
|
|
|
|
|
|
// // 正确显示一次整串
|
|
|
|
|
|
// // ==========================
|
|
|
|
|
|
// LCD_ShowChineseString(curr_x, y, (uint8_t *)p, fc, bc, size, mode);
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:在指定区间 [x1, x2] 内自动对齐显示汉字串
|
|
|
|
|
|
入口数据:x1 区域左边界X坐标
|
|
|
|
|
|
x2 区域右边界X坐标
|
|
|
|
|
|
y Y坐标
|
|
|
|
|
|
p 汉字串
|
|
|
|
|
|
align 对齐方式:LCD_ALIGN_LEFT / CENTER / RIGHT
|
|
|
|
|
|
fc 字体颜色
|
|
|
|
|
|
bc 背景色
|
|
|
|
|
|
mode 显示模式
|
|
|
|
|
|
size 汉字尺寸(16)
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
uint32_t LCD_ShowChinese_AutoAlign(uint16_t x1, uint16_t x2, uint16_t y, const uint8_t *p,
|
|
|
|
|
|
uint8_t align, uint16_t fc, uint16_t bc, uint8_t mode, uint8_t size)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t CHAR_WIDTH = size;
|
|
|
|
|
|
uint16_t str_total_width = 0;
|
|
|
|
|
|
uint16_t curr_x = 0;
|
|
|
|
|
|
const uint8_t *p_tmp = p;
|
|
|
|
|
|
uint16_t area_width = x2 - x1 + 1; // 区域总宽度
|
|
|
|
|
|
|
|
|
|
|
|
// 计算汉字串总宽度
|
|
|
|
|
|
while (*p_tmp != '\0')
|
|
|
|
|
|
{
|
|
|
|
|
|
if ((uint8_t)*p_tmp > 0x80) // 汉字
|
|
|
|
|
|
{
|
|
|
|
|
|
str_total_width += CHAR_WIDTH;
|
|
|
|
|
|
p_tmp += 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
p_tmp++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 根据对齐方式计算最终 X 坐标
|
|
|
|
|
|
switch (align)
|
|
|
|
|
|
{
|
|
|
|
|
|
case LCD_ALIGN_CENTER:
|
|
|
|
|
|
curr_x = x1 + (area_width - str_total_width) / 2;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case LCD_ALIGN_RIGHT:
|
|
|
|
|
|
curr_x = x2 - str_total_width + 1;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case LCD_ALIGN_LEFT:
|
|
|
|
|
|
default:
|
|
|
|
|
|
curr_x = x1;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 显示
|
|
|
|
|
|
LCD_ShowChineseString(curr_x, y, (uint8_t *)p, fc, bc, size, mode);
|
|
|
|
|
|
return curr_x;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:在指定区间 [x1, x2] 内,清除自动对齐显示的中文字符串
|
|
|
|
|
|
入口数据:x1 显示区域的左边界 X 坐标
|
|
|
|
|
|
x2 显示区域的右边界 X 坐标
|
|
|
|
|
|
y 字符串显示的起始 Y 坐标
|
|
|
|
|
|
p 需要清除的中文字符串(与显示时一致)
|
|
|
|
|
|
align 对齐方式(与显示时一致:左/中/右)
|
|
|
|
|
|
bc 清除时使用的背景填充色
|
|
|
|
|
|
mode 显示模式
|
|
|
|
|
|
size 汉字大小(16)
|
|
|
|
|
|
返回值: 无
|
|
|
|
|
|
说明: 与 LCD_ShowChinese_AutoAlign 完全配对,精准清除显示区域
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
void LCD_ClearChinese_AutoAlign(uint16_t x1, uint16_t x2, uint16_t y, const uint8_t *p,
|
|
|
|
|
|
uint8_t align, uint8_t fc,uint16_t bc, uint8_t mode, uint8_t size)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t CHAR_WIDTH = size; // 汉字宽度 = 字体尺寸
|
|
|
|
|
|
uint16_t str_total_width = 0;
|
|
|
|
|
|
uint16_t curr_x = 0;
|
|
|
|
|
|
const uint8_t *p_tmp = p;
|
|
|
|
|
|
uint16_t area_width = x2 - x1 + 1; // 显示区间总宽度
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 计算汉字字符串总宽度
|
|
|
|
|
|
while (*p_tmp != '\0')
|
|
|
|
|
|
{
|
|
|
|
|
|
if ((uint8_t)*p_tmp > 0x80) // 判断为汉字(2字节)
|
|
|
|
|
|
{
|
|
|
|
|
|
str_total_width += CHAR_WIDTH;
|
|
|
|
|
|
p_tmp += 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
p_tmp++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (str_total_width == 0) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 根据对齐方式,计算汉字实际显示的起始 X 坐标
|
|
|
|
|
|
switch (align)
|
|
|
|
|
|
{
|
|
|
|
|
|
case LCD_ALIGN_CENTER:
|
|
|
|
|
|
curr_x = x1 + (area_width - str_total_width) / 2;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case LCD_ALIGN_RIGHT:
|
|
|
|
|
|
curr_x = x2 - str_total_width + 1;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case LCD_ALIGN_LEFT:
|
|
|
|
|
|
default:
|
|
|
|
|
|
curr_x = x1;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 用背景色填充整块汉字区域,精准清除
|
|
|
|
|
|
LCD_FillByColor(curr_x, y, curr_x + str_total_width - 1, y + size - 1, bc);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:在指定区间 [x1, x2] 内自动对齐显示 ASCII 字符串(英文/数字)
|
|
|
|
|
|
入口数据:x1 区域左边界X坐标
|
|
|
|
|
|
x2 区域右边界X坐标
|
|
|
|
|
|
y Y坐标
|
|
|
|
|
|
p 字符串
|
|
|
|
|
|
align 对齐方式:LCD_ALIGN_LEFT / CENTER / RIGHT
|
|
|
|
|
|
fc 字体颜色
|
|
|
|
|
|
bc 背景色
|
|
|
|
|
|
mode 显示模式
|
|
|
|
|
|
size 字体大小(16=8*16,24=12*24)
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
uint16_t LCD_ShowString_AutoAlign(uint16_t x1, uint16_t x2, uint16_t y, const uint8_t *p,
|
|
|
|
|
|
uint8_t align, uint16_t fc, uint16_t bc, uint8_t mode, uint8_t size)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t CHAR_WIDTH, CHAR_HEIGHT;
|
|
|
|
|
|
|
2026-08-28 11:24:06 +08:00
|
|
|
|
if (!LCD_GetAsciiMetrics(size, &CHAR_WIDTH, &CHAR_HEIGHT))
|
|
|
|
|
|
return 0;
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
|
|
|
|
|
uint16_t str_len = 0;
|
|
|
|
|
|
uint16_t str_total_width;
|
|
|
|
|
|
uint16_t curr_x = 0;
|
|
|
|
|
|
uint16_t area_width = x2 - x1 + 1; // 区间总宽度
|
|
|
|
|
|
|
|
|
|
|
|
// 计算字符串长度
|
|
|
|
|
|
while (p[str_len] != '\0')
|
|
|
|
|
|
{
|
|
|
|
|
|
str_len++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算字符串总宽度
|
|
|
|
|
|
str_total_width = str_len * CHAR_WIDTH;
|
|
|
|
|
|
|
|
|
|
|
|
// 根据对齐方式计算起始 X 坐标
|
|
|
|
|
|
switch (align)
|
|
|
|
|
|
{
|
|
|
|
|
|
case LCD_ALIGN_CENTER:
|
|
|
|
|
|
// 在区间内居中
|
|
|
|
|
|
curr_x = x1 + (area_width - str_total_width) / 2;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case LCD_ALIGN_RIGHT:
|
|
|
|
|
|
// 在区间内靠右
|
|
|
|
|
|
curr_x = x2 - str_total_width + 1;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case LCD_ALIGN_LEFT:
|
|
|
|
|
|
default:
|
|
|
|
|
|
// 在区间内靠左
|
|
|
|
|
|
curr_x = x1;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 显示字符串
|
|
|
|
|
|
while (*p != '\0')
|
|
|
|
|
|
{
|
|
|
|
|
|
LCD_ShowChar(curr_x, y, *p, fc, bc, CHAR_HEIGHT, mode);
|
|
|
|
|
|
curr_x += CHAR_WIDTH;
|
|
|
|
|
|
p++;
|
|
|
|
|
|
}
|
|
|
|
|
|
return curr_x;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:在指定区间 [x1, x2] 内,清除自动对齐显示的 ASCII 字符串(数字/字母)
|
|
|
|
|
|
入口数据:x1 显示区域的左边界 X 坐标
|
|
|
|
|
|
x2 显示区域的右边界 X 坐标
|
|
|
|
|
|
y 字符串显示的起始 Y 坐标
|
|
|
|
|
|
p 需要清除的字符串(必须与显示时的字符串一致)
|
|
|
|
|
|
align 对齐方式(与显示时一致:左/中/右)
|
|
|
|
|
|
bc 清除时使用的背景填充色
|
|
|
|
|
|
mode 显示模式(与显示时保持一致)
|
|
|
|
|
|
size 字体大小 16/24
|
|
|
|
|
|
返回值: 无
|
|
|
|
|
|
说明: 自动计算字符串位置和宽度,使用背景色填充整块区域,实现干净清除
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
void LCD_ClearString_AutoAlign(uint16_t x1, uint16_t x2, uint16_t y, const uint8_t *p,
|
|
|
|
|
|
uint8_t align, uint16_t fc,uint16_t bc, uint8_t mode, uint8_t size)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t CHAR_WIDTH, CHAR_HEIGHT;
|
|
|
|
|
|
|
|
|
|
|
|
// 根据字体尺寸,设置字符宽度和高度
|
|
|
|
|
|
if(size == 16)
|
|
|
|
|
|
{
|
|
|
|
|
|
CHAR_WIDTH = 8; // 8*16 字体
|
|
|
|
|
|
CHAR_HEIGHT = 16;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if(size == 24)
|
|
|
|
|
|
{
|
|
|
|
|
|
CHAR_WIDTH = 12; // 12*24 字体
|
|
|
|
|
|
CHAR_HEIGHT = 24;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return; // 不支持的字体
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t str_len = 0;
|
|
|
|
|
|
uint16_t str_total_width;
|
|
|
|
|
|
uint16_t curr_x = 0;
|
|
|
|
|
|
uint16_t area_width = x2 - x1 + 1; // 显示区间总宽度
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 计算字符串字符个数
|
|
|
|
|
|
while (p[str_len] != '\0')
|
|
|
|
|
|
{
|
|
|
|
|
|
str_len++;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (str_len == 0) return; // 空串直接返回
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 计算字符串整体占用宽度
|
|
|
|
|
|
str_total_width = str_len * CHAR_WIDTH;
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 根据对齐方式,计算字符串实际显示的起始 X 坐标
|
|
|
|
|
|
switch (align)
|
|
|
|
|
|
{
|
|
|
|
|
|
case LCD_ALIGN_CENTER:
|
|
|
|
|
|
curr_x = x1 + (area_width - str_total_width) / 2;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case LCD_ALIGN_RIGHT:
|
|
|
|
|
|
curr_x = x2 - str_total_width + 1;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case LCD_ALIGN_LEFT:
|
|
|
|
|
|
default:
|
|
|
|
|
|
curr_x = x1;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 用背景色填充整块字符串区域,实现干净清除
|
|
|
|
|
|
LCD_FillByColor(curr_x, y, curr_x + str_total_width - 1, y + CHAR_HEIGHT - 1, bc);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
// 带垂直渐变的汉字显示(先画渐变背景,再叠加显示文字)
|
|
|
|
|
|
// 入口数据:x1,x2 水平区间
|
|
|
|
|
|
// y 顶部Y坐标
|
|
|
|
|
|
// p 汉字串
|
|
|
|
|
|
// align 对齐方式
|
|
|
|
|
|
// fc 文字颜色
|
|
|
|
|
|
// top/bot 渐变顶部/底部颜色
|
|
|
|
|
|
// size 汉字尺寸(16)
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
uint32_t LCD_ShowChinese_AutoAlign_Gradient(uint16_t x1, uint16_t x2, uint16_t y,
|
|
|
|
|
|
const uint8_t *p, uint8_t align, uint16_t fc,
|
|
|
|
|
|
uint16_t color_top, uint16_t color_bottom, uint8_t size)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t CHAR_WIDTH = size;
|
|
|
|
|
|
uint16_t str_total_width = 0;
|
|
|
|
|
|
uint16_t curr_x = 0;
|
|
|
|
|
|
const uint8_t *p_tmp = p;
|
|
|
|
|
|
uint16_t area_width = x2 - x1 + 1;
|
|
|
|
|
|
|
|
|
|
|
|
// 计算汉字串总宽度
|
|
|
|
|
|
while (*p_tmp != '\0')
|
|
|
|
|
|
{
|
|
|
|
|
|
if ((uint8_t)*p_tmp > 0x80)
|
|
|
|
|
|
{
|
|
|
|
|
|
str_total_width += CHAR_WIDTH;
|
|
|
|
|
|
p_tmp += 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
p_tmp++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (str_total_width == 0) return 0;
|
|
|
|
|
|
|
|
|
|
|
|
// 根据对齐方式计算起始X
|
|
|
|
|
|
switch (align)
|
|
|
|
|
|
{
|
|
|
|
|
|
case LCD_ALIGN_CENTER:
|
|
|
|
|
|
curr_x = x1 + (area_width - str_total_width) / 2;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case LCD_ALIGN_RIGHT:
|
|
|
|
|
|
curr_x = x2 - str_total_width + 1;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case LCD_ALIGN_LEFT:
|
|
|
|
|
|
default:
|
|
|
|
|
|
curr_x = x1;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 画垂直渐变背景
|
|
|
|
|
|
LCD_FillGradient(curr_x, y, curr_x + str_total_width, y + size, color_top, color_bottom);
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 叠加模式显示文字(mode=1,只画笔画不画背景)
|
|
|
|
|
|
LCD_ShowChinese_AutoAlign(x1, x2, y, p, align, fc, 0, 1, size);
|
|
|
|
|
|
return curr_x;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
// 带垂直渐变的 ASCII 字符串显示
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
uint16_t LCD_ShowString_AutoAlign_Gradient(uint16_t x1, uint16_t x2, uint16_t y,
|
|
|
|
|
|
const uint8_t *p, uint8_t align, uint16_t fc,
|
|
|
|
|
|
uint16_t color_top, uint16_t color_bottom, uint8_t size)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t CHAR_WIDTH, CHAR_HEIGHT;
|
|
|
|
|
|
|
2026-08-28 11:24:06 +08:00
|
|
|
|
if (!LCD_GetAsciiMetrics(size, &CHAR_WIDTH, &CHAR_HEIGHT))
|
|
|
|
|
|
return 0;
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
|
|
|
|
|
uint16_t str_len = 0;
|
|
|
|
|
|
uint16_t str_total_width;
|
|
|
|
|
|
uint16_t curr_x = 0;
|
|
|
|
|
|
uint16_t area_width = x2 - x1 + 1;
|
|
|
|
|
|
|
|
|
|
|
|
while (p[str_len] != '\0') str_len++;
|
|
|
|
|
|
if (str_len == 0) return 0;
|
|
|
|
|
|
|
|
|
|
|
|
str_total_width = str_len * CHAR_WIDTH;
|
|
|
|
|
|
|
|
|
|
|
|
switch (align)
|
|
|
|
|
|
{
|
|
|
|
|
|
case LCD_ALIGN_CENTER:
|
|
|
|
|
|
curr_x = x1 + (area_width - str_total_width) / 2;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case LCD_ALIGN_RIGHT:
|
|
|
|
|
|
curr_x = x2 - str_total_width + 1;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case LCD_ALIGN_LEFT:
|
|
|
|
|
|
default:
|
|
|
|
|
|
curr_x = x1;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 画垂直渐变背景
|
|
|
|
|
|
LCD_FillGradient(curr_x, y, curr_x + str_total_width, y + CHAR_HEIGHT, color_top, color_bottom);
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 叠加模式显示文字(mode=1)
|
|
|
|
|
|
LCD_ShowString_AutoAlign(x1, x2, y, p, align, fc, 0, 1, size);
|
|
|
|
|
|
return curr_x;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
2026-08-31 06:10:13 +08:00
|
|
|
|
函数说明:圆角框 + 左箭头。bg_color 为框背景(普通态灰色 / 焦点蓝色)
|
|
|
|
|
|
******************************************************************************/
|
2026-08-26 07:26:58 +08:00
|
|
|
|
void LCD_DrawArrow_Left(uint16_t x, uint16_t y, uint8_t size, uint16_t color, uint16_t bg_color)
|
|
|
|
|
|
{
|
2026-08-31 06:10:13 +08:00
|
|
|
|
int16_t box_side = size * 2 + 5;
|
2026-08-26 07:26:58 +08:00
|
|
|
|
int16_t box_x = x - box_side / 2;
|
|
|
|
|
|
int16_t box_y = y - box_side / 2;
|
|
|
|
|
|
LCD_FillRoundRect(box_x, box_y, box_side, box_side, 3, bg_color);
|
|
|
|
|
|
|
|
|
|
|
|
int16_t i;
|
|
|
|
|
|
for(i = 0; i < size; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
LCD_DrawLine(
|
|
|
|
|
|
x - i,
|
|
|
|
|
|
y - size + i,
|
|
|
|
|
|
x - i,
|
|
|
|
|
|
y + size - i,
|
|
|
|
|
|
color
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void LCD_DrawArrow_Right(uint16_t x, uint16_t y, uint8_t size, uint16_t color, uint16_t bg_color)
|
|
|
|
|
|
{
|
2026-08-31 06:10:13 +08:00
|
|
|
|
int16_t box_side = size * 2 + 5;
|
2026-08-26 07:26:58 +08:00
|
|
|
|
int16_t box_x = x - box_side / 2;
|
|
|
|
|
|
int16_t box_y = y - box_side / 2;
|
|
|
|
|
|
LCD_FillRoundRect(box_x, box_y, box_side, box_side, 3, bg_color);
|
|
|
|
|
|
|
|
|
|
|
|
int16_t i;
|
|
|
|
|
|
for(i = 0; i < size; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
LCD_DrawLine(
|
|
|
|
|
|
x + i,
|
|
|
|
|
|
y - size + i,
|
|
|
|
|
|
x + i,
|
|
|
|
|
|
y + size - i,
|
|
|
|
|
|
color
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
// 绘制向右的空心尖括号箭头(无填充、无底边、无背景框)
|
|
|
|
|
|
// 等边三角形,只保留指向右侧的两条斜边
|
|
|
|
|
|
// 入口数据:x,y 箭头尖端坐标(尖角处)
|
|
|
|
|
|
// size 箭头大小(边长,越大箭头越宽)
|
|
|
|
|
|
// thick 线条粗细(像素数,1=单线,2=加粗...)
|
|
|
|
|
|
// color 颜色
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
void LCD_DrawChevron_Right(uint16_t x, uint16_t y, uint8_t size, uint8_t thick, uint16_t color)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 上斜线:从左下 (x, y-size) 向右上汇聚到 (x+size, y),thick条平行线
|
|
|
|
|
|
for (uint8_t i = 0; i < thick; i++) {
|
|
|
|
|
|
LCD_DrawLine(x, y - size + i, x + size - i, y, color);
|
|
|
|
|
|
}
|
|
|
|
|
|
// 下斜线:从左上 (x, y+size) 向右下汇聚到 (x+size, y),thick条平行线
|
|
|
|
|
|
for (uint8_t i = 0; i < thick; i++) {
|
|
|
|
|
|
LCD_DrawLine(x, y + size - i, x + size - i, y, color);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:画【圆角框 + 居中加号 +】
|
|
|
|
|
|
入口数据:x, y 中心点坐标
|
|
|
|
|
|
size 整体大小(框越大,数字越大)
|
|
|
|
|
|
radius 圆角半径(建议 3~5)
|
|
|
|
|
|
fg_color 加号颜色
|
|
|
|
|
|
bg_color 圆角框背景色
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
void LCD_DrawPlus_RoundBox(uint16_t x, uint16_t y, uint8_t size, uint8_t radius, uint16_t fg_color, uint16_t bg_color)
|
|
|
|
|
|
{
|
|
|
|
|
|
int16_t i;
|
|
|
|
|
|
uint8_t box_w = size; // 框宽度
|
|
|
|
|
|
uint8_t box_h = size; // 框高度
|
|
|
|
|
|
uint8_t line_w = 4; // 线条粗细
|
|
|
|
|
|
|
2026-08-31 06:10:13 +08:00
|
|
|
|
LCD_FillRoundRect(x - box_w/2, y - box_h/2, box_w, box_h, radius, bg_color);
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 2. 画水平居中横线
|
|
|
|
|
|
for(i = 0; i < line_w; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
LCD_DrawLine(
|
|
|
|
|
|
x - box_w/3, y - line_w/2 + i,
|
|
|
|
|
|
x + box_w/3, y - line_w/2 + i,
|
|
|
|
|
|
fg_color
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 画垂直居中竖线
|
|
|
|
|
|
for(i = 0; i < line_w; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
LCD_DrawLine(
|
|
|
|
|
|
x - line_w/2 + i, y - box_h/3,
|
|
|
|
|
|
x - line_w/2 + i, y + box_h/3,
|
|
|
|
|
|
fg_color
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:画【圆角框 + 居中减号 -】
|
|
|
|
|
|
入口数据:x, y 中心点坐标
|
|
|
|
|
|
size 整体大小
|
|
|
|
|
|
radius 圆角半径
|
|
|
|
|
|
fg_color 减号颜色
|
|
|
|
|
|
bg_color 圆角框背景色
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
void LCD_DrawMinus_RoundBox(uint16_t x, uint16_t y, uint8_t size, uint8_t radius, uint16_t fg_color, uint16_t bg_color)
|
|
|
|
|
|
{
|
|
|
|
|
|
int16_t i;
|
|
|
|
|
|
uint8_t box_w = size;
|
|
|
|
|
|
uint8_t box_h = size;
|
|
|
|
|
|
uint8_t line_w = 2;
|
|
|
|
|
|
|
2026-08-31 06:10:13 +08:00
|
|
|
|
LCD_FillRoundRect(x - box_w/2, y - box_h/2, box_w, box_h, radius, bg_color);
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 2. 画水平居中横线
|
|
|
|
|
|
for(i = 0; i < line_w; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
LCD_DrawLine(
|
|
|
|
|
|
x - box_w/3, y - line_w/2 + i,
|
|
|
|
|
|
x + box_w/3, y - line_w/2 + i,
|
|
|
|
|
|
fg_color
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-08-28 10:07:48 +08:00
|
|
|
|
* @brief 仅顶部圆角、底部平齐的实心竖条
|
|
|
|
|
|
*/
|
|
|
|
|
|
static void LCD_FillRoundTopRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r, uint16_t color)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(w == 0 || h == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(r > (w / 2))
|
|
|
|
|
|
{
|
|
|
|
|
|
r = w / 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(r > h)
|
|
|
|
|
|
{
|
|
|
|
|
|
r = h;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(r == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
LCD_FillByColor(x, y, x + w, y + h, color);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LCD_FillRoundRect(x, y, w, h, r, color);
|
|
|
|
|
|
if(h > r)
|
|
|
|
|
|
{
|
|
|
|
|
|
LCD_FillByColor(x, y + h - r, x + w, y + h, color);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief RGB565 两色按比例混合
|
|
|
|
|
|
*/
|
|
|
|
|
|
static uint16_t LCD_BlendColor565(uint16_t c0, uint16_t c1, uint8_t num, uint8_t den)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint16_t r0 = (c0 >> 11) & 0x1F;
|
|
|
|
|
|
uint16_t g0 = (c0 >> 5) & 0x3F;
|
|
|
|
|
|
uint16_t b0 = c0 & 0x1F;
|
|
|
|
|
|
uint16_t r1 = (c1 >> 11) & 0x1F;
|
|
|
|
|
|
uint16_t g1 = (c1 >> 5) & 0x3F;
|
|
|
|
|
|
uint16_t b1 = c1 & 0x1F;
|
|
|
|
|
|
uint16_t r;
|
|
|
|
|
|
uint16_t g;
|
|
|
|
|
|
uint16_t b;
|
|
|
|
|
|
|
|
|
|
|
|
if(den == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return c1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
r = r0 + (uint16_t)(r1 - r0) * num / den;
|
|
|
|
|
|
g = g0 + (uint16_t)(g1 - g0) * num / den;
|
|
|
|
|
|
b = b0 + (uint16_t)(b1 - b0) * num / den;
|
|
|
|
|
|
return (r << 11) | (g << 5) | b;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 绘制音量条(5格实心,从左到右亮度递增,对齐需求图)
|
|
|
|
|
|
* @param volume_level: 音量等级(0-5,0=静音,5=最大)
|
|
|
|
|
|
* @note 强度为 N 时显示前 N 格实心条;最右点亮格最亮(白),向左依次变暗
|
2026-08-26 07:26:58 +08:00
|
|
|
|
*/
|
|
|
|
|
|
void Draw_Volume_Bar(uint16_t x, uint16_t y, uint8_t volume_level,uint8_t scale,uint16_t color_on, uint16_t color_off)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t i;
|
2026-08-28 10:07:48 +08:00
|
|
|
|
uint8_t bar_count = 5;
|
|
|
|
|
|
uint8_t w = 3 * scale;
|
|
|
|
|
|
uint8_t gap = 2 * scale;
|
|
|
|
|
|
uint8_t radius = 1 * scale;
|
|
|
|
|
|
uint8_t height[5] = {6, 9, 12, 15, 18};
|
|
|
|
|
|
uint8_t max_h = height[4];
|
|
|
|
|
|
uint16_t clear_w;
|
|
|
|
|
|
uint16_t dim_color = color_off;
|
|
|
|
|
|
|
|
|
|
|
|
(void)color_on;
|
|
|
|
|
|
|
|
|
|
|
|
if(volume_level > 5)
|
|
|
|
|
|
{
|
|
|
|
|
|
volume_level = 5;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
clear_w = (uint16_t)(w + gap) * bar_count - gap;
|
|
|
|
|
|
LCD_FillByColor(x, y, x + clear_w, y + max_h * scale, BLACK);
|
|
|
|
|
|
|
|
|
|
|
|
if(volume_level == 0)
|
2026-08-26 07:26:58 +08:00
|
|
|
|
{
|
2026-08-28 10:07:48 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < bar_count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint16_t curr_x = x + (w + gap) * i;
|
|
|
|
|
|
uint8_t curr_h = height[i] * scale;
|
|
|
|
|
|
uint8_t curr_y = y + (max_h * scale - curr_h);
|
|
|
|
|
|
uint16_t bar_color;
|
|
|
|
|
|
|
|
|
|
|
|
if(i >= volume_level)
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(volume_level == 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
bar_color = WHITE;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
/* 左暗右亮:第1格最暗,当前档位的最右格为全白 */
|
|
|
|
|
|
bar_color = LCD_BlendColor565(dim_color, WHITE, i, volume_level - 1);
|
|
|
|
|
|
}
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
2026-08-28 10:07:48 +08:00
|
|
|
|
LCD_FillRoundTopRect(curr_x, curr_y, w, curr_h, radius, bar_color);
|
2026-08-26 07:26:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///**
|
|
|
|
|
|
// * @brief 绘制电池图标+电量百分比
|
|
|
|
|
|
// * @param x/y: 电池图标左上角坐标, battery_percent: 电量(0-100)
|
|
|
|
|
|
// */
|
|
|
|
|
|
//void Draw_Battery_Icon(uint16_t x, uint16_t y, uint8_t battery_percent)
|
|
|
|
|
|
//{
|
|
|
|
|
|
//// LCD_FillByColor(x,y,x+25,y+20);
|
|
|
|
|
|
// LCD_FillRoundRect(x, y, 25, 15,2,WHITE);
|
|
|
|
|
|
// LCD_FillRoundRect(x+1, y+1, 23, 13,0,BLACK);
|
|
|
|
|
|
// LCD_FillRoundRect(x+1+1, y+1+1, 21, 11,0,WHITE);
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-08-28 10:09:22 +08:00
|
|
|
|
* @brief 绘制电池图标(圆角线框 + 内填充 + 百分比,对齐需求图)
|
2026-08-26 07:26:58 +08:00
|
|
|
|
*/
|
|
|
|
|
|
void Draw_Battery_Icon(uint16_t x, uint16_t y, uint8_t battery_percent,uint8_t scale, uint16_t border_color, uint16_t bg_color, uint16_t fill_color)
|
|
|
|
|
|
{
|
2026-08-28 10:09:22 +08:00
|
|
|
|
uint16_t bat_w = 24 * scale;
|
|
|
|
|
|
uint16_t bat_h = 11 * scale;
|
|
|
|
|
|
uint8_t round_r = 2 * scale;
|
|
|
|
|
|
uint8_t stroke = 1 * scale;
|
|
|
|
|
|
uint16_t fill_gap = 2 * scale;
|
2026-08-28 10:34:27 +08:00
|
|
|
|
uint8_t text_size = 16 * scale; /* 16px ASCII 字体渲染可靠;13px 位图与驱动不匹配会乱码 */
|
|
|
|
|
|
uint8_t status_bar_h = 26 * scale;
|
2026-08-28 10:09:22 +08:00
|
|
|
|
uint8_t Info[40];
|
2026-08-28 10:07:48 +08:00
|
|
|
|
uint16_t pole_w = 2 * scale;
|
2026-08-28 10:09:22 +08:00
|
|
|
|
uint16_t pole_h = 5 * scale;
|
|
|
|
|
|
uint16_t pole_x;
|
|
|
|
|
|
uint16_t pole_y;
|
|
|
|
|
|
uint16_t inner_w;
|
|
|
|
|
|
uint16_t inner_h;
|
2026-08-28 10:07:48 +08:00
|
|
|
|
uint16_t fill_w;
|
|
|
|
|
|
uint16_t text_x;
|
2026-08-28 10:09:22 +08:00
|
|
|
|
uint16_t text_y;
|
|
|
|
|
|
uint16_t clear_h;
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
2026-08-28 10:09:22 +08:00
|
|
|
|
if(battery_percent > 100)
|
|
|
|
|
|
{
|
|
|
|
|
|
battery_percent = 100;
|
|
|
|
|
|
}
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
2026-08-28 10:09:22 +08:00
|
|
|
|
clear_h = (bat_h > text_size) ? bat_h : text_size;
|
2026-08-28 10:34:27 +08:00
|
|
|
|
if(status_bar_h > clear_h)
|
|
|
|
|
|
{
|
|
|
|
|
|
clear_h = status_bar_h;
|
|
|
|
|
|
}
|
|
|
|
|
|
LCD_FillByColor(x, 0, 240, clear_h, BLACK);
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
2026-08-28 10:09:22 +08:00
|
|
|
|
/* 圆角外壳:外框 + 内挖空 */
|
|
|
|
|
|
LCD_FillRoundRect(x, y, bat_w, bat_h, round_r, border_color);
|
|
|
|
|
|
if(bat_w > 2 * stroke && bat_h > 2 * stroke)
|
2026-08-26 07:26:58 +08:00
|
|
|
|
{
|
2026-08-28 10:09:22 +08:00
|
|
|
|
LCD_FillRoundRect(x + stroke, y + stroke,
|
|
|
|
|
|
bat_w - 2 * stroke, bat_h - 2 * stroke,
|
|
|
|
|
|
(round_r > stroke) ? (round_r - stroke) : 0,
|
|
|
|
|
|
bg_color);
|
2026-08-26 07:26:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-28 10:09:22 +08:00
|
|
|
|
inner_w = bat_w - 2 * fill_gap;
|
|
|
|
|
|
inner_h = bat_h - 2 * fill_gap;
|
|
|
|
|
|
fill_w = inner_w * battery_percent / 100;
|
|
|
|
|
|
|
|
|
|
|
|
/* 从左向右实心填充,宽度与百分比一致 */
|
2026-08-28 10:07:48 +08:00
|
|
|
|
if(battery_percent > 0 && fill_w > 0)
|
|
|
|
|
|
{
|
2026-08-28 10:09:22 +08:00
|
|
|
|
if(fill_w > inner_w)
|
|
|
|
|
|
{
|
|
|
|
|
|
fill_w = inner_w;
|
|
|
|
|
|
}
|
|
|
|
|
|
LCD_FillRoundRect(x + fill_gap, y + fill_gap,
|
|
|
|
|
|
fill_w, inner_h,
|
|
|
|
|
|
1 * scale, fill_color);
|
2026-08-28 10:07:48 +08:00
|
|
|
|
}
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
2026-08-28 10:07:48 +08:00
|
|
|
|
/* 右侧正极小凸起 */
|
2026-08-28 10:09:22 +08:00
|
|
|
|
pole_x = x + bat_w;
|
|
|
|
|
|
pole_y = y + (bat_h - pole_h) / 2;
|
|
|
|
|
|
LCD_FillRoundRect(pole_x, pole_y, pole_w, pole_h, 1 * scale, border_color);
|
2026-08-26 07:26:58 +08:00
|
|
|
|
|
2026-08-28 10:07:48 +08:00
|
|
|
|
sprintf((char*)Info, "%d%%", battery_percent);
|
|
|
|
|
|
text_x = pole_x + pole_w + 2 * scale;
|
2026-08-28 10:34:27 +08:00
|
|
|
|
text_y = (status_bar_h - text_size) / 2;
|
|
|
|
|
|
LCD_ShowString(text_x, text_y, Info, WHITE, BLACK, text_size, 0);
|
2026-08-26 07:26:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
函数说明:绘制充电图标(绿色空心圆环 + 居中闪电标志)
|
|
|
|
|
|
入口数据:x,y 图标中心点坐标
|
|
|
|
|
|
scale 缩放倍数(1=原始大小)
|
|
|
|
|
|
ring_color 圆环颜色(建议 GREEN/0x07E0)
|
|
|
|
|
|
返回值: 无
|
|
|
|
|
|
说明: 圆环外半径 = 40*scale,环粗 = 20*scale
|
|
|
|
|
|
闪电标志居中在圆环内,由 4 条线段组成
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
void Draw_Charging_Icon(uint16_t x, uint16_t y, uint8_t scale, uint16_t ring_color)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t outer_r = 40 * scale; // 外圈半径
|
|
|
|
|
|
uint8_t inner_r = 20 * scale; // 内圈半径(外半径 - 环粗)
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 1. 绘制绿色空心圆环 =====
|
|
|
|
|
|
// 用 LCD_DrawCircle 逐圈绘制(circle 本身是 1px 线宽)
|
|
|
|
|
|
// 从 inner_r 到 outer_r 画同心圆,形成粗环
|
|
|
|
|
|
for (uint8_t i = inner_r; i <= outer_r; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
LCD_DrawCircle(x, y, i, ring_color);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 2. 绘制居中的闪电标志(3px 粗线) =====
|
|
|
|
|
|
uint8_t s = scale;
|
|
|
|
|
|
|
|
|
|
|
|
// 每段画 3 条平行线(偏移 -1, 0, +1)形成 3px 粗的闪电
|
|
|
|
|
|
for (int8_t offset = -1; offset <= 1; offset++)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 顶部 → 右中(斜线)
|
|
|
|
|
|
LCD_DrawLine(
|
|
|
|
|
|
x - 4*s + offset, y - 16*s,
|
|
|
|
|
|
x + 3*s + offset, y - 5*s,
|
|
|
|
|
|
ring_color
|
|
|
|
|
|
);
|
|
|
|
|
|
// 右中 → 左中(横线,Y方向偏移)
|
|
|
|
|
|
LCD_DrawLine(
|
|
|
|
|
|
x + 3*s, y - 5*s + offset,
|
|
|
|
|
|
x - 3*s, y + 5*s + offset,
|
|
|
|
|
|
ring_color
|
|
|
|
|
|
);
|
|
|
|
|
|
// 左中 → 底部(斜线)
|
|
|
|
|
|
LCD_DrawLine(
|
|
|
|
|
|
x - 3*s + offset, y + 5*s,
|
|
|
|
|
|
x + 4*s + offset, y + 16*s,
|
|
|
|
|
|
ring_color
|
|
|
|
|
|
);
|
|
|
|
|
|
// 水平填充中段(Y偏移)
|
|
|
|
|
|
LCD_DrawLine(
|
|
|
|
|
|
x - 4*s, y + 5*s + offset,
|
|
|
|
|
|
x + 4*s, y + 5*s + offset,
|
|
|
|
|
|
ring_color
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
///******************************************************************************
|
|
|
|
|
|
// 函数说明:画【向左】实心三角箭头
|
|
|
|
|
|
// 入口数据:x, y 箭头中心点坐标
|
|
|
|
|
|
// size 箭头大小(建议 5~15)
|
|
|
|
|
|
// color 箭头颜色
|
|
|
|
|
|
// 返回值: 无
|
|
|
|
|
|
//******************************************************************************/
|
|
|
|
|
|
//void LCD_DrawArrow_Left(uint16_t x, uint16_t y, uint8_t size, uint16_t color)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// int16_t i;
|
|
|
|
|
|
// // 逐行画实心左箭头
|
|
|
|
|
|
// for(i = 0; i < size; i++)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// // 画水平线:越靠近中间,线越长 → 形成三角
|
|
|
|
|
|
// LCD_DrawLine(
|
|
|
|
|
|
// x - i, // X起点
|
|
|
|
|
|
// y - size + i, // Y起点
|
|
|
|
|
|
// x - i, // X终点
|
|
|
|
|
|
// y + size - i, // Y终点
|
|
|
|
|
|
// color
|
|
|
|
|
|
// );
|
|
|
|
|
|
// }
|
|
|
|
|
|
//}
|
|
|
|
|
|
//
|
|
|
|
|
|
///******************************************************************************
|
|
|
|
|
|
// 函数说明:画【向右】实心三角箭头
|
|
|
|
|
|
// 入口数据:x, y 箭头中心点坐标
|
|
|
|
|
|
// size 箭头大小(建议 5~15)
|
|
|
|
|
|
// color 箭头颜色
|
|
|
|
|
|
// 返回值: 无
|
|
|
|
|
|
//******************************************************************************/
|
|
|
|
|
|
//void LCD_DrawArrow_Right(uint16_t x, uint16_t y, uint8_t size, uint16_t color)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// int16_t i;
|
|
|
|
|
|
// // 逐行画实心右箭头
|
|
|
|
|
|
// for(i = 0; i < size; i++)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// LCD_DrawLine(
|
|
|
|
|
|
// x + i, // X起点
|
|
|
|
|
|
// y - size + i, // Y起点
|
|
|
|
|
|
// x + i, // X终点
|
|
|
|
|
|
// y + size - i, // Y终点
|
|
|
|
|
|
// color
|
|
|
|
|
|
// );
|
|
|
|
|
|
// }
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
|