2. 开发环境搭建:从零开始,让代码跑起来

说实话,很多初学者在环境搭建这一步就被劝退了。我当年第一次搞嵌入式 HMI 开发,光配交叉编译链就折腾了两天。嗯,今天咱们把这层窗户纸捅破,你跟着我一步步来,半小时内就能看到第一个“Hello World”在屏幕上亮起来。

2.1 选哪个框架?Qt for MCU 还是 LVGL?

这是你面临的第一个选择题。我直接给你结论:

对比项 Qt for MCU LVGL
授权方式 商业授权(贵) MIT 开源(免费)
资源占用 RAM ≥ 256KB,Flash ≥ 2MB RAM ≥ 8KB,Flash ≥ 64KB
开发语言 C++ / QML C(纯 C)
学习曲线 陡峭(需要懂 Qt 生态) 平缓(上手快)
适合场景 高端仪表、车载、工业 HMI 中低端 MCU、小屏、快速原型

我个人习惯用 LVGL 做教学,原因很简单:免费、轻量、社区活跃。你拿它练手,成本几乎为零。等后面做产品级项目时,再根据硬件选型决定是否切到 Qt。

我的建议: 如果你是学生或个人开发者,直接选 LVGL。如果是公司项目且预算充足,Qt for MCU 的生态工具链确实更成熟。

2.2 安装 LVGL 模拟器环境(基于 SDL2)

咱们先从 PC 模拟器开始。为什么?因为每次改代码都烧录到开发板上,太慢了。在 PC 上跑模拟器,改完立刻看到效果,效率翻倍。

步骤一:安装 SDL2 库

LVGL 的模拟器依赖 SDL2 做显示和输入。不同系统命令不一样:

  • Ubuntu/Debian: sudo apt install libsdl2-dev
  • macOS: brew install sdl2
  • Windows: 去 libsdl.org 下载开发库,解压到项目目录
我曾经踩过的坑: 在 Windows 上直接双击 SDL2.dll 是不行的。你必须把 dll 放到 exe 同级目录,或者在 CMake 里指定路径。我第一次搞的时候,程序一直闪退,查了半天才发现是 dll 没加载上。

步骤二:克隆 LVGL 模拟器项目

git clone https://github.com/lvgl/lv_port_pc_eclipse.git
cd lv_port_pc_eclipse

这个项目已经帮你配好了 LVGL 源码和 SDL2 驱动。你只需要编译就行。

步骤三:编译并运行

mkdir build && cd build
cmake ..
make -j4
./demo

如果一切顺利,你会看到一个灰色窗口弹出来,里面有几个 LVGL 的示例控件。恭喜,模拟器环境搭好了!

2.3 配置交叉编译工具链(ARM GCC)

模拟器跑通了,接下来要让代码真正在 MCU 上跑。这需要交叉编译——说白了,就是在 PC 上编译出 ARM 芯片能执行的机器码。

下载 ARM GCC 工具链

我推荐用 ARM 官方维护的 GNU Arm Embedded Toolchain:

  • 下载地址:developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain
  • 选择 gcc-arm-none-eabi 版本(注意是 none-eabi,不是 linux-gnu)

解压后,把 bin 目录加到系统 PATH 里。验证一下:

arm-none-eabi-gcc --version
# 输出类似:arm-none-eabi-gcc (GNU Tools for Arm Embedded Processors) 10.3.1 20210621
关键点: 交叉编译器的前缀是 arm-none-eabi-,这意味着它生成的是裸机代码,没有操作系统依赖。如果你的 MCU 跑 FreeRTOS 或 RT-Thread,依然用这个工具链。

配置 CMake 交叉编译文件

在 LVGL 项目中,创建一个 arm-gcc.cmake 文件:

set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)

set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

编译时指定这个文件:

cmake -DCMAKE_TOOLCHAIN_FILE=arm-gcc.cmake ..
make

2.4 搭建 QEMU 模拟器(可选但推荐)

如果你手头没有开发板,QEMU 可以模拟一个 ARM 开发板环境。我经常用它做快速验证。

安装 QEMU

sudo apt install qemu-system-arm

准备一个裸机程序

以 STM32F407 为例,QEMU 支持 netduinoplus2 开发板模型。你需要准备:

  • 启动文件 startup_stm32f407.s
  • 链接脚本 stm32f407.ld
  • 主程序 main.c

编译后生成 main.elf,然后用 QEMU 运行:

qemu-system-arm -M netduinoplus2 -kernel main.elf -nographic
小技巧: 加上 -serial stdio 参数,可以把 MCU 的串口输出重定向到终端。这样你就能看到 printf 打印了。

2.5 第一个“Hello World”程序

环境都搭好了,咱们写个最简单的 LVGL 程序,在屏幕上显示“Hello World”。

代码示例

#include "lvgl.h"
#include "lv_drivers/display/sdl.h"

int main(void)
{
    /* 初始化 LVGL */
    lv_init();

    /* 初始化 SDL 显示驱动 */
    sdl_init();

    /* 创建一个标签控件 */
    lv_obj_t *label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "Hello World!");
    lv_obj_center(label);

    /* 主循环 */
    while(1) {
        lv_task_handler();
        SDL_Delay(5);
    }

    return 0;
}

编译运行

mkdir build && cd build
cmake ..
make
./hello_world

你会看到窗口中央显示“Hello World!”。嗯,第一个 HMI 程序跑起来了。

背后的原理: lv_label_create 在屏幕上创建一个标签对象,lv_label_set_text 设置显示内容,lv_obj_center 让它居中。主循环里 lv_task_handler() 负责处理 LVGL 的内部任务,比如刷新显示、处理输入。

2.6 本章知识体系总览

下面这张图帮你理清整个环境搭建的脉络:

开发环境搭建知识体系 开发环境搭建知识体系 HMI 开发环境 框架选择 Qt for MCU LVGL PC 模拟器 SDL2 驱动 CMake 编译 目标硬件 ARM GCC QEMU 核心流程 选择框架 → 搭建 PC 模拟器 → 配置交叉编译链 → 部署到目标硬件

2.7 常见问题与避坑指南

  • SDL2 窗口黑屏: 检查是否调用了 sdl_init(),以及主循环里有没有 SDL_Delay()。我曾经忘了加延时,CPU 跑满导致窗口无响应。
  • 交叉编译链接报错: 确认链接脚本里的 Flash 和 RAM 地址与你的 MCU 型号匹配。STM32F407 的 Flash 起始地址是 0x08000000,RAM 是 0x20000000。
  • QEMU 无法启动: 试试加 -d in_asm 参数查看反汇编输出,看程序是不是卡在启动文件里了。
重要提醒: 不要在生产项目里直接用模拟器验证所有功能。模拟器无法模拟外设时序,比如 SPI 屏幕刷新、ADC 采样等。模拟器只适合做 UI 逻辑验证。

好了,环境搭好了,第一个程序也跑起来了。接下来你就可以开始真正设计仪表界面了。记住,开发环境就像工具箱,工具顺手了,活才能干得快。