🖼️ ESP32 墨水屏实战:从点亮到低功耗物联网终端
📅 2026-05-31 · 📂 硬件编程 · ⏱ 阅读约 7 分钟
📺 B站推荐视频:[Mpy]全网最简单最易学的esp32驱动墨水屏的教程!
📖 概述
墨水屏(E-Paper / E-Ink)是一种基于电泳技术的反射式显示屏。它最大的特点是断电后图像仍然保持,零功耗维持显示内容。在阳光下清晰可读、无蓝光伤害,是电子价签、物联网信息终端、电子日历的首选显示方案。
本文将基于 ESP32 + Waveshare 2.9 寸墨水屏模块,带你从接线、驱动库安装到完整代码,实现图片显示、文字绘制和局部刷新三大核心技能。学完之后,你可以结合之前学过的 WiFi(5/6)和低功耗(5/17),打造一个用电池续航数月的无线信息终端。
💡 墨水屏 vs TFT/LCD:墨水屏不需要背光,靠环境光反射显示,像纸一样。刷新一次后可以断电,图像永久保留。缺点是刷新速度较慢(全刷约2-3秒)、只有黑白(带红/黄的版本稍贵),不适合播放视频和快速动画。
📦 物料清单
| 物料 | 型号/参数 | 参考价格(¥) |
| 主控板 | ESP32 DevKit V1 (38Pin) | 18 ~ 30 |
| 墨水屏模块 | Waveshare 2.9" E-Paper (B/W) 296×128 | 55 ~ 75 |
| 墨水屏模块 | Waveshare 2.9" E-Paper (B/W/R) 296×128 三色 | 65 ~ 85 |
| 杜邦线 | 母对母 10cm × 8 根 | 3 ~ 5 |
| 面包板 | 830 孔 | 5 ~ 10 |
| USB 数据线 | Micro USB | 已有 |
推荐入门选择 Waveshare 2.9" 黑白版,性价比高、驱动的兼容性好。如果你确定需要红色标注功能(如温度超阈值标红),可以选三色版,但刷新时间是黑白版的2倍(约15秒)。
🔌 接线图
墨水屏采用 SPI 通信协议,需要连接 7 根信号线 + VCC/GND。以下接线适配 Waveshare E-Paper Driver HAT 的默认引脚:
Waveshare 2.9" E-Paper → ESP32 DevKit V1
═══════════════════════════════════════════
VCC (红) → 3.3V
GND (黑) → GND
DIN (蓝/MOSI) → GPIO 23 (VSPI MOSI)
SCLK (绿/SCK) → GPIO 18 (VSPI SCK)
CS (黄/片选) → GPIO 5
DC (橙/数据指令) → GPIO 17
RST (棕/复位) → GPIO 16
BUSY (紫/忙检测) → GPIO 4
💡 关于电平:Waveshare 2.9" 墨水屏模块板载电平转换,支持 3.3V/5V。ESP32 的 3.3V GPIO 直接连接即可,不需要额外的电平转换模块。
💻 基础代码:显示文字与图片
Arduino IDE 中搜索安装 GxEPD2 库(作者:Jean-Marc Zingg),它支持市面上几乎所有主流墨水屏型号。
1. 环境配置
在 Arduino IDE 的库管理器中搜索 GxEPD2,安装最新版本(会自动安装依赖库 Adafruit GFX)。
2. 完整示例代码:显示文字、线条和位图
// ESP32 + Waveshare 2.9" E-Paper (B/W) 完整示例
// 功能:显示中文标题、绘制表格、显示自定义位图
#include <GxEPD2_BW.h> // 黑白墨水屏用 BW,三色用 3C
// 根据型号选择对应的类 —— 2.9" 296×128 黑白屏
GxEPD2_BW<GxEPD2_290, GxEPD2_290::HEIGHT> display(
GxEPD2_290(/*CS=*/5, /*DC=*/17, /*RST=*/16, /*BUSY=*/4)
);
void setup() {
Serial.begin(115200);
Serial.println("墨水屏初始化中...");
display.init(115200); // SPI 通信初始化
display.setRotation(1); // 横屏显示(旋转90度)
// ===== 第一页:标题与文字 =====
display.setFullWindow(); // 全屏刷新模式
display.firstPage();
do {
display.fillScreen(GxEPD_WHITE); // 白色背景
// 标题栏
display.fillRect(0, 0, 296, 36, GxEPD_BLACK);
display.setTextColor(GxEPD_WHITE);
display.setFont(&FreeSansBold12pt7b);
display.setCursor(10, 26);
display.print("ESP32 E-Paper");
// 信息行
display.setTextColor(GxEPD_BLACK);
display.setFont(&FreeSans9pt7b);
display.setCursor(10, 66);
display.print("Temp: 26.5 C");
display.setCursor(10, 86);
display.print("Humi: 58 %");
// 分隔线
display.drawLine(0, 100, 296, 100, GxEPD_BLACK);
// 页脚
display.setFont(&FreeMono9pt7b);
display.setCursor(10, 120);
display.print("2026-05-31 06:30");
}
while (display.nextPage());
Serial.println("显示完成!进入深度睡眠...");
// 显示完成后进入深度睡眠,功耗低至 ~10uA
display.hibernate();
esp_deep_sleep_start();
}
void loop() {
// 永远不会执行到这里(深度睡眠后重启)
}
💡 代码解析:
• firstPage() / nextPage() 是 GxEPD2 特有的分页绘制模式,框架自动处理显存分配
• hibernate() 让墨水屏进入超低功耗状态,配合 ESP32 deep_sleep() 实现电池长续航
• 如果要显示中文,需要搭配 U8g2_for_Adafruit_GFX 库渲染中文字体
🚀 进阶应用
1. 局部刷新(Partial Update)
全屏刷新约 2-3 秒且有闪烁。GxEPD2 支持局部刷新,只更新屏幕的一部分,速度更快且无闪烁:
// 局部刷新示例 —— 只更新温湿度数字区域
display.setPartialWindow(10, 50, 200, 40); // 局部窗口 x,y,w,h
display.firstPage();
do {
display.fillRect(10, 50, 200, 40, GxEPD_WHITE); // 清空区域
display.setCursor(10, 78);
display.print("Temp: 27.1 C");
} while (display.nextPage());
⚠️ 局部刷新的"鬼影"问题:频繁局部刷新会在屏幕留下淡淡的残影。建议每 10-20 次局部刷新后,执行一次全屏刷新来清除残影。GxEPD2 提供了 display.powerOff() + 延时 + display.init() 的清理技巧。
2. 显示自定义位图
使用 image2cpp 在线工具(javl.github.io/image2cpp),将 PNG/JPG 图片转换为 Arduino 位图数组,然后用 drawBitmap() 方法显示:
// 墨水屏显示自定义 Logo(296×128 黑白位图)
static const unsigned char logo_bitmap[] PROGMEM = {
// image2cpp 生成的数组 —— 296*128/8 = 4736 字节
0xff, 0xff, 0xff, /* ... 4736 bytes total ... */
};
void showLogo() {
display.setFullWindow();
display.firstPage();
do {
display.drawBitmap(0, 0, logo_bitmap, 296, 128, GxEPD_BLACK);
} while (display.nextPage());
}
3. 无线更新显示内容
结合之前学过的 WiFi(5/6)+ HTTP(5/7)知识,可通过 HTTP GET 请求获取天气/新闻数据,刷新到墨水屏上:
// 伪代码:WiFi 获取天气 → 墨水屏显示
connectWiFi("SSID", "PASSWORD");
String weather = httpGet("http://api.weatherapi.com/v1/current.json?...&q=Shanghai");
display.setPartialWindow(0, 40, 296, 80);
display.firstPage();
do {
display.setCursor(10, 65);
display.print(weather); // 天气数据直接输出到屏幕
} while (display.nextPage());
display.hibernate(); // 显示完休眠,等着下次唤醒
esp_deep_sleep(600 * 1000000); // 10分钟后唤醒刷新
🏗️ 实战场景
场景一:桌面天气预报站
功能描述:每天早上自动更新当日天气,墨水屏持续显示,零功耗维持。整机电池供电,一次充电用3个月以上。
物料组合:ESP32 + Waveshare 2.9" E-Paper + 18650 电池 + TP4056 充电模块
联动已学模块:
| 功能 | 使用模块 | 对应教程 |
| 联网获取天气 | WiFi + HTTP Client | 5/6、5/7 |
| 低功耗长续航 | Deep Sleep + 墨水屏休眠 | 5/17 |
| 温湿度本地监测 | DHT22 传感器 | 5/16 |
| 显示输出 | 墨水屏(本文) | 5/31 |
场景二:电子墨水价签 / 办公桌牌
功能描述:通过手机 BLE 连接 ESP32,发送文字或二维码到墨水屏显示。适合会议室桌牌、仓库货架标签、展览展品说明牌。
物料组合:ESP32 + 2.9" E-Paper + (可选)3D打印外壳
联动已学模块:
| 功能 | 使用模块 | 对应教程 |
| 手机无线控制 | BLE 蓝牙通信 | 5/10、5/11 |
| 图形化显示 | 墨水屏 + 中文字库 | 5/31 |
| 二维码生成 | qrcode 库(Arduino) | 扩展自学 |
⚠️ 常见问题
⚠️ 屏幕白屏无任何显示
这是最常见的入坑问题。排查顺序:① 检查 BUSY 引脚接线(最容易被忽略的一根线);② 确认 SPI 引脚是否与代码中一致(CS=5, DC=17, RST=16, BUSY=4);③ 确认库中选用的型号类是否正确(GxEPD2_290 是 2.9" 黑白版,三色版要用 GxEPD2_290_3C)。
⚠️ 显示内容模糊或有很多横纹
通常是供电不足。墨水屏刷新时峰值电流可达 40mA。务必使用 ESP32 的 3.3V 引脚供电而非 5V + 面包板分压。如果你的 ESP32 板载 3.3V LDO 功率不足(如某些 Mini D1 板),改用独立 3.3V 稳压模块供电。
⚠️ 长时间显示不动后出现残影/"烧屏"
墨水屏并不是真的"烧屏",而是长时间保持同一画面后电荷残留。处理方法:① 代码中先全屏显示白色再刷新内容;② 不要超过 24 小时不刷新;③ 如果已出现残影,连续全屏黑白交替刷新 5-10 次可恢复。
⚠️ 不支持在阳光下暴晒
墨水屏的工作温度通常在 0°C ~ 50°C 之间。阳光直射导致屏幕温度超过 50°C 时,黑色会变灰甚至永久损伤。户外使用建议加遮阳罩,或者选用宽温墨水屏模组。
📚 小结与下期预告
今天你解锁了 ESP32 驱动墨水屏的完整技能链:SPI 接线 → GxEPD2 库 → 全屏/局部刷新 → 自定义位图 → 低功耗休眠。结合 WiFi + BLE + 低功耗,你可以做出真正可落地的物联网终端产品。
下一期,我们将深入工业通信领域,学习 RS485 总线——如何在一条双绞线上挂载上百个设备,并实现千米级的可靠数据传输。别错过!