嵌入式开发中经常遇到一个头疼的问题:如何在有限的硬件资源下优雅地显示中文。U8G2作为嵌入式图形库的佼佼者,虽然自带英文字体支持,但对中文的支持却需要开发者自己动手。这就像给你一套精美的西餐餐具,却要你自己打造筷子来吃中餐。
我遇到过最典型的场景是在128x64的OLED屏上显示产品参数。系统自带的英文字体很漂亮,但一到中文就变成乱码。最初尝试过外挂字库芯片的方案,不仅增加了BOM成本,读取速度还慢得让人抓狂。后来发现U8G2其实支持BDF点阵字体,这才打开了新世界的大门。
BDF字体就像乐高积木,每个字都是固定大小的像素块。它的优势在于:
但直接使用现成的BDF字体往往不合适。比如文泉驿的9pt字体包含6000+常用汉字,实际项目可能只需要几十个特定字符(如"温度"、"湿度"等)。这就好比带着整个工具箱出门,其实只需要一把螺丝刀。
TTF就像用数学公式描述的矢量图,可以无限缩放而不失真。BDF则是固定分辨率的像素图,放大后会出现锯齿。这就解释了为什么直接转换会有毛边问题——矢量到点阵的采样过程就像用网格临摹一幅画,细节必然丢失。
在技术实现上:
经过多次踩坑,我最终选定了Easy-u8g2-font-generate-tools这个Python工具。原版工具已经三年没更新,存在几个痛点:
我的改进版主要做了这些优化:
安装非常简单:
bash复制git clone https://gitee.com/etberzin/Easy-u8g2-font-generate-tools
cd Easy-u8g2-font-generate-tools
pip install -r requirements.txt
建议将字体文件放在指定目录:
/font文件夹/bdf文件夹/text文件夹对于中文显示,推荐这些开源字体:
字符集准备:
创建一个UTF-8编码的txt文件,例如menu.txt,内容包含所有需要显示的汉字:
code复制主菜单
设置
温度
湿度
返回
运行转换工具:
bash复制python main.py
关键参数设置:
输出结果:
code/目录下生成C/C++源文件bdf.tga预览图毛边问题:
字号不匹配:
python复制# 字号与像素对应关系
size_map = {
'9pt': (12,12),
'10pt': (13,13),
'11pt': (15,15),
'12pt': (16,16)
}
字符缺失:
生成的文件结构示例:
code复制u8g2_font_menu.c
u8g2_font_menu.h
头文件内容模板:
c复制#pragma once
#include "u8g2.h"
extern const uint8_t u8g2_font_menu[] U8G2_FONT_SECTION("u8g2_font_menu");
使用时只需:
c复制u8g2_SetFont(&u8g2, u8g2_font_menu);
u8g2_DrawUTF8(&u8g2, 10, 20, "温度:25℃");
对于资源紧张的MCU:
PROGMEM关键字将字体存入Flash实测数据对比(STM32F103):
| 方案 | Flash占用 | RAM占用 |
|---|---|---|
| 全字库 | 256KB | 0 |
| 裁剪50字 | 3KB | 0 |
| 外挂字库 | 2KB | 1KB缓存 |
遇到显示错位时检查:
调试小技巧:
c复制// 显示字体边界框
u8g2_DrawFrame(&u8g2, x, y-height, width, height);
对于需要动态变更内容的场景(如用户输入),可以采用:
| 方案 | 优点 | 缺点 |
|---|---|---|
| BDF裁剪 | 资源占用低 | 静态字符集 |
| 外挂字库 | 字符齐全 | 速度慢 |
| 取模软件 | 完全可控 | 开发量大 |
| 图片渲染 | 效果精美 | 占用空间大 |
在ESP32上的实测数据显示:
关键代码片段:
c复制// 创建显示列表
u8g2_uint_t dl = u8g2_GetDisplayList(&u8g2, "你好世界");
// 重复使用
u8g2_DrawDisplayList(&u8g2, x, y, dl);
经过多个项目的实战检验,这套字体定制方案在STM32、ESP8266、ESP32等平台上都表现稳定。特别是在智能家居控制面板这类需要中英文混合显示的场合,既能保证显示效果,又不会过度消耗宝贵的硬件资源。