U8g2lib 详解
U8g2lib 是一个用于单色图形显示器 (monochrome graphics displays) 的开源嵌入式图形库。它支持各种 OLED 和 LCD 显示器,例如经典的 128x64 SSD1306 OLED 显示器。U8g2lib 以其广泛的硬件支持、丰富的字体集、高效的内存使用以及强大的图形绘制功能而闻名。它是 U8glib 的继任者,相比 U8glib,U8g2lib 在内存效率和功能上进行了优化和扩展,支持帧缓冲模式 (full buffer) 和页缓冲模式 (page buffer)。
核心思想:提供一个统一的 API 接口,驱动各种单色图形显示器,并提供一套完整的图形绘制和字体渲染功能,同时兼顾嵌入式设备的资源限制。 开发者无需关心底层显示器的驱动细节,专注于界面设计。
一、为什么需要 U8g2lib?嵌入式显示器的痛点
在嵌入式系统中集成单色图形显示器时,开发者常常面临以下挑战:
- 硬件驱动复杂:不同的显示器控制器 (如 SSD1306, SH1106, ST7920) 有不同的初始化序列、命令集和数据传输协议(SPI, I2C, 并行)。手动编写驱动非常耗时且容易出错。
- 字体渲染困难:在低分辨率单色屏幕上显示文字需要专业的字体处理,包括位图字体存储、字符渲染算法和抗锯齿处理。
- 图形绘制基础功能缺失:画点、线、矩形、圆等基本图形功能需要从零开始实现。
- 内存资源限制:嵌入式微控制器(如 Arduino UNO 的 ATmega328P, ESP32/ESP8266)通常内存有限。全屏帧缓冲可能会消耗大量 RAM。
- 缺乏统一 API:每个显示器可能需要不同的库,导致项目更换显示器时需要大量代码修改。
U8g2lib 通过提供一个统一、强大且内存优化的解决方案,解决了这些痛点。
二、U8g2lib 的主要特性
2.1 广泛的硬件支持
- 控制器:支持 SSD1306, SH1106, ST7920, PCD8544 (Nokia 5110), ILI9341 (作为单色模式) 等数十种流行的 OLED/LCD 控制器。
- 接口:支持 I2C, SPI (3线/4线), 并行接口。
- 开发板:高度兼容 Arduino, ESP32, ESP8266, STM32 等各种微控制器平台。
2.2 两种缓冲模式
U8g2lib 提供了两种核心的屏幕更新策略,以适应不同内存需求的场景:
全帧缓冲模式 (Full Buffer Mode):
- 工作原理:在微控制器的 RAM 中分配一块与整个显示器屏幕大小一致的位图缓冲区。所有绘制操作都在这个内存缓冲区中进行,然后一次性将整个缓冲区的内容传输到显示器。
- 优点:
- 绘制性能高:绘制操作在内存中进行,速度快。
- 图形效果好:支持复杂的图形效果和动画,无闪烁。
- 缺点:
- 内存消耗大:一个 128x64 像素的屏幕需要
128 * 64 / 8 = 1024字节的 RAM。对于内存有限的微控制器(如 Arduino UNO 的 2KB RAM),这可能是个问题。
- 内存消耗大:一个 128x64 像素的屏幕需要
- 适用场景:ESP32/ESP8266 等拥有较多 RAM 的设备,需要复杂动画或流畅用户界面的应用。
初始化示例 (Full Buffer):
1
2U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_UNUSED, /* clock=*/ SCL, /* data=*/ SDA);
// 其中 '_F_' 表示 Full Buffer 模式页缓冲模式 (Page Buffer Mode):
- 工作原理:将显示器屏幕分成若干“页”,每次只在 RAM 中分配一个页大小的缓冲区。绘制操作针对当前页进行,然后将该页的内容传输到显示器。重复此过程直到所有页都被更新。
- 优点:
- 内存消耗极低:一个 128x64 的屏幕通常分为 8 页 (每页 8 行)。每页只需要
128 * 8 / 8 = 128字节的 RAM。 - 高度内存优化:非常适合内存受限的微控制器。
- 内存消耗极低:一个 128x64 的屏幕通常分为 8 页 (每页 8 行)。每页只需要
- 缺点:
- 绘制速度相对慢:每次更新都需要循环绘制所有页,可能会有轻微闪烁或绘制延迟。
- 复杂图形处理受限:复杂的图形操作(如跨页的动画)可能需要更复杂的逻辑。
- 适用场景:Arduino UNO 等内存极其有限的设备,静态或简单图形显示。
初始化示例 (Page Buffer):
1
2U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_UNUSED, /* clock=*/ SCL, /* data=*/ SDA);
// 其中 '_1_' 表示 Page Buffer 模式 (1页)
2.3 丰富的字体库
- 内置字体:U8g2lib 提供了大量高质量的位图字体,包括各种大小、风格和语言(支持中文等)。
- 字体编辑器:提供了工具(如
bdfconv)可以将标准字体转换为 U8g2lib 兼容格式。
2.4 强大的图形绘制功能
- 基本图形:画点 (
drawPixel), 线 (drawLine), 矩形 (drawBox,drawFrame), 圆 (drawCircle), 椭圆 (drawEllipse)。 - 高级图形:多边形 (
drawPolygon), 位图 (drawBitmap), XBM (drawXBM)。 - 文本输出:设置字体 (
setFont), 绘制字符串 (drawStr), 获取文本宽度 (getStrWidth)。
2.5 国际化支持
- 支持 UTF-8 编码,可以显示各种语言字符,包括中文、日文、韩文等。
- 需要选择包含对应字符集的字体。
三、U8g2lib 的基本使用流程 (Arduino/ESP32 为例)
3.1 1. 安装库
在 Arduino IDE 或 PlatformIO 中搜索 U8g2 并安装。
3.2 2. 选择合适的显示器构造函数
这是 U8g2lib 使用的关键一步。根据你的显示器型号、分辨率、接口类型和缓冲模式,选择一个合适的构造函数。
构造函数命名规则: U8G2_<控制器>_<分辨率>_<模式>_<接口> [参数]
<控制器>:如SSD1306,SH1106,ST7920。<分辨率>:如128X64,128X32。<模式>:_F_:全帧缓冲 (Full Buffer)_N_:不使用帧缓冲 (No Buffer),直接写入硬件,适用于较小的显示器或极度内存受限场景。_1_:页缓冲 (Page Buffer),每次传输一个页。_2_:页缓冲,每次传输 2 个页。
<接口>:_HW_I2C:硬件 I2C_SW_I2C:软件 I2C_HW_SPI:硬件 SPI_SW_SPI:软件 SPI_8BIT_PARALLEL:8位并行接口
- [参数]:如
U8G2_R0(屏幕旋转 0 度),U8G2_R1(旋转 90 度),U8G2_R2(旋转 180 度),U8G2_R3(旋转 270 度)。
示例:
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_UNUSED, SCL, SDA);- SSD1306 控制器,128x64 分辨率,全帧缓冲,硬件 I2C 接口,不旋转。
U8X8_UNUSED表示没有硬件复位引脚。SCL,SDA是 I2C 引脚,对于硬件 I2C,通常会自动使用默认引脚,但明确指定也无妨。
U8G2_SH1106_128X64_NONAME_1_HW_SPI u8g2(U8G2_R0, 10, 9, 8, 7);- SH1106 控制器,128x64 分辨率,页缓冲 (1 页),硬件 SPI 接口,不旋转。
- 引脚参数顺序通常是:
U8G2_R0, cs, dc, res, sck, mosi(对于 SPI)。这里cs=10, dc=9, res=8, (sck=默认), (mosi=默认)。
3.3 3. 基本代码结构
1 |
|
3.4 4. 常用函数
u8g2.begin(): 初始化显示器。u8g2.clearBuffer(): 清空内部帧缓冲区(仅全帧缓冲模式)。u8g2.sendBuffer(): 将帧缓冲区内容发送到显示器(仅全帧缓冲模式)。u8g2.firstPage()/u8g2.nextPage(): 用于页缓冲模式的循环。u8g2.setFont(const u8g2_font_t *font): 设置当前字体。u8g2.drawStr(u8g2_uint_t x, u8g2_uint_t y, const char *s): 在指定位置绘制字符串。u8g2.drawUTF8(u8g2_uint_t x, u8g2_uint_t y, const char *s): 绘制 UTF-8 编码的字符串。u8g2.drawPixel(u8g2_uint_t x, u8g2_uint_t y): 画点。u8g2.drawLine(u8g2_uint_t x1, u8g2_uint_t y1, u8g2_uint_t x2, u8g2_uint_t y2): 画线。u8g2.drawBox(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h): 绘制填充矩形。u8g2.drawFrame(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h): 绘制矩形边框。u8g2.drawCircle(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad, uint8_t opt): 绘制圆。u8g2.setCursor(u8g2_uint_t x, u8g2_uint_t y): 设置文本光标位置。u8g2.print(...): 类似Serial.print(),用于在当前光标位置打印数据。u8g2.getDisplayWidth()/u8g2.getDisplayHeight(): 获取显示器宽度和高度。
四、高级特性与优化
字体选择:U8g2lib 的字体名称通常包含信息,如
u8g2_font_ncenB14_tr:ncen:字体家族 (New Century Schoolbook)B:粗体 (Bold)14:字高 (14 像素)tr:透明 (Transparent),即背景不绘制。tf表示填充 (Filled) 背景。
选择合适的字体对于优化显示效果和内存占用很重要。
自定义字体:使用
bdfconv工具将.bdf字体文件转换为 C 数组,并集成到项目中。电源管理:
u8g2.setPowerSave(0)(打开屏幕),u8g2.setPowerSave(1)(关闭屏幕),在需要省电时非常有用。对比度设置:
u8g2.setContrast(value)可以调整 OLED 显示器的亮度。旋转与翻转:在构造函数中选择
U8G2_R0到U8G2_R3进行旋转,u8g2.setFlipMode(1)可以进行水平/垂直翻转。内存优化 (Page Buffer):
- 在内存受限的设备上,优先使用页缓冲模式 (
_1_或_N_)。 u8g2.firstPage(); do { ... } while(u8g2.nextPage());是页缓冲模式的标准循环结构。
- 在内存受限的设备上,优先使用页缓冲模式 (
动画:
- 全帧缓冲模式更适合动画,因为可以在内存中高效绘制多帧,然后快速刷新。
- 页缓冲模式下实现动画需要更精细的绘制控制,可能需要在每个
nextPage()迭代中更新动画元素。
五、U8g2lib 与 U8glib 的区别
U8g2lib 是 U8glib 的现代版本,主要改进包括:
- 内存优化:U8g2lib 提供了更灵活的内存管理(全帧缓冲、页缓冲、无缓冲),特别是在页缓冲模式下更加高效。
- 统一 API:U8g2lib 的 API 设计更加统一和简洁。
- 字体改进:支持的字体更多,并且对字体的渲染和管理进行了优化。
- 国际化:更好的 UTF-8 支持。
- 硬件支持:支持更多新型显示器控制器。
对于新项目,强烈推荐使用 U8g2lib。
六、总结
U8g2lib 是嵌入式领域中一个非常成熟和强大的单色图形库。它以其广泛的硬件兼容性、灵活的缓冲模式、丰富的字体和全面的图形绘制功能,极大地简化了单色显示器的开发。无论是对于内存有限的 Arduino UNO,还是资源更丰富的 ESP32,U8g2lib 都能提供高效且高质量的显示解决方案。掌握 U8g2lib 的使用,将使您能够轻松地为您的嵌入式项目创建富有表现力的用户界面。
