分享

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

 新用户0118F7lQ 2021-05-07

在上一篇中,小编为大家简单介绍了LVGL库,并且介绍了如何实现lvgl和MicroPython的绑定,使得lvgl以MicroPython模块的形式供用户通过Python进行调用,方便开发。

本篇小编将继续承接上文,介绍如何添加输入/输出驱动,以将我们绘制的GUI界面显示到显示设备。同时,输入设备方便我们进行人机交互。


输入/输出设备驱动添加


既然要使用Python进行GUI开发,那么驱动当然也要注册为MicroPython模块,才像话嘛。
同时,由于LVGL可以配置为使用不同的显示器和输入设备。这样一来,如果单纯的只提供C语言编写的驱动程序,每更换驱动就要重新将新的驱动程序替换到工程中,重新编译。考虑到注册驱动程序的本质,实际上就是调用注册函数(disp_drv_register),并将函数指针作为参数传递,函数指针指向用于访问真正的显示/输入设备。
为了实现这一点,当在MicroPython中使用LVGL时,用C语言实现显示和输入驱动程序更有意义。但是,设备的注册是需要在MicroPython脚本中进行的,即前文所说的,驱动程序本身需要定义成对应的MicroPython模块。这样用户就可以轻松地选择和替换驱动程序,而无需构建项目和修改C文件。
不过,从技术上讲,驱动程序不仅仅局限于C,也可以用纯纯的MicroPyhon,通过回调函数来编写。进行驱动注册的代码实现:
# 所编写的模块驱动
import lvgl_helper

# 注册显示驱动.

disp_buf1 = lv.disp_buf_t()
buf1_1 = bytes(480*10) # 声明lvgl绘制GUI的buffer,lvgl支持1-2个
# buffer
disp_buf1.init(buf1_1, None, len(buf1_1)//4)
disp_drv = lv.disp_drv_t()
disp_drv.init()
disp_drv.buffer = disp_buf1
disp_drv.flush_cb = lvgl_helper.flush # 注册显示回调函数
disp_drv.hor_res = 480
disp_drv.ver_res = 320
disp_drv.register()

# 注册输入驱动

indev_drv = lv.indev_drv_t()
indev_drv.init()
indev_drv.type = lv.INDEV_TYPE.POINTER
indev_drv.read_cb = lvgl_helper.capture # 注册输入回调函数
indev_drv.register()

这里,我们定义了一个叫做lvgl_helper的模块,其中包括一个叫做flush的函数,负责将lvgl绘制好的GUI刷新到显示设备,另一个函数叫做capture,负责处理输入请求,获取用户输入。

接下来,让我们看看这两个函数是怎么实现的。

首先是lvgl_helper.flush函数,具有三个参数,作用就是将lvgl绘制的目标区域刷新到显示设备:

STATIC mp_obj_t mp_flush(mp_obj_t disp_drv, mp_obj_t area, mp_obj_t color){
// 显示设备指针
lv_disp_drv_t *disp_ptr = GET_PTR_FROM_OBJ(lv_disp_drv_t, disp_drv);
// 待刷新区域
lv_area_t *area_ptr = GET_PTR_FROM_OBJ(lv_area_t, area);
// 待刷新目标地址指针
lv_color_t *color_ptr = GET_PTR_FROM_OBJ(lv_color_t, color);
// 获取刷新区域宽和高
uint16_t w = lv_area_get_width(area_ptr);
uint16_t h = lv_area_get_height(area_ptr);
// 真正的刷新函数,根据不同硬件定制化实现
Update_FrameBuffer((void*)color_ptr, w, h, COLOR_DEPTH, NULL);
// 很重要,在刷新完成后,需要通知lvgl,刷新完毕,可以继续绘制,否则会一直阻塞
// 直到刷新完毕
lv_disp_flush_ready(disp_ptr);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_3(mp_flush_obj, mp_flush);

与之对应的输入函数,看似简单一点,只有2个参数,其目的就是获取屏幕触摸坐标:

STATIC mp_obj_t mp_capture(mp_obj_t indev_drv, mp_obj_t data){ // 输入设备指针
lv_indev_drv_t *indev_ptr = GET_PTR_FROM_OBJ(lv_indev_drv_t, indev_drv);
// 存储获取的触摸位置坐标(x,y)
lv_indev_data_t* data_ptr = GET_PTR_FROM_OBJ(lv_indev_data_t, data);
// 触摸屏驱动,需要自行实现
DEMO_ReadTouch(indev_ptr, data_ptr, resolution.w, resolution.h);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_capture_obj, mp_capture);

有了显示和输入设备的驱动,就可以算的上万事具备了,不过,东风还没来。

lvgl规定,画面的刷新以及响应输入设备,是通过周期性的调用lv.task_handler()函数实现的,同时需要通过lv.tick_inc(x)函数提供内部时钟。而对于MicroPython,函数的周期性调用有点特殊,是通过周期性的调用mp_sched_schedule函数来实现的。

为了做到周期性调用这一硬性规定,推荐的做法是实现一个timer,软件/硬件的都可以,但是硬件时钟当然最好,并将周期函数以callback的形式注册到timer中:

def timer_callback(self):
lv.tick_inc(10)
lv.task_handler()
timer.init(50) # 刷新时间可以自行调整
timer.callback(timer_callback)

这样,一切就都准备就绪了,让我们来搭建一个简单的界面玩一下。


实战操练与效果展示


这次的小demo包括:按钮,滑动条,键盘,文本框以及一个图片控件。

先看下实际效果:

图片

图片

图片

是不是界面很熟悉,是的,小编前面说过了,MicroPython环境依托于openART软件包,因此,我们可以使用openMV IDE进行代码的编写和下载,并通过预览窗口进行GUI预览。

下面逐段说明一下控件所对应的代码实现:

0) 初始化:

import lv
lv.init()
scr = lv.obj() # declare the screen to show
1) 按钮
btn = lv.btn(lv.scr_act())
# 对齐属性以及位置坐标
btn.align(lv.scr_act(), lv.ALIGN.IN_BOTTOM_LEFT, 10, -20)
btn.toggle() # 翻转显示,蓝底白字/白底蓝字
label = lv.label(btn) # 控件名字
label.set_text('start')

2) 滑动条:

slider = lv.slider(lv.scr_act())
slider.align(lv.scr_act(), lv.ALIGN.OUT_RIGHT_TOP, -50, -10)
# 滑动条宽和高
slider.set_width(10)
slider.set_height(300)
# 滑动条范围
slider.set_range(10, 200)
# 滑动条初始值
slider.set_value(100, 0)

3) 键盘:

keyboard = lv.keyboard(lv.scr_act())
# 数字键盘
# keyboard.set_mode(keyboard.MODE.NUM)
# 大写字母键盘
# keyboard.set_mode(keyboard.MODE.TEXT_UPPER)
# 小写字母键盘
# keyboard.set_mode(keyboard.MODE.TEXT_LOWER)
# 特殊符号键盘
# keyboard.set_mode(keyboard.MODE.SPECIAL)
keyboard.align(lv.scr_act(), lv.ALIGN.IN_TOP_LEFT, 0, 0)

4) 文本框:

text = lv.textarea(lv.scr_act())
text.align(lv.scr_act(), lv.ALIGN.IN_BOTTOM_LEFT, 0, 0)
# 设置控件为可拖拽属性
text.drag(True)

5) 图片:

# 读取图片数据
img_data = open('/sd/blue_flower_16.txt').read()
img = lv.img(lv.scr_act())
img.align(lv.scr_act(), lv.ALIGN.CENTER, 0, 0)
# 设置图像属性
img_dsc = lv.img_dsc_t(
{
'header': {'always_zero': 0, 'w': 100, 'h': 75, 'cf': lv.img.CF.TRUE_COLOR},
'data_size': len(img_data),
'data': img_data,
}
)
img.set_src(img_dsc)

尽管是几个简单的控件的使用,验证了我们的带MicroPython绑定的lvgl已经成功移植到了我们的板子上。

相信大家看完之后,已经跃跃欲试了,那就开始动手吧!

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多