第二章 开发环境搭建:MCU平台选型、LVGL源码获取、移植步骤详解、第一个LVGL工程点亮屏幕
好,咱们正式开始动手了。上一章聊了LVGL能做什么,这一章咱们就把它跑起来。很多初学者卡在环境搭建这一步,其实说白了就是几个关键点没摸透。我当年第一次移植LVGL的时候,也折腾了两天才把屏幕点亮。今天我把这些坑都给你指出来,你照着做,半天之内肯定能亮屏。
2.1 MCU平台选型:别盲目追求高性能
选开发板,是第一步。我见过不少新手,一上来就买几百块的旗舰开发板,结果大部分资源都用不上。其实LVGL对硬件的要求,比你想象的要低。
核心要求就三点:
- RAM:至少 8KB,推荐 16KB 以上。LVGL的显存和控件对象都吃RAM。
- Flash:至少 128KB,推荐 256KB 以上。LVGL库本身就要占几十KB,再加上字体和图片。
- 主频:至少 72MHz,推荐 100MHz 以上。频率太低,刷新动画会卡顿。
我个人习惯用 STM32F4 系列 或者 ESP32 作为入门平台。STM32F4 资料多,稳定;ESP32 自带WiFi和蓝牙,做物联网项目很方便。你想想看,如果你只是学LVGL,买个STM32F407 或者 ESP32-DevKitC 就完全够用了,几十块钱搞定。
我的推荐清单:
| 平台 | RAM | Flash | 主频 | 适合场景 |
|---|---|---|---|---|
| STM32F407 | 192KB | 1MB | 168MHz | 入门、工业控制 |
| ESP32 | 520KB | 4MB | 240MHz | 物联网、智能家居 |
| STM32H743 | 1MB | 2MB | 480MHz | 复杂UI、高性能需求 |
注意: 别选太冷门的芯片。我曾经有个学生选了某国产小众MCU,结果LVGL的驱动接口文档都找不到,折腾了一周。选主流平台,遇到问题网上随便一搜就有答案。
2.2 LVGL源码获取:官方渠道最靠谱
源码去哪下?别去第三方网站乱找。我建议你直接去 GitHub 上搜 lvgl/lvgl。这是官方仓库,永远是最新版本。
下载方式有两种:
- 直接下载ZIP包: 点绿色的 "Code" 按钮,选 "Download ZIP"。简单粗暴,适合新手。
- 使用Git克隆: 在终端里执行
git clone https://github.com/lvgl/lvgl.git。这样以后更新方便,我推荐你用这种方式。
下载完后,你会看到一堆文件夹。别慌,核心代码都在 src 目录下。你只需要关注这几个:
lvgl/src:LVGL 核心库,所有控件、绘图、输入设备的代码都在这里。lvgl/examples:官方示例,很有参考价值。我刚开始学的时候,就是靠看这些示例入门的。lvgl/demos:一些完整的演示工程,比如音乐播放器、仪表盘。你可以直接烧录到板子上看看效果。
小技巧: 下载时注意版本号。LVGL v8 和 v9 的API有变化。我建议你从 v8.3.x 开始学,资料最全,社区最活跃。等熟悉了再升级到 v9。
2.3 移植步骤详解:三步走,不迷路
移植LVGL,说白了就是把LVGL的代码和你的硬件驱动连接起来。我把它总结成三步:
第一步:复制文件到工程
把你下载的 lvgl 文件夹整个复制到你的MCU工程目录下。然后在IDE里把 lvgl/src 下的所有 .c 文件添加进来。嗯,这里要注意,别漏了 lvgl/src/extra 目录下的文件,那里有很多好用的扩展控件。
第二步:配置 lv_conf.h
这是最关键的一步。在 lvgl 目录下有一个 lv_conf_template.h 文件,把它复制到工程根目录,重命名为 lv_conf.h。然后打开它,修改几个关键参数:
/* 颜色深度,根据你的屏幕设置 */
#define LV_COLOR_DEPTH 16
/* 内存分配大小,给LVGL用的RAM */
#define LV_MEM_SIZE (32U * 1024U)
/* 开启显示驱动和输入设备驱动 */
#define LV_USE_DISPLAY 1
#define LV_USE_INDEV 1
/* 开启你需要的控件 */
#define LV_USE_BTN 1
#define LV_USE_LABEL 1
#define LV_USE_SLIDER 1
// ... 其他控件按需开启
我曾经犯过一个错误,就是 LV_MEM_SIZE 设得太小,结果程序跑起来就死机。后来我改成 32KB,就稳定了。你根据你的MCU RAM大小来调整,一般设个 16KB 到 64KB 就行。
第三步:实现底层接口
LVGL需要你提供三个底层函数:
- 显示刷新:
void my_disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)。这个函数负责把LVGL计算好的像素数据刷到屏幕上。 - 触摸输入:
void my_touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)。这个函数负责读取触摸屏的坐标。 - 系统时钟:
uint32_t my_tick_get(void)。这个函数返回一个毫秒级的时间戳,LVGL用它来做动画和定时任务。
这三个函数怎么写?我直接给你一个模板:
/* 显示刷新函数 */
void my_disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
int32_t x, y;
for(y = area->y1; y <= area->y2; y++) {
for(x = area->x1; x <= area->x2; x++) {
/* 调用你的屏幕驱动,在(x,y)位置画一个像素 */
set_pixel(x, y, color_p->full);
color_p++;
}
}
lv_disp_flush_ready(disp_drv); /* 通知LVGL刷新完成 */
}
/* 触摸输入函数 */
void my_touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
/* 读取触摸坐标,假设存在全局变量 touch_x, touch_y, touch_pressed */
data->point.x = touch_x;
data->point.y = touch_y;
data->state = touch_pressed ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
}
/* 系统时钟函数 */
uint32_t my_tick_get(void)
{
return HAL_GetTick(); /* 使用HAL库的滴答定时器 */
}
关键点: 记得在 main() 函数里调用 lv_init() 初始化LVGL,然后注册你的显示驱动和输入驱动。代码大概长这样:
lv_init();
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.flush_cb = my_disp_flush;
lv_disp_drv_register(&disp_drv);
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = my_touchpad_read;
lv_indev_drv_register(&indev_drv);
2.4 第一个LVGL工程:点亮屏幕,显示"Hello World"
移植完成后,咱们来写第一个程序。目标很简单:在屏幕中央显示一行 "Hello, LVGL!"。
在 main() 函数的大循环里,加上这段代码:
while(1) {
lv_timer_handler(); /* 处理LVGL的任务,比如动画、刷新 */
my_delay_ms(5); /* 适当延时,别让CPU跑满 */
}
然后在 main() 函数初始化部分,创建一个标签:
/* 创建一个标签控件 */
lv_obj_t * label = lv_label_create(lv_scr_act()); /* 在当前屏幕上创建 */
lv_label_set_text(label, "Hello, LVGL!"); /* 设置文字 */
lv_obj_center(label); /* 居中显示 */
编译、下载、复位。如果一切顺利,你的屏幕上应该会出现 "Hello, LVGL!" 这几个字。
如果屏幕没亮,别急。 先检查硬件连接:电源、地线、SPI/I2C 引脚对不对。然后用逻辑分析仪看看有没有数据波形。我曾经有一次折腾了半天,结果是屏幕的复位引脚没拉高。这种低级错误,你注意一下就能避免。
2.5 避坑指南:我踩过的那些坑
最后,分享几个我实际项目中遇到的坑,你提前知道,能省不少时间:
- 内存不足: 如果你发现程序跑着跑着就卡死,多半是
LV_MEM_SIZE设小了。加大它,或者开启LVGL的内存监控功能LV_USE_MEM_MONITOR来查看使用情况。 - 刷新率太低: 屏幕刷新慢,动画一卡一卡的。检查你的显示刷新函数,别用
HAL_Delay()这种阻塞延时。用DMA传输数据,效率能提升好几倍。 - 触摸不准: 触摸坐标偏移或者反向。检查你的触摸驱动,确认坐标转换是否正确。我一般会在触摸读取函数里加个打印,把原始坐标打出来看看。
好了,环境搭建就讲到这里。下一章咱们开始正式学习LVGL的控件,第一个就是按钮。你先把屏幕点亮,咱们下章见。