侧边栏切换

LVGL学习之LVGL的初始化和屏幕的翻转

最后编辑于: 2021-09-06 14:59  |  分类: 嵌入式软件开发  |  标签: LVGL GUI   |  浏览数: 7673  |  评论数: 0


0. 前言

前一段买了ESP32-S2-HMI-DevKit-1开发板,通过折腾了几个官方自带的例程之后,也算是对这个开发板和其所用的LVGL有了个初步的了解。

下面要进一步的学习LVGL了。

引述一下这个开发板官方的介绍:

该开发板是基于 ESP32-S2 的 HMI 开发板,其板载资源如下图所示。

该开发板使用 ESP32-S2-WROVER 模组,模组内置 4 MB flash 和 2 MB PSRAM。开发板搭载了一块使用 16 位 8080 并口的 4.3 寸 TFT-LCD,分辨率为 480×800,配有 256 级硬件 DC 背光调节电路(V1.1 版本开发板暂未配备该功能)。并配备了电容式触摸面板,使用 I2C 接口进行通讯。

开发板上搭载了带有三轴加速计和三轴陀螺仪的惯性传感器、环境光传感器、温湿度传感器、IO 扩展器、I2C ADC、可编程 RGB LED 灯、麦克风、音频功放,SD 卡接口等。

该开发板提供了多个扩展接口方便用户进行二次开发,包括 5 V 与 3.3 V 电源接口、程序下载/UART 接口、I2C 接口、SPI 接口、USB 接口(支持 USB OTG)、TWAI(兼容 CAN 2.0)接口等。

开发板配备了一块 1950 mAh 的单芯锂离子电池,并配有充电 IC 可对电池进行充电。

1. LVGL的Get_started

LVGL官方文档的第三章就是Get started, 官方文档写的很好, 看完这一章基本也就可入门了.

(在此, 不得不吐槽一下, 网上搜索LVGL的中文文档, 我只搜到韦东山的百问网一家, 但写得真不怎么样, 条例不清晰, 重点不突出,

看它远没有看官方英文文档效率高. 我一开始先在百问网上看了大概一个小时, 实在觉得烂看不下去, 就下载了官方英文文档的pdf看,

觉得我在百问网上白白浪费了一个小时, 后悔之极.)

现将官方文档"第三章 Get started中的 3.1.2 Add LVGL into your project" 下节, 列在下面, 我觉得这部分比较重要,

且本文下一节也要用到.

If you would rather try LVGL on your own project follow these steps:

static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf1[DISP_HOR_RES * DISP_VER_RES / 10]; /*Declare a buffer for 1/10 screen size*/
lv_disp_draw_buf_init(&draw_buf, buf1, NULL, MY_DISP_HOR_RES * MY_DISP_VER_SER / 10);  /*Initialize the display buffer.*/
static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
disp_drv.flush_cb = my_disp_flush; /*Set your driver function*/
disp_drv.draw_buf = &draw_buf; /*Assign the buffer to the display*/
disp_drv.hor_res = MY_DISP_HOR_RES; /*Set the horizontal resolution of the display*/
disp_drv.ver_res = MY_DISP_VER_RES; /*Set the vertical resolution of the display*/
lv_disp_drv_register(&disp_drv); /*Finally register the driver*/

void my_disp_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p)
{
int32_t x, y;
/*It's a very slow but simple implementation.
*`set_pixel` needs to be written by you to a set pixel on the screen*/
for(y = area->y1; y <= area->y2; y++) {
for(x = area->x1; x <= area->x2; x++) {
set_pixel(x, y, *color_p);
color_p++;
}
}
lv_disp_flush_ready(disp); /* Indicate you are ready with the flushing*/
}
static lv_indev_drv_t indev_drv; /*Descriptor of a input device driver*/
lv_indev_drv_init(&indev_drv); /*Basic initialization*/
indev_drv.type = LV_INDEV_TYPE_POINTER; /*Touch pad is a pointer-like device*/
indev_drv.read_cb = my_touchpad_read; /*Set your driver function*/
lv_indev_drv_register(&indev_drv); /*Finally register the driver*/

void my_touchpad_read(lv_indev_t * indev, lv_indev_data_t * data)
{
/*`touchpad_is_pressed` and `touchpad_get_xy` needs to be implemented by you*/
if(touchpad_is_pressed()) {
data->state = LV_INDEV_STATE_PRESSED;
touchpad_get_xy(&data->point.x, &data->point.y);
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
}

For a more detailed guide go to the Porting section.

1.1 关于ESP32-S2-HMI开发板上LVGL的初始化

阅读开发板的源代码, 发现其main函数里调用了一个lvgl_init()函数,

这个函数的定义在lvlg_port.c文件中, 在其源码里, 实现了上面所列文档中的大部分步骤:

详细阅读此函数源码, 对于了解LVGL的初始化过程, 还是很有收益的.

2. LVGL屏幕翻转的实现

开发板的例程都是横屏的, 而我想做个竖屏的界面.

那我就需要选择屏幕, 先看看屏幕旋转LVGL的官方文档是怎么说的把:

官方文档的 4.2.3 Rotation 小节专门讲这个, 摘抄如下:

LVGL supports rotation of the display in 90 degree increments. You can select whether you'd like software rotation or hardware rotation.

If you select software rotation (sw_rotate flag set to 1), LVGL will perform the rotation for you. Your driver can and should assume that the screen width and height have not changed. Simply flush pixels to the display as normal. Software rotation requires no additional logic in your flush_cb callback.

There is a noticeable amount of overhead to performing rotation in software, which is why hardware rotation is also available. In this mode, LVGL draws into the buffer as though your screen now has the width and height inverted. You are responsible for rotating the provided pixels yourself.

The default rotation of your display when it is initialized can be set using the rotated flag. The available options are LV_DISP_ROT_NONE, LV_DISP_ROT_90, LV_DISP_ROT_180, or LV_DISP_ROT_270. The rotation values are relative to how you would rotate the physical display in the clockwise direction. Thus, LV_DISP_ROT_90 means you rotate the hardware 90 degrees clockwise, and the display rotates 90 degrees counterclockwise to compensate.

Display rotation can also be changed at runtime using the lv_disp_set_rotation(disp, rot) API.

总结一下:

2.1 代码实现

2.1.1 初始化时 旋转屏幕

实现屏幕旋转, 关键是将sw_rotate标志为1, 那sw_rotate在哪里呢?

sw_rotate实际上是lv_disp_drv_t结构体中的一个field, 此结构体的定义在…/lv_hal/lv_hal_disp.h文件中,

节选如下:

/**
* Display Driver structure to be registered by HAL
*/
typedef struct _disp_drv_t {

lv_coord_t hor_res; /**< Horizontal resolution. */
lv_coord_t ver_res; /**< Vertical resolution. */

/** Pointer to a buffer initialized with `lv_disp_buf_init()`.
* LVGL will use this buffer(s) to draw the screens contents */
lv_disp_buf_t * buffer;

#if LV_ANTIALIAS
uint32_t antialiasing : 1; /**< 1: antialiasing is enabled on this display. */
#endif
uint32_t rotated : 2;
uint32_t sw_rotate : 1; /**< 1: use software rotation (slower) */
......
...
.
} lv_disp_drv_t;

细心的读者可能会发现lv_disp_drv_t这个名字, 本文前面出现过,

在前面讲述官方文档"第三章 Get started中的 3.1.2 Add LVGL into your project" 一节中,

这一步的实例代码里:

static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
disp_drv.flush_cb = my_disp_flush; /*Set your driver function*/
disp_drv.draw_buf = &draw_buf; /*Assign the buffer to the display*/
disp_drv.hor_res = MY_DISP_HOR_RES; /*Set the horizontal resolution of the display*/
disp_drv.ver_res = MY_DISP_VER_RES; /*Set the vertical resolution of the display*/
lv_disp_drv_register(&disp_drv); /*Finally register the driver*/

已经用到过lv_disp_drv_t, 定义了一个lv_disp_drv_t变量, 并初始化了其中的一些field值.

所以我们要想在初始化设定sw_rotate的值, 也要在这里.

上面 1.1节已经提到, 开发板的相关初始化代码在lvgl_init()函数里, 我们在此函数里修改即可, 代码如下:

...
/*Create a display*/
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.buffer = &disp_buf;
disp_drv.flush_cb = lvgl_flush_cb;
disp_drv.sw_rotate = 1;   // add for rotation
disp_drv.rotated = LV_DISP_ROT_90;   // add for rotation
lv_disp_drv_register(&disp_drv);
...

如上, 增加2行, 就成功将屏幕旋转了90度.

2.1.2 运行时 旋转屏幕

根据官方文档的这一句话:

Display rotation can also be changed at runtime using the lv_disp_set_rotation(disp, rot) API.

我们实现了代码如下:

static void btn_rotate_cb(lv_obj_t *obj, lv_event_t event)
{
if (LV_EVENT_CLICKED == event) {
lv_disp_set_rotation(NULL, LV_DISP_ROT_NONE);
}
}

我在屏幕上添加了一个按钮, 上面函数是此按钮的事件响应函数, 此按钮一旦被点击, 就将屏幕的旋转归0.

至此, 关于LVGL的屏幕旋转功能摸得差不多了, 对LVGL的学习又更进了一步.


上一篇: 康托尔、哥德尔、图灵——永恒的金色对角线

下一篇: matlab卷积函数——conv2