告别乱码!手把手教你为Arduino OLED屏添加自定义中文字体(基于u8g2库)

张开发
2026/4/8 16:51:17 15 分钟阅读

分享文章

告别乱码!手把手教你为Arduino OLED屏添加自定义中文字体(基于u8g2库)
告别乱码手把手教你为Arduino OLED屏添加自定义中文字体基于u8g2库在嵌入式开发中OLED屏幕因其低功耗、高对比度和体积小巧等优势成为DIY项目的热门选择。然而当项目需要显示中文时许多开发者都会遇到一个共同的难题默认字库要么无法显示中文要么出现乱码。本文将带你一步步解决这个问题使用u8g2库为Arduino项目添加自定义中文字体让你的OLED屏幕完美呈现中文内容。1. 准备工作与环境搭建在开始之前我们需要准备以下工具和材料硬件设备Arduino开发板如Arduino Uno、Nano或ESP8266/ESP32OLED显示屏支持I2C或SPI接口连接线若干软件工具Arduino IDE建议使用最新版本u8g2库可通过Arduino库管理器安装Python环境用于运行字体生成工具字体资源选择一款适合你项目的TTF格式中文字体推荐字体下载网站Google Fonts、Font Squirrel等提示在选择字体时建议优先考虑免费商用字体避免版权问题。同时过于复杂的字体可能会占用较多存储空间对于资源有限的Arduino开发板需要特别注意。2. 使用u8g2字体生成工具u8g2库提供了一个强大的字体生成工具可以将TTF字体转换为适用于嵌入式设备的精简格式。以下是详细的操作步骤2.1 获取并配置字体生成工具首先从u8g2官方GitHub仓库下载字体生成工具git clone https://github.com/olikraus/u8g2.git cd u8g2/tools/font/bdfconv工具目录结构如下bdfconv/ ├── README.md ├── bdfconv.c ├── bdfconv.h └── Makefile2.2 编译字体生成工具在Linux或Mac系统下可以直接使用make命令编译makeWindows用户可以使用MinGW或Cygwin环境进行编译也可以下载预编译的二进制文件。2.3 生成精简字库为了节省宝贵的存储空间我们需要只包含项目实际需要显示的汉字。假设我们的项目只需要显示温度25℃这几个字符可以使用以下命令./bdfconv -v -b 0 -f 1 -M chinese.map -n myfont -o myfont.c myfont.ttf参数说明-b 0指定字体起始编码-f 1指定字体格式-M chinese.map指定字符映射文件-n myfont指定生成的字体名称-o myfont.c指定输出文件名3. 将字体集成到Arduino项目3.1 创建字体文件在Arduino项目目录下创建一个新的文件夹命名为fonts然后将生成的myfont.c文件放入其中。同时创建一个对应的头文件myfont.h#ifndef _MYFONT_H #define _MYFONT_H #include U8g2lib.h extern const uint8_t myfont[]; #endif3.2 在项目中使用自定义字体在Arduino主程序中添加以下代码来使用我们生成的自定义字体#include U8g2lib.h #include fonts/myfont.h U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset*/ U8X8_PIN_NONE); void setup() { u8g2.begin(); u8g2.setFont(myfont); } void loop() { u8g2.firstPage(); do { u8g2.setCursor(0, 20); u8g2.print(温度25℃); } while (u8g2.nextPage()); delay(1000); }4. 优化与问题排查4.1 内存优化技巧对于资源有限的Arduino开发板可以采取以下优化措施精简字符集只包含项目实际需要的字符调整字体大小较小的字体占用更少空间使用PROGMEM将字体数据存储在程序存储器而非RAM中const uint8_t myfont[] PROGMEM { // 字体数据 };4.2 常见问题及解决方案问题现象可能原因解决方案编译错误字体太大字体数据超出可用存储空间精简字符集或减小字体尺寸显示乱码字符编码不匹配确保生成字体时使用正确的编码屏幕无显示硬件连接错误检查I2C/SPI接口连接字体显示不完整字体高度设置不当调整setCursor的Y坐标4.3 高级技巧动态加载字体对于ESP32等支持文件系统的开发板可以考虑将字体存储在SPIFFS中实现动态加载#include SPIFFS.h void loadFontFromFS(const char* path) { File file SPIFFS.open(path, r); if(!file) { Serial.println(Failed to open font file); return; } size_t fontSize file.size(); uint8_t* fontData (uint8_t*)malloc(fontSize); if(file.read(fontData, fontSize) ! fontSize) { Serial.println(Failed to read font data); free(fontData); return; } u8g2.setFont(fontData); file.close(); } void setup() { SPIFFS.begin(); loadFontFromFS(/fonts/myfont.bin); }5. 实际应用案例5.1 智能家居状态显示屏一个典型的应用场景是制作一个智能家居状态显示屏可以显示当前室内温度、湿度以及设备状态等信息。使用自定义中文字体可以让显示更加直观友好。void displayHomeStatus(float temp, float humi, bool acStatus) { u8g2.firstPage(); do { u8g2.setCursor(0, 16); u8g2.print(室内环境); u8g2.setCursor(0, 32); u8g2.print(温度); u8g2.print(temp, 1); u8g2.print(℃); u8g2.setCursor(0, 48); u8g2.print(湿度); u8g2.print(humi, 1); u8g2.print(%); u8g2.setCursor(0, 64); u8g2.print(空调); u8g2.print(acStatus ? 开启 : 关闭); } while (u8g2.nextPage()); }5.2 个性化电子时钟另一个常见应用是制作个性化电子时钟可以显示日期、时间以及自定义问候语。通过使用不同的字体风格可以创造出独特的视觉效果。void displayClock(int hour, int minute, int second, const char* greeting) { char timeStr[9]; sprintf(timeStr, %02d:%02d:%02d, hour, minute, second); u8g2.firstPage(); do { u8g2.setFont(u8g2_font_wqy16_t_gb2312); u8g2.setCursor(0, 16); u8g2.print(greeting); u8g2.setFont(myfont_large); u8g2.setCursor(0, 48); u8g2.print(timeStr); } while (u8g2.nextPage()); }在实际项目中我发现字体生成工具对文件路径中的中文字符特别敏感这可能是很多初学者遇到的第一个障碍。建议将所有相关文件都放在纯英文路径下可以避免90%以上的初始化问题。另外对于需要频繁更新的显示内容可以考虑使用双缓冲技术来减少闪烁提升用户体验。

更多文章