update to 1.3.1 ver

This commit is contained in:
fsender
2023-11-07 16:41:37 +08:00
parent a8b2540468
commit 85a785eabd
31 changed files with 272 additions and 128 deletions

View File

@@ -1,3 +1,23 @@
## Release 1.3.1 - 2023/11/7
1. 增加了分步绘制的支持. 可以使用 READGUY_FAST_START 等绘制选项来控制绘制过程:
- READGUY_SLOW 慢刷, 完整的进行一次慢刷, 等于连续执行慢刷开始和慢刷结束.
- READGUY_FAST 快刷, 完整的进行一次快刷, 需要等待刷完才能继续执行代码.
- READGUY_SLOW_START 慢刷开始, 此过程不会进行等待, 发送完要刷新的缓存之后立刻返回
- READGUY_FAST_START 快刷开始.
- READGUY_SLOW_END 慢刷结束, 调用慢刷开始之后才能执行. 会等待到屏幕刷完再执行后续操作.
- READGUY_FAST_END 快刷结束, 如果两次调用间隔时间屏幕已经刷完, 那么该函数会完成刷屏后续操作之后立刻返回.
2. 修复了首次配置驱动时, 墨水屏显示页面错位的bug (现在对于新设备, 配置起来会像以前一样丝滑)
3. 修复若干其他bug
## Release 1.3.0 - 2023/11/6 ## Release 1.3.0 - 2023/11/6
1. 增加了真.保姆级的教程 (详细到注释比代码多很多倍) 1. 增加了真.保姆级的教程 (详细到注释比代码多很多倍)

View File

@@ -4,7 +4,7 @@
<img src="extra/artset/readguy_theme3.png" width="30%" height="auto"> <img src="extra/artset/readguy_theme3.png" width="30%" height="auto">
**版本1.3.0正式发布欢迎分享、star和fork~** 上面的图是项目看板娘, 盖. 可爱的盖姐在等你哟~ **版本1.3.1正式发布欢迎分享、star和fork~** 上面的图是项目看板娘, 盖. 可爱的盖姐在等你哟~
欢迎克隆, 项目交流QQ群: 926824162 (萌新可以进来问问题的哟), 项目的 Bilibili 主页: [BV1f94y187wz](https://www.bilibili.com/video/BV1f94y187wz/) 记得三连+关注我这个宝藏up主哦~ 欢迎克隆, 项目交流QQ群: 926824162 (萌新可以进来问问题的哟), 项目的 Bilibili 主页: [BV1f94y187wz](https://www.bilibili.com/video/BV1f94y187wz/) 记得三连+关注我这个宝藏up主哦~

View File

@@ -157,8 +157,8 @@ void setup(){ //Arduino的setup函数. 这个函数在上电之后仅执行一
//guy.setCursor(10,10); //设置显示的坐标 //guy.setCursor(10,10); //设置显示的坐标
//guy.print("Hello Readguy!"); //使用这个函数也能显示出字符串, 但是需要提前使用setCursor确定显示坐标 //guy.print("Hello Readguy!"); //使用这个函数也能显示出字符串, 但是需要提前使用setCursor确定显示坐标
guy.display(true); // 快速刷新. 将屏幕缓存内的内容显示到墨水屏幕上. 可简写为 guy.display(), 效果一样. guy.display(READGUY_FAST); // 快速刷新. 将屏幕缓存内的内容显示到墨水屏幕上. 可简写为 guy.display(), 效果一样.
//guy.display(false); // 慢速刷新. //guy.display(READGUY_SLOW); // 慢速刷新.
//想知道更多内容, 欢迎移步到其他示例. //想知道更多内容, 欢迎移步到其他示例.
} }

View File

@@ -11,6 +11,25 @@
* @brief ReadGuy功能演示. * @brief ReadGuy功能演示.
* 将根目录下的data文件夹 上传到LittleFS之后运行效果更佳 * 将根目录下的data文件夹 上传到LittleFS之后运行效果更佳
* 或者可以准备一张SD卡,并准备在卡的根目录下放置data文件夹内的文件. * 或者可以准备一张SD卡,并准备在卡的根目录下放置data文件夹内的文件.
* 就是SD卡内放data文件夹内的所有文件, 不能额外套文件夹.
* 如果你的SD卡插入电脑上显示为可移动磁盘, 那么双击SD卡目录就要看到这个文件夹里的文件
*
* 默认的文件系统为SD卡. 当没有插入SD卡时, 会读取LittleFS文件系统.
* 没有条件准备SD卡的, 可以烧录LittleFS文件系统.
*
* 对于ESP8266 Arduino 用户, 在项目草图文件夹内新建一个data文件夹, 并放入文件 (示例已提供data文件夹)
* 再在 arduinoIDE 的工具选项里选择 ESP8266 LittleFS Data Upload.
* 没有这个选项的需要参考以下文档安装ESP8266 Sketch upload tool
* https://randomnerdtutorials.com/install-esp8266-nodemcu-littlefs-arduino/
*
* 对于ESP32 Arduino 用户, 也要在项目草图文件夹内放一个data文件夹, 并把文件放入其中 (示例已提供data文件夹)
* 再在 arduinoIDE 的工具选项里选择 ESP32 Sketch data upload, 最后选择LittleFS.
* 没有这个选项的需要参考以下文档安装ESP32 LittleFS upload tool
* https://randomnerdtutorials.com/esp32-littlefs-arduino-ide/
*
* 对于PlatformIO 用户, 需要进入platformIO扩展界面, 选择Upload Filesystem Image, 上传项目文件.
* ESP8266和ESP32都要用这种方法.
*
* 用于演示BMP格式图片灰度显示. * 用于演示BMP格式图片灰度显示.
* *
* @note 食用方法: * @note 食用方法:
@@ -76,14 +95,14 @@ void setup(){
guy.drawString("Hello Readguy!",10,10); //用此函数将字符串显示到屏幕缓存内 guy.drawString("Hello Readguy!",10,10); //用此函数将字符串显示到屏幕缓存内
//guy.print("Hello Readguy!"); //使用这个函数也能显示出字符串, 但是需要提前使用setCursor确定显示坐标 //guy.print("Hello Readguy!"); //使用这个函数也能显示出字符串, 但是需要提前使用setCursor确定显示坐标
guy.display(true); // 快速刷新. 将屏幕缓存内的内容显示到墨水屏幕上 guy.display(READGUY_FAST); // 快速刷新. 将屏幕缓存内的内容显示到墨水屏幕上
//guy.display(false); // 慢速刷新. //guy.display(READGUY_SLOW); // 慢速刷新.
guy.setCursor(10,30); //设置显示的坐标 guy.setCursor(10,30); //设置显示的坐标
guy.print("Hello~"); //或者用print函数在屏幕上打印字符串, 数值, 字符等等... 两种函数都行 guy.print("Hello~"); //或者用print函数在屏幕上打印字符串, 数值, 字符等等... 两种函数都行
guy.display(false); // 慢速刷新. 慢刷的对比度显著高于快速刷新, 而且可以消除残影 guy.display(READGUY_SLOW); // 慢速刷新. 慢刷的对比度显著高于快速刷新, 而且可以消除残影
guy.drawString(guy.SDinside()?"SD card OK.":"No SD card!",10,50); //检查readguy是否插入了SD卡 guy.drawString(guy.SDinside()?"SD card OK.":"No SD card!",10,50); //检查readguy是否插入了SD卡
@@ -134,7 +153,7 @@ void setup(){
guy.fillScreen(1); guy.fillScreen(1);
guy.display(false); // 慢速刷新. 慢刷的对比度显著高于快速刷新, 而且可以消除残影 guy.display(READGUY_SLOW); // 慢速刷新. 慢刷的对比度显著高于快速刷新, 而且可以消除残影
for(int i=1;i<16;i++){ //灰度测试, 循环设置不同灰度 for(int i=1;i<16;i++){ //灰度测试, 循环设置不同灰度
@@ -203,7 +222,7 @@ void setup(){
guy.setFont(&FreeMonoBold9pt7b); //设置文本字体 guy.setFont(&FreeMonoBold9pt7b); //设置文本字体
guy.setTextColor(0); //设置文本颜色 guy.setTextColor(0); //设置文本颜色
guy.fillScreen(1); //用白色清屏. guy.fillScreen(1); //用白色清屏.
guy.display(false); //慢刷. 注意, 进行慢刷操作之后, 所有之前显示的灰度内容均会被重新刷成纯黑色 guy.display(READGUY_SLOW); //慢刷. 注意, 进行慢刷操作之后, 所有之前显示的灰度内容均会被重新刷成纯黑色
//不管是浅灰色还是深灰色, 进行慢刷之后只有黑白色. 原来的非白色像素(浅灰色,深灰色和黑色等) 会全刷成白色. //不管是浅灰色还是深灰色, 进行慢刷之后只有黑白色. 原来的非白色像素(浅灰色,深灰色和黑色等) 会全刷成白色.
guy.drawString("Rotation 0",10,12); //默认旋转方向为0. 实际的默认方向取决于屏幕IC. 大多数屏幕IC是竖屏. guy.drawString("Rotation 0",10,12); //默认旋转方向为0. 实际的默认方向取决于屏幕IC. 大多数屏幕IC是竖屏.
@@ -239,13 +258,13 @@ void setup(){
guy.setTextColor(1); //设置文本颜色为白色,因为被反色的屏幕的当前像素颜色以黑色像素为主 guy.setTextColor(1); //设置文本颜色为白色,因为被反色的屏幕的当前像素颜色以黑色像素为主
guy.drawString("Wake Up! ~\\(^_^)/~",10,50); //退出睡眠状态 guy.drawString("Wake Up! ~\\(^_^)/~",10,50); //退出睡眠状态
guy.display(false); //使用慢刷 来唤醒处于低功耗状态下的屏幕. guy.display(READGUY_SLOW); //使用慢刷 来唤醒处于低功耗状态下的屏幕.
// ------------------ 6 - 可以利用灰度来达到的一些显示效果 --<<<<<< // ------------------ 6 - 可以利用灰度来达到的一些显示效果 --<<<<<<
guy.fillScreen(1); //清屏 guy.fillScreen(1); //清屏
guy.display(FILL_WHITE,false); //慢刷清屏. 左侧的FILL_WHITE表示 不写入屏幕缓存, 直接刷全白 guy.display(FILL_WHITE,READGUY_SLOW); //慢刷清屏. 左侧的FILL_WHITE表示 不写入屏幕缓存, 直接刷全白
//可以改为FILL_BLACK来设置写入缓存全黑. //可以改为FILL_BLACK来设置写入缓存全黑.
//以上的方式均不会修改屏幕缓存中的内容. 右侧的false表示全屏慢刷. //以上的方式均不会修改屏幕缓存中的内容. 右侧的false表示全屏慢刷.

View File

@@ -70,8 +70,8 @@ void setup(){
//guy.setCursor(10,10); //设置显示的坐标 //guy.setCursor(10,10); //设置显示的坐标
//guy.print("Hello Readguy!"); //使用这个函数也能显示出字符串, 但是需要提前使用setCursor确定显示坐标 //guy.print("Hello Readguy!"); //使用这个函数也能显示出字符串, 但是需要提前使用setCursor确定显示坐标
guy.display(true); // 快速刷新. 将屏幕缓存内的内容显示到墨水屏幕上 guy.display(READGUY_FAST); // 快速刷新. 将屏幕缓存内的内容显示到墨水屏幕上
//guy.display(false); // 慢速刷新. //guy.display(READGUY_SLOW); // 慢速刷新.
//想知道更多内容, 欢迎移步到其他示例. //想知道更多内容, 欢迎移步到其他示例.
} }

View File

@@ -15,6 +15,29 @@
* - 运行的会很缓慢, 因为示例的图片文件比较大. * - 运行的会很缓慢, 因为示例的图片文件比较大.
* 1. 在运行过ex01或者ex02的开发板上 编译烧录本程序. * 1. 在运行过ex01或者ex02的开发板上 编译烧录本程序.
* 2. 将该项目data文件夹内的所有文件放置于SD卡的根目录上. * 2. 将该项目data文件夹内的所有文件放置于SD卡的根目录上.
* 就是SD卡内放data文件夹内的所有文件, 不能额外套文件夹.
* 如果你的SD卡插入电脑上显示为可移动磁盘, 那么双击SD卡目录就要看到这个文件夹里的文件
*
* 将根目录下的data文件夹 上传到LittleFS之后运行效果更佳
* 或者可以准备一张SD卡,并准备在卡的根目录下放置data文件夹内的文件.
* 就是SD卡内放data文件夹内的所有文件, 不能额外套文件夹.
* 如果你的SD卡插入电脑上显示为可移动磁盘, 那么双击SD卡目录就要看到这个文件夹里的文件
*
* 默认的文件系统为SD卡. 当没有插入SD卡时, 会读取LittleFS文件系统.
* 没有条件准备SD卡的, 可以烧录LittleFS文件系统.
*
* 对于ESP8266 Arduino 用户, 在项目草图文件夹内新建一个data文件夹, 并放入文件 (示例已提供data文件夹)
* 再在 arduinoIDE 的工具选项里选择 ESP8266 LittleFS Data Upload.
* 没有这个选项的需要参考以下文档安装ESP8266 Sketch upload tool
* https://randomnerdtutorials.com/install-esp8266-nodemcu-littlefs-arduino/
*
* 对于ESP32 Arduino 用户, 也要在项目草图文件夹内放一个data文件夹, 并把文件放入其中 (示例已提供data文件夹)
* 再在 arduinoIDE 的工具选项里选择 ESP32 Sketch data upload, 最后选择LittleFS.
* 没有这个选项的需要参考以下文档安装ESP32 LittleFS upload tool
* https://randomnerdtutorials.com/esp32-littlefs-arduino-ide/
*
* 对于PlatformIO 用户, 需要进入platformIO扩展界面, 选择Upload Filesystem Image, 上传项目文件.
* ESP8266和ESP32都要用这种方法.
* *
* {0} 代码食用注意事项: * {0} 代码食用注意事项:
* 这一部分的代码很难读, 或者按维莫斯小姐的说法, 很 "抽象" . * 这一部分的代码很难读, 或者按维莫斯小姐的说法, 很 "抽象" .
@@ -174,13 +197,13 @@ void setup(){
delay(2000); delay(2000);
guy.display(FILL_WHITE,true); //在保持屏幕缓存不变的时候快速刷新白屏. guy.display(FILL_WHITE,READGUY_FAST); //在保持屏幕缓存不变的时候快速刷新白屏.
guy.drawImage(sp,0,0,guy.width(),guy.height()); //绘画的画布可以被放大或者缩小到任意宽度和高度. guy.drawImage(sp,0,0,guy.width(),guy.height()); //绘画的画布可以被放大或者缩小到任意宽度和高度.
//此处的参数调用表示将会在屏幕坐标(0,0)开始显示, 显示的画布宽度缩放到屏幕宽度, 画布高度缩放到屏幕高度. //此处的参数调用表示将会在屏幕坐标(0,0)开始显示, 显示的画布宽度缩放到屏幕宽度, 画布高度缩放到屏幕高度.
guy.display(); //调用display函数刷屏. guy.display(); //调用display函数刷屏.
delay(2000); delay(2000);
guy.display(FILL_WHITE,true); //在保持屏幕缓存不变的时候快速刷新白屏 guy.display(FILL_WHITE,READGUY_FAST); //在保持屏幕缓存不变的时候快速刷新白屏
guy.fillScreen(1); //白屏清屏(清屏幕缓存) guy.fillScreen(1); //白屏清屏(清屏幕缓存)
guy.drawImage(sp,10,10,65,50); //缩放: 缩小到65X50 guy.drawImage(sp,10,10,65,50); //缩放: 缩小到65X50
guy.display(); //调用display函数刷屏. guy.display(); //调用display函数刷屏.
@@ -244,7 +267,7 @@ void setup(){
im.filename=BMP_FILE; //在此直接设置文件路径和文件名. im.filename=BMP_FILE; //在此直接设置文件路径和文件名.
guy.display(FILL_WHITE,false); //将屏幕全刷成白屏. 为了即将的图片刷新. guy.display(FILL_WHITE,READGUY_SLOW); //将屏幕全刷成白屏. 为了即将的图片刷新.
//建议在使用drawImageFile函数之前, 使用慢刷刷白屏, 可以保证显示效果清晰可见. //建议在使用drawImageFile函数之前, 使用慢刷刷白屏, 可以保证显示效果清晰可见.
im.drawImageFile(); //显示BMP格式.图片. im会自动识别文件扩展名并绘制. im.drawImageFile(); //显示BMP格式.图片. im会自动识别文件扩展名并绘制.
@@ -265,7 +288,7 @@ void setup(){
im.background=0; //设置背景颜色, 0黑1白, 此处设为背景色为黑色. im.background=0; //设置背景颜色, 0黑1白, 此处设为背景色为黑色.
guy.display(FILL_WHITE,false); //将屏幕全刷成白屏. 为了即将的图片刷新. guy.display(FILL_WHITE,READGUY_SLOW); //将屏幕全刷成白屏. 为了即将的图片刷新.
im.drawImageFile(); //显示JPG格式.图片. im会自动识别文件扩展名并绘制. im.drawImageFile(); //显示JPG格式.图片. im会自动识别文件扩展名并绘制.
delay(2000); delay(2000);
@@ -279,7 +302,7 @@ void setup(){
im.scalex=400.0f/1280.0f; im.scalex=400.0f/1280.0f;
im.scaley=300.0f/576.0f; im.scaley=300.0f/576.0f;
guy.display(FILL_WHITE, false);//显示. 此处的功能就是将显示缓存输出到屏幕上 guy.display(FILL_WHITE, READGUY_SLOW);//显示. 此处的功能就是将显示缓存输出到屏幕上
im.drawImageFile(); //显示PNG格式.图片. ESP8266可能不会绘制. im.drawImageFile(); //显示PNG格式.图片. ESP8266可能不会绘制.
delay(2000); delay(2000);
@@ -308,7 +331,7 @@ void setup(){
im.exPoolSize=MEM_POOL; //设置外部缓存内存大小 im.exPoolSize=MEM_POOL; //设置外部缓存内存大小
guy.setGreyQuality(1); //设置灰度模式为默认灰度显示模式 guy.setGreyQuality(1); //设置灰度模式为默认灰度显示模式
guy.display(FILL_WHITE,false); //将屏幕全刷成白屏. 为了即将显示灰度图. guy.display(FILL_WHITE,READGUY_SLOW); //将屏幕全刷成白屏. 为了即将显示灰度图.
im.enableFloyd=0; //禁用掉抖动算法. im.enableFloyd=0; //禁用掉抖动算法.
@@ -316,7 +339,7 @@ void setup(){
delay(2000); delay(2000);
guy.display(FILL_WHITE,false); //将屏幕全刷成白屏. 为了即将显示灰度图. guy.display(FILL_WHITE,READGUY_SLOW); //将屏幕全刷成白屏. 为了即将显示灰度图.
im.enableFloyd=1; // 重新启用抖动算法. im.enableFloyd=1; // 重新启用抖动算法.
@@ -351,7 +374,7 @@ void setup(){
} }
guy.drawLine(guy.width(),0,0,guy.height(),0); guy.drawLine(guy.width(),0,0,guy.height(),0);
guy.display(false); //刷新屏幕, 显示绘画的线段 guy.display(READGUY_SLOW); //刷新屏幕, 显示绘画的线段
//im.baseFs=&guy.guyFS(); //直接更改im内的数据即可设置绘制参数. 在此处就是设置文件系统. //im.baseFs=&guy.guyFS(); //直接更改im内的数据即可设置绘制参数. 在此处就是设置文件系统.
im.filename=BMP_FILE; //在此直接设置文件路径和文件名. im.filename=BMP_FILE; //在此直接设置文件路径和文件名.

View File

@@ -11,7 +11,7 @@
"type": "git", "type": "git",
"url": "https://github.com/fsender/readguy" "url": "https://github.com/fsender/readguy"
}, },
"version": "1.3.0", "version": "1.3.1",
"frameworks": "arduino", "frameworks": "arduino",
"platforms": ["espressif32", "espressif8266"], "platforms": ["espressif32", "espressif8266"],
"headers": "readguy.h", "headers": "readguy.h",

View File

@@ -1,5 +1,5 @@
name=readguy name=readguy
version=1.3.0 version=1.3.1
author=fsender <f_ender@163.com> author=fsender <f_ender@163.com>
maintainer=fsender <f_ender@163.com> maintainer=fsender <f_ender@163.com>
sentence=A free E-paper display driver library supports 16-level greyscale. sentence=A free E-paper display driver library supports 16-level greyscale.

View File

@@ -110,7 +110,9 @@ void drvBase::drv_fullpart(bool part){ //切换慢刷/快刷功能
if(!part) iLut=15; //恢复默认的灰度模式 if(!part) iLut=15; //恢复默认的灰度模式
Init(part?lut_fast:lut_slow); Init(part?lut_fast:lut_slow);
}*/ }*/
void drvBase::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新等功能 void drvBase::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷新等功能
if(m&1){//stage 1
if(lastRefresh) drv_dispWriter(f,2);
if(sleeping) Init(lut_slow); if(sleeping) Init(lut_slow);
BeginTransfer(); BeginTransfer();
SetMemory(); // bit set = white, bit reset = black SetMemory(); // bit set = white, bit reset = black
@@ -123,14 +125,22 @@ void drvBase::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新等
guy_epdCmd(0x20); guy_epdCmd(0x20);
guy_epdCmd(0xff); guy_epdCmd(0xff);
EndTransfer(); EndTransfer();
guy_epdBusy((this->lut == (const uint8_t*)lut_fast)?idleFastRf:idleSlowRf); lastRefresh=millis();
BeginTransfer(); }
SetMemory(); // bit set = white, bit reset = black
guy_epdBusy(90); if(m&2){//stage 2
guy_epdCmd(0x26); /* will send the color data */ uint32_t ms=millis()-lastRefresh;
for (int i = 0; i < epdHeight*epdWidth / 8; i++) uint32_t u=(this->lut == (const uint8_t*)lut_fast)?idleFastRf:idleSlowRf;
SpiTransfer(f(i)); if(ms<u) guy_epdBusy(u-ms);
EndTransfer(); lastRefresh=0;
BeginTransfer();
SetMemory(); // bit set = white, bit reset = black
guy_epdBusy(90);
guy_epdCmd(0x26); /* will send the color data */
for (int i = 0; i < epdHeight*epdWidth / 8; i++)
SpiTransfer(f(i));
EndTransfer();
}
} }
void drvBase::drv_sleep() { //开始屏幕睡眠 void drvBase::drv_sleep() { //开始屏幕睡眠
if(RST_PIN>=0) { //未定义RST_PIN时无法唤醒 if(RST_PIN>=0) { //未定义RST_PIN时无法唤醒

View File

@@ -42,7 +42,7 @@ public:
virtual int drv_ID() const=0; virtual int drv_ID() const=0;
void drv_init(); //初始化屏幕 void drv_init(); //初始化屏幕
void drv_fullpart(bool part); //切换慢刷/快刷功能 void drv_fullpart(bool part); //切换慢刷/快刷功能
void drv_dispWriter(std::function<uint8_t(int)> f); //按照函数刷新 void drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m=3); //按照函数刷新
void drv_sleep() ; //开始屏幕睡眠 void drv_sleep() ; //开始屏幕睡眠
int drv_width() const { return epdWidth; }; //返回显示区域宽度 int drv_width() const { return epdWidth; }; //返回显示区域宽度
int drv_height() const{ return epdHeight; }; //返回显示区域高度 int drv_height() const{ return epdHeight; }; //返回显示区域高度

View File

@@ -148,7 +148,9 @@ void drvSSD168x::drv_fullpart(bool part){ //切换慢刷/快刷功能
if(!part) { iLut=15; greyScaling=0; } if(!part) { iLut=15; greyScaling=0; }
_part=part; _part=part;
} }
void drvSSD168x::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新 void drvSSD168x::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷新
if(m&1){//stage 1
if(lastRefresh) drv_dispWriter(f,2);
BeginTransfer(); BeginTransfer();
if(_part){ if(_part){
//Reset(); //Reset();
@@ -196,7 +198,15 @@ void drvSSD168x::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
guy_epdParam(_part?0x0f:0xc7); guy_epdParam(_part?0x0f:0xc7);
guy_epdCmd(0x20); guy_epdCmd(0x20);
EndTransfer(); EndTransfer();
guy_epdBusy(_part?600:2300); lastRefresh=millis();
}
if(m&2){//stage 2
uint32_t ms=millis()-lastRefresh;
uint32_t u=_part?600:2300;
if(ms<u) guy_epdBusy(u-ms);
lastRefresh=0;
}
//guy_epdBusy(_part?600:2300);
} }
void drvSSD168x::drv_sleep() { //开始屏幕睡眠 void drvSSD168x::drv_sleep() { //开始屏幕睡眠
if(RST_PIN>=0){ //无法唤醒 if(RST_PIN>=0){ //无法唤醒

View File

@@ -40,7 +40,7 @@ public:
virtual int drv_ID() const =0; virtual int drv_ID() const =0;
void drv_init(); //初始化屏幕 void drv_init(); //初始化屏幕
void drv_fullpart(bool part); //切换慢刷/快刷功能 void drv_fullpart(bool part); //切换慢刷/快刷功能
void drv_dispWriter(std::function<uint8_t(int)> f); //按照函数刷新 void drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m=3); //按照函数刷新
void drv_sleep() ; //开始屏幕睡眠 void drv_sleep() ; //开始屏幕睡眠
int drv_width() const { return epdWidth; }; //返回显示区域宽度 int drv_width() const { return epdWidth; }; //返回显示区域宽度
int drv_height() const{ return epdHeight; }; //返回显示区域高度 int drv_height() const{ return epdHeight; }; //返回显示区域高度

View File

@@ -119,7 +119,9 @@ void drv::drv_fullpart(bool part){ //初始化慢刷功能
epdFull = !part; epdFull = !part;
//epd_Init(); //epd_Init();
} }
void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新 void drv::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷新
if(m&1){//stage 1
if(lastRefresh) drv_dispWriter(f,2);
BeginTransfer(); BeginTransfer();
if(epdFull) { //当刷新模式从快刷切换为慢刷时, 需要发送一次init if(epdFull) { //当刷新模式从快刷切换为慢刷时, 需要发送一次init
epdFull=0; epdFull=0;
@@ -143,7 +145,15 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
guy_epdParam(epdFull?0xc4:0x04); guy_epdParam(epdFull?0xc4:0x04);
guy_epdCmd(0x20); guy_epdCmd(0x20);
EndTransfer(); EndTransfer();
guy_epdBusy(epdFull?1600:310); lastRefresh=millis();
}
if(m&2){//stage 2
lastRefresh=0;
uint32_t ms=millis()-lastRefresh;
uint32_t u=epdFull?1600:310;
if(ms<u) guy_epdBusy(u-ms);
}
//guy_epdBusy(epdFull?1600:310);
} }
void drv::drv_sleep() { //开始屏幕睡眠 void drv::drv_sleep() { //开始屏幕睡眠
if(RST_PIN>=0){ //RST_PIN<0 无法唤醒 if(RST_PIN>=0){ //RST_PIN<0 无法唤醒

View File

@@ -47,7 +47,7 @@ public:
int drv_ID() const { return READGUY_DEV_213A; } int drv_ID() const { return READGUY_DEV_213A; }
void drv_init(); //初始化屏幕 void drv_init(); //初始化屏幕
void drv_fullpart(bool part); //切换慢刷/快刷功能 void drv_fullpart(bool part); //切换慢刷/快刷功能
void drv_dispWriter(std::function<uint8_t(int)> f); //按照函数刷新 void drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m=3); //按照函数刷新
void drv_sleep() ; //开始屏幕睡眠 void drv_sleep() ; //开始屏幕睡眠
int drv_width() const { return EPD_REAL_WIDTH; }; //返回显示区域宽度 int drv_width() const { return EPD_REAL_WIDTH; }; //返回显示区域宽度
//int drv_panelwidth() const { return GUY_D_WIDTH; }; //返回缓存的数据宽度 //int drv_panelwidth() const { return GUY_D_WIDTH; }; //返回缓存的数据宽度

View File

@@ -152,7 +152,9 @@ void drv_base::drv_setDepth(uint8_t i){
SendLuts(1); SendLuts(1);
EndTransfer(); EndTransfer();
} }
void drv_base::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新 void drv_base::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷新
if(m&1){//stage 1
if(lastRefresh) drv_dispWriter(f,2);
BeginTransfer(); BeginTransfer();
epd_init(); epd_init();
SendLuts(part_mode); SendLuts(part_mode);
@@ -169,17 +171,29 @@ void drv_base::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
send_zoneInfo(); send_zoneInfo();
guy_epdCmd(0x12); guy_epdCmd(0x12);
EndTransfer(); EndTransfer();
guy_epdBusy(-200);
} }
else{ else{
guy_epdCmd(0x12); guy_epdCmd(0x12);
EndTransfer(); EndTransfer();
guy_epdBusy(-2000); }
BeginTransfer(); lastRefresh=millis();
epd_init(); }
SendLuts(1); if(m&2){//stage 2
guy_epdCmd(0x92); uint32_t ms=millis()-lastRefresh;
EndTransfer(); if(part_mode){
if(ms<200) guy_epdBusy(ms-200);
//guy_epdBusy(-200);
}
else{
if(ms<2000) guy_epdBusy(ms-2000);
//guy_epdBusy(-2000);
BeginTransfer();
epd_init();
SendLuts(1);
guy_epdCmd(0x92);
EndTransfer();
}
lastRefresh=0;
} }
} }
void drv_base::drv_sleep() { //开始屏幕睡眠 void drv_base::drv_sleep() { //开始屏幕睡眠

View File

@@ -39,7 +39,7 @@ public:
virtual int drv_ID() const=0; virtual int drv_ID() const=0;
void drv_init(); //初始化屏幕 void drv_init(); //初始化屏幕
void drv_fullpart(bool part); //切换慢刷/快刷功能 void drv_fullpart(bool part); //切换慢刷/快刷功能
void drv_dispWriter(std::function<uint8_t(int)> f); //按照函数刷新 void drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m=3); //按照函数刷新
void drv_sleep() ; //开始屏幕睡眠 void drv_sleep() ; //开始屏幕睡眠
int drv_width() const { return epdWidth; }; //返回显示区域宽度 int drv_width() const { return epdWidth; }; //返回显示区域宽度
int drv_height() const{ return epdHeight; }; //返回显示区域高度 int drv_height() const{ return epdHeight; }; //返回显示区域高度

View File

@@ -120,7 +120,9 @@ void drv::drv_fullpart(bool part){ //切换慢刷/快刷功能
} }
part_mode=part; part_mode=part;
} }
void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新 void drv::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷新
if(m&1){//stage 1
if(lastRefresh) drv_dispWriter(f,2);
if(sleeping) Init(); if(sleeping) Init();
BeginTransfer(); BeginTransfer();
guy_epdCmd(0x4E); guy_epdParam(0x00); guy_epdParam(0x00); guy_epdCmd(0x4E); guy_epdParam(0x00); guy_epdParam(0x00);
@@ -138,7 +140,15 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
Load_LUT(!part_mode); Load_LUT(!part_mode);
guy_epdCmd(0x20); guy_epdCmd(0x20);
EndTransfer(); EndTransfer();
guy_epdBusy(part_mode?500:1300); lastRefresh=millis();
}
if(m&2){//stage 2
uint32_t ms=millis()-lastRefresh;
uint32_t u=part_mode?500:1300;
if(ms<u) guy_epdBusy(u-ms);
lastRefresh=0;
}
//guy_epdBusy(part_mode?500:1300);
} }
void drv::drv_sleep() { //开始屏幕睡眠 void drv::drv_sleep() { //开始屏幕睡眠
if(RST_PIN>=0){ if(RST_PIN>=0){

View File

@@ -40,7 +40,7 @@ public:
int drv_ID() const { return READGUY_DEV_370A; } int drv_ID() const { return READGUY_DEV_370A; }
void drv_init(); //初始化屏幕 void drv_init(); //初始化屏幕
void drv_fullpart(bool part); //切换慢刷/快刷功能 void drv_fullpart(bool part); //切换慢刷/快刷功能
void drv_dispWriter(std::function<uint8_t(int)> f); //按照函数刷新 void drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m=3); //按照函数刷新
void drv_sleep() ; //开始屏幕睡眠 void drv_sleep() ; //开始屏幕睡眠
int drv_width() const { return GUY_D_WIDTH; }; //返回显示区域宽度 int drv_width() const { return GUY_D_WIDTH; }; //返回显示区域宽度
int drv_height() const{ return GUY_D_HEIGHT; }; //返回显示区域高度 int drv_height() const{ return GUY_D_HEIGHT; }; //返回显示区域高度

View File

@@ -185,7 +185,9 @@ void drv::drv_fullpart(bool part){ //初始化慢刷功能
if(epdFull<=1) epdFull = !part; //epdFull==2代表睡眠中, 不能快刷 if(epdFull<=1) epdFull = !part; //epdFull==2代表睡眠中, 不能快刷
if(epdFull) GreyScaling=0; if(epdFull) GreyScaling=0;
} }
void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新 void drv::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷新
if(m&1){//stage 1
if(lastRefresh) drv_dispWriter(f,2);
BeginTransfer(); BeginTransfer();
epd_Init(); epd_Init();
SetMemory(); SetMemory();
@@ -211,9 +213,7 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
SetLut(lut_213_B72_Full); SetLut(lut_213_B72_Full);
guy_epdCmd(0x22); guy_epdCmd(0x22);
guy_epdParam(0xc4); guy_epdParam(0xc4);
guy_epdCmd(0x20); //guy_epdBusy(1600); //等待刷完
EndTransfer();
guy_epdBusy(1600); //等待刷完
} }
else{ //快刷 else{ //快刷
guy_epdCmd(0x2c); //may a mistake? 此处不需要设置vcom guy_epdCmd(0x2c); //may a mistake? 此处不需要设置vcom
@@ -221,17 +221,24 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
SetLut(GreyScalingHighQuality?lut_213_B72_16grey:lut_213_B72); SetLut(GreyScalingHighQuality?lut_213_B72_16grey:lut_213_B72);
guy_epdCmd(0x22); guy_epdCmd(0x22);
guy_epdParam(0x04); guy_epdParam(0x04);
guy_epdCmd(0x20);
EndTransfer();
guy_epdBusy(260); //等待屏幕刷新完成
} }
BeginTransfer(); //write again guy_epdCmd(0x20);
SetMemory();
guy_epdCmd(0x26);
for (int i = 0; i < GUY_D_HEIGHT*GUY_D_WIDTH/8; i++)
SpiTransfer(f(i)); //按照给定的RAM写入数据
EndTransfer(); EndTransfer();
if(epdFull) power_down(); lastRefresh=millis();
}
if(m&2){//stage 2
uint32_t ms=millis()-lastRefresh;
uint32_t u=epdFull?1600:260;
if(ms<u) guy_epdBusy(u-ms); //等待屏幕刷新完成
lastRefresh=0;
BeginTransfer(); //write again
SetMemory();
guy_epdCmd(0x26);
for (int i = 0; i < GUY_D_HEIGHT*GUY_D_WIDTH/8; i++)
SpiTransfer(f(i)); //按照给定的RAM写入数据
EndTransfer();
if(epdFull) power_down();
}
} }
void drv::drv_draw16grey_step(std::function<uint8_t(int)> f, int step){ void drv::drv_draw16grey_step(std::function<uint8_t(int)> f, int step){
if(_quality&1) return readguyEpdBase::drv_draw16grey_step(f,step); if(_quality&1) return readguyEpdBase::drv_draw16grey_step(f,step);

View File

@@ -41,7 +41,7 @@ public:
int drv_ID() const { return READGUY_DEV_420A; } int drv_ID() const { return READGUY_DEV_420A; }
void drv_init(); //初始化屏幕 void drv_init(); //初始化屏幕
void drv_fullpart(bool part); //切换慢刷/快刷功能 void drv_fullpart(bool part); //切换慢刷/快刷功能
void drv_dispWriter(std::function<uint8_t(int)> f); //按照函数刷新 void drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m=3); //按照函数刷新
void drv_sleep() ; //开始屏幕睡眠 void drv_sleep() ; //开始屏幕睡眠
int drv_width() const { return GUY_D_WIDTH; }; //返回显示区域宽度 int drv_width() const { return GUY_D_WIDTH; }; //返回显示区域宽度
int drv_height() const{ return GUY_D_HEIGHT; }; //返回显示区域高度 int drv_height() const{ return GUY_D_HEIGHT; }; //返回显示区域高度

View File

@@ -147,7 +147,9 @@ const PROGMEM unsigned char drv::lutFast_b_w[] ={ 0x5a,2,0,63,0,1 };
const PROGMEM unsigned char drv::lutFast_w_b[] ={ 0x84,2,0,48,0,1 }; const PROGMEM unsigned char drv::lutFast_w_b[] ={ 0x84,2,0,48,0,1 };
const PROGMEM unsigned char drv::lutFast_b_b[] ={ 0x01,2,0,48,0,1 }; const PROGMEM unsigned char drv::lutFast_b_b[] ={ 0x01,2,0,48,0,1 };
//void drv::epd_display(){ //void drv::epd_display(){
void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新 void drv::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷新
if(m&1){//stage 1
if(lastRefresh) drv_dispWriter(f,2);
BeginTransfer(); BeginTransfer();
Init(part_mode); Init(part_mode);
if(part_mode){ if(part_mode){
@@ -181,7 +183,13 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
} }
guy_epdCmd(0x12); guy_epdCmd(0x12);
EndTransfer(); EndTransfer();
guy_epdBusy(part_mode?-800:-3600); lastRefresh=millis();
}
if(m&2){//stage 2
uint32_t ms=millis()-lastRefresh;
uint32_t u=part_mode?800:3600;
if(ms<u) guy_epdBusy(ms-u);
lastRefresh=0;
BeginTransfer(); BeginTransfer();
if(part_mode){ if(part_mode){
sendArea(); sendArea();
@@ -189,7 +197,6 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/8;i++) for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/8;i++)
SpiTransfer(f(i)); SpiTransfer(f(i));
guy_epdCmd(0x92); guy_epdCmd(0x92);
EndTransfer();
} }
else{ else{
Init(2); Init(2);
@@ -199,6 +206,7 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
SpiTransfer(f(i)); SpiTransfer(f(i));
guy_epdCmd(0x92); guy_epdCmd(0x92);
guy_epdCmd(0x02); guy_epdCmd(0x02);
}
EndTransfer(); EndTransfer();
guy_epdBusy(-20); guy_epdBusy(-20);
} }

View File

@@ -44,7 +44,7 @@ public:
void drv_init(); //初始化屏幕 void drv_init(); //初始化屏幕
//void drv_draw16grey(uint8_t *d16bit); //void drv_draw16grey(uint8_t *d16bit);
void drv_fullpart(bool part); //切换慢刷/快刷功能 void drv_fullpart(bool part); //切换慢刷/快刷功能
void drv_dispWriter(std::function<uint8_t(int)> f); //按照函数刷新 void drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m=3); //按照函数刷新
void drv_sleep() ; //开始屏幕睡眠 void drv_sleep() ; //开始屏幕睡眠
int drv_width() const { return GUY_D_WIDTH; }; //返回显示区域宽度 int drv_width() const { return GUY_D_WIDTH; }; //返回显示区域宽度
int drv_height() const{ return GUY_D_HEIGHT; }; //返回显示区域高度 int drv_height() const{ return GUY_D_HEIGHT; }; //返回显示区域高度

View File

@@ -77,6 +77,7 @@ int readguyEpdBase::IfInit(SPIClass &c,int8_t cs,int8_t dc,int8_t rst,int8_t bus
DigitalWrite(DC_PIN,HIGH); DigitalWrite(DC_PIN,HIGH);
if(BUSY_PIN>=0) pinMode(BUSY_PIN, INPUT); if(BUSY_PIN>=0) pinMode(BUSY_PIN, INPUT);
_spi = &c; _spi = &c;
lastRefresh=0;
//_spi->begin(); //_spi->begin();
//_spi->beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0)); //_spi->beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
@@ -161,8 +162,7 @@ void readguyEpdBase::Reset(uint32_t minTime)
void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_t x,uint16_t y,int o, void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_t x,uint16_t y,int o,
uint16_t fw, uint16_t fh){ uint16_t fw, uint16_t fh){
#ifndef FLOYD_STEINBERG_DITHERING static const PROGMEM uint8_t bayer_tab [64]={
static const uint8_t bayer_tab [64]={
0, 32, 8, 40, 2, 34, 10, 42, 0, 32, 8, 40, 2, 34, 10, 42,
48, 16, 56, 24, 50, 18, 58, 26, 48, 16, 56, 24, 50, 18, 58, 26,
12, 44, 4, 36, 14, 46, 6, 38, 12, 44, 4, 36, 14, 46, 6, 38,
@@ -172,24 +172,21 @@ void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_
15, 47, 7, 39, 13, 45, 5, 37, 15, 47, 7, 39, 13, 45, 5, 37,
63, 31, 55, 23, 61, 29, 53, 21 63, 31, 55, 23, 61, 29, 53, 21
}; };
#endif
if(!fw) fw=spr.width(); if(!fw) fw=spr.width();
if(!fh) fh=spr.height(); if(!fh) fh=spr.height();
if((!fw) || (!fh)) return; if((!fw) || (!fh)) return;
if(o==0 || o==1){ if(o==0 || o==1){
readBuff = new uint16_t[spr.width()]; readBuff = new uint16_t[spr.width()];
#ifdef FLOYD_STEINBERG_DITHERING
floyd_tab[0] = new int16_t [fw]; floyd_tab[0] = new int16_t [fw];
floyd_tab[1] = new int16_t [fw]; floyd_tab[1] = new int16_t [fw];
for(int j=0;j<fw;j++){ floyd_tab[0][j] = 0; floyd_tab[1][j] = 0; } for(int j=0;j<fw;j++){ floyd_tab[0][j] = 0; floyd_tab[1][j] = 0; }
#endif
writeBuff = new uint8_t[(fw+7)>>3]; writeBuff = new uint8_t[(fw+7)>>3];
} }
sprbase.fillRect(x,y,fw,fh,1); sprbase.fillRect(x,y,fw,fh,1);
for(int32_t i=y;i<(int32_t)fh+y;i++){ for(int32_t i=y;i<(int32_t)fh+y;i++){
spr.readRect(0,(i-y)*spr.height()/fh,spr.width(),1,readBuff);
#ifdef FLOYD_STEINBERG_DITHERING
uint_fast8_t buff8bit=0; uint_fast8_t buff8bit=0;
spr.readRect(0,(i-y)*spr.height()/fh,spr.width(),1,readBuff);
if(_quality&2){
for(int32_t j=0;j<fw;j++){ for(int32_t j=0;j<fw;j++){
int gv=greysc(readBuff[j*spr.width()/fw]); int gv=greysc(readBuff[j*spr.width()/fw]);
int32_t flodelta = floyd_tab[i&1][j]+(int32_t)((gv<<8)|gv); int32_t flodelta = floyd_tab[i&1][j]+(int32_t)((gv<<8)|gv);
@@ -218,24 +215,24 @@ void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_
{ floyd_tab[!(i&1)][j+1] += (flodelta )>>4; } { floyd_tab[!(i&1)][j+1] += (flodelta )>>4; }
} }
for(int floi=0;floi<fw;floi++) floyd_tab[i&1][floi]=0; for(int floi=0;floi<fw;floi++) floyd_tab[i&1][floi]=0;
#else
for(int32_t j=0;j<w;j++){
uint_fast8_t buff8bit=0;
for(uint_fast8_t b=0;b<8;b++)
buff8bit |= (bayer_tab[(b<<3)|(i&7)]<(greysc(readBuff[j*spr.width()/fw])>>2))<<(7-b);
writeBuff[j]=buff8bit;
} }
#endif else{
for(int32_t j=0;j<((fw+7)>>3);j++){
buff8bit=0;
for(uint_fast8_t b=0;b<8;b++)
buff8bit |= ((pgm_read_byte(bayer_tab+((b<<3)|(i&7)))<<2)+2
<greysc(readBuff[((j<<3)+b)*spr.width()/fw]))<<(7-b);
writeBuff[j]=buff8bit;
}
}
sprbase.drawBitmap(x,i,writeBuff,fw,1,1,0); sprbase.drawBitmap(x,i,writeBuff,fw,1,1,0);
} }
//_display((const uint8_t*)sprbase.getBuffer()); //显示 //_display((const uint8_t*)sprbase.getBuffer()); //显示
if(o==0 || o==3){ if(o==0 || o==3){
delete []readBuff; delete []readBuff;
delete []writeBuff; delete []writeBuff;
#ifdef FLOYD_STEINBERG_DITHERING
delete [] floyd_tab[0] ; delete [] floyd_tab[0] ;
delete [] floyd_tab[1] ; delete [] floyd_tab[1] ;
#endif
} }
} }
//不支持的话使用单色抖动刷屏 //不支持的话使用单色抖动刷屏
@@ -247,10 +244,8 @@ void readguyEpdBase::drv_draw16grey(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16
if((!fw) || (!fh)) return; if((!fw) || (!fh)) return;
readBuff = new uint16_t[spr.width()]; readBuff = new uint16_t[spr.width()];
if(_quality&2){ if(_quality&2){
#ifdef FLOYD_DITHERING_16GREY
floyd_tab[0] = new int16_t [fw]; floyd_tab[0] = new int16_t [fw];
floyd_tab[1] = new int16_t [fw]; floyd_tab[1] = new int16_t [fw];
#endif
} }
writeBuff = new uint8_t[(fw+7)>>3]; writeBuff = new uint8_t[(fw+7)>>3];
sprbase.fillRect(x,y,fw,fh,1); sprbase.fillRect(x,y,fw,fh,1);
@@ -260,15 +255,12 @@ void readguyEpdBase::drv_draw16grey(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16
drv_dispWriter(FILL_WHITE); drv_dispWriter(FILL_WHITE);
drv_fullpart(1); drv_fullpart(1);
for(uint_fast8_t k=1;k<16;k++){ //亮度为15的不用绘制,因为本来就是白色 for(uint_fast8_t k=1;k<16;k++){ //亮度为15的不用绘制,因为本来就是白色
#ifdef FLOYD_DITHERING_16GREY
if(_quality&2) for(int j=0;j<fw;j++){ floyd_tab[0][j] = 0; floyd_tab[1][j] = 0; } if(_quality&2) for(int j=0;j<fw;j++){ floyd_tab[0][j] = 0; floyd_tab[1][j] = 0; }
#endif
for(int i=y;i<(int32_t)fh+y;i++){ for(int i=y;i<(int32_t)fh+y;i++){
uint_fast8_t buff8bit=0; uint_fast8_t buff8bit=0;
spr.readRect(0,(i-y)*spr.height()/fh,spr.width(),1,readBuff); spr.readRect(0,(i-y)*spr.height()/fh,spr.width(),1,readBuff);
for(int32_t j=0;j<fw;j++){ for(int32_t j=0;j<fw;j++){
//for(uint_fast8_t b=0;b<8;b++){ //for(uint_fast8_t b=0;b<8;b++){
#ifdef FLOYD_DITHERING_16GREY
uint_fast8_t cg=0; uint_fast8_t cg=0;
if(_quality&2){ if(_quality&2){
int gv=greysc(readBuff[j*spr.width()/fw]); int gv=greysc(readBuff[j*spr.width()/fw]);
@@ -284,9 +276,7 @@ void readguyEpdBase::drv_draw16grey(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16
if(j!=fw-1) { floyd_tab[!(i&1)][j+1] += (fd )>>4; } if(j!=fw-1) { floyd_tab[!(i&1)][j+1] += (fd )>>4; }
} }
else{ cg=greysc(readBuff[j*spr.width()/fw])>>4; } else{ cg=greysc(readBuff[j*spr.width()/fw])>>4; }
#else //uint_fast8_t cg=greysc(readBuff[j*spr.width()/fw])>>4;
uint_fast8_t cg=greysc(readBuff[j*spr.width()/fw])>>4;
#endif
if(negativeOrder) if(negativeOrder)
buff8bit |= (cg<k)<<((~j)&7); buff8bit |= (cg<k)<<((~j)&7);
else{ else{
@@ -300,9 +290,7 @@ void readguyEpdBase::drv_draw16grey(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16
//} //}
//sprbase.drawPixel(x+j,i,(greysc(readBuff[j*spr.width()/fw])/16)==(15-k)); //sprbase.drawPixel(x+j,i,(greysc(readBuff[j*spr.width()/fw])/16)==(15-k));
} }
#ifdef FLOYD_DITHERING_16GREY
if(_quality&2) for(int floi=0;floi<fw;floi++) floyd_tab[i&1][floi]=0; if(_quality&2) for(int floi=0;floi<fw;floi++) floyd_tab[i&1][floi]=0;
#endif
sprbase.drawBitmap(x,i,writeBuff,fw,1,1,0); sprbase.drawBitmap(x,i,writeBuff,fw,1,1,0);
} }
drv_draw16grey_step((const uint8_t*)sprbase.getBuffer(),k); //使用灰度显示函数 drv_draw16grey_step((const uint8_t*)sprbase.getBuffer(),k); //使用灰度显示函数
@@ -310,10 +298,8 @@ void readguyEpdBase::drv_draw16grey(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16
delete []readBuff; delete []readBuff;
delete []writeBuff; delete []writeBuff;
if(_quality&2){ if(_quality&2){
#ifdef FLOYD_DITHERING_16GREY
delete [] floyd_tab[0] ; delete [] floyd_tab[0] ;
delete [] floyd_tab[1] ; delete [] floyd_tab[1] ;
#endif
} }
} /* END OF FILE. ReadGuy project. } /* END OF FILE. ReadGuy project.
Copyright (C) 2023 FriendshipEnder. */ Copyright (C) 2023 FriendshipEnder. */

View File

@@ -55,9 +55,8 @@ protected:
#endif #endif
uint16_t *readBuff;// = new uint16_t[spr.width()]; uint16_t *readBuff;// = new uint16_t[spr.width()];
uint8_t *writeBuff;// = new uint8_t[w]; uint8_t *writeBuff;// = new uint8_t[w];
#if (defined(FLOYD_DITHERING_16GREY) || defined(FLOYD_STEINBERG_DITHERING))
int16_t *floyd_tab[2]; int16_t *floyd_tab[2];
#endif uint32_t lastRefresh;
public: public:
readguyEpdBase(void); readguyEpdBase(void);
@@ -82,9 +81,9 @@ public:
virtual int drv_ID() const =0; //返回驱动代号 virtual int drv_ID() const =0; //返回驱动代号
virtual void drv_init()=0; //初始化屏幕 virtual void drv_init()=0; //初始化屏幕
virtual void drv_fullpart(bool part)=0; //初始化慢刷功能 virtual void drv_fullpart(bool part)=0; //初始化慢刷功能
void _display(const uint8_t *d){ drv_dispWriter([&](int n)->uint8_t{return d[n];}); } void _display(const uint8_t *d,uint8_t m=3){ drv_dispWriter([&](int n)->uint8_t{return d[n];},m); }
virtual void drv_dispWriter(std::function<uint8_t(int)>)=0; //按照显示函数刷新 virtual void drv_dispWriter(std::function<uint8_t(int)>,uint8_t m=3)=0; //按照显示函数刷新
void drv_color(uint8_t c){ drv_dispWriter([=](int)->uint8_t{return c;}); } //单色刷新 void drv_color(uint8_t c,uint8_t m=3){ drv_dispWriter([=](int)->uint8_t{return c;},m); } //单色刷新
virtual void drv_sleep() =0; //开始屏幕睡眠 virtual void drv_sleep() =0; //开始屏幕睡眠
virtual int drv_width() const=0; //返回显示区域宽度, 即使旋转了也不能影响此函数输出 virtual int drv_width() const=0; //返回显示区域宽度, 即使旋转了也不能影响此函数输出
virtual int drv_height()const=0; //返回显示区域高度, 即使旋转了也不能影响此函数输出 virtual int drv_height()const=0; //返回显示区域高度, 即使旋转了也不能影响此函数输出

View File

@@ -73,7 +73,7 @@
//#define _DEFINA_SD_CS_PIN 0 //#define _DEFINA_SD_CS_PIN 0
// * for NodeMcu ctg stack LCF board // * for NodeMcu ctg stack LCF board
#define WHITE_GAP 8 #define WHITE_GAP 2
#ifdef ESP8266 #ifdef ESP8266
#define DISPLAY_TYPE_ST7789_240320 //2.0寸的ST7789 IPS TFT模块 #define DISPLAY_TYPE_ST7789_240320 //2.0寸的ST7789 IPS TFT模块

View File

@@ -40,7 +40,9 @@ void drv::drv_init(){
void drv::drv_fullpart(bool part){ void drv::drv_fullpart(bool part){
partMode=part; partMode=part;
} }
void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新 void drv::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷新
if(m&1){//stage 1
if(lastRefresh) drv_dispWriter(f,2);
uint16_t dat[8]; uint16_t dat[8];
unsigned short xbits=(drv_width()+7)/8; unsigned short xbits=(drv_width()+7)/8;
if(partMode==0){ if(partMode==0){
@@ -79,7 +81,13 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
} }
} }
} }
yield(); }
lastRefresh=millis();
}
if(m&2){//stage 2
uint32_t ms=millis()-lastRefresh;
if(ms<150) DelayMs(150-ms);
lastRefresh=0;
} }
} }
void drv::drv_sleep() {} void drv::drv_sleep() {}

View File

@@ -41,7 +41,7 @@ public:
int drv_ID() const { return MEPD_DEBUG_DISPLAY; } int drv_ID() const { return MEPD_DEBUG_DISPLAY; }
void drv_init(); //初始化屏幕 void drv_init(); //初始化屏幕
void drv_fullpart(bool part); //切换慢刷/快刷功能 void drv_fullpart(bool part); //切换慢刷/快刷功能
void drv_dispWriter(std::function<uint8_t(int)> f); //单色刷新 void drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m=3); //单色刷新
void drv_sleep() ; //开始屏幕睡眠 void drv_sleep() ; //开始屏幕睡眠
int drv_width() const { return ips.width()-2*WHITE_GAP; } //返回显示区域宽度 int drv_width() const { return ips.width()-2*WHITE_GAP; } //返回显示区域宽度
int drv_height() const{ return ips.height()-2*WHITE_GAP; } //返回显示区域高度 int drv_height() const{ return ips.height()-2*WHITE_GAP; } //返回显示区域高度

View File

@@ -41,9 +41,9 @@
//另外, 在提交新版本之前, 不要忘记在github上创建release, 否则Arduino IDE会读不到 //另外, 在提交新版本之前, 不要忘记在github上创建release, 否则Arduino IDE会读不到
#define READGUY_V_MAJOR 1 #define READGUY_V_MAJOR 1
#define READGUY_V_MINOR 3 #define READGUY_V_MINOR 3
#define READGUY_V_PATCH 0 #define READGUY_V_PATCH 1
#define READGUY_VERSION_VAL (READGUY_V_MAJOR*1000+READGUY_V_MINOR*100+READGUY_V_PATCH*10) #define READGUY_VERSION_VAL (READGUY_V_MAJOR*1000+READGUY_V_MINOR*100+READGUY_V_PATCH*10)
#define READGUY_VERSION "1.3.0" #define READGUY_VERSION "1.3.1"
#ifdef ESP8266 #ifdef ESP8266
#define _READGUY_PLATFORM "ESP8266" #define _READGUY_PLATFORM "ESP8266"

View File

@@ -191,7 +191,7 @@ bool ReadguyDriver::server_loop(){ //此时等待网页操作完成响应...
} }
if(refFlag!=127) { if(refFlag!=127) {
Serial.printf("randch: %d %c\n",randomch[refFlag],(char)(randomch[refFlag])); Serial.printf("randch: %d %c\n",randomch[refFlag],(char)(randomch[refFlag]));
drawChar((width()>>1)-46+refFlag*24,(height()>>1)-14,randomch[refFlag],true,false,4); drawChar((guy_dev->drv_width()>>1)-46+refFlag*24,(guy_dev->drv_height()>>1)-14,randomch[refFlag],true,false,4);
guy_dev->drv_fullpart(1); guy_dev->drv_fullpart(1);
guy_dev->_display((const uint8_t*)getBuffer()); guy_dev->_display((const uint8_t*)getBuffer());
} }
@@ -311,13 +311,14 @@ void ReadguyDriver::handleInitPost(){
setEpdDriver(); //尝试初始化屏幕 setEpdDriver(); //尝试初始化屏幕
Serial.println(F("[Guy] Init details...")); Serial.println(F("[Guy] Init details..."));
setTextSize(1); setTextSize(1);
drawCenterString(setSDcardDriver()?"SD Init OK!":"SD Init failed!",width()>>1,(height()>>1)+20); drawCenterString(setSDcardDriver()?"SD Init OK!":"SD Init failed!",
guy_dev->drv_width()>>1,(guy_dev->drv_height()>>1)+20);
setButtonDriver(); //初始化按钮.. setButtonDriver(); //初始化按钮..
//} //尝试初始化按键, 调用后, 若SD卡初始化成功, READGUY_sd_ok的值会变成1 //} //尝试初始化按键, 调用后, 若SD卡初始化成功, READGUY_sd_ok的值会变成1
drawRect((width()>>1)-46 ,(height()>>1)-14,20,28,0); drawRect((guy_dev->drv_width()>>1)-46 ,(guy_dev->drv_height()>>1)-14,20,28,0);
drawRect((width()>>1)-46+24,(height()>>1)-14,20,28,0); drawRect((guy_dev->drv_width()>>1)-46+24,(guy_dev->drv_height()>>1)-14,20,28,0);
drawRect((width()>>1)-46+48,(height()>>1)-14,20,28,0); drawRect((guy_dev->drv_width()>>1)-46+48,(guy_dev->drv_height()>>1)-14,20,28,0);
drawRect((width()>>1)-46+72,(height()>>1)-14,20,28,0); drawRect((guy_dev->drv_width()>>1)-46+72,(guy_dev->drv_height()>>1)-14,20,28,0);
spibz++; spibz++;
guy_dev->drv_fullpart(1); guy_dev->drv_fullpart(1);
guy_dev->_display((const uint8_t*)getBuffer()); guy_dev->_display((const uint8_t*)getBuffer());

View File

@@ -180,11 +180,10 @@ void ReadguyDriver::setEpdDriver(bool initepd/* ,int g_width,int g_height */){
//else guy_width = guy_dev->drv_width(); //宽度必须是8的倍数, 但这个可以由GFX自动计算 //else guy_width = guy_dev->drv_width(); //宽度必须是8的倍数, 但这个可以由GFX自动计算
//if(g_height) guy_height = g_height; //if(g_height) guy_height = g_height;
//else guy_height = guy_dev->drv_height(); //else guy_height = guy_dev->drv_height();
Serial.println(F("[Guy EPD] EPD init OK"));
//以下依赖于你的图形驱动 //以下依赖于你的图形驱动
setColorDepth(1); //单色模式 setColorDepth(1); //单色模式
createPalette(); //初始化颜色系统 createPalette(); //初始化颜色系统
Serial.printf_P(PSTR("[Guy EPD] mono set: w: %d, h: %d\n"),guy_dev->drv_width(),guy_dev->drv_height()); Serial.printf_P(PSTR("[Guy EPD] EPD init OK: w: %d, h: %d\n"),guy_dev->drv_width(),guy_dev->drv_height());
//创建画布. 根据LovyanGFX的特性, 如果以前有画布会自动重新生成新画布 //创建画布. 根据LovyanGFX的特性, 如果以前有画布会自动重新生成新画布
//此外, 即使画布宽度不是8的倍数(如2.13寸单色),也支持自动补全8的倍数 ( 250x122 => 250x128 ) //此外, 即使画布宽度不是8的倍数(如2.13寸单色),也支持自动补全8的倍数 ( 250x122 => 250x128 )
//为了保证图片显示功能的正常使用, 高度也必须是8的倍数. //为了保证图片显示功能的正常使用, 高度也必须是8的倍数.
@@ -370,32 +369,41 @@ void ReadguyDriver::setBright(int d){
digitalWrite(READGUY_bl_pin,d?HIGH:LOW); digitalWrite(READGUY_bl_pin,d?HIGH:LOW);
} }
} }
void ReadguyDriver::display(bool part){ void ReadguyDriver::display(uint8_t part){
//真的是我c++的盲区了啊....搜索了半天才找到可以这么玩的 //真的是我c++的盲区了啊....搜索了半天才找到可以这么玩的
//......可惜'dynamic_cast' not permitted with -fno-rtti //......可惜'dynamic_cast' not permitted with -fno-rtti
// static bool _part = 0; 记忆上次到底是full还是part, 注意启动时默认为full // static bool _part = 0; 记忆上次到底是full还是part, 注意启动时默认为full
if(READGUY_cali==127){ if(READGUY_cali==127){
//in_press(); //暂停, 然后读取按键状态 spibz //in_press(); //暂停, 然后读取按键状态 spibz
guy_dev->drv_fullpart(part); guy_dev->drv_fullpart(part&1);
guy_dev->_display((const uint8_t*)getBuffer()); guy_dev->_display((const uint8_t*)getBuffer(),((part>>1)?part>>1:3));
//in_release(); //恢复 //in_release(); //恢复
} }
} }
void ReadguyDriver::display(std::function<uint8_t(int)> f, bool part){ void ReadguyDriver::display(const uint8_t *buf, uint8_t part){
if(READGUY_cali==127){ if(READGUY_cali==127){
//in_press(); //暂停, 然后读取按键状态 spibz //in_press(); //暂停, 然后读取按键状态 spibz
guy_dev->drv_fullpart(part); guy_dev->drv_fullpart(part&1);
guy_dev->drv_dispWriter(f); guy_dev->_display(buf,((part>>1)?part>>1:3));
//in_release(); //恢复
}
}
void ReadguyDriver::display(std::function<uint8_t(int)> f, uint8_t part){
if(READGUY_cali==127){
//in_press(); //暂停, 然后读取按键状态 spibz
guy_dev->drv_fullpart(part&1);
guy_dev->drv_dispWriter(f,((part>>1)?part>>1:3));
//in_release(); //恢复 //in_release(); //恢复
} }
} }
void ReadguyDriver::drawImage(LGFX_Sprite &base, LGFX_Sprite &spr,uint16_t x,uint16_t y,uint16_t zoomw, uint16_t zoomh) { void ReadguyDriver::drawImage(LGFX_Sprite &base, LGFX_Sprite &spr,uint16_t x,uint16_t y,uint16_t zoomw, uint16_t zoomh) {
if(READGUY_cali==127) guy_dev->drv_drawImage(base, spr, x, y, 0, zoomw, zoomh); if(READGUY_cali==127) guy_dev->drv_drawImage(base, spr, x, y, 0, zoomw, zoomh);
} }
void ReadguyDriver::drawImageStage(LGFX_Sprite &spr,uint16_t x,uint16_t y,uint8_t stage, void ReadguyDriver::drawImageStage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_t x,uint16_t y,uint8_t stage,
uint8_t totalstage,uint16_t zoomw,uint16_t zoomh) { uint8_t totalstage,uint16_t zoomw,uint16_t zoomh) {
if(READGUY_cali!=127 || stage>=totalstage) return; if(READGUY_cali!=127 || stage>=totalstage) return;
guy_dev->drv_drawImage(*this, spr, x, y, (totalstage<=1)?0:(stage==0?1:(stage==(totalstage-1)?3:2)),zoomw,zoomh); //Serial.printf("stage: %d/%d\n",stage+1,totalstage);
guy_dev->drv_drawImage(sprbase, spr, x, y, (totalstage<=1)?0:(stage==0?1:(stage==(totalstage-1)?3:2)),zoomw,zoomh);
} }
void ReadguyDriver::setDepth(uint8_t d){ void ReadguyDriver::setDepth(uint8_t d){
if(READGUY_cali==127 && guy_dev->drv_supportGreyscaling()) guy_dev->drv_setDepth(d); if(READGUY_cali==127 && guy_dev->drv_supportGreyscaling()) guy_dev->drv_setDepth(d);

View File

@@ -132,6 +132,13 @@
#define READGUY_buttons (config_data[21]) //按钮个数, 0-3都有可能 #define READGUY_buttons (config_data[21]) //按钮个数, 0-3都有可能
#endif #endif
#define READGUY_SLOW 0
#define READGUY_FAST 1
#define READGUY_SLOW_START 2
#define READGUY_FAST_START 3
#define READGUY_SLOW_END 4
#define READGUY_FAST_END 5
class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类 class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
public: public:
#ifdef READGUY_ESP_ENABLE_WIFI #ifdef READGUY_ESP_ENABLE_WIFI
@@ -155,7 +162,9 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
/// @brief 返回显示亮度 /// @brief 返回显示亮度
int getBright() const { return currentBright; } int getBright() const { return currentBright; }
/// @brief 刷新显示到屏幕上 /// @brief 刷新显示到屏幕上
void display(bool part = true); void display(uint8_t part = READGUY_FAST);
/// @brief 刷新显示到屏幕上
void display(const uint8_t *buf, uint8_t part = READGUY_FAST);
/** @brief 刷新显示到屏幕上, 可以自定义读取指定位置像素的函数 /** @brief 刷新显示到屏幕上, 可以自定义读取指定位置像素的函数
* @param f 自定义的函数. 此函数将在读取像素并输出到墨水屏时被调用. * @param f 自定义的函数. 此函数将在读取像素并输出到墨水屏时被调用.
* 每次调用需要返回 "参数对应位置" 的8个像素的颜色信息(凑成一字节). 其中左侧应在高位,右侧应在低位. * 每次调用需要返回 "参数对应位置" 的8个像素的颜色信息(凑成一字节). 其中左侧应在高位,右侧应在低位.
@@ -170,7 +179,7 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
* @endcode * @endcode
* 该函数会将参数从0开始,每次逐渐增加1的顺序来被调用. 即先调用f(0),再f(1),f(2),f(3)... 以此类推. * 该函数会将参数从0开始,每次逐渐增加1的顺序来被调用. 即先调用f(0),再f(1),f(2),f(3)... 以此类推.
*/ */
void display(std::function<uint8_t(int)> f, bool part = true); void display(std::function<uint8_t(int)> f, uint8_t part = READGUY_FAST);
/// @brief 显示图片, 使用抖动算法. 可以用省内存的方法显示, 可以缩放到指定的宽度和高度 /// @brief 显示图片, 使用抖动算法. 可以用省内存的方法显示, 可以缩放到指定的宽度和高度
void drawImage(LGFX_Sprite &spr,uint16_t x,uint16_t y,uint16_t zoomw=0, uint16_t zoomh=0){ void drawImage(LGFX_Sprite &spr,uint16_t x,uint16_t y,uint16_t zoomw=0, uint16_t zoomh=0){
if(READGUY_cali==127) drawImage(*this,spr,x,y,zoomw,zoomh); if(READGUY_cali==127) drawImage(*this,spr,x,y,zoomw,zoomh);
@@ -368,14 +377,16 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
//constexpr int memHeight () const { return guy_height ; } //返回显存高度(不是画幅高度),不会随着画布旋转改变 //constexpr int memHeight () const { return guy_height ; } //返回显存高度(不是画幅高度),不会随着画布旋转改变
int drvWidth () const { return READGUY_cali==127?guy_dev->drv_width():0; } //返回显示屏硬件宽度(不是画幅宽度) int drvWidth () const { return READGUY_cali==127?guy_dev->drv_width():0; } //返回显示屏硬件宽度(不是画幅宽度)
int drvHeight() const { return READGUY_cali==127?guy_dev->drv_height():0; } //返回显示屏硬件高度(不是画幅高度) int drvHeight() const { return READGUY_cali==127?guy_dev->drv_height():0; } //返回显示屏硬件高度(不是画幅高度)
int width () const { return READGUY_cali==127?((getRotation()&1)?drvHeight():drvWidth()):0; } int width () const { return (getRotation()&1)?drvHeight():drvWidth(); }
int height() const { return READGUY_cali==127?((getRotation()&1)?drvWidth():drvHeight()):0; } int height() const { return (getRotation()&1)?drvWidth():drvHeight(); }
// private: // private:
void implBeginTransfer() { guy_dev->BeginTransfer(); } //此函数用于开启SPI传输, 只能在自定义刷屏函数中使用!! void implBeginTransfer() { guy_dev->BeginTransfer(); } //此函数用于开启SPI传输, 只能在自定义刷屏函数中使用!!
void implEndTransfer() { guy_dev->EndTransfer(); } //此函数用于开启SPI传输, 只能在自定义刷屏函数中使用!! void implEndTransfer() { guy_dev->EndTransfer(); } //此函数用于开启SPI传输, 只能在自定义刷屏函数中使用!!
/// @brief 分阶段显示图片, 使用抖动算法. 更加的省内存.目前函数 /// @brief 分阶段显示图片, 使用抖动算法. 更加的省内存.目前函数
void drawImageStage(LGFX_Sprite &spr,uint16_t x,uint16_t y,uint8_t stage,uint8_t totalstage, void drawImageStage(LGFX_Sprite &spr,uint16_t x,uint16_t y,uint8_t stage,uint8_t totalstage,
uint16_t zoomw=0,uint16_t zoomh=0); uint16_t zoomw=0,uint16_t zoomh=0){ drawImageStage(*this,spr,x,y,stage,totalstage,zoomw,zoomh); }
void drawImageStage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_t x,uint16_t y,
uint8_t stage,uint8_t totalstage,uint16_t zoomw=0,uint16_t zoomh=0);
}; };
#endif /* END OF FILE. ReadGuy project. #endif /* END OF FILE. ReadGuy project.
Copyright (C) 2023 FriendshipEnder. */ Copyright (C) 2023 FriendshipEnder. */