绘图仪(写字机)——移植LVGL(9)

绘图仪(写字机)——LVGL v8.2 迁移实战

本文总结了将 LVGL v8.2 移植到绘图仪(写字机)项目的全过程,包括源码裁剪、工程路径配置、lv_conf.h 开关修改、显示驱动端口配置和缓存方案说明。文章目录如下:

  • 一、准备 LVGL 源码文件
  • 二、配置工程 include 路径
  • 三、修改 lv_conf.h
  • 四、修改 lv_port_disp_template (显示端口)
  • 五、显示驱动初始化示例

一、准备 LVGL 源码文件

  1. 获取 LVGL v8.2 源码(推荐官方 GitHub Release)。
  2. 在本地工程创建目录(例如:LVGL)。
  3. 裁剪无关模块,只保留核心(corehaldrawwidgetsfontmisc 相关)。
  4. 复制到 LVGL 目录后,确保目录结构清晰、无多层嵌套。

参考截图:

VGL源码

LVGL源码修改

LVGL文件层次结构


二、配置工程 include 路径

以 Eclipse/Keil/VSTudio 等 IDE 为例:

  • 右键项目 → Properties → C/C++ General → Paths and Symbols。
  • LVGL 源码路径加入编译器 Include 路径(例如 ..\LVGL\src)。

参考截图:添加LVGL文件路径


三、修改 lv_conf.h

为了启用 LVGL 配置选项和内核特性,需要把 lv_conf.h 中的开关从 0 改为 1

#if 1 /*Set it to "1" to enable content*/

这个开关打开之后,可继续按项目需求分别启用 LV_USE_LOGLV_USE_GPULV_USE_FS 等功能。


四、修改 lv_port_disp_template.c/h

lv_port_disp_template.clv_port_disp_template.h 中相关端口开关:

#if 1

并在 lv_port_disp_init 中选择适合本项目的缓存模式。

缓冲方案说明

  • 1)单缓冲(Simple)
    • lvgl 绘制到一个缓存,flush 后再开始下一次绘制。
    • 代码简单、内存低,适合初期功能验证。
  • 2)双缓冲(双 buffer)
    • lvgl 绘制到 buffer A ,flush A 时同时绘制 B。
    • 建议配合 DMA,渲染与传输并行,提高帧率。
  • 3)全屏双缓冲(full_refresh=1)
    • 两块全屏缓冲区,直接切换地址,最低闪烁但内存占用最高。

选择单缓冲示例

  • 使用 draw_buf_dsc_1
  • 缓冲大小 320 * 10(10 行)。

五、显示驱动初始化示例(推荐)

void lv_port_disp_init(void) {
   /* 初始化硬件显示控制器 */
   disp_init();

   /* 创建绘制缓存 */
   static lv_disp_draw_buf_t draw_buf_dsc_1;
   static lv_color_t buf_1[320 * 10];
   lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, 320 * 10);

   /* 注册显示驱动 */
   static lv_disp_drv_t disp_drv;
   lv_disp_drv_init(&disp_drv);

   disp_drv.hor_res = 320;
   disp_drv.ver_res = 240;
   disp_drv.flush_cb = disp_flush;
   disp_drv.draw_buf = &draw_buf_dsc_1;
   // disp_drv.full_refresh = 1; // 需要全屏双缓冲时启用
   lv_disp_drv_register(&disp_drv);
}

可选调优配置

  • disp_drv.hor_resdisp_drv.ver_res 设为实际屏幕分辨率。
  • disp_drv.gpu_fill_cb 可配置硬件加速填充函数(若有)。
  • lv_disp_draw_buf_initbuf_size 可根据内存和性能做动态调整(一般不小于 1 行)。

六、常见问题与排查建议

  • 若编译出错,检查 include 路径与宏 LV_CONF_INCLUDE_SIMPLE 是否正确。
  • 若界面异常,仅显示部分/闪烁,先确认 flush_cb 实现与 buffer 匹配。
  • 调试阶段开启 LV_USE_LOGLV_USE_PERF_MONITOR 观察帧率与内存。

七、结语

本文已完成从源码裁剪到显示驱动注册的关键步骤。 //disp_drv.gpu_fill_cb = gpu_fill;

/*Finally register the driver*/
lv_disp_drv_register(&disp_drv);

}


修改后

```C
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[320 * 10];                          /*A buffer for 10 rows*/
   lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, 320 * 10);   /*Initialize the display buffer*/

   /* Example for 2) */
//   static lv_disp_draw_buf_t draw_buf_dsc_2;
//   static lv_color_t buf_2_1[MY_DISP_HOR_RES * 10];                       /*A buffer for 10 rows*/
//   static lv_color_t buf_2_2[MY_DISP_HOR_RES * 10];                       /*An other buffer for 10 rows*/
//   lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 10);   /*Initialize the display buffer*/

   /* Example for 3) also set disp_drv.full_refresh = 1 below*/
//   static lv_disp_draw_buf_t draw_buf_dsc_3;
//   static lv_color_t buf_3_1[MY_DISP_HOR_RES * MY_DISP_VER_RES];           /*A screen sized buffer*/
//   static lv_color_t buf_3_2[MY_DISP_HOR_RES * MY_DISP_VER_RES];           /*Another screen sized buffer*/
//   lv_disp_draw_buf_init(&draw_buf_dsc_3, buf_3_1, buf_3_2, MY_DISP_VER_RES * LV_VER_RES_MAX);   /*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 = 320; //使用的屏幕尺寸(分辨率)
   disp_drv.ver_res = 240;

   /*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);
}

放入自己的屏幕初始化配置

/*Initialize your display and the required peripherals.*/
static void disp_init(void)
{
   /*You code here*/
ILI9341_LCD_Init();
}

放入自己的屏幕打点函数

static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
   /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/

ILI9341_Draw_Rec_LVGL(area->x1, area->y1, area->x2, area->y2, (uint16_t *)color_p);
   /*IMPORTANT!!!
    *Inform the graphics library that you are ready with the flushing*/
   lv_disp_flush_ready(disp_drv);
}

四、修改lv_port_indev_template.c/h

点击lv_port_indev_template.c/h文件,将

#if 0

修改为

#if 1

对内容进行裁剪,仅保留触摸部分,修改后的代码如下:

/**
* @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_template.h"
#include "../../lvgl.h"
#include "XPT2046_touch.h"

/*********************
*     DEFINES
*********************/

/**********************
*     TYPEDEFS
**********************/


extern strType_XPT2046_TouchPara strXPT2046_TouchPara;

/**********************
* 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;

/**********************
*     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);


}

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

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

/*Initialize your touchpad*/
static void touchpad_init(void)
{
   /*Your code comes here*/
XPT2046_Init();
}

/*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)
{
   /*Your code comes here*/
if(XPT2046_TouchDetect() == TOUCH_PRESSED)
{
return true;
}
else
{
return false;
}

}

/*Get the x and y coordinates if the touchpad is pressed*/
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
{
   /*Your code comes here*/


  (*x) = XPT2046_GetPoint_X();
  (*y) = XPT2046_GetPoint_Y();
}


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

/*This dummy typedef exists purely to silence -Wpedantic.*/
typedef int keep_pedantic_happy;
#endif
文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇