LVGL学习 stm32f407-board-lvgl v8,20道高频面试题(含答案)

208 阅读9分钟

文末

篇幅有限没有列举更多的前端面试题,小编把整理的前端大厂面试题PDF分享出来,一共有269页

开源分享:docs.qq.com/doc/DSmRnRG… 在这里插入图片描述
LVGL 是一款具有丰富的部件,具备高级图形特性,支持多种输入设备, 多国语言和独立于硬件之外等免费的开源图形库。接下来我们来看一下 LVGL 图形用户库的主要特点:

  1. 强大的构建块:按钮、图表、列表、滑块、图像等部件。
  2. 具有高级图形属性:具有动画、抗锯齿、不透明度、平滑滚动的高级图形。
  3. 支持各种输入设备:如触摸、鼠标、键盘、编码器。
  4. 支持多语言:UTF-8 编码。
  5. 支持多显示器:它可以同时使用多个 TFT 或者单色显示器。
  6. 支持多种样式属性:它具有类 CSS 样式的完全可定制的图形元素。
  7. 独立于硬件之外:它与任何微控制器或显示器一起使用。
  8. 可扩展性:它能够以小内存运行(最低 64 kB 闪存,16 kB RAM 的 MCU)。
  9. 支持操作系统、外部存储器和 GPU(不是必需的)。
  10. 具有高级图形效果:可进行单帧缓冲区操作。
  11. 纯 C 编写: C 语言编写以获得最大的兼容性。

移植工作

  1. 获取LVGL源码
    从 LVGL 官方 GitHub 网址(github.com/lvgl/lvgl/)…
    在这里插入图片描述
  2. 把文件中的 lv_conf_template.h 文件名修改成 lv_conf.h 文件名
    在这里插入图片描述
  3. .打开 lv_conf.h 文件,修改条件编译指令,如下源码所示。
    在这里插入图片描述
  4. 打开 examples 文件夹,除了 porting 文件夹外,用户可以删除其他文件和文件夹在这里插入图片描述
    把porting文件夹重新命名为lvgl_driver,并修改文件名称。
    在这里插入图片描述
    在这里插入图片描述
  5. 准备一个裸机工程,其中包括lcd,touch驱动,能正常使用,建立LVGL文件夹。
    在这里插入图片描述
  6. 在工程中,创建lvgl/src,lvgl/config/,lvgl/port,lvgl/app
    在这里插入图片描述
  7. 添加lvgl源码文件
    lvgl/config中主要是lvgl.h lv_conf.h配置文件
    在这里插入图片描述
    lvgl/port中主要是lv_port_disp.c,lv_port_indev.c文件,显示与输入接口文件
    在这里插入图片描述
    lvgl/src中主要是lvgl组件的源代码文件,比较重要,把src文件夹下面的所有的C文件全部添加进去,包括子文件夹下面的,添加比较繁琐。(也可以不用添加全部的,参考正点原子的教程,在这里,我是添加了所有的)
    在这里插入图片描述lvgl/app中主要是lvgl案例演示源代码
    在这里插入图片描述
  8. 添加文件路径(参考正点原子教程,这里有的教程会添加非常的多的路径,但是正点原子的教程没有很多路径,我也是参考的,建议参考正点原子的文件夹架构)
    如果使用我的文件结果这样子是可以的编译通过的,不过我在后面应该是修改了一下头文件包含的位置,可能与lvgl源码中的写法不一样,仅供参考。
    在这里插入图片描述
    工程结构如下
    在这里插入图片描述
    在这里插入图片描述
  9. 添加部分相关文件
    lvgl 的 1ms 心跳 通过调用定时器3
//==================================================================================================
// 实现功能:定时器3中断服务函数
// 函数说明: TIM3\_IRQHandler
// 函数备注: 
//--------------------------------------------------------------------------------------------------
// | - | - | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 
//==================================================================================================

void TIM3\_IRQHandler(void)
{
	if(TIM\_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断
	{
        lv\_tick\_inc(1);//lvgl的1ms中断
	}
	TIM\_ClearITPendingBit(TIM3,TIM_IT_Update);  //清除中断标志位
}

修改disp代码

/\*\*
 \* @file lv\_port\_disp\_templ.c
 \*
 \*/

/\*Copy this file as "lv\_port\_disp.c" and set this value to "1" to enable content\*/
#if 1

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \* INCLUDES
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
#include "lv\_port\_disp.h"
#include <stdbool.h>
#include "lcd.h"
/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \* DEFINES
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
//#ifndef MY\_DISP\_HOR\_RES
// #warning Please define or replace the macro MY\_DISP\_HOR\_RES with the actual screen width, default value 320 is used for now.
// #define MY\_DISP\_HOR\_RES 320
//#endif

//#ifndef MY\_DISP\_VER\_RES
// #warning Please define or replace the macro MY\_DISP\_HOR\_RES with the actual screen height, default value 240 is used for now.
// #define MY\_DISP\_VER\_RES 240
//#endif

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \* TYPEDEFS
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \* STATIC PROTOTYPES
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
static void disp\_init(void);

static void disp\_flush(lv\_disp\_drv\_t \* disp_drv, const lv\_area\_t \* area, lv\_color\_t \* color_p);
//static void gpu\_fill(lv\_disp\_drv\_t \* disp\_drv, lv\_color\_t \* dest\_buf, lv\_coord\_t dest\_width,
// const lv\_area\_t \* fill\_area, lv\_color\_t color);

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \* STATIC VARIABLES
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \* MACROS
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \* GLOBAL FUNCTIONS
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/

void lv\_port\_disp\_init(void)
{
    /\*-------------------------
 \* Initialize your display
 \* -----------------------\*/
// disp\_init();

    /\*-----------------------------
 \* Create a buffer for drawing
 \*----------------------------\*/

    /\*\*
 \* LVGL requires a buffer where it internally draws the widgets.
 \* Later this buffer will passed to your display driver's `flush\_cb` to copy its content to your display.
 \* The buffer has to be greater than 1 display row
 \*
 \* There are 3 buffering configurations:
 \* 1. Create ONE buffer:
 \* LVGL will draw the display's content here and writes it to your display
 \*
 \* 2. Create TWO buffer:
 \* LVGL will draw the display's content to a buffer and writes it your display.
 \* You should use DMA to write the buffer's content to the display.
 \* It will enable LVGL to draw the next part of the screen to the other buffer while
 \* the data is being sent form the first buffer. It makes rendering and flushing parallel.
 \*
 \* 3. Double buffering
 \* Set 2 screens sized buffers and set disp\_drv.full\_refresh = 1.
 \* This way LVGL will always provide the whole rendered screen in `flush\_cb`
 \* and you only need to change the frame buffer's address.
 \*/

    /\* Example for 1) \*/
    static lv\_disp\_draw\_buf\_t draw_buf_dsc_1;
    static lv\_color\_t buf_1[LV_HOR_RES_MAX \* 10];                          /\*A buffer for 10 rows\*/
    lv\_disp\_draw\_buf\_init(&draw_buf_dsc_1, buf_1, NULL, LV_HOR_RES_MAX \* 10);   /\*Initialize the display buffer\*/

    /\*-----------------------------------
 \* Register the display in LVGL
 \*----------------------------------\*/

    static lv\_disp\_drv\_t disp_drv;                         /\*Descriptor of a display driver\*/
    lv\_disp\_drv\_init(&disp_drv);                    /\*Basic initialization\*/

    /\*Set up the functions to access to your display\*/

    /\*Set the resolution of the display\*/
    disp_drv.hor_res = lcddev.width;
    disp_drv.ver_res = lcddev.height;

    /\*Used to copy the buffer's content to the display\*/
    disp_drv.flush_cb = disp_flush;

    /\*Set a display buffer\*/
    disp_drv.draw_buf = &draw_buf_dsc_1;

    /\*Required for Example 3)\*/
    //disp\_drv.full\_refresh = 1

    /\* Fill a memory array with a color if you have GPU.
 \* Note that, in lv\_conf.h you can enable GPUs that has built-in support in LVGL.
 \* But if you have a different GPU you can use with this callback.\*/
    //disp\_drv.gpu\_fill\_cb = gpu\_fill;

    /\*Finally register the driver\*/
    lv\_disp\_drv\_register(&disp_drv);
}

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \* STATIC FUNCTIONS
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/

/\*Initialize your display and the required peripherals.\*/
//static void disp\_init(void)
//{
// /\*You code here\*/
//}

volatile bool disp_flush_enabled = true;

/\* Enable updating the screen (the flushing process) when disp\_flush() is called by LVGL
 \*/
void disp\_enable\_update(void)
{
    disp_flush_enabled = true;
}

/\* Disable updating the screen (the flushing process) when disp\_flush() is called by LVGL
 \*/
void disp\_disable\_update(void)
{
    disp_flush_enabled = false;
}

/\*Flush the content of the internal buffer the specific area on the display
 \*You can use DMA or any hardware acceleration to do this operation in the background but
 \*'lv\_disp\_flush\_ready()' has to be called when finished.\*/
static void disp\_flush(lv\_disp\_drv\_t \* disp_drv, const lv\_area\_t \* area, lv\_color\_t \* color_p)
{

    LCD\_Color\_Fill(area->x1,area->y1,area->x2,area->y2,(u16\*)color_p);
    lv\_disp\_flush\_ready(disp_drv);
}

#else /\*Enable this file at the top\*/

/\*This dummy typedef exists purely to silence -Wpedantic.\*/
typedef int keep_pedantic_happy;
#endif

基本上只要修改disp_flush函数,不同的屏幕显示接口移植

修改indev代码,配置好触摸屏驱动

/\*\*
 \* @file lv\_port\_indev\_templ.c
 \*
 \*/

/\*Copy this file as "lv\_port\_indev.c" and set this value to "1" to enable content\*/
#if 1

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \* INCLUDES
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
#include "lv\_port\_indev.h"
#include "../lvgl.h"
#include "touch.h"
/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \* DEFINES
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \* TYPEDEFS
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \* STATIC PROTOTYPES
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/

static void touchpad\_init(void);
static void touchpad\_read(lv\_indev\_drv\_t \* indev_drv, lv\_indev\_data\_t \* data);
static bool touchpad\_is\_pressed(void);
static void touchpad\_get\_xy(lv\_coord\_t \* x, lv\_coord\_t \* y);

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \* STATIC VARIABLES
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
lv\_indev\_t \* indev_touchpad;

static int32\_t encoder_diff;
static lv\_indev\_state\_t encoder_state;

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \* MACROS
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \* GLOBAL FUNCTIONS
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/

void lv\_port\_indev\_init(void)
{
    static lv\_indev\_drv\_t indev_drv;

    /\*------------------
 \* Touchpad
 \* -----------------\*/

    /\*Initialize your touchpad if you have\*/
    touchpad\_init();

    /\*Register a touchpad input device\*/
    lv\_indev\_drv\_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = touchpad_read;
    indev_touchpad = lv\_indev\_drv\_register(&indev_drv);

/\*------------------
 \* Touchpad
 \* -----------------\*/

/\*Initialize your touchpad\*/
static void touchpad\_init(void)
{
    /\*Your code comes here\*/
    tp_dev.init();
    if (0 == (tp_dev.touchtype & 0x80))
    {
        TP\_Adjust();
        TP\_Save\_Adjdata();
    }
}

/\*Will be called by the library to read the touchpad\*/
static void touchpad\_read(lv\_indev\_drv\_t \* indev_drv, lv\_indev\_data\_t \* data)
{
    static lv\_coord\_t last_x = 0;
    static lv\_coord\_t last_y = 0;

    /\*Save the pressed coordinates and the state\*/
    if(touchpad\_is\_pressed()) 
   {
        touchpad\_get\_xy(&last_x, &last_y);
        data->state = LV_INDEV_STATE_PR;
    }
    else {
        data->state = LV_INDEV_STATE_REL;
    }

    /\*Set the last pressed coordinates\*/
    data->point.x = last_x;
    data->point.y = last_y;
}

/\*Return true is the touchpad is pressed\*/
static bool touchpad\_is\_pressed(void)
{
    
    if(tp_dev.sta & TP_PRES_DOWN)
      return true;
    return false;

}
#### 总结一下



面试前要精心做好准备,简历上写的知识点和原理都需要准备好,项目上多想想难点和亮点,这是面试时能和别人不一样的地方。

还有就是表现出自己的谦虚好学,以及对于未来持续进阶的规划,企业招人更偏爱稳定的人。

**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://docs.qq.com/doc/DSmRnRGxvUkxTREhO)**

万事开头难,但是程序员这一条路坚持几年后发展空间还是非常大的,一切重在坚持。



为了帮助大家更好更高效的准备面试,特别整理了《前端工程师面试手册》电子稿文件。

![](https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/b5f3f50829c34988bccb45188ded3a27~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3MzM5MTQ5MjgwNjA=:q75.awebp?rk3s=f64ab15b&x-expires=1771314651&x-signature=2VFjuVVAFQHbSfZ77j5f2J2QbVg%3D)



![](https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/bd69fde8bdb249589db57e08e25e3719~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3MzM5MTQ5MjgwNjA=:q75.awebp?rk3s=f64ab15b&x-expires=1771314651&x-signature=11z9c45d3rytlHiMgQI8L8u8Ww8%3D)



**前端面试题汇总**



![](https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/c5d94aa7a4844f82bfb3aeb58676ab6c~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3MzM5MTQ5MjgwNjA=:q75.awebp?rk3s=f64ab15b&x-expires=1771314651&x-signature=dPXgtxODkEjrDFLOai5d033Vbpo%3D)

**JavaScript**



![](https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/b5e8a64c78574008b74fa9eb266e7b52~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3MzM5MTQ5MjgwNjA=:q75.awebp?rk3s=f64ab15b&x-expires=1771314651&x-signature=88wvwiyiblCDq%2F%2FGmdgvFgpJujE%3D)



**性能**

![](https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/f7747523022b4b6b893b0ddeff8036bd~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3MzM5MTQ5MjgwNjA=:q75.awebp?rk3s=f64ab15b&x-expires=1771314651&x-signature=78WJ4tj1R6cDFinsuoil%2FESWt0o%3D)



**linux**



![](https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/484967846e334b00b93cb2481e740a20~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3MzM5MTQ5MjgwNjA=:q75.awebp?rk3s=f64ab15b&x-expires=1771314651&x-signature=ngWnmYkMZw4Wt%2BMVjSSEO%2BWjaak%3D)



**前端资料汇总**

![](https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/6a1219ba621c4a2ebdf5611d65c080ee~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3MzM5MTQ5MjgwNjA=:q75.awebp?rk3s=f64ab15b&x-expires=1771314651&x-signature=Fv5G4%2B34YQ3ZGiPDXf%2FGjBNQhPU%3D)

前端工程师岗位缺口一直很大,符合岗位要求的人越来越少,所以学习前端的小伙伴要注意了,一定要把技能学到扎实,做有含金量的项目,这样在找工作的时候无论遇到什么情况,问题都不会大。