LVGL[display]

第一部分:文件结构概览

LVGL Display模块由三个核心文件组成:

  • lv_display_private.h - 内部数据结构定义
  • lv_display.h - 公共接口声明
  • lv_display.c - 函数实现

第二部分:lv_display_private.h - 核心数据结构

cpp 复制代码
struct _lv_display_t {
    /*---------------------
     * 分辨率相关参数
     *--------------------*/
    int32_t hor_res;                    /**< 水平分辨率(像素)*/
    int32_t ver_res;                    /**< 垂直分辨率(像素)*/
    int32_t physical_hor_res;           /**< 完整/物理显示的水平分辨率,-1表示全屏模式 */
    int32_t physical_ver_res;           /**< 完整/物理显示的垂直分辨率,-1表示全屏模式 */
    int32_t offset_x;                   /**< 相对于完整/物理显示的水平偏移量,0表示全屏模式 */
    int32_t offset_y;                   /**< 相对于完整/物理显示的垂直偏移量,0表示全屏模式 */
    uint32_t dpi;                       /**< 显示器的DPI(每英寸点数),默认值为LV_DPI_DEF */

    /*---------------------
     * 缓冲区管理
     *--------------------*/
    lv_draw_buf_t * buf_1;              /**< 缓冲区1 */
    lv_draw_buf_t * buf_2;              /**< 缓冲区2 */
    lv_draw_buf_t * buf_act;            /**< 内部使用,当前活动缓冲区 */
    
    lv_display_flush_cb_t flush_cb;     /**< 必需:将内部缓冲区写入显示器,完成后必须调用lv_display_flush_ready() */
    lv_display_flush_wait_cb_t flush_wait_cb; /**< 用于等待刷新完成,如果不设置则使用flushing标志 */
    
    volatile int flushing;              /**< 1:刷新正在进行中(不能是位域,避免IRQ清除时的读写修改问题) */
    volatile int flushing_last;         /**< 1:这是要刷新的最后一块(不能是位域,避免IRQ清除时的读写修改问题) */
    volatile uint32_t last_area : 1;    /**< 1:正在渲染最后区域 */
    volatile uint32_t last_part : 1;    /**< 1:正在渲染当前区域的最后部分 */
    
    lv_display_render_mode_t render_mode;   /**< 渲染模式 */
    uint32_t antialiasing : 1;          /**< 1:在此显示器上启用抗锯齿 */
    uint32_t tile_cnt : 8;              /**< 将显示缓冲区划分为这些数量的平铺 */
    uint32_t rendering_in_progress : 1; /**< 1:当前屏幕渲染正在进行中 */
    lv_color_format_t color_format;     /**< 颜色格式 */

    /*---------------------
     * 无效区域管理(核心优化机制)
     *--------------------*/
    lv_area_t inv_areas[LV_INV_BUF_SIZE];       /**< 无效化(标记为重绘)的区域数组 */
    uint8_t inv_area_joined[LV_INV_BUF_SIZE];   /**< 无效区域合并状态数组 */
    uint32_t inv_p;                             /**< 无效区域指针 */
    int32_t inv_en_cnt;                         /**< 无效使能计数器 */
    lv_ll_t sync_areas;                         /**< 双缓冲同步区域(上次刷新期间重绘) */
    
    lv_draw_buf_t _static_buf1;     /**< 当用户传入原始缓冲区作为显示绘制缓冲区时使用 */
    lv_draw_buf_t _static_buf2;     /**< 第二个静态缓冲区 */

    /*---------------------
     * 层系统管理
     *--------------------*/
    lv_layer_t * layer_head;                    /**< 层头指针 */
    void (*layer_init)(lv_display_t * disp, lv_layer_t * layer);     /**< 层初始化函数指针 */
    void (*layer_deinit)(lv_display_t * disp, lv_layer_t * layer);  /**< 层反初始化函数指针 */

    /*---------------------
     * 屏幕管理
     *--------------------*/
    lv_obj_t ** screens;        /**< 屏幕对象数组 */
    lv_obj_t * sys_layer;       /**< 系统层(@see lv_display_get_layer_sys)*/
    lv_obj_t * top_layer;       /**< 顶层(@see lv_display_get_layer_top)*/
    lv_obj_t * act_scr;         /**< 当前在此显示器上活动的屏幕 */
    lv_obj_t * bottom_layer;    /**< 底层(@see lv_display_get_layer_bottom)*/
    lv_obj_t * prev_scr;        /**< 前一个屏幕,用于屏幕动画 */
    lv_obj_t * scr_to_load;     /**< 在lv_screen_load_anim中准备加载的屏幕 */
    uint32_t screen_cnt;        /**< 屏幕数量 */
    uint8_t draw_prev_over_act : 1; /**< 1:在活动屏幕上绘制前一个屏幕 */
    uint8_t del_prev : 1;       /**< 1:屏幕加载动画完成后自动删除前一个屏幕 */

    /*---------------------
     * 其他功能
     *--------------------*/
    void * driver_data;         /**< 自定义驱动数据 */
    void * user_data;           /**< 自定义用户数据 */
    lv_event_list_t event_list; /**< 事件列表 */
    uint32_t rotation : 3;      /**< lv_display_rotation_t的元素(旋转角度)*/
    lv_theme_t * theme;         /**< 分配给屏幕的主题 */
    lv_timer_t * refr_timer;    /**< 定期检查脏区域并刷新它们的定时器 */
    uint32_t last_activity_time;/**< 此显示器上最后活动的时间 */
    lv_area_t refreshed_area;   /**< 正在刷新的区域 */

#if LV_USE_PERF_MONITOR
    /* 性能监控相关(可选)*/
    lv_obj_t * perf_label;
    lv_sysmon_backend_data_t perf_sysmon_backend;
    lv_sysmon_perf_info_t perf_sysmon_info;
#endif

#if LV_USE_MEM_MONITOR
    /* 内存监控相关(可选)*/
    lv_obj_t * mem_label;
#endif
};

第三部分:lv_display.h - 公共接口定义

1. 显示旋转枚举:

cpp 复制代码
typedef enum {
    LV_DISPLAY_ROTATION_0 = 0,     /**< 不旋转(0度)*/
    LV_DISPLAY_ROTATION_90,        /**< 顺时针旋转90度 */
    LV_DISPLAY_ROTATION_180,       /**< 顺时针旋转180度 */
    LV_DISPLAY_ROTATION_270        /**< 顺时针旋转270度 */
} lv_display_rotation_t;

2. 渲染模式枚举:

cpp 复制代码
typedef enum {
    /**
     * 使用缓冲区渲染屏幕的较小部分。
     * 这样缓冲区可以比显示器小以节省RAM。建议至少使用1/10屏幕大小的缓冲区。
     */
    LV_DISPLAY_RENDER_MODE_PARTIAL,

    /**
     * 缓冲区必须是屏幕大小,LVGL将在缓冲区的正确位置渲染。
     * 这样缓冲区始终包含整个图像。只有更改的区域会被更新。
     * 使用2个缓冲区时,缓冲区内容会自动保持同步,在flush_cb中只需要地址更改。
     */
    LV_DISPLAY_RENDER_MODE_DIRECT,

    /**
     * 即使只改变了一个像素也始终重绘整个屏幕。
     * 使用2个缓冲区时,在flush_cb中只需要地址更改。
     */
    LV_DISPLAY_RENDER_MODE_FULL,
} lv_display_render_mode_t;

3. 屏幕加载动画枚举:

cpp 复制代码
typedef enum {
    LV_SCR_LOAD_ANIM_NONE,              /**< 无动画 */
    LV_SCR_LOAD_ANIM_OVER_LEFT,         /**< 从左侧滑入 */
    LV_SCR_LOAD_ANIM_OVER_RIGHT,        /**< 从右侧滑入 */
    LV_SCR_LOAD_ANIM_OVER_TOP,          /**< 从顶部滑入 */
    LV_SCR_LOAD_ANIM_OVER_BOTTOM,       /**< 从底部滑入 */
    LV_SCR_LOAD_ANIM_MOVE_LEFT,         /**< 向左移动 */
    LV_SCR_LOAD_ANIM_MOVE_RIGHT,        /**< 向右移动 */
    LV_SCR_LOAD_ANIM_MOVE_TOP,          /**< 向上移动 */
    LV_SCR_LOAD_ANIM_MOVE_BOTTOM,       /**< 向下移动 */
    LV_SCR_LOAD_ANIM_FADE_IN,           /**< 淡入 */
    LV_SCR_LOAD_ANIM_FADE_OUT,          /**< 淡出 */
    LV_SCR_LOAD_ANIM_OUT_LEFT,          /**< 向左滑出 */
    LV_SCR_LOAD_ANIM_OUT_RIGHT,         /**< 向右滑出 */
    LV_SCR_LOAD_ANIM_OUT_TOP,           /**< 向上滑出 */
    LV_SCR_LOAD_ANIM_OUT_BOTTOM,        /**< 向下滑出 */
} lv_screen_load_anim_t;

核心函数接口分类:

1. 显示设备管理:
cpp 复制代码
/**
 * 创建新的显示设备
 * @param hor_res   水平分辨率(像素)
 * @param ver_res   垂直分辨率(像素)
 * @return          显示对象指针,出错时返回NULL
 */
lv_display_t * lv_display_create(int32_t hor_res, int32_t ver_res);

/**
 * 删除显示设备
 * @param disp      显示指针
 */
void lv_display_delete(lv_display_t * disp);

/**
 * 设置默认显示设备,新屏幕将默认创建在此显示设备上
 * @param disp      显示指针
 */
void lv_display_set_default(lv_display_t * disp);

/**
 * 获取默认显示设备
 * @return          默认显示指针
 */
lv_display_t * lv_display_get_default(void);
2. 分辨率管理:
cpp 复制代码
/**
 * 设置显示分辨率,会发送LV_EVENT_RESOLUTION_CHANGED事件
 * @param disp      显示指针
 * @param hor_res   新的水平分辨率
 * @param ver_res   新的垂直分辨率
 */
void lv_display_set_resolution(lv_display_t * disp, int32_t hor_res, int32_t ver_res);

/**
 * 设置显示旋转角度,LVGL会自动交换水平和垂直分辨率
 * @param disp      显示指针(NULL使用默认显示)
 * @param rotation  LV_DISPLAY_ROTATION_0/90/180/270
 */
void lv_display_set_rotation(lv_display_t * disp, lv_display_rotation_t rotation);

/**
 * 设置DPI(每英寸点数)
 * @param disp      显示指针
 * @param dpi       新的DPI
 */
void lv_display_set_dpi(lv_display_t * disp, int32_t dpi);
3. 缓冲区管理:
cpp 复制代码
/**
 * 设置显示缓冲区
 * @param disp          显示指针
 * @param buf1          第一个缓冲区
 * @param buf2          第二个缓冲区(NULL表示单缓冲)
 * @param buf_size      缓冲区大小(像素数)
 * @param color_format  颜色格式
 */
void lv_display_set_buffers(lv_display_t * disp, void * buf1, void * buf2, 
                           uint32_t buf_size, lv_color_format_t color_format);

/**
 * 设置刷新回调函数
 * @param disp      显示指针
 * @param flush_cb  刷新回调函数
 */
void lv_display_set_flush_cb(lv_display_t * disp, lv_display_flush_cb_t flush_cb);
4. 屏幕管理:
cpp 复制代码
/**
 * 在默认显示设备上加载屏幕
 * @param scr       屏幕指针
 */
void lv_screen_load(struct _lv_obj_t * scr);

/**
 * 带动画切换屏幕
 * @param scr       新屏幕指针
 * @param anim_type 动画类型(lv_screen_load_anim_t)
 * @param time      动画时间
 * @param delay     延迟时间
 * @param auto_del  true:自动删除旧屏幕
 */
void lv_screen_load_anim(lv_obj_t * scr, lv_screen_load_anim_t anim_type, 
                        uint32_t time, uint32_t delay, bool auto_del);

/**
 * 获取默认显示设备的活动屏幕
 * @return          活动屏幕指针
 */
lv_obj_t * lv_screen_active(void);

第四部分:lv_display.c - 核心函数实现

核心函数实现详解

1. lv_display_create - 显示设备创建函数(最关键)

函数原型:

cpp 复制代码
lv_display_t * lv_display_create(int32_t hor_res, int32_t ver_res)
实现原理详解:
cpp 复制代码
lv_display_t * lv_display_create(int32_t hor_res, int32_t ver_res)
{
    // 1. 分配显示设备内存
    lv_display_t * disp = lv_ll_ins_head(disp_ll_p);
    LV_ASSERT_MALLOC(disp);
    if(!disp) return NULL;

    // 2. 清零内存,确保所有成员初始值为0
    lv_memzero(disp, sizeof(lv_display_t));

    // 3. 设置基本分辨率参数
    disp->hor_res          = hor_res;           // 水平分辨率
    disp->ver_res          = ver_res;           // 垂直分辨率
    disp->physical_hor_res = -1;                // 物理分辨率设为-1(全屏模式)
    disp->physical_ver_res = -1;
    disp->offset_x         = 0;                   // 偏移量设为0
    disp->offset_y         = 0;
    disp->antialiasing     = LV_COLOR_DEPTH > 8 ? 1 : 0;  // 根据颜色深度设置抗锯齿
    disp->dpi              = LV_DPI_DEF;        // 默认DPI
    disp->color_format     = LV_COLOR_FORMAT_NATIVE;    // 原生颜色格式

    // 4. 设置渲染分块数量(用于多线程渲染)
#if defined(LV_DRAW_SW_DRAW_UNIT_CNT) && (LV_DRAW_SW_DRAW_UNIT_CNT != 0)
    disp->tile_cnt = LV_DRAW_SW_DRAW_UNIT_CNT;
#else
    disp->tile_cnt = 1;  // 默认单线程
#endif

    // 5. 初始化层系统
    disp->layer_head = lv_malloc(sizeof(lv_layer_t));
    LV_ASSERT_MALLOC(disp->layer_head);
    if(disp->layer_head == NULL) return NULL;
    lv_layer_init(disp->layer_head);

    // 6. 设置层缓冲区参数
    if(disp->layer_init) disp->layer_init(disp, disp->layer_head);
    disp->layer_head->buf_area.x1 = 0;
    disp->layer_head->buf_area.y1 = 0;
    disp->layer_head->buf_area.x2 = hor_res - 1;
    disp->layer_head->buf_area.y2 = ver_res - 1;
    disp->layer_head->color_format = disp->color_format;

    // 7. 初始化无效区域管理
    disp->inv_en_cnt = 1;              // 使能无效区域计数
    disp->last_activity_time = lv_tick_get();  // 记录创建时间

    // 8. 初始化同步区域链表(双缓冲用)
    lv_ll_init(&disp->sync_areas, sizeof(lv_area_t));

    // 9. 临时设置默认显示,用于创建默认屏幕
    lv_display_t * disp_def_tmp = disp_def;
    disp_def = disp;

    // 10. 创建刷新定时器(核心机制)
    disp->refr_timer = lv_timer_create(lv_display_refr_timer, LV_DEF_REFR_PERIOD, disp);
    LV_ASSERT_MALLOC(disp->refr_timer);
    if(disp->refr_timer == NULL) {
        lv_free(disp);
        return NULL;
    }

    // 11. 初始化主题系统
#if LV_USE_THEME_DEFAULT
    if(lv_theme_default_is_inited() == false) {
        disp->theme = lv_theme_default_init(disp, lv_palette_main(LV_PALETTE_BLUE), 
                                          lv_palette_main(LV_PALETTE_RED),
                                          LV_THEME_DEFAULT_DARK, LV_FONT_DEFAULT);
    }
    else {
        disp->theme = lv_theme_default_get();
    }
#endif

    // 12. 创建四层结构(从底到顶)
    disp->bottom_layer = lv_obj_create(NULL);  // 底层
    disp->act_scr      = lv_obj_create(NULL);  // 默认屏幕
    disp->top_layer    = lv_obj_create(NULL);  // 顶层
    disp->sys_layer    = lv_obj_create(NULL);  // 系统层

    // 13. 清除样式,确保纯净状态
    lv_obj_remove_style_all(disp->bottom_layer);
    lv_obj_remove_style_all(disp->top_layer);
    lv_obj_remove_style_all(disp->sys_layer);
    
    // 14. 设置不可点击(顶层和系统层)
    lv_obj_remove_flag(disp->top_layer, LV_OBJ_FLAG_CLICKABLE);
    lv_obj_remove_flag(disp->sys_layer, LV_OBJ_FLAG_CLICKABLE);

    // 15. 禁用滚动条
    lv_obj_set_scrollbar_mode(disp->bottom_layer, LV_SCROLLBAR_MODE_OFF);
    lv_obj_set_scrollbar_mode(disp->top_layer, LV_SCROLLBAR_MODE_OFF);
    lv_obj_set_scrollbar_mode(disp->sys_layer, LV_SCROLLBAR_MODE_OFF);

    // 16. 使能默认屏幕无效区域(触发首次刷新)
    lv_obj_invalidate(disp->act_scr);

    // 17. 恢复默认显示设置
    disp_def = disp_def_tmp;
    if(disp_def == NULL) disp_def = disp;

    // 18. 添加刷新请求事件监听
    lv_display_add_event_cb(disp, disp_event_cb, LV_EVENT_REFR_REQUEST, NULL);

    // 19. 立即准备刷新定时器(确保启动时立即刷新)
    lv_timer_ready(disp->refr_timer);

    // 20. 初始化性能监控(如启用)
#if LV_USE_PERF_MONITOR
    lv_sysmon_show_performance(disp);
#endif

    return disp;
}

2. lv_display_set_buffers - 缓冲区设置函数(核心)

函数原型:

cpp 复制代码
void lv_display_set_buffers(lv_display_t * disp, void * buf1, void * buf2, 
                           uint32_t buf_size, lv_display_render_mode_t render_mode)
实现原理详解:
cpp 复制代码
void lv_display_set_buffers(lv_display_t * disp, void * buf1, void * buf2, uint32_t buf_size,
                            lv_display_render_mode_t render_mode)
{
    // 1. 参数验证
    LV_ASSERT_MSG(buf1 != NULL, "Null buffer");  // 第一个缓冲区不能为空
    
    // 2. 获取显示参数
    lv_color_format_t cf = lv_display_get_color_format(disp);
    uint32_t w = lv_display_get_horizontal_resolution(disp);
    uint32_t h = lv_display_get_vertical_resolution(disp);
    
    LV_ASSERT_MSG(w != 0 && h != 0, "display resolution is 0");

    // 3. 内存对齐检查(硬件要求)
    LV_ASSERT_FORMAT_MSG(buf1 == lv_draw_buf_align(buf1, cf), 
                         "buf1 is not aligned: %p", buf1);
    LV_ASSERT_FORMAT_MSG(buf2 == NULL || buf2 == lv_draw_buf_align(buf2, cf), 
                         "buf2 is not aligned: %p", buf2);

    // 4. 计算行跨度(考虑对齐和颜色格式)
    uint32_t stride = lv_draw_buf_width_to_stride(w, cf);
    
    // 5. 根据渲染模式处理缓冲区大小
    if(render_mode == LV_DISPLAY_RENDER_MODE_PARTIAL) {
        /* 部分模式:根据缓冲区大小计算可渲染的高度 */
        h = buf_size / stride;
        LV_ASSERT_MSG(h != 0, "the buffer is too small");
    }
    else {
        /* 全屏/直接模式:需要全屏大小的缓冲区 */
        LV_ASSERT_FORMAT_MSG(stride * h <= buf_size, 
                             "%s mode requires screen sized buffer(s)",
                             render_mode == LV_DISPLAY_RENDER_MODE_FULL ? "FULL" : "DIRECT");
    }

    // 6. 初始化静态缓冲区结构
    lv_draw_buf_init(&disp->_static_buf1, w, h, cf, stride, buf1, buf_size);
    lv_draw_buf_init(&disp->_static_buf2, w, h, cf, stride, buf2, buf_size);
    
    // 7. 设置显示缓冲区指针
    lv_display_set_draw_buffers(disp, &disp->_static_buf1, 
                               buf2 ? &disp->_static_buf2 : NULL);
    
    // 8. 设置渲染模式
    lv_display_set_render_mode(disp, render_mode);
}

3. lv_screen_load_anim - 屏幕切换动画函数

函数原型:

cpp 复制代码
void lv_screen_load_anim(lv_obj_t * scr, lv_screen_load_anim_t anim_type, 
                        uint32_t time, uint32_t delay, bool auto_del)
实现原理详解:
cpp 复制代码
void lv_screen_load_anim(lv_obj_t * scr, lv_screen_load_anim_t anim_type, uint32_t time, uint32_t delay,
                         bool auto_del)
{
    // 1. 获取显示设备和当前屏幕
    lv_display_t * d = lv_obj_get_display(scr);
    if(d == NULL) return;
    
    lv_obj_t * prev_scr = d->act_scr;
    
    // 2. 设置动画参数
    d->scr_to_load = scr;
    d->del_prev = auto_del;
    
    // 3. 根据动画类型设置不同的动画参数
    switch(anim_type) {
        case LV_SCR_LOAD_ANIM_NONE:
            // 无动画,直接加载
            scr_load_internal(scr);
            return;
            
        case LV_SCR_LOAD_ANIM_OVER_LEFT:
        case LV_SCR_LOAD_ANIM_OVER_RIGHT:
        case LV_SCR_LOAD_ANIM_OVER_TOP:
        case LV_SCR_LOAD_ANIM_OVER_BOTTOM:
            // 覆盖动画:新屏幕从边缘滑入
            d->draw_prev_over_act = false;
            break;
            
        case LV_SCR_LOAD_ANIM_MOVE_LEFT:
        case LV_SCR_LOAD_ANIM_MOVE_RIGHT:
        case LV_SCR_LOAD_ANIM_MOVE_TOP:
        case LV_SCR_LOAD_ANIM_MOVE_BOTTOM:
            // 移动动画:两个屏幕同时移动
            d->draw_prev_over_act = true;
            break;
            
        case LV_SCR_LOAD_ANIM_FADE_IN:
            // 淡入动画
            lv_obj_set_style_opa(scr, LV_OPA_TRANSP, 0);  // 初始透明
            break;
    }
    
    // 4. 创建动画对象
    lv_anim_t a;
    lv_anim_init(&a);
    lv_anim_set_var(&a, scr);
    lv_anim_set_time(&a, time);
    lv_anim_set_delay(&a, delay);
    lv_anim_set_start_cb(&a, scr_load_anim_start);  // 动画开始回调
    
    // 5. 根据动画类型设置动画函数
    switch(anim_type) {
        case LV_SCR_LOAD_ANIM_OVER_LEFT:
        case LV_SCR_LOAD_ANIM_MOVE_LEFT:
            lv_anim_set_values(&a, lv_display_get_horizontal_resolution(d), 0);
            lv_anim_set_exec_cb(&a, set_x_anim);
            break;
            
        case LV_SCR_LOAD_ANIM_OVER_RIGHT:
        case LV_SCR_LOAD_ANIM_MOVE_RIGHT:
            lv_anim_set_values(&a, -lv_display_get_horizontal_resolution(d), 0);
            lv_anim_set_exec_cb(&a, set_x_anim);
            break;
            
        case LV_SCR_LOAD_ANIM_FADE_IN:
            lv_anim_set_values(&a, LV_OPA_TRANSP, LV_OPA_COVER);
            lv_anim_set_exec_cb(&a, opa_scale_anim);
            break;
    }
    
    // 6. 设置动画完成回调
    lv_anim_set_ready_cb(&a, scr_anim_completed);
    
    // 7. 启动动画
    lv_anim_start(&a);
}

4. 刷新等待机制(flush_wait_cb)

实现原理:

cpp 复制代码
// 在刷新过程中,LVGL使用以下机制等待刷新完成:

// 1. 设置刷新状态
disp->flushing = 1;        // 开始刷新
disp->flushing_last = 1;   // 标记为最后一块

// 2. 调用用户提供的flush_cb
if(disp->flush_cb) {
    disp->flush_cb(disp, area, color_p);
}

// 3. 等待刷新完成(两种机制)
if(disp->flush_wait_cb) {
    // 方式1:用户自定义等待机制(推荐)
    disp->flush_wait_cb(disp);
}
else {
    // 方式2:轮询flushing标志
    while(disp->flushing) {
        // 等待flushing被lv_display_flush_ready()清除
    }
}

// 4. 用户在中断中调用lv_display_flush_ready()
void lv_display_flush_ready(lv_display_t * disp)
{
    disp->flushing = 0;    // 清除刷新标志
}

核心数据结构与交互机制

1. 显示状态管理

  • 四层结构:底层 → 屏幕层 → 系统层 → 顶层
  • 状态同步:使用volatile确保多线程安全
  • 内存管理:静态缓冲区 + 动态分配

2. 无效区域管理(性能优化核心)

cpp 复制代码
// 无效区域环形缓冲区
lv_area_t inv_areas[LV_INV_BUF_SIZE];
uint8_t inv_area_joined[LV_INV_BUF_SIZE];  // 合并状态
uint32_t inv_p;                            // 当前位置指针

// 工作流程:
// 1. 对象改变 → 标记区域无效
// 2. 区域合并 → 减少重绘次数  
// 3. 刷新时 → 只重绘无效区域
// 4. 双缓冲 → 同步区域管理

3. 渲染流程

cpp 复制代码
// 1. 定时器触发 lv_display_refr_timer()
// 2. 检查无效区域 inv_areas[]
// 3. 按渲染模式处理:
//    - PARTIAL: 部分重绘
//    - DIRECT:  直接渲染到缓冲区
//    - FULL:    全屏重绘
// 4. 调用flush_cb写入硬件
// 5. 等待flush_ready()完成
相关推荐
boneStudent2 小时前
STM32H750多通道数据采集系统
stm32·单片机·嵌入式硬件
龙大大L3 小时前
第七章、7.1 ESP32 触摸传感器超详细教程(Arduino 环境)实战指南
单片机·嵌入式硬件·esp32
zzcufo3 小时前
多邻国学习笔记第五阶段第10-11部分
笔记·学习·c#
小渔村的拉线工3 小时前
18.SPI通信的原理及相关知识
单片机·嵌入式硬件·spi通信·全双工通信·主从机通信
youcans_4 小时前
【动手学STM32G4】(13)STM32G431之 TIM+ADC
stm32·单片机·嵌入式硬件·定时器
航Hang*4 小时前
计算机等级考试(二级WPS)---第1章:综合应用基础---第2节:PDF文件应用
笔记·学习·pdf·wps·计算机二级·计算机等级考试
zhangrelay4 小时前
Linux(ubuntu)如何锁定cpu频率工作在最低能耗模式下
linux·笔记·学习
老神在在0014 小时前
Token身份验证完整流程
java·前端·后端·学习·java-ee
兔子,你孩子掉了4 小时前
【gd32vf103 折腾】基于gcc+make的开发环境配置
单片机·硬件工程