跳转到内容

电子墨水屏文本渲染

电子墨水屏文本渲染

本节介绍使用 GxEPD2 和 AdaFruit GFX 库在电子纸显示屏上渲染文本。正确的文本布局对于创建可读的工厂仪表板至关重要。完成本节后,你将能够:

  • 在电子纸屏幕的各个位置显示文本
  • 使用内置字体更改字体大小和样式
  • 水平和垂直对齐文本
  • 在单个屏幕上组合多个文本元素

开始本节前,请确保:

  • 已安装 GxEPD2 库(参见 02-03
  • 显示屏已接线并验证
  • 基本理解显示坐标

电子纸显示屏使用标准的笛卡尔坐标系,原点在左上角:

(0,0) ──────────────────────────── X(宽度)
│ +-------------------+
│ | |
│ | 显示区域 |
│ | |
│ +-------------------+
Y(高度)

对于 2.13” 显示屏(250×122 像素)

  • X 范围:0 到 249(水平)
  • Y 范围:0 到 121(垂直)
  • 文本使用 display.setCursor(x, y) 放置

AdaFruit GFX 库提供多种内置字体:

字体名称大小用例
(默认)5×7 px最小文本、调试输出
&FreeMono9pt7b9pt 等宽表格数据
&FreeMonoBold12pt7b12pt 粗体等宽标题、KPI
&FreeMonoBold18pt7b18pt 粗体等宽大数字
&FreeMonoBold24pt7b24pt 粗体等宽非常大数值
&FreeSans9pt7b9pt 无衬线正文
&FreeSansBold12pt7b12pt 粗体无衬线章节标题
&FreeSerif12pt7b12pt 衬线装饰性文本
&TomThumb3×5 px超小标签

字体命名约定&FontNameSizept7b 其中:

  • & 是引用字体时必需的前缀
  • 7b 表示 7 位字符编码(标准 ASCII)
#include <GxEPD2_BW.h>
#define EPD_CS 5
#define EPD_DC 17
#define EPD_RST 16
#define EPD_BUSY 4
GxEPD2_BW<GxEPD2_213_B72, GxEPD2_213_B72::HEIGHT> display(
GxEPD2_213_B72(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)
);
void setup() {
Serial.begin(115200);
display.init(115200);
display.setRotation(1); // 横向
// 清除屏幕
display.fillScreen(GxEPD_WHITE);
// 在指定坐标绘制文本
display.setCursor(10, 20);
display.print("第1行:工厂显示屏");
display.setCursor(10, 35);
display.print("第2行:温度:25.5°C");
display.setCursor(10, 50);
display.print("第3行:湿度:60%");
// 推送显示
display.display();
}
void loop() {}

预期结果:左侧显示三行小文本。

#include <GxEPD2_BW.h>
GxEPD2_BW<GxEPD2_213_B72, GxEPD2_213_B72::HEIGHT> display(
GxEPD2_213_B72(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)
);
void setup() {
display.init(115200);
display.setRotation(1);
display.fillScreen(GxEPD_WHITE);
// 默认 5x7 字体
display.setCursor(0, 10);
display.print("默认字体(5x7)");
// 9pt 等宽
display.setFont(&FreeMono9pt7b);
display.setCursor(0, 30);
display.print("9pt 等宽");
// 12pt 粗体等宽
display.setFont(&FreeMonoBold12pt7b);
display.setCursor(0, 55);
display.print("12pt 粗体");
// 18pt 粗体等宽(大数字)
display.setFont(&FreeMonoBold18pt7b);
display.setCursor(0, 85);
display.print("42.5");
display.display();
}
void loop() {}

注意:使用 setFont() 更改字体后,光标位置行为会变化。基于字体的光标使用字体的基线作为 Y 参考点,而默认字体使用左上角。

要水平居中文本,使用文本边界计算位置:

#include <GxEPD2_BW.h>
GxEPD2_BW<GxEPD2_213_B72, GxEPD2_213_B72::HEIGHT> display(
GxEPD2_213_B72(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)
);
void centerText(const char* text, int y, const GFXfont* font) {
display.setFont(font);
// 获取文本边界
int16_t x1, y1;
uint16_t w, h;
display.getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
// 计算居中的 X 位置
int16_t x = (display.width() - w) / 2;
// 在居中位置绘制文本
display.setCursor(x, y);
display.print(text);
}
void setup() {
display.init(115200);
display.setRotation(1);
display.fillScreen(GxEPD_WHITE);
// 标题居中
display.setTextColor(GxEPD_BLACK);
display.setFont(&FreeMonoBold12pt7b);
centerText("工厂状态", 25, &FreeMonoBold12pt7b);
// 温度值居中
centerText("温度:25.5°C", 60, &FreeMono9pt7b);
// 湿度值居中
centerText("湿度:60%", 85, &FreeMono9pt7b);
display.display();
}
void loop() {}

电子纸显示屏支持 4 种旋转模式:

// 旋转值
display.setRotation(0); // 0° - 竖屏(默认)
display.setRotation(1); // 90° - 横屏
display.setRotation(2); // 180° - 倒置竖屏
display.setRotation(3); // 270° - 倒置横屏

工厂仪表板通常使用

  • 旋转 1(横屏):用于更宽的数据表显示
  • 旋转 0(竖屏):用于 KPI 式单值显示
void displayText(const char* title, const char* value1, const char* value2) {
display.fillScreen(GxEPD_WHITE);
// 标题
display.setFont(&FreeMonoBold12pt7b);
display.setCursor(5, 25);
display.print(title);
// 水平分隔线
display.drawFastHLine(0, 35, display.width(), GxEPD_BLACK);
// 值 1
display.setFont(&FreeMono9pt7b);
display.setCursor(5, 55);
display.print(value1);
// 值 2
display.setCursor(5, 80);
display.print(value2);
display.display();
}
// 在 setup() 中使用:
// displayText("工厂 A", "温度:25.5°C", "湿度:60%");

上传文本渲染草图后,验证:

  • 文本出现在预期位置
  • 不同字体正确显示
  • 居中文本正确对齐
  • 旋转按预期改变方向
  • 文本可读(白底黑字)

症状

  • 随机字符而非可读文本

解决方案

  • 确保字体引用时带有 & 前缀(例如 &FreeMono9pt7b
  • 检查字体是否在草图作用域内定义
  • 不要在字体更改之间意外使用 setFont(NULL)

症状

  • 文本超出显示边界
  • 文本底部缺失

解决方案

  • 在绘图前使用 display.getTextBounds() 测量文本宽度
  • 确保 Y 位置考虑了字体高度(较大字体需要更多垂直空间)
  • 减小字体大小或文本行长度

症状

  • 居中文本未真正居中
  • 多行文本未垂直对齐

解决方案

// 使用辅助函数实现一致对齐
int16_t getCenteredX(const char* text, const GFXfont* font) {
display.setFont(font);
int16_t x1, y1;
uint16_t w, h;
display.getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
return (display.width() - w) / 2;
}
  • 表格数据使用等宽字体——确保列正确对齐
  • KPI 首选粗体字体——远距离阅读效果更好
  • 预先计算文本边界以实现可靠居中
  • 避免在工厂车间使用小字体(< 9pt)
  • 不要在单个屏幕上混合过多字体大小——最多保持在 2-3 种
  • 避免不必要的字体更改——每次 setFont() 调用都会增加处理开销

模板 1:单一 KPI(工厂 KPI 看板)

┌─────────────────────────────────────┐
│ 生产线 A │ ← 12pt 粗体,居中
├─────────────────────────────────────┤
│ │
│ 25,847 │ ← 24pt 粗体,居中
│ 今日产量 │ ← 9pt,居中
│ │
│ 目标:30,000 │ 同比 +5.3% │ ← 9pt 等宽,两列
└─────────────────────────────────────┘

模板 2:多传感器读数

┌─────────────────────────────────────┐
│ 环境监测 │ 14:30 │ ← 带时间的标题
├─────────────────────────────────────┤
│ 温度 │ 25.5°C │ 正常 │
│ 湿度 │ 60% │ 正常 │
│ 气压 │ 1013hPa │ 稳定 │
│ 光照 │ 450 lux │ 良好 │
└─────────────────────────────────────┘
  1. 文本渲染使用 AdaFruit GFX 原语——setCursor()setFont()print()
  2. 字体选择影响光标行为——基于字体的字体使用基线 Y 坐标
  3. 使用 getTextBounds() 进行精确定位——居中和对齐的关键
  4. 显示旋转改变坐标系——在初始化时设置一次
  5. 保持文本布局简洁——最多 2-3 种字体大小以确保可读性