在线时间4071 小时
UID3441752
注册时间2017-11-21
NXP金币752102
TA的每日心情 | 开心 2024-3-26 15:16 |
---|
签到天数: 266 天 [LV.8]以坛为家I
管理员
- 积分
- 32055
- 最后登录
- 2024-4-30
|
还在用C编写LVGL上的画面,何不试试Python? (2)
在上一篇中,小编为大家简单介绍了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已经成功移植到了我们的板子上。
相信大家看完之后,已经跃跃欲试了,那就开始动手吧!
|
|