想了解更多关于开源的量化内容,请访问:
51CTO 开源基础软件社区
https://ost.51cto.com
LVGL(Light and Versatile Graphics Library)是系统一个开源轻量级显示框架,支持多类型显示设备&&输入设备,量化作为一个开源图形库,系统自带了三十多种小组件供开发者使用。量化兼容低配置的系统嵌入式开发,可以以极低的量化配置要求完成丝滑动画。LVGL其强大的系统功能,使得它在物联网设备中应用比比皆是量化。
前一阵子开发了润和hispark_pegasus Hi3861开发板上的系统SSD1306,其提供的量化开发库开发起来还是较为困难,于是系统想尝试将LVGL移植到OpenHarmony轻量化系统上,便于后续OpenHarmony物联网设备的量化屏幕开发,大大降低屏幕开发的时间成本。
本文章将简单介绍LVGL的主要开发流程,OpenHarmony->LVGL的具体移植期待后续文章。
LVGL的初始化主要流程为以下步骤:
初始化lv_disp_draw_buf_t && lv_disp_drv_t这两个结构体然后对应初始化绘制缓冲区的内部图形缓冲区,显示驱动程序。
对于lv_disp_draw_buf_t:
/*一个静态或全局变量来存储缓冲区*/
static lv_disp_draw_buf_t disp_buf;
/*静态或全局缓冲区(s)。第二个缓冲区是可选的*/
static lv_color_t buf_1[MY_DISP_HOR_RES * 10];
static lv_color_t buf_2[MY_DISP_HOR_RES * 10];
/*初始化函数,第三变量可以为NULL */
lv_disp_draw_buf_init(&disp_buf, buf_1, buf_2, MY_DISP_HOR_RES*10);
更大的缓冲区能带来更高的性能,但超过1/10屏幕大小的缓冲区之后性能没有显著提升,因而建议稍微大于1/10屏幕大小的缓冲区即可.
只使用一个缓冲区,那么需要等待LVGL刷新了之后才能渲染下一帧.而使用到两个缓冲区后,LVGL可以同时进行刷新和渲染。
对于lv_disp_drv_t:
初始化中可以启用 full_refresh 以强制 LVGL 始终重绘整个屏幕。这适用于单/双缓冲模式。
如果启用该模式并提供 2 个屏幕大小的绘制缓冲区,LVGL 的显示处理就像“传统”双缓冲一样工作。
这意味着在 flush_cb 中只有帧缓冲区的地址需要更改为提供的指针(color_p 参数)。 如果 MCU 具有 LCD 控制器外围设备而不是外部显示控制器(例如 ILI9341 或 SSD1963),则应使用此配置。
对于上面的缓冲区初始化完成之后,可以初始化显示驱动结构体lv_disp_drv_t。
lv_disp_flush_ready(&disp_drv) 需要在刷新准备好时调用。 LVGL 可能会以多个块呈现屏幕,因此多次调用 flush_cb。要查看当前是否是渲染的最后一个块,请使用 lv_disp_flush_is_last(&disp_drv)。
对于lv_disp_drv_t对象而言,还有一些可选择的成员可以修改:
static lv_disp_drv_t disp_drv; //静态的一个显示驱动结构体
lv_disp_drv_init(&disp_drv); //初始化结构体
disp_drv.draw_buf = &disp_buf; //指向上一章显示缓存的指针
disp_drv.flush_cb = my_flush_cb; //回调函数,将缓冲区的内容复制到显示器的特定区域
disp_drv.hor_res = 320; //水平像素
disp_drv.ver_res = 240; //垂直像素
lv_disp_t * disp; //保存返回值
disp = lv_disp_drv_register(&disp_drv); //注册结构体
//回调函数
void my_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
//最简单的情况下(但也最慢)
int32_t x, y;
for(y = area->y1; y <= area->y2; y++) {
for(x = area->x1; x <= area->x2; x++) {
put_px(x, y, *color_p);
color_p++;
}
}
//通知LVGL准备刷新
lv_disp_flush_ready(disp_drv);
}
对于输入设备,首先要区分是何种类型输入设备,不同输入设备都有不同的初始化驱动API
LVGL将输入设备分成了四种类型:
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv); //初始化结构体
indev_drv.type =LV_INDEV_TYPE_POINTER; //输入设备类型,当前为鼠标
indev_drv.read_cb =... //回调函数,用于定期(几乎实时)获取输入设备的数据
lv_indev_t * my_indev = lv_indev_drv_register(&indev_drv); //注册输入设备
对于触摸板,鼠标等指针类的输入设备,他们的回调函数可以如下设置。
void my_input_read(lv_indev_drv_t * drv, lv_indev_data_t*data)
{
if(touchpad_pressed) {
data->point.x = touchpad_x;
data->point.y = touchpad_y;
data->state = LV_INDEV_STATE_PRESSED;
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
}
若是需要显示光标,则如下:
lv_indev_t * mouse_indev = lv_indev_drv_register(&indev_drv);
//图像声明
LV_IMG_DECLARE(mouse_cursor_icon);
//创建光标对象
lv_obj_t * cursor_obj = lv_img_create(lv_scr_act(), NULL);
//设置光标图像的来源
lv_img_set_src(cursor_obj, &mouse_cursor_icon);
//链接显示驱动
lv_indev_set_cursor(mouse_indev, cursor_obj);
//设置光标点击
lv_obj_set_click(cursor_obj, false);
使用编码器可以做到以下事件:
void encoder_read(lv_indev_drv_t * drv, lv_indev_data_t*data){
data->enc_diff = enc_get_new_moves();
if(enc_pressed()) data->state = LV_INDEV_STATE_PRESSED;
else data->state = LV_INDEV_STATE_RELEASED;
}
由于屏幕驱动会占用系统的大量资源,所以在不需要屏幕驱动时,可以选择睡眠LVGL子系统,减少对资源的占用时,可以参考以下代码:
while(1) {
//一秒内无操作
if(lv_disp_get_inactive_time(NULL) < 1000) {
//LVGL处理相关任务
lv_task_handler();
}
/*Sleep after 1 sec inactivity*/
else {
timer_stop(); //定时器暂停
sleep(); //休眠线程
}
my_delay_ms(5);
}
当需要唤醒时,对输入设备进行操作以唤醒LVGL。
将下面代码加入输入设备读取功能里面。
lv_tick_inc(LV_DISP_DEF_REFR_PERIOD); //唤醒任务
timer_start(); //重启定时器
lv_task_handler(); //启动LVGL处理相关任务
想了解更多关于开源的内容,请访问:
51CTO 开源基础软件社区
https://ost.51cto.com
责任编辑:jianghua 来源: 51CTO 开源基础软件社区 LVGL鸿蒙(责任编辑:娱乐)
2022年全球人工智能软件市场规模将达625亿美元 相比2021年增长21.3%
新筑股份(002480.SZ):拟开展融资性售后回租业务 租赁期限3年