还在用C编写LVGL上的画面,何不试试Python? (1)

最近,小编接触到了一个叫做LVGL的神奇东东,一句话形容下小编试玩的感受,那简直就是爱不释手。

说起LVGL,他可算不上一个新兴事物了,人家到今天已经年满11周岁了,所以,小编对他也算是相见恨晚。

LVGL:何方神圣?

LVGL全称Light and Versatile Graphics Library,强调轻量级以及多用途,是一款开源的图形化库,提供给用户创建嵌入式GUI所需的一切,具有易于使用的图形元素,漂亮的视觉效果以及最重要的——低内存占用。
2016年,LVGL在GitHub上推出了他的第一个公开版本。但是说起LVGL的真正诞生日,要回溯到2009年。这个项目最开始的时候,实际上是一个个人项目,项目作者是来自匈牙利的Gabor Kiss-Vamosi。Kiss在2009年开始编写LittleVGL。并在2016年将其重新发布在GitHub上。自此,超过100名贡献者加入这个项目,使其成为了最受欢迎的嵌入式图形库之一。
更加详细的介绍,以及LVGL的开发哲学,,小编在这里就不再扩展了。
说回本文,一般的,我们在使用LVGL时,往往都是基于C环境开发的,构建代码->编译->下载->调试,哪怕我们只想要修改其中一丢丢,我们也要不厌其烦的重复再重复这一过程。
如果换作Python呢?开发效率可就大大不同了,作为一门非编译型语言,用Python开发代码,可以大大的缩减开发流程,我们要做的,就只剩下构建代码->调试,让我们真正的体验到所见即所得,满满的幸福感。
所以,今天我们要聊的就是基于MicroPython开发LVGL。

为什么是Micropython LVGL?

首先,MicroPython不用多说,是能在微控制器上使用的Python。有了它,我们可以编写并在裸板上运行Python3代码。

MicroPython目前还没有一个好用的GUI库,而LVGL又是一个用C实现的GUI库,同时,LVGL是一款以面向对象风格编写的库,因此,可以平滑过渡到那些高级语言,比如Python。

Micropython LVGL能做什么?

首先得益于Python的语言特性,可以进行GUI的快速原型开发,缩短GUI的更改和微调周期。

其次,通过定义可重用的组合对象,如继承、异常处理等,可以用更抽象的方式构建GUI。

最后,小编认为也是最重要的,能够让更多的用户接触到LVGL,毕竟,现在即便不了解C语言,也能在嵌入式系统上创建一个漂亮的GUI了。

下面,小编就给大家分享一下开发一个带Micropython绑定的LVGL的部署步骤。在这之前,小编先给大家看一个简单的小例子:

import lvgl as lv
lv.init()
scr = lv.obj()
btn = lv.btn(scr)
btn.align(lv.scr_act(), lv.ALIGN.CENTER, 0, 0)
label = lv.label(btn)
label.set_text('Button')
lv.scr_load(scr)

看,是不是很简单,这样一小段代码,我们就创建一个按钮控件,并设置其为居中对齐,添加了标签:“Button”,最后通过调用lv.scr_load将其加载到屏幕上以进行显示。

相信我,这只是冰山一脚,反正小编是已经喜欢上用Python开发LVGL了。

部署步骤

在开始之前,我们要先准备下粮草,这是文中所需要的lvgl相关代码,文中用到的MicroPython环境基于openART软件平台。下面正式开始。

接触过MicroPython的朋友们,应该知道,想要导出可供Python调用的API,需要编写对应的MicroPython模块对象,那么LVGL也是如此。

首先,我们要准备一个包含用户访问LVGL的库,所需要的类和函数的MicroPython模块。幸运的是,我们并不需要自己辛苦码字,LVGL官方为我们提供了自动化的解决方案。代码中一个叫做gen_mpy.py的脚本负责自动生成这一模块。脚本本身会对lvgl的头文件进行预处理并进行解析,随后生成C语言形式的lv_mpy.c,这里面定义了MicroPython模块(API)以从MicroPython端访问LVGL。

不过,这一次,小编决定另辟蹊径,用一个更加简单的办法。

仔细翻找代码包,还会发现一个文件,叫做lv_mpy_example.c,里面几乎包含了我们所需要的所有lvgl控件,有了它,我们可以直接拿过来加载到我们的工程中,不用再手动执行gen_mpy.py。

不过,要注意的是,lv_mpy.c所定义的MicroPython模块都是静态即static的,唯一导出的符号是mp_module_lvgl,即所导出的lvgl模块本身,用户需要手动将这一模块注册到MicroPython中,才可以以import lvgl这种形式调用:

#define MICROPY_PORT_BUILTIN_MODULES \{ MP_OBJ_NEW_QSTR(MP_QSTR_lvgl), MP_ROM_PTR(&mp_module_lvgl)}

接下来,让我们聊聊内存管理部分。

当lvgl作为MicroPython的模块使用时,其内存管理实际上是依赖于MicroPython的垃圾回收机制(gc)。也正由于此,我们可以任性的声明/使用变量,不用纠结何时释放他们。因为垃圾的回收,gc帮我们干了。我们可以开心的做一个甩手掌柜。

不过要注意的是,想要让lvgl工作正常,需要将lvgl的“root”全局变量全部注册到MicroPython的root pointers中,以防这些变量被当成垃圾丢掉,这个LV_ROOTS是在lv_gc.h中的宏定义,包含了lvgl所用到的所有root变量。

#define LV_ITERATE_ROOTS(f) \
f(lv_ll_t, _lv_task_ll) /*Linked list to store the lv_tasks*/ \
f(lv_ll_t, _lv_disp_ll) /*Linked list of screens*/ \
f(lv_ll_t, _lv_indev_ll) /*Linked list of input device*/ \
f(lv_ll_t, _lv_drv_ll) \
f(lv_ll_t, _lv_file_ll) \
f(lv_ll_t, _lv_anim_ll) \
f(lv_ll_t, _lv_group_ll) \
f(lv_ll_t, _lv_img_defoder_ll) \
f(lv_ll_t, _lv_obj_style_trans_ll) \
f(lv_img_cache_entry_t*, _lv_img_cache_array) \
f(lv_task_t*, _lv_task_act) \
f(lv_mem_buf_arr_t , _lv_mem_buf) \
f(_lv_draw_mask_saved_arr_t , _lv_draw_mask_list) \
f(void * , _lv_theme_material_styles) \
f(void * , _lv_theme_template_styles) \
f(void * , _lv_theme_mono_styles) \
f(void * , _lv_theme_empty_styles) \
f(uint8_t *, _lv_font_decompr_buf) \

#define LV_DEFINE_ROOT(root_type, root_name) root_type root_name;
#define LV_ROOTS LV_ITERATE_ROOTS(LV_DEFINE_ROOT)

#define MICROPY_PORT_ROOT_POINTERS \
LV_ROOTS \
void *mp_lv_user_data;

说到这儿,小编要拍着胸脯向大家保证了,现在lvgl MicroPython部分就已经全部绑定好了,是的,就是这么简单。

我们现在连上板子,打开一个控制台,趁它不注意输入import lvgl,然后输入help(lvgl),出现以下log,就说明我们已经成功将模块导入了。

且听下回分解

至此,我们已经完成了lvgl与MicroPython的绑定,也可以说,软件部署部分可以告一段落了。

下一步就是为lvgl添加硬件支持了,包括LCD显示屏 触摸驱动,毕竟lvgl不同寻常,我们真正的目的是拿他来搭建GUI,显示出来才是最重要的,而不是让我们辛苦搭建的东西躺在内存里不见天日。

不过,小编在这里要先卖个关子,将在下一篇介绍MicroPython绑定下的lvgl的显示/输入驱动添加方法。并且会展示一个实际的使用例子。

(0)

相关推荐