《Arduino 手册(思路与案例)》栏目介绍:
在电子制作与智能控制的应用领域:广泛涉及了Arduino BLDC、Arduino CNC、Arduino ESP32 SPP、Arduino FreeRTOS、Arduino FOC、Arduino GRBL、Arduino HTTP、Arduino HUB75、Arduino IoT Cloud、Arduino JSON、Arduino LCD、Arduino OLED、Arduino LVGL、Arduino PID 及 Arduino TFT 等方面的相关拓展思路和众多参考案例。本专栏目前博客近2300篇。
https://blog.csdn.net/weixin_41659040/category_12422453.html
Arduino是一个开放源码的电子原型平台,它可以让你用简单的硬件和软件来创建各种互动的项目。Arduino的核心是一个微控制器板,它可以通过一系列的引脚来连接各种传感器、执行器、显示器等外部设备。Arduino的编程是基于C/C++语言的,你可以使用Arduino IDE(集成开发环境)来编写、编译和上传代码到Arduino板上。Arduino还有一个丰富的库和社区,你可以利用它们来扩展Arduino的功能和学习Arduino的知识。
Arduino的特点是:
1、开放源码:Arduino的硬件和软件都是开放源码的,你可以自由地修改、复制和分享它们。
2、易用:Arduino的硬件和软件都是为初学者和非专业人士设计的,你可以轻松地上手和使用它们。
3、便宜:Arduino的硬件和软件都是非常经济的,你可以用很低的成本来实现你的想法。
4、多样:Arduino有多种型号和版本,你可以根据你的需要和喜好来选择合适的Arduino板。
5、创新:Arduino可以让你用电子的方式来表达你的创意和想象,你可以用Arduino来制作各种有趣和有用的项目,如机器人、智能家居、艺术装置等。
Arduino E-Ink(电子墨水屏) 是近年来在低功耗嵌入式显示系统中广泛应用的一种新型显示技术。它与传统 TFT、OLED 等屏幕有着本质区别,特别适用于需要长时间静态显示、低刷新频率、节能的场景。
一、主要特点
- 超低功耗
E-Ink 屏幕仅在刷新画面时消耗电力,显示内容保持不变时几乎不耗电。
非常适合电池供电设备或太阳能供电系统,可显著延长续航时间。 - 阳光下可视性强
借助环境光反射原理,E-Ink 屏幕在强光下依旧清晰可见,优于 OLED 和 LCD。
无背光设计使其更适合户外或高亮度环境下的使用。 - 黑白/灰阶显示为主
大多数 E-Ink 屏幕为单色(黑白)或有限灰阶(如 3bit),色彩表现能力弱于 TFT 或 OLED。
这使得其更适用于文字、图标、仪表等简洁信息的展示。 - 刷新率低,不适合动态内容
刷新一次通常需要几百毫秒至数秒,且频繁刷新会导致残影问题。
不适合播放视频、动画或实时图形更新类应用。 - 驱动复杂度较高
相比普通字符型 LCD,E-Ink 屏幕需要精确控制波形驱动(Driver Waveform),否则容易出现残影或老化现象。
通常依赖专用库(如 GxEPD2、Adafruit_EPD)进行图像缓冲和刷新控制。 - 寿命长,耐久性好
E-Ink 屏幕具有很高的耐久性,理论上可支持数十万次刷新,不易老化。
对比 OLED 的“烧屏”风险,E-Ink 更加稳定可靠。
二、应用场景
- 智能标签(Smart Label)
应用于零售行业,作为货架价格标签、库存管理标签等,可远程更新商品信息。
示例:超市电子价签系统。 - 智能家居显示终端
显示温湿度、空气质量、日程提醒、门锁状态等信息。
可作为壁挂式低功耗家庭信息中心。 - 便携式电子设备
如电子书阅读器(Kindle)、智能手表辅助显示界面、户外导航设备等。
特别适合需要长时间待机、无需频繁刷新的设备。 - 农业与环境监测
在温室大棚、气象站、水质检测点部署低功耗显示屏,展示传感器数据。
示例:太阳能供电的空气污染监测站显示模块。 - 工业与物流追踪
工业设备状态显示面板、资产追踪标签、运输过程中的温湿度记录仪等。
支持无线通信 + E-Ink 的组合方案,实现远程监控。
三、注意事项
- 刷新策略优化
避免不必要的刷新操作,尽量采用局部刷新(Partial Refresh)减少闪烁与延迟。
全局刷新(Full Update)虽然显示效果更好,但耗时较长且易造成视觉不适。 - 内存占用问题
E-Ink 屏幕分辨率较高时,帧缓冲区(Frame Buffer)会占用大量 RAM。
对于 Arduino UNO/Nano 等低端设备,建议选择小尺寸或使用外部 SRAM 缓冲。 - 驱动库的选择与配置
推荐使用主流开源库如:
GxEPD2:功能强大,支持多种 E-Ink 模块。
Adafruit_EPD:适用于 Adafruit 自家模块。
注意 SPI 速率、引脚映射、复位逻辑是否匹配硬件。 - 避免残影与图像老化
长时间显示相同内容可能导致“图像残留”,称为“残影效应”。
建议定期执行“清除刷新”(Clear Update)或随机扰动内容布局来缓解。 - 电源管理策略
可结合 Arduino 的休眠模式,在非工作时段关闭屏幕供电或进入低功耗模式。
使用 MOSFET 控制屏幕电源,进一步降低待机电流。 - 开发调试难度较大
由于刷新速度慢,调试过程中需耐心等待每次更新结果。
建议先在 TFT/OLED 上验证逻辑,再迁移到 E-Ink 平台。
在 Arduino 项目中,E-Ink 之循环更新进度条(Cyclic Progress Bar on E-Ink Display) 是一种将任务执行状态以图形化方式呈现在电子墨水屏上的技术。由于 E-Ink 屏幕的刷新机制和功耗特性,这种“动态”进度条的设计需要兼顾显示效果、用户体验与系统资源之间的平衡。
一、主要特点
- 低功耗下的“伪动态”更新
E-Ink 屏幕仅在刷新时消耗电能,因此即使实现“循环更新”的进度条,其整体功耗仍远低于 TFT 或 OLED。
进度条的变化是“伪动态”的,即通过定时刷新局部区域或整个屏幕来模拟动画效果。 - 刷新率限制明显
刷新一次通常需要几百毫秒到数秒,不适合高频更新。
因此,进度条的更新频率应控制在合理范围(如每秒一次或更慢),以避免闪烁或残影。 - 支持局部刷新(Partial Update)
部分 E-Ink 模块支持局部刷新功能,可以只更新进度条部分区域,减少全屏刷新带来的延迟和视觉干扰。
可显著提升用户体验并延长屏幕寿命。 - 图形绘制能力有限但足够
借助图形库(如 GxEPD2、Adafruit GFX)可轻松绘制矩形、填充矩形等基本形状,用于构建进度条。
虽然不能实现复杂的渐变或色彩过渡,但对于黑白进度条已足够清晰直观。 - 适合周期性任务展示
可用于表示定时任务、传感器采集周期、数据上传过程等,帮助用户理解设备运行状态。
二、应用场景
- 智能农业监测系统
显示土壤湿度采集或灌溉任务的完成进度,提示用户当前阶段。 - 远程气象站
在数据采集过程中,用进度条表示传感器轮询进度或数据打包上传状态。 - 电池电量指示器
结合电压检测模块,用进度条形式显示电池剩余电量,替代传统数字显示。 - 物联网设备状态反馈
在设备启动、配置同步、固件更新等操作中,提供可视化进度反馈。 - 教育类嵌入式项目
教学演示中用于说明任务调度、定时器中断等功能,增强学生对系统行为的理解。
三、注意事项
- 刷新策略优化
避免频繁刷新:建议设定一个合理的刷新间隔(如 500ms~1s),以平衡响应速度与视觉体验。
优先使用局部刷新:若硬件支持,尽量只刷新进度条所在的区域,而非整屏刷新。 - 内存管理
绘制图形会占用帧缓冲区(Frame Buffer),高分辨率屏幕可能超出低端 Arduino 的 RAM 容量。
推荐使用小尺寸屏幕(如 2.13"、2.9")或选择支持外部缓存的控制器(如 ESP32)。 - 驱动库适配与调试
使用主流开源库:
GxEPD2:功能强大,支持多种 E-Ink 模块。
Adafruit_EPD:适用于 Adafruit 自家模块。
注意 SPI 速率、引脚映射、复位逻辑是否匹配硬件。 - 防止图像残留(残影)
长时间在同一位置刷新相同内容可能导致残影。
建议定期执行全屏刷新或轻微扰动进度条位置,防止老化。 - 界面设计优化
合理设置进度条长度与位置,确保在不同分辨率下都能清晰显示。
可配合文字说明(如百分比)提升信息传达效率。 - 电源管理优化
在非刷新时段关闭屏幕供电,可使用 MOSFET 控制 VCC。
结合 Arduino 的休眠模式进一步降低整体功耗。
1、基础循环更新进度条
#include <GxEPD2_BW.h> // 引入单色E-Ink显示屏库
#define EPD_CS 5
#define EPD_DC 0
#define EPD_RST 2
#define EPD_BUSY 15
GxEPD2_BW<GxEPD2_213_B72, GxEPD2_213_B72::HEIGHT> epd(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY);
void setup() {
epd.init(115200); // 初始化E-Ink显示屏,设置波特率
epd.setRotation(1); // 设置屏幕旋转方向
}
void loop() {
for (int i = 0; i <= 100; i++) {
epd.fillScreen(GxEPD_WHITE); // 清屏
epd.setTextColor(GxEPD_BLACK); // 设置文本颜色为黑色
epd.setTextSize(2); // 设置文本大小
epd.setCursor(10, 30); // 设置文本起始位置
epd.print("Progress: ");
epd.print(i);
epd.print("%");
epd.fillRect(10, 50, i * 2, 10, GxEPD_BLACK); // 绘制进度条
epd.display(); // 显示内容
delay(100); // 控制进度条更新速度
}
}
要点解读:
进度条绘制:通过epd.fillRect函数绘制进度条,进度条的长度根据当前进度动态调整。
动态更新:使用for循环逐步增加进度条的长度,模拟进度的增加。
屏幕刷新:每次更新进度条后调用epd.display函数刷新屏幕,显示新的进度条。
2、带文本提示的循环更新进度条
#include <GxEPD2_BW.h> // 引入单色E-Ink显示屏库
#define EPD_CS 5
#define EPD_DC 0
#define EPD_RST 2
#define EPD_BUSY 15
GxEPD2_BW<GxEPD2_213_B72, GxEPD2_213_B72::HEIGHT> epd(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY);
void setup() {
epd.init(115200); // 初始化E-Ink显示屏,设置波特率
epd.setRotation(1); // 设置屏幕旋转方向
}
void loop() {
for (int i = 0; i <= 100; i++) {
epd.fillScreen(GxEPD_WHITE); // 清屏
epd.setTextColor(GxEPD_BLACK); // 设置文本颜色为黑色
epd.setTextSize(2); // 设置文本大小
epd.setCursor(10, 30); // 设置文本起始位置
epd.print("Progress: ");
epd.print(i);
epd.print("%");
epd.fillRect(10, 50, i * 2, 10, GxEPD_BLACK); // 绘制进度条
epd.display(); // 显示内容
delay(100); // 控制进度条更新速度
}
}
要点解读:
文本提示:在进度条上方显示当前进度的百分比,增强用户对进度的直观感受。
动态更新:进度条的长度和文本提示同步更新,确保信息的一致性。
屏幕刷新:每次更新后刷新屏幕,显示新的进度条和文本提示。
3、模拟任务执行的循环更新进度条
#include <GxEPD2_BW.h> // 引入单色E-Ink显示屏库
#define EPD_CS 5
#define EPD_DC 0
#define EPD_RST 2
#define EPD_BUSY 15
GxEPD2_BW<GxEPD2_213_B72, GxEPD2_213_B72::HEIGHT> epd(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY);
void setup() {
epd.init(115200); // 初始化E-Ink显示屏,设置波特率
epd.setRotation(1); // 设置屏幕旋转方向
}
void loop() {
for (int i = 0; i <= 100; i++) {
epd.fillScreen(GxEPD_WHITE); // 清屏
epd.setTextColor(GxEPD_BLACK); // 设置文本颜色为黑色
epd.setTextSize(2); // 设置文本大小
epd.setCursor(10, 30); // 设置文本起始位置
epd.print("Task Progress: ");
epd.print(i);
epd.print("%");
epd.fillRect(10, 50, i * 2, 10, GxEPD_BLACK); // 绘制进度条
epd.display(); // 显示内容
delay(100); // 控制进度条更新速度
}
}
要点解读:
任务模拟:通过循环逐步增加进度条的长度,模拟任务的执行过程。
进度条绘制:进度条的长度根据当前进度动态调整,直观显示任务的完成情况。
屏幕刷新:每次更新进度条后调用epd.display函数刷新屏幕,显示新的进度条。
4、基于ESP32的SPI接口E-Ink进度条(实时数据监控)
#include <GxEPD2_BW.h>
#include <GxEPD2_3C.h>
#include <Fonts/FreeMonoBold9pt7b.h>
#define EPD_CS 5
#define EPD_DC 17
#define EPD_RESET 16
#define EPD_BUSY 4
GxEPD2_BW<GxEPD2_154_T8, GxEPD2_154_T8::HEIGHT> display(GxEPD2_154_T8(/*CS=*/ EPD_CS, /*DC=*/ EPD_DC, /*RST=*/ EPD_RESET, /*BUSY=*/ EPD_BUSY));
void setup() {
display.init();
display.setRotation(1);
display.fillScreen(GxEPD_WHITE);
display.setTextColor(GxEPD_BLACK);
display.setFont(&FreeMonoBold9pt7b);
}
void loop() {
static int progress = 0;
static unsigned long startTime = millis();
// 更新进度条(0-100%)
display.fillRect(10, 10, 200, 20, GxEPD_WHITE); // 清除旧进度条
display.fillRect(10, 10, 200 * progress / 100, 20, GxEPD_BLACK); // 绘制新进度条
// 显示剩余时间(假设总耗时10秒)
int elapsed = (millis() - startTime) / 1000;
int remaining = max(0, 10 - elapsed);
display.setCursor(10, 40);
display.print("剩余时间: ");
display.print(remaining);
display.print("秒");
display.display(); // 刷新屏幕
progress = (progress + 1) % 101; // 循环进度
delay(1000); // 1秒更新一次
}
要点解读
硬件接口:使用ESP32的SPI接口驱动E-Ink,需配置CS、DC、RST、BUSY引脚。
双缓冲机制:通过fillRect清除旧进度条区域,避免画面闪烁。
时间计算:基于millis()函数计算剩余时间,模拟真实下载场景。
5、基于STM32的I²C接口E-Ink进度条(低功耗设备)
#include <Wire.h>
#include <GxEPD2_BW.h>
#define EPD_I2C_ADDR 0x3C
GxEPD2_BW<GxEPD2_154_T8, GxEPD2_154_T8::HEIGHT> display(EPD_I2C_ADDR);
void setup() {
Wire.begin();
display.init();
display.setRotation(1);
display.fillScreen(GxEPD_WHITE);
}
void loop() {
static int batteryLevel = 0;
// 模拟电池充电(每5秒增加10%)
display.fillRect(10, 10, 200, 20, GxEPD_WHITE);
display.fillRect(10, 10, 200 * batteryLevel / 100, 20, GxEPD_BLACK);
// 显示电量百分比
display.setCursor(10, 40);
display.print("电量: ");
display.print(batteryLevel);
display.print("%");
display.display();
batteryLevel = (batteryLevel + 10) % 101;
// 进入低功耗模式(示例:延迟5秒)
delay(5000);
// 可添加STM32的睡眠指令(如HAL_PWR_EnterSTOPMode)
}
要点解读
I²C通信:通过Wire库初始化I²C接口,简化硬件连接。
低功耗设计:使用delay模拟低功耗延迟,实际应用中可结合STM32的STOP模式。
进度条样式:通过调整矩形宽度实现百分比映射,避免复杂计算。
6、基于Arduino Uno的并行接口E-Ink进度条(低成本方案)
#include <GxEPD2_BW.h>
// 模拟并行接口引脚定义(需根据实际硬件调整)
#define EPD_D0 2
#define EPD_D1 3
#define EPD_D2 4
#define EPD_D3 5
#define EPD_D4 6
#define EPD_D5 7
#define EPD_D6 8
#define EPD_D7 9
#define EPD_CS 10
#define EPD_DC 11
#define EPD_RST 12
#define EPD_BUSY 13
GxEPD2_BW<GxEPD2_154_T8, GxEPD2_154_T8::HEIGHT> display(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY);
void setup() {
display.init();
display.setRotation(1);
display.fillScreen(GxEPD_WHITE);
}
void loop() {
static int downloadProgress = 0;
static int initProgress = 0;
// 更新下载进度条
display.fillRect(10, 10, 200, 10, GxEPD_WHITE);
display.fillRect(10, 10, 200 * downloadProgress / 100, 10, GxEPD_BLACK);
// 更新初始化进度条
display.fillRect(10, 30, 200, 10, GxEPD_WHITE);
display.fillRect(10, 30, 200 * initProgress / 100, 10, GxEPD_BLACK);
display.display();
downloadProgress = (downloadProgress + 1) % 101;
initProgress = (initProgress + 2) % 101; // 不同速度模拟
delay(200); // 快速更新以演示并行效果
}
要点解读
并行接口:直接操作GPIO引脚模拟并行通信,需根据E-Ink模块数据手册调整时序。
多进度条:通过调整Y坐标和高度实现并行显示,适用于复杂任务监控。
性能优化:减少display.display()调用频率,避免频繁刷新导致屏幕残留。
注意,以上案例只是为了拓展思路,仅供参考。它们可能有错误、不适用或者无法编译。您的硬件平台、使用场景和Arduino版本可能影响使用方法的选择。实际编程时,您要根据自己的硬件配置、使用场景和具体需求进行调整,并多次实际测试。您还要正确连接硬件,了解所用传感器和设备的规范和特性。涉及硬件操作的代码,您要在使用前确认引脚和电平等参数的正确性和安全性。