4、内置字体使用:LVGL内置字体(montserrat系列)的启用与配置,字体大小与粗细选择

好,咱们进入第四章。这一章聊点实在的——LVGL 自带的 montserrat 字体到底怎么用。

很多新手一上来就想着搞自定义字体,觉得内置字体不够炫。其实没必要。montserrat 这套字体,LVGL 团队已经帮你优化好了渲染路径,直接用能省不少事。我早期做的一个工业仪表项目,就是全程用 montserrat 系列,跑在 STM32F4 上,帧率稳稳的。

4.1 montserrat 字体家族概览

LVGL 内置的 montserrat 字体,说白了就是一套无衬线西文字体。它覆盖了基本的 ASCII 字符、数字、标点,以及部分拉丁扩展字符。你不需要额外加载任何字体文件,只要在 lv_conf.h 里打开对应的宏就行。

这套字体按粗细和大小分成了多个变体。我整理了一张表,方便你对照选择:

宏定义名称 像素大小 粗细等级 适用场景
LV_FONT_MONTSERRAT_8 8 px 常规 状态栏、小图标标签
LV_FONT_MONTSERRAT_10 10 px 常规 紧凑列表项、辅助文字
LV_FONT_MONTSERRAT_12 12 px 常规 按钮文字、普通标签
LV_FONT_MONTSERRAT_14 14 px 常规 正文、对话框内容
LV_FONT_MONTSERRAT_16 16 px 常规 标题、菜单项
LV_FONT_MONTSERRAT_18 18 px 常规 次级标题
LV_FONT_MONTSERRAT_20 20 px 常规 主标题
LV_FONT_MONTSERRAT_22 22 px 常规 大标题、弹窗标题
LV_FONT_MONTSERRAT_24 24 px 常规 大号数字、强调文字
LV_FONT_MONTSERRAT_26 26 px 常规 超大标题
LV_FONT_MONTSERRAT_28 28 px 常规 仪表盘数值
LV_FONT_MONTSERRAT_30 30 px 常规 特大显示
LV_FONT_MONTSERRAT_32 32 px 常规 特大显示
LV_FONT_MONTSERRAT_34 34 px 常规 超大数值
LV_FONT_MONTSERRAT_36 36 px 常规 超大数值
LV_FONT_MONTSERRAT_38 38 px 常规 超大数值
LV_FONT_MONTSERRAT_40 40 px 常规 超大数值
LV_FONT_MONTSERRAT_42 42 px 常规 超大数值
LV_FONT_MONTSERRAT_44 44 px 常规 超大数值
LV_FONT_MONTSERRAT_46 46 px 常规 超大数值
LV_FONT_MONTSERRAT_48 48 px 常规 超大数值
LV_FONT_MONTSERRAT_12_SUBPX 12 px 常规 + 亚像素 高DPI屏幕小字
LV_FONT_MONTSERRAT_28_COMPRESSED 28 px 常规 + 压缩 Flash紧张的设备
LV_FONT_MONTSERRAT_10 到 _48 的 _NORMAL 变体 同上 常规 同上
我的习惯: 项目初期只开 3-4 个字号。比如 12px 给按钮,16px 给正文,24px 给标题。等界面定型了再按需补其他字号。别一股脑全开,Flash 会哭的。

4.2 启用内置字体:lv_conf.h 配置

启用 montserrat 字体,核心就是改 lv_conf.h。找到 LV_FONT_MONTSERRAT 相关的宏,把对应的值从 0 改成 1。

举个例子,你想用 16px 和 24px 的常规字体:

/* lv_conf.h */
#define LV_FONT_MONTSERRAT_16  1   /* 启用 16px 常规 */
#define LV_FONT_MONTSERRAT_24  1   /* 启用 24px 常规 */

编译后,LVGL 会自动把这些字体的位图数据链接进固件。你不需要额外 include 任何头文件,直接通过 &lv_font_montserrat_16 这个指针就能引用。

注意: 每个启用的字体都会增加 Flash 占用。16px 常规字体大约占 5-8 KB,24px 大约占 12-18 KB。如果你的 MCU Flash 只有 256 KB,建议最多开 5 个字号。

4.3 字体大小与粗细的选择策略

选字号和粗细,不是拍脑袋决定的。我总结了几条实战经验:

  • 阅读距离决定字号: 手持设备(距离 30 cm),12-16 px 足够。车载或工控屏(距离 50-70 cm),建议 18-24 px。如果做的是智能手表,8-12 px 就够,但要注意开启抗锯齿。
  • 粗细影响可读性: montserrat 常规体(Normal)的笔画粗细适中,适合正文。但如果你做的是深色背景上的白色文字,常规体可能会显得细。这时候可以考虑用粗体变体——不过 LVGL 内置的 montserrat 没有单独的粗体宏,你需要用 lv_font_set_bold() 在运行时加粗,或者自己生成粗体字体。
  • 亚像素渲染慎用: LV_FONT_MONTSERRAT_12_SUBPX 这个变体用了亚像素抗锯齿,显示效果更平滑。但它只适用于已知像素排列的 LCD 屏(比如 RGB 条纹排列)。OLED 屏用亚像素反而会有色边。我踩过这个坑,后来老老实实换回常规抗锯齿。

核心原则: 字号越小,越要关注渲染质量。8-12 px 的字体,必须开启抗锯齿(LV_FONT_MONTSERRAT_8 默认带抗锯齿)。14 px 以上可以酌情关闭抗锯齿以提升性能。

4.4 在代码中使用内置字体

启用之后,怎么用?很简单。创建标签或按钮时,直接指定字体指针:

/* 创建一个标签,使用 16px montserrat 字体 */
lv_obj_t *label = lv_label_create(lv_scr_act());
lv_obj_set_style_text_font(label, &lv_font_montserrat_16, 0);
lv_label_set_text(label, "Hello LVGL");

/* 创建一个按钮,使用 24px 字体 */
lv_obj_t *btn = lv_btn_create(lv_scr_act());
lv_obj_t *btn_label = lv_label_create(btn);
lv_obj_set_style_text_font(btn_label, &lv_font_montserrat_24, 0);
lv_label_set_text(btn_label, "Click Me");

这里有个细节:&lv_font_montserrat_16 这个符号是 LVGL 编译时自动生成的。你不需要自己声明 extern,直接拿来用就行。

4.5 字体选择与性能的权衡

你可能会问:字号越大,渲染越慢,对吧?

对,但不全对。LVGL 的字体渲染性能主要受三个因素影响:

  1. 字符缓存命中率: 首次绘制一个字符时,LVGL 会解码位图并缓存。后续再画同一个字符,直接从缓存取,速度极快。所以频繁切换字体或使用大量生僻字符,会降低缓存命中率。
  2. 抗锯齿开销: 开启抗锯齿(默认就是开的),每个字符的渲染时间大约增加 30%-50%。对于 16 px 以下的字体,这个开销值得。对于 24 px 以上的字体,你可以考虑关闭抗锯齿来换性能。
  3. 字体位图大小: 字号越大,每个字符的位图越大,渲染时内存拷贝的开销也越大。48 px 的字符,渲染时间大约是 16 px 的 6-8 倍。

我个人的建议:如果你的界面需要频繁更新文字(比如实时数据刷新),尽量用 16-20 px 的字体,并保持抗锯齿开启。如果只是静态界面,用大字号也没问题。

4.6 知识体系结构图

下面这张图帮你理清 montserrat 内置字体的使用脉络:

montserrat 内置字体使用流程 lv_conf.h 配置 选择字号 (8-48 px) 小字号 (8-14 px) 中字号 (16-24 px) 大字号 (26-48 px) 建议:开启抗锯齿 使用 SUBPX 变体 建议:保持抗锯齿 适合正文和按钮 建议:可关闭抗锯齿 注意 Flash 占用 代码中使用 &lv_font_montserrat_XX 根据字号选择渲染策略

4.7 避坑指南

最后分享几个我踩过的坑:

  • 宏没开全: 有一次我开了 LV_FONT_MONTSERRAT_16,但忘了开 LV_USE_FONT_MONTSERRAT 总开关。编译没报错,但运行时字体显示全是方框。检查了半小时才发现。嗯,这种低级错误,犯一次就记住了。
  • 字体指针写错: &lv_font_montserrat_16 中间是下划线,不是连字符。我见过有人写成 &lv_font_montserrat-16,编译直接报错。
  • Flash 爆了: 曾经在一个 128 KB Flash 的芯片上,一口气开了 8 个字号。编译通过,下载后系统起不来。后来用 map 文件一看,字体数据占了 90 KB。从那以后,我养成了先看 .map 文件再决定开几个字号的习惯。
小技巧: 如果你不确定某个字号是否够用,可以先在 PC 模拟器上跑。LVGL 的 PC 模拟器(SDL 版)支持所有内置字体,切换字号看效果非常方便。等确定了再开宏,省得反复烧录。