2. 屏幕尺寸与分辨率适配

任务说明

本案例面向一块具体的嵌入式屏幕(例如 320×240 的 RGB 接口 LCD),需要完成两件事:一是根据屏幕的物理尺寸与像素分辨率,正确初始化 LVGL 的显示缓冲区与刷新回调;二是让 LVGL 的坐标系统与屏幕像素一一对应,确保绘制任何控件都不会出现偏移、截断或拉伸。最终通过一个简单的全屏着色与坐标探针控件,验证显示区域完全覆盖屏幕且坐标原点在左上角。

硬件与依赖假设

本案例以常见的 ST7789 驱动、320×240 分辨率、RGB 565 色彩格式的 SPI 接口屏幕为例。实际项目中,你只需要替换为所用屏幕的驱动初始化函数与像素写入函数即可。LVGL 版本要求 v8.x,并已正确移植了 lv_port_disp 模板文件。

核心实现

LVGL 的显示适配核心在于三个参数:水平分辨率、垂直分辨率和缓冲区策略。以下代码在 lv_conf.h 中完成基础配置,并在显示驱动初始化文件中设置正确的分辨率和刷新回调。

/* lv_conf.h 中与显示相关的关键配置 */
#define LV_COLOR_DEPTH     16          /* RGB565 */
#define LV_HOR_RES_MAX     320         /* 屏幕物理像素宽 */
#define LV_VER_RES_MAX     240         /* 屏幕物理像素高 */
#define LV_DPI_DEF         96          /* 逻辑DPI,用于字体缩放参考 */
/* disp_drv.c —— 显示驱动初始化与刷新回调 */
#include "lvgl.h"
#include "st7789.h"   /* 假设已有屏幕驱动,提供 st7789_init() 和 st7789_fill_rect() */

/* 显示缓冲区:使用两个半帧缓冲区,便于LVGL后台刷新 */
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf_1[320 * 40];   /* 每行320像素,40行高 */
static lv_color_t buf_2[320 * 40];

/* 刷新回调:将LVGL渲染好的缓冲区内容写入屏幕 */
static void disp_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
{
    /* 将像素数据按区域直接交给屏幕驱动 */
    st7789_fill_rect(area->x1, area->y1, area->x2, area->y2,
                     (uint16_t *)&color_p->full);
    lv_disp_flush_ready(disp_drv);   /* 通知LVGL本次刷新完成 */
}

/* 显示驱动初始化 —— 在 main() 中调用 */
void lv_port_disp_init(void)
{
    /* 初始化屏幕硬件 */
    st7789_init();

    /* 初始化LVGL显示缓冲区 */
    lv_disp_draw_buf_init(&draw_buf, buf_1, buf_2, sizeof(buf_1) / sizeof(lv_color_t));

    /* 注册显示驱动 */
    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;
    lv_disp_drv_register(&disp_drv);
}

验证方法

完成上述初始化后,在 main() 中调用 lv_port_disp_init(),然后创建一个覆盖全屏的纯色对象和一个坐标探针标签,用于直观判断适配是否正确。

/* main.c 中的验证代码 */
void create_verification_ui(void)
{
    /* 1. 全屏红色背景:若分辨率适配错误,会出现未覆盖区域或颜色溢出 */
    lv_obj_t *bg = lv_obj_create(lv_scr_act());
    lv_obj_set_size(bg, 320, 240);
    lv_obj_set_pos(bg, 0, 0);
    lv_obj_set_style_bg_color(bg, lv_color_hex(0xFF0000), 0);

    /* 2. 在屏幕四个角落放置小圆点,用于检测坐标偏移 */
    lv_obj_t *dot_tl = lv_obj_create(lv_scr_act());
    lv_obj_set_size(dot_tl, 10, 10);
    lv_obj_set_pos(dot_tl, 0, 0);
    lv_obj_set_style_bg_color(dot_tl, lv_color_hex(0x00FF00), 0);

    lv_obj_t *dot_br = lv_obj_create(lv_scr_act());
    lv_obj_set_size(dot_br, 10, 10);
    lv_obj_set_pos(dot_br, 310, 230);   /* 320-10=310, 240-10=230 */
    lv_obj_set_style_bg_color(dot_br, lv_color_hex(0x00FF00), 0);

    /* 3. 中心位置显示分辨率文本,便于肉眼确认 */
    lv_obj_t *label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "320x240");
    lv_obj_center(label);
}

int main(void)
{
    lv_init();
    lv_port_disp_init();      /* 分辨率适配的关键初始化 */
    create_verification_ui();

    while (1) {
        lv_timer_handler();
        delay_ms(5);
    }
}

判定标准

  • 屏幕完全显示红色且无黑边、无溢出,说明 hor_res 与 ver_res 设置正确;
  • 左上角与右下角的绿色圆点完整可见且紧贴屏幕边缘,说明坐标原点与像素映射无偏移;
  • 中心文字“320x240”清晰无变形,说明像素格式与缓冲区大小匹配。
LVGL 分辨率适配验证拓扑 红色全屏背景 (320 × 240) (0,0) (310,230) 320x240 Y+ X+ 关键配置项 LV_HOR_RES_MAX = 320 LV_VER_RES_MAX = 240 LV_COLOR_DEPTH = 16 (RGB565) disp_drv.hor_res = 320 disp_drv.ver_res = 240 缓冲区:2 × (320×40) 像素 刷新回调:st7789_fill_rect() ✓ 验证点:四角坐标 + 全屏覆盖 若绿点未贴边 → 坐标偏移;若红底未满屏 → 分辨率错误

常见问题排查

  • 画面偏移但尺寸正确:检查 st7789_fill_rect 的坐标是否从 0 开始,部分屏幕驱动需要设置列/行偏移寄存器(如 ST7789 的 MADCTL)。
  • 画面闪烁或撕裂:缓冲区过小或未使用双缓冲,可增大缓冲区高度或启用 LVGL 的 LV_COLOR_SCREEN_TRANSP 相关优化。
  • 颜色显示异常:确认 LV_COLOR_DEPTH 与屏幕驱动的 RGB 格式一致,RGB565 与 RGB888 混用会导致颜色错乱。