lv_arduino(3.0.1)
一、lvgl基本介绍
1、什么是lvgl
LVGL(Light and Versatile Embedded Graphics Library)是一个轻量级的嵌入式图形库。LVGL的项目作者是来自匈牙利首都布达佩斯的 Gábor Kiss-Vámosi,他在2016年将其发布在 GitHub上。
当时叫 LittlevGL而不是LVGL,后来作者重新命名为 LVGL,甚至连仓库地址都改了。 像一般的开源项目的那样,它是作为一个人的项目开始的。 从那时起,陆续有近 100 名贡献者参与了项目开发,使得 LVGL 逐渐成为最受欢迎的嵌入式图形库之一。LVGL 项目(包括所有存储库)在 MIT license 许可下获得许可。这意味着您甚至可以在商业项目中使用它。
LVGL用C语言编写,以实现最大的兼容性(与C ++兼容),模拟器可在没有嵌入式硬件的PC上启动嵌入式GUI设计,同时LVGL作为一个图形库,它自带着接近三十多种小工具可以供开发者使用。这些强大的构建块按钮搭配上带有非常丝滑的动画以及可以做到平滑滚动的高级图形,同时兼具着不高的配置要求以及开源属性,显著的优势使得LVGL蔚然成风,成为广大开发者在选择GUI时的第一选择。
2、lvgl的主要特性
3、硬件要求
基本上,每个能够驱动显示器的现代控制器都适合运行LVGL。最低要求是:
注意: 内存使用情况可能因体系结构、编译器和构建选项而异。
4、版本
- lvgl核心存储库遵循语义版本控制规则:
- 不兼容的API的主要版本更改。例如, v5.0.0,v6.0.0。大约每年一次
- 次要版本,用于新的但向后兼容的功能。例如, v6.1.0,v6.2.0。每 3-4 个月一次
- 修补程序版本,用于向后兼容的错误修复。例如,v6.1.1,v6.1.2。每周按需发布
- 核心存储库至少具有以下分支:
- master: 最新版本,补丁直接合并在这里。
- release/vX.Y: 次要版本的稳定版本
- fix/some-description: bug修复的临时分支
- feat/some-description: 新功能开发的临时分支
- 版本支持情况
在 v8 之前,每个主要系列的最后一个次要版本支持 1 年。 从 v8 开始,每个次要版本都支持 1 年。
5、为什么是lv_arduino
3.0.1是lv_arduino的最后一个版本,与之对应的 lvgl 版本是7.11.0。lv_arduino最后一次提交是2020.12.4,github仓库已经存档了。为什么讲这个lv_arduino,原因很简单,就是版本更高的lvgl在arduino上使用rp2040没用起来。
简单来说,就是由于编译器生成的汇编代码中存在一些不对齐的指令造成的。汇编代码中的指令需要按照特定的规则对齐,以确保正确的执行。不对齐的指令可能会导致处理器无法正确解析和执行这些指令,从而引发错误。lvgl的开发人员将它归结为编译器问题,并且说降低优化级别可以避开此问题,github的lvgl仓库中,关于此问题的issue。我暂时没找到简单的办法实现这种解决办法:
1.找到编译器命令行中的优化选项,通常是类似于“-O2”或“-Os”的选项。
2.将优化选项修改为较低的级别,例如“-O1”或“-O0”。
补充:
1.我有些疑问,如果仅是编译器问题,为什么低版本的lvgl(7.11.0)不会引发此问题?如果和lvgl库本身有关,那么改变那个地方是不是也能避免这个报错?但是我没有找到这个地方,在这里提到主要是为了让之后也遇到这个问题,然后又特别想用lvgl最新版本(兼容性更好,附加功能更加完善)的人,多一条解决道路。
2.gcc编译流程
二、移植概述
注:后续内容大多基于lvgl 7.11.0版本,有高版本的会做说明,原因前面已经说了。
1、系统框架
LVGL的系统框架主要包括以下几个核心组件:
- 显示器驱动(Display Driver):LVGL通过显示器驱动与硬件进行交互,实现图形的绘制和显示。显示器驱动将硬件相关的操作封装起来,提供统一的接口供LVGL调用。
- 触摸驱动(Touch Driver):LVGL可以与触摸屏设备进行交互,通过触摸驱动接收用户的触摸输入。触摸驱动将触摸屏设备的操作封装起来,提供统一的接口供LVGL调用。
- 显示对象(Display Objects):LVGL提供了一系列的显示对象,例如窗口、标签、按钮、图像等,用于构建用户界面。每个显示对象具有自己的属性和行为,可以接收用户输入、响应事件,并进行相应的图形渲染。
- 事件处理(Event Handling):LVGL提供事件处理机制,可以捕获用户的输入事件,并将其发送给相应的显示对象进行处理。开发者可以通过注册事件处理函数来响应特定的事件,从而实现用户界面的交互逻辑。
- 样式系统(Style System):LVGL的样式系统允许开发者定义和管理显示对象的外观和样式。开发者可以为每个显示对象指定样式,包括颜色、字体、边框等属性,从而实现自定义的外观效果。
- 内存管理(Memory Management):LVGL提供了灵活的内存管理机制,可以适应不同的内存约束和需求。开发者可以根据自己的情况选择适合的内存管理策略,以确保LVGL在有限的资源下运行良好。
通过这些组件的协作,LVGL提供了一个完整的系统框架,用于开发嵌入式系统的图形界面。开发者可以根据自己的需求和硬件平台,使用LVGL构建出功能丰富、易于使用的用户界面。
LVGL本身是一个图形库。
我们的应用程序通过调用LVGL库来创建GUI。它包含一个HAL(硬件抽象层)接口,用于注册显示和输入设备驱动程序。驱动程序除特定的驱动程序外,它还有其他的功能,可驱动显示器GPU、读取触摸板或按钮的输入。
MCU有两种典型的硬件设置。一个带有内置LCD/TFT驱动器的外围设备,而另一种是没有内置LCD/TFT驱动器的外围设备。相同的是,这两种情况都需要一个帧缓冲区来存储屏幕的当前图像。
集成了TFT/LCD驱动器的MCU如果MCU集成了TFT/LCD驱动器外围设备,则可以直接通过RGB接口连接显示器。在这种情况下,帧缓冲区可以位于内部RAM(如果MCU有足够的RAM)中,也可以位于外部RAM(如果MCU具有存储器接口)中。
如果MCU没有集成TFT/LCD驱动程序接口,则必须使用外部显示控制器(例如SSD1963、SSD1306、ILI9341 )。在这种情况下,MCU可以通过并行端口,SPI或通过I2C与显示控制器进行通信。帧缓冲区通常位于显示控制器中,从而为MCU节省了大量RAM。
2、开始使用lvgl
1)、使用lvgl官方示例
- 目录 lvgl 就是 lvgl 的官方图形库
- 目录 lv_drivers 是 lvgl 输入输出设备驱动官方示例配置
- 目录 lv_examples 是 lvgl 的官方demo(可选,但不要直接使用到实际项目中)
上面的三个库中有一个类似名为 lv_conf_template.h 的配置头文件(template就是模板的意思)。通过它可以设置库的基本行为,裁剪不需要模块和功能,在编译时调整内存缓冲区的大小等等。
- 将 lvgl/lv_conf_template.h 复制到 lvgl 同级目录下,并将其重命名为
lv_conf.h
。打开文件并将开头的#if 0
更改为#if 1
以使能其内容。 - 将 lv_drivers/lv_drv_conf_template.h 复制到 lv_drivers 同级目录下,并将其重命名为
lv_drv_conf.h
。打开文件并将开头的#if 0
更改为#if 1
以使能其内容。 - (可选)将 lv_examples/lv_ex_conf_template.h 复制到 lv_examples 同级目录下,并将其重命名为
lv_ex_conf.h
。打开文件并将开头的#if 0
更改为#if 1
以使能其内容。
在配置文件中,注释说明了各个选项的含义。我们在移植时至少要检查以下三个配置选项,其他配置根据具体的需要进行修改:
-
LV_HOR_RES_MAX
显示器的水平分辨率。 -
LV_VER_RES_MAX
显示器的垂直分辨率。 -
LV_COLOR_DEPTH
颜色深度,其可以是:
- 8 - RG332
- 16 - RGB565
- 32 - (RGB888和ARGB8888)
2)、使用lv_arduino
【LVGL库】: lv_arduino
【屏幕驱动】: TFT_eSPI
这里我使用的是rp2040,并且没有触摸(如果有触摸可以使用【触摸驱动】: TFT_Touch)。
I、lv_arduino默认就有lv_conf.h
并且已经使能,不过还是至少应该打开确认分辨率和色深。
II、屏幕我这里使用的是st7789,并且rp2040引脚也是自定义的就没有采用已经写好的配置文件,而是直接使用User_Setup.h,自己修改。
User_Setup_Select.h默认如下:
// Only ONE line below should be uncommented to define your setup. Add extra lines and files as needed.
#include <User_Setup.h> // Default setup is root library folder
//#include <User_Setups/Setup1_ILI9341.h> // Setup file for ESP8266 configured for my ILI9341
//#include <User_Setups/Setup2_ST7735.h> // Setup file for ESP8266 configured for my ST7735
//#include <User_Setups/Setup3_ILI9163.h> // Setup file for ESP8266 configured for my ILI9163
//#include <User_Setups/Setup4_S6D02A1.h> // Setup file for ESP8266 configured for my S6D02A1
//#include <User_Setups/Setup5_RPi_ILI9486.h> // Setup file for ESP8266 configured for my stock RPi TFT
//#include <User_Setups/Setup6_RPi_Wr_ILI9486.h> // Setup file for ESP8266 configured for my modified RPi TFT
//#include <User_Setups/Setup7_ST7735_128x128.h> // Setup file for ESP8266 configured for my ST7735 128x128 display
//#include <User_Setups/Setup8_ILI9163_128x128.h> // Setup file for ESP8266 configured for my ILI9163 128x128 display
//#include <User_Setups/Setup9_ST7735_Overlap.h> // Setup file for ESP8266 configured for my ST7735
//#include <User_Setups/Setup10_RPi_touch_ILI9486.h> // Setup file for ESP8266 configured for ESP8266 and RPi TFT with touch
...
User_Setup.h修改如下:
根据屏幕型号,选择屏幕驱动:
// Only define one driver, the other ones must be commented out
// #define ILI9341_DRIVER // Generic driver for common displays
//#define ILI9341_2_DRIVER // Alternative ILI9341 driver, see https://github.com/Bodmer/TFT_eSPI/issues/1172
//#define ST7735_DRIVER // Define additional parameters below for this display
//#define ILI9163_DRIVER // Define additional parameters below for this display
//#define S6D02A1_DRIVER
//#define RPI_ILI9486_DRIVER // 20MHz maximum SPI
//#define HX8357D_DRIVER
//#define ILI9481_DRIVER
//#define ILI9486_DRIVER
//#define ILI9488_DRIVER // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high)
//#define ST7789_DRIVER // Full configuration option, define additional parameters below for this display
#define ST7789_2_DRIVER // Minimal configuration option, define additional parameters below for this display
//#define R61581_DRIVER
//#define RM68140_DRIVER
//#define ST7796_DRIVER
//#define SSD1351_DRIVER
//#define SSD1963_480_DRIVER
//#define SSD1963_800_DRIVER
//#define SSD1963_800ALT_DRIVER
//#define ILI9225_DRIVER
//#define GC9A01_DRIVER
如果显示器红蓝颠倒,可以调整如下宏:
// For ST7735, ST7789 and ILI9341 ONLY, define the colour order IF the blue and red are swapped on your display
// Try ONE option at a time to find the correct colour order for your display
#define TFT_RGB_ORDER TFT_RGB // Colour order Red-Green-Blue
// #define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red
根据屏幕尺寸选择:
// For ST7789, ST7735, ILI9163 and GC9A01 ONLY, define the pixel width and height in portrait orientation
// #define TFT_WIDTH 80
// #define TFT_WIDTH 128
// #define TFT_WIDTH 172 // ST7789 172 x 320
#define TFT_WIDTH 240 // ST7789 240 x 240 and 240 x 320
// #define TFT_HEIGHT 160
// #define TFT_HEIGHT 128
// #define TFT_HEIGHT 240 // ST7789 240 x 240
#define TFT_HEIGHT 320 // ST7789 240 x 320
// #define TFT_HEIGHT 240 // GC9A01 240 x 240
根据原理图修改屏幕的驱动引脚:
#define TFT_MISO 0
#define TFT_MOSI 3 // In some display driver board, it might be written as "SDA" and so on.
#define TFT_SCLK 2
#define TFT_CS 1 // Chip select control pin
#define TFT_DC 7 // Data Command control pin
#define TFT_RST 6 // Reset pin (could connect to Arduino RESET pin)
#define TFT_BL 12 // LED back-light
使用rp2040需打开此宏:
// For RP2040 processor and SPI displays, uncomment the following line to use the PIO interface.
#define RP2040_PIO_SPI // Leave commented out to use standard RP2040 SPI port interface
III、第三步自然是打开示例ino,由于lv_arduino自带了使用TFT_eSPI的示例 ESP32_TFT_eSPI.ino可以直接参考,不需要下载lv_examples。
3、简单的驱动接口注册
因为我这里不仅需要使用lvgl的各种控件,还需要显示U盘的图片。也就是说,需要访问文件系统,还需要图片文件的解码。
下图是lv_arduino和lvgl(8.3.0)文件系统接口文件对比,可以明显看到,新版的lvgl包含的功能更加全面,所以能够使用最好使用最新版的lvgl。
lv_arduino没有图片解码的文件,但是lvgl有;并且lv_fs_fatfs.c比lv_port_fs_template.c更详尽,于是一并拿过来修改。
主要就是完善以下文件系统的接口:
/**********************
* STATIC PROTOTYPES
**********************/
static void fs_init(void);
static void * fs_open(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode);
static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p);
static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br);
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence);
static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p);
static void * fs_dir_open(lv_fs_drv_t * drv, const char * path);
static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn);
static lv_fs_res_t fs_dir_close(lv_fs_drv_t * drv, void * dir_p);
在调用如下函数后,即可在LVGL中注册文件系统接口:
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_fs_fatfs_init(void)
{
/*----------------------------------------------------
* Initialize your storage device and File System
* -------------------------------------------------*/
fs_init();
/*---------------------------------------------------
* Register the file system interface in LVGL
*--------------------------------------------------*/
/*Add a simple drive to open images*/
static lv_fs_drv_t fs_drv; /*A driver descriptor*/
lv_fs_drv_init(&fs_drv);
/*Set up fields...*/
fs_drv.letter = LV_FS_FATFS_LETTER;
fs_drv.cache_size = LV_FS_FATFS_CACHE_SIZE;
fs_drv.open_cb = fs_open;
fs_drv.close_cb = fs_close;
fs_drv.read_cb = fs_read;
fs_drv.write_cb = fs_write;
fs_drv.seek_cb = fs_seek;
fs_drv.tell_cb = fs_tell;
fs_drv.dir_close_cb = fs_dir_close;
fs_drv.dir_open_cb = fs_dir_open;
fs_drv.dir_read_cb = fs_dir_read;
lv_fs_drv_register(&fs_drv);
}
至于像bmp和png图片解码器的注册则是更简单,因为lvgl已经完成了这些解码器,直接调用初始化接口:
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_bmp_init(void)
{
lv_img_decoder_t * dec = lv_img_decoder_create();
lv_img_decoder_set_info_cb(dec, decoder_info);
lv_img_decoder_set_open_cb(dec, decoder_open);
lv_img_decoder_set_read_line_cb(dec, decoder_read_line);
lv_img_decoder_set_close_cb(dec, decoder_close);
}
当然,如果你和我一样使用老版本的lvgl,比如lv_arduino,要使用这些功能就还得修改一下版本兼容问题,如果使用最新版的lvgl,则是直接在lv_conf.h使能和配置即可:
/*API for FATFS (needs to be added separately). Uses f_open, f_read, etc*/
#define LV_USE_FS_FATFS 0
#if LV_USE_FS_FATFS
#define LV_FS_FATFS_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
#define LV_FS_FATFS_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/
#endif
/*PNG decoder library*/
#define LV_USE_PNG 0
/*BMP decoder library*/
#define LV_USE_BMP 0
4、demo简单说明
#include <lvgl.h>
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI(); /* TFT instance */
static lv_disp_buf_t disp_buf; // 用于表示LVGL库中的显示缓冲区
static lv_color_t buf[LV_HOR_RES_MAX * 10]; // 用于存储显示缓冲区的像素数据
// 使用打印的话,不止使能配置这里,还要记得去lv_conf.h中配置 LV_USE_LOG 、 LV_LOG_LEVEL 和 LV_LOG_PRINTF
#define USE_LV_LOG 1 /* 启用/禁用日志模块 */
#if USE_LV_LOG != 0
/* 串口调试
*/
void my_print(lv_log_level_t level, const char * file, uint32_t line, const char * dsc)
{
Serial.printf("%s@%d->%s\r\n", file, line, dsc);
Serial.flush();
}
#endif
// 这将会是注册到lvgl系统的显示驱动接口,该驱动接口使用的就是 TFT_eSPI
/* 屏幕刷新 */
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
uint32_t w = (area->x2 - area->x1 + 1);
uint32_t h = (area->y2 - area->y1 + 1);
tft.startWrite();
tft.setAddrWindow(area->x1, area->y1, w, h);
tft.pushColors(&color_p->full, w * h, true);
tft.endWrite();
lv_disp_flush_ready(disp);
}
/* 读取输入设备(这里是模拟编码器) */
bool read_encoder(lv_indev_drv_t * indev, lv_indev_data_t * data)
{
static int32_t last_diff = 0;
int32_t diff = 0; /* Dummy - no movement */
int btn_state = LV_INDEV_STATE_REL; /* Dummy - no press */
data->enc_diff = diff - last_diff;;
data->state = btn_state;
last_diff = diff;
return false;
}
void setup()
{
Serial.begin(115200); /* prepare for possible serial debug */
lv_init();
#if USE_LV_LOG != 0
lv_log_register_print_cb(my_print); /* register print function for debugging */
#endif
// 显示器驱动的初始化依然要在这里完成
tft.begin(); /* TFT init */
tft.setRotation(1); /* Landscape orientation */
/*
disp_buf 变量用于管理缓冲区,这里进行初始化,将实际的单个缓冲区buf放入其中。
关于缓冲区大小,有 3 种情况:
一个缓冲区 LVGL将屏幕的内保存到缓冲区中并将其发送到显示器。缓冲区可以小于屏幕。在这种情况下,较大的区域将被重画成多个部分。
如果只有很小的区域发生变化(例如按下按钮),则只会刷新该部分的区域。
两个非屏幕大小的缓冲区 具有两个缓冲区的 LVGL 可以将其中一个作为显示缓冲区,而另一缓冲区的内容发送到后台显示。应该使用 DMA
或其他硬件将数据传输到显示器,以让CPU同时绘图。这样,渲染和刷新并行处理。与 一个缓冲区 的情况类似,如果缓冲区小于要刷新的区
域,LVGL将按块绘制显示内容
两个屏幕大小的缓冲区 与两个非屏幕大小的缓冲区相反,LVGL将始终提供整个屏幕的内容,而不仅仅是块。这样,驱动程序可以简单地将帧缓
冲区的地址更改为从 LVGL 接收的缓冲区。因此,当MCU具有 LCD/TFT 接口且帧缓冲区只是 RAM 中的一个位置时,这种方法的效果很好。
*/
lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);
/* 将缓冲区和显示器驱动接口注册到lvgl */
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = 320;
disp_drv.ver_res = 240;
disp_drv.flush_cb = my_disp_flush;
disp_drv.buffer = &disp_buf;
lv_disp_drv_register(&disp_drv);
/* 初始化(虚拟)输入设备驱动程序 */
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_ENCODER;
indev_drv.read_cb = read_encoder;
lv_indev_drv_register(&indev_drv);
/* 创建简单字符标签 */
lv_obj_t *label = lv_label_create(lv_scr_act(), NULL);
lv_label_set_text(label, "Hello Arduino! (V7.0.X)");
lv_obj_align(label, NULL, LV_ALIGN_CENTER, 0, 0);
/* 在屏幕上显示文件系统里面的图片,wink.png 。当然,你得确保你完成了解码器初始化,以及文件系统接口的完善和初始化*/
lv_obj_t * img;
img = lv_img_create(lv_scr_act(), NULL);
lv_img_set_src(img, "A:/home/libs/png/wink.png");
lv_obj_set_size(img, 150, 150);
}
void loop()
{
lv_task_handler(); /* 让GUI完成它的工作 */
delay(5);
}
lv_task_handler()
是 LVGL(LittlevGL)库中的一个函数,用于处理 LVGL 的任务调度。
LVGL 是一个事件驱动的图形库,它使用任务调度器来管理和执行各种任务。任务可以是定时器、动画、界面刷新等操作,通过任务调度器进行管理可以确保这些任务按照预定的时间和顺序执行。
lv_task_handler()
函数的作用是在主循环中调用,它会处理和执行所有已注册的 LVGL 任务。在每次调用时,lv_task_handler()
函数会检查每个任务的状态和时间,然后决定是否执行该任务。
具体的功能和意义包括:
- 执行定时任务:LVGL 支持注册定时器任务,可以在一定的时间间隔内执行某些操作。
lv_task_handler()
函数会检查定时器任务的时间是否到达,如果到达则执行相应的操作。 - 处理动画任务:LVGL 支持动画效果,例如渐变、移动等。
lv_task_handler()
函数会检查动画任务的状态和时间,更新动画的状态,以实现平滑的动画效果。 - 刷新界面任务:LVGL 提供了界面刷新机制,可以根据需要更新显示内容。
lv_task_handler()
函数会检查界面刷新任务的状态和时间,根据需要刷新界面,确保显示内容的准确性和实时性。 - 处理事件任务:LVGL 接收和处理用户输入事件,例如按钮点击、触摸屏输入等。
lv_task_handler()
函数会检查事件任务的状态和时间,处理接收到的事件,并触发相应的回调函数或操作。
通过调用 lv_task_handler()
函数,可以确保 LVGL 中的各种任务得到及时执行,从而保证图形界面的正常运行和响应。一般情况下,lv_task_handler()
函数需要在主循环中以适当的频率被调用,以满足任务调度的需求。
三、和其他图形库对比
LVGL(LittlevGL)和其他一些嵌入式图形库相比,各自具有一些优点和缺点。以下是对LVGL和其他几个常见嵌入式图形库的优缺点的简要概述:
1、LVGL(LittlevGL):
优点:
- 开源免费:LVGL是一个开源的图形库,可以免费使用和修改。
- 轻量级:LVGL具有较小的代码体积和内存占用,适用于资源受限的嵌入式系统。
- 高度可定制:LVGL提供了丰富的配置选项和可扩展性,开发者可以根据需要进行灵活定制。
- 跨平台支持:LVGL支持多种嵌入式平台和显示器驱动,具有较好的移植性。
缺点:
- 学习曲线:LVGL的API和配置选项较多,学习和掌握需要一定的时间和精力。
- 文档资源:相对其他商业图形库而言,LVGL的文档和示例资源相对较少,可能需要更多的自学和实践。
2、µGUI:
优点:
- 轻量级:µGUI具有小巧简单的特点,适用于资源受限的嵌入式系统。
- 易于使用:µGUI提供简单的API和基本的图形元素,上手较快。
缺点:
- 功能有限:相对于其他图形库,µGUI的功能较为有限,不支持复杂的图形效果和高级控件。
3、TouchGFX:
优点:
- 高性能:TouchGFX利用硬件加速技术,提供了较高的图形渲染性能。
- 丰富的图形元素:TouchGFX提供了丰富的图形元素和动画效果,可以创建出精美的用户界面。
缺点:
- 商业授权:TouchGFX是商业图形库,需要购买相应的许可证才能使用。
- 学习成本:TouchGFX的学习曲线较陡峭,需要一定的学习和掌握。
4、EmWin:
优点:
- 优化性能:EmWin具有高度优化的绘图算法,提供了较高的图形渲染性能。
- 丰富的控件库:EmWin提供了丰富的图形控件,可以快速构建出复杂的用户界面。
缺点:
- 商业授权:EmWin是商业图形库,需要购买相应的许可证才能使用。
- 资源占用较大:相对于一些轻量级图形库,EmWin的代码体积和内存占用较大。
5、NanosGUI:
优点:
- 轻量级:NanosGUI具有较小的代码体积和内存占用,适用于资源受限的嵌入式系统。
- 易于使用:NanosGUI提供简单易用的API和丰富的图形元素,上手较快。
- 跨平台支持:NanosGUI支持多种嵌入式平台和显示器驱动。
缺点:
- 功能相对较少:相对于一些其他图形库,NanosGUI的功能可能较为有限。
6、Qt for Embedded:
优点:
- 强大的功能:Qt for Embedded提供了丰富的图形和应用开发框架,支持复杂的图形界面和交互。
- 跨平台支持:Qt for Embedded具有良好的跨平台性,可在多种嵌入式平台上运行。
- 大型社区支持:Qt具有庞大的开发者社区和活跃的生态系统,提供丰富的文档、示例和支持资源。
缺点:
- 资源占用较大:相对于一些轻量级图形库,Qt for Embedded的代码体积和内存占用较大。
- 商业授权:Qt for Embedded有商业版和开源版两种许可证,商业版需要购买相应的许可证才能使用。
7、AWTK
优点:
- 跨平台支持:AWTK支持多种操作系统和平台,包括Linux、Windows、macOS、Android等,具有很好的跨平台兼容性。
- 丰富的控件库:AWTK提供了大量的内置控件,如按钮、标签、滚动条、列表框等,使开发者可以快速构建丰富多样的用户界面。
- 良好的扩展性:AWTK允许开发者通过自定义控件和主题,扩展和定制界面的外观和行为,以满足特定的应用需求。
- 轻量级和高效性能:AWTK采用精简的设计和高效的渲染机制,具有较小的内存占用和快速的响应速度,适用于资源有限的嵌入式设备。
- 良好的文档和社区支持:AWTK提供了详细的文档和示例代码,以及活跃的社区支持,开发者可以快速入门并获得帮助。
缺点:
- 学习曲线较陡:由于AWTK具有一定的复杂性和灵活性,初学者可能需要花费一些时间来学习和理解其概念和使用方法。
- 非常规的API设计:AWTK采用了一种非常规的API设计风格,相对于传统的GUI库,开发者可能需要适应和理解其特有的编程模式和风格。
- 社区相对较小:相比一些主流的图形界面库,AWTK的社区规模相对较小,可能会导致一些限制和较少的资源和工具支持。
8、miniGUI
优点:
- 轻量级和高效性能:MiniGUI的设计目标是在资源受限的嵌入式设备上提供高效的图形界面显示和操作体验,它采用了精简的设计和高效的渲染机制,具有较小的内存占用和快速的响应速度。
- 可定制性强:MiniGUI提供了灵活的配置选项和扩展机制,开发者可以根据项目需求和硬件平台的特点进行定制,包括选择需要的图形引擎、控件库和主题等,以满足不同应用场景的需求。
- 多平台支持:MiniGUI支持多种操作系统和平台,包括Linux、Windows、Android等,具有较好的跨平台兼容性,方便在不同平台上进行开发和移植。
- 完善的控件库和工具:MiniGUI提供了丰富的控件库,包括按钮、标签、文本框、列表框等常用控件,以及图形绘制、字体管理等功能模块。此外,MiniGUI还提供了可视化界面编辑工具和调试工具,方便开发者进行界面设计和调试。
缺点:
- 学习曲线较陡:MiniGUI的学习曲线相对较陡,特别是对于初学者来说,需要花费一些时间来熟悉其架构和使用方式。
- 可定制性有限:虽然MiniGUI提供了一定程度的定制性,但相比其他一些图形界面库,其可定制性相对较有限,特定需求的定制可能需要深入了解其内部机制和代码。
四、部件描述
效的图形界面显示和操作体验,它采用了精简的设计和高效的渲染机制,具有较小的内存占用和快速的响应速度。
2. 可定制性强:MiniGUI提供了灵活的配置选项和扩展机制,开发者可以根据项目需求和硬件平台的特点进行定制,包括选择需要的图形引擎、控件库和主题等,以满足不同应用场景的需求。
3. 多平台支持:MiniGUI支持多种操作系统和平台,包括Linux、Windows、Android等,具有较好的跨平台兼容性,方便在不同平台上进行开发和移植。
4. 完善的控件库和工具:MiniGUI提供了丰富的控件库,包括按钮、标签、文本框、列表框等常用控件,以及图形绘制、字体管理等功能模块。此外,MiniGUI还提供了可视化界面编辑工具和调试工具,方便开发者进行界面设计和调试。
缺点:
- 学习曲线较陡:MiniGUI的学习曲线相对较陡,特别是对于初学者来说,需要花费一些时间来熟悉其架构和使用方式。
- 可定制性有限:虽然MiniGUI提供了一定程度的定制性,但相比其他一些图形界面库,其可定制性相对较有限,特定需求的定制可能需要深入了解其内部机制和代码。
四、部件描述
五、详细功能