3 Commits
1.3.0 ... 1.3.2

Author SHA1 Message Date
fsender
2aca106448 feat: new button gesture 2023-11-08 16:44:42 +08:00
fsender
d24639a962 fix memory bug 2023-11-07 21:26:51 +08:00
fsender
85a785eabd update to 1.3.1 ver 2023-11-07 16:41:37 +08:00
34 changed files with 364 additions and 162 deletions

View File

@@ -1,3 +1,39 @@
## Release 1.3.2 - 2023/11/8
1. 按键驱动 (guy_button) 获得新操作更新: (New button gesture)
- 单按键操作更新: 现在双击效果为选择/确定, 三击效果为返回, 长按效果为向上翻页;
- 单按键新增点按后长按操作;
- 双按键新增按住按键1点按按键2操作;
- 三按键新增按住按键1点按按键3操作.
2. 新增获取系统内存的API函数 getFreeMem().
3. 修复若干驱动层bug.
## 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.2正式发布欢迎分享、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

@@ -61,16 +61,16 @@ uint8_t readguyImage::drawImgHandler(int r, LGFX_Sprite *spr){
//_x=y-r/stage*_h; yd=0; //_x=y-r/stage*_h; yd=0;
//_y=x;//(widthDiv8<<3)-x-1; //_y=x;//(widthDiv8<<3)-x-1;
_x=x-r/stage*_h; _x=x-r/stage*_h;
_y=y; yd=0; _y=y+w-guy->drvWidth(); yd=0;
if(_x<0){ xd=-_x; _x=0; } if(_x<0){ xd=-_x; _x=0; }
break; break;
case 2: case 2:
_x=x; xd=0; _x=x+w-guy->drvWidth(); xd=0;
_y=y-(GUY_STAGES-r/stage-1)*_h; _y=y+(r/stage+1)*_h-h;
if(_y<0){ yd=-_y; _y=0; } if(_y<0){ yd=-_y; _y=0; }
break; break;
case 3: case 3:
_x=x-(GUY_STAGES-r/stage-1)*_h; _x=x+(r/stage+1)*_h-h;
_y=y; yd=0; _y=y; yd=0;
if(_x<0){ xd=-_x; _x=0; } if(_x<0){ xd=-_x; _x=0; }
break; break;
@@ -234,7 +234,7 @@ void readguyImage::drawImageFile(bool use16grey){
_pool=exPool; _pool=exPool;
} }
if(_pool==nullptr) { if(_pool==nullptr) {
_h=(h+7)>>3; //设置缓存区的高度. 更多内存将可以更快显示 _h=h>>3; //设置缓存区的高度. 更多内存将可以更快显示
_pool=(uint8_t *)guy->getBuffer(); _pool=(uint8_t *)guy->getBuffer();
} }
//(guy->guyMemoryHeight()+7)>>3 返回高度,并补齐后右移三位 (等效于除以2³, 分成8份) //(guy->guyMemoryHeight()+7)>>3 返回高度,并补齐后右移三位 (等效于除以2³, 分成8份)
@@ -275,7 +275,7 @@ void readguyImage::drawImageFile(bool use16grey){
} }
else{ else{
// ************* 提示: 编写此示例时的最新版本LovyanGFX库不提供此函数. 请看ex06_Image.ino文件开头的解决方法! // ************* 提示: 编写此示例时的最新版本LovyanGFX库不提供此函数. 请看ex06_Image.ino文件开头的解决方法!
guy->display(std::bind(&readguyImage::drawImgHandler,this,std::placeholders::_1,&bmpspr)); guy->display(std::bind(&readguyImage::drawImgHandler,this,std::placeholders::_1,&bmpspr),READGUY_FAST);
// 此函数过不了编译 需要改库. // 此函数过不了编译 需要改库.
} }

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.2",
"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.2
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

@@ -78,11 +78,18 @@ void guy_button::begin(uint8_t _pin, std_U8_function_U8 f, bool activeLow /* = t
state = get_state_cb(pin); state = get_state_cb(pin);
min_debounce =25; //去抖时间 min_debounce =25; //去抖时间
long_press_ms =300; //长按持续时间+双击识别间隔最大时间 long_press_ms =300; //长按持续时间+双击识别间隔最大时间
long_repeat_ms =150; //长按连按间隔时间 long_repeat_ms =200; //长按连按间隔时间
multibtn =0; multibtn =0;
lk=0; lk=0;
} }
bool guy_button::isPressedRaw() {
int mi=millis();
while(lk) if(millis()-mi>GUYBTN_READ_TIMEOUT) return 0; //等待数据读完
lk=3;
bool willreturn = (get_state_cb(pin) == _pressedState);
lk=0;
return willreturn;
}
uint8_t guy_button::read() { //注意ticker不能在此触发 uint8_t guy_button::read() { //注意ticker不能在此触发
int mi=millis(); int mi=millis();
while(lk) if(millis()-mi>GUYBTN_READ_TIMEOUT) return 0; //等待数据读完 while(lk) if(millis()-mi>GUYBTN_READ_TIMEOUT) return 0; //等待数据读完
@@ -91,13 +98,14 @@ uint8_t guy_button::read() { //注意ticker不能在此触发
if(state == _pressedState && n - down_ms>= long_press_ms && long_clicked < n){ if(state == _pressedState && n - down_ms>= long_press_ms && long_clicked < n){
long_clicked = trig_mode?(n+long_repeat_ms):0xfffffffful; long_clicked = trig_mode?(n+long_repeat_ms):0xfffffffful;
lk=0; lk=0;
return GUYBUTTON_long_click; return (click_count>=3)?GUYBUTTON_xxlong_click:\
((click_count==2)?GUYBUTTON_xlong_click:GUYBUTTON_long_click);
} }
uint8_t res = last_click_type; uint8_t res = last_click_type;
last_click_type = GUYBUTTON_empty; last_click_type = GUYBUTTON_empty;
was_pressed = false; was_pressed = false;
lk=0; lk=0;
return (res==GUYBUTTON_long_click)?GUYBUTTON_empty:res; return (res>=GUYBUTTON_long_click)?GUYBUTTON_empty:res;
} }
void guy_button::loop() { void guy_button::loop() {
@@ -140,8 +148,9 @@ void guy_button::loop() {
// was there a longclick? // was there a longclick?
if (longclick_detected) { if (longclick_detected) {
// was it part of a combination? // was it part of a combination?
if (click_count == 1) { if (click_count) {
last_click_type = GUYBUTTON_long_click; last_click_type = (click_count>=3)?GUYBUTTON_xxlong_click:\
((click_count==2)?GUYBUTTON_xlong_click:GUYBUTTON_long_click);
was_pressed = true; was_pressed = true;
} }
longclick_detected = false; longclick_detected = false;

View File

@@ -76,14 +76,17 @@ SOFTWARE.
#define GUYBUTTON_double_click 2 #define GUYBUTTON_double_click 2
#define GUYBUTTON_triple_click 3 #define GUYBUTTON_triple_click 3
#define GUYBUTTON_long_click 4 #define GUYBUTTON_long_click 4
#define GUYBUTTON_xlong_click 5
#define GUYBUTTON_xxlong_click 6
#define GUYBTN_READ_TIMEOUT 100 #define GUYBTN_READ_TIMEOUT 100
#define GUYBTN_LOOP_TIMEOUT 10 #define GUYBTN_LOOP_TIMEOUT 10
class guy_button{ class guy_button{
protected: public:
uint16_t min_debounce ; //去抖时间 uint16_t min_debounce ; //去抖时间
uint16_t long_press_ms ; //长按持续时间+双击识别间隔最大时间 uint16_t long_press_ms ; //长按持续时间+双击识别间隔最大时间
uint16_t long_repeat_ms ; //长按连按间隔时间 uint16_t long_repeat_ms ; //长按连按间隔时间
protected:
uint8_t pin = 255; //未定义引脚 uint8_t pin = 255; //未定义引脚
uint8_t state; uint8_t state;
uint8_t prev_state; uint8_t prev_state;
@@ -114,16 +117,19 @@ class guy_button{
void setLongRepeatMode(bool trigMode) { trig_mode = trigMode; } void setLongRepeatMode(bool trigMode) { trig_mode = trigMode; }
unsigned int wasPressedFor() const { return down_time_ms; } unsigned int wasPressedFor() const { return down_time_ms; }
bool isPressed() const { return (state == _pressedState); } bool isPressed() const { return (state == _pressedState); }
bool isPressedRaw() { return (get_state_cb(pin) == _pressedState); } bool isPressedRaw(); // { return (get_state_cb(pin) == _pressedState); }
bool wasPressed(){ if(was_pressed){ was_pressed = false; return true; } return false; } bool wasPressed(){ if(was_pressed){ was_pressed = false; return true; } return false; }
uint8_t getNumberOfClicks() const{ return click_count;} uint8_t getNumberOfClicks() const{ return click_count;}
uint8_t getType() const { return last_click_type; } uint8_t getType() const { return last_click_type; }
uint8_t read(); uint8_t read();
void loop(); void loop();
void setMultiBtn(uint8_t btns) { multibtn = btns; } void setMultiBtn(uint8_t btns) { multibtn = btns; }
void setMinDebounce(short n) { min_debounce =n;} //去抖时间 /* void setMinDebounce(short n) { min_debounce =n;} //去抖时间
void setLongPressMs(short n) { long_press_ms =n;} //长按持续时间+双击识别间隔最大时间 void setLongPressMs(short n) { long_press_ms =n;} //长按持续时间+双击识别间隔最大时间
void setLongRepeat(short n) { long_repeat_ms =n;} //长按连按间隔时间 void setLongRepeat(short n) { long_repeat_ms =n;} //长按连按间隔时间
void getMinDebounce(short n) { min_debounce =n;} //去抖时间
void getLongPressMs(short n) { long_press_ms =n;} //长按持续时间+双击识别间隔最大时间
void getLongRepeat(short n) { long_repeat_ms =n;} //长按连按间隔时间 */
}; };
#endif /* END OF FILE. ReadGuy project. */ #endif /* END OF FILE. ReadGuy project. */

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
uint32_t ms=millis()-lastRefresh;
uint32_t u=epdFull?1600:310;
if(ms<u) guy_epdBusy(u-ms);
lastRefresh=0;
}
//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,8 @@ 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)) return; //stage 1
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 +80,6 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
} }
} }
} }
yield();
} }
} }
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

@@ -6,7 +6,7 @@
* @file guy_version.h * @file guy_version.h
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder * @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
* @brief readguy 版本控制文件. * @brief readguy 版本控制文件.
* @version 1.0 * @version 1.3.2
* @date 2023-09-21 * @date 2023-09-21
* @attention * @attention
@@ -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 2
#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.2"
#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());
@@ -644,7 +645,7 @@ const PROGMEM char ReadguyDriver::verify2_html[] =
"al\" method=\"POST\"><input type=\'text\' name=\'t_verify\' maxlength=\"6"; "al\" method=\"POST\"><input type=\'text\' name=\'t_verify\' maxlength=\"6";
const PROGMEM char ReadguyDriver::verifybtn_html[3][200] = { const PROGMEM char ReadguyDriver::verifybtn_html[3][200] = {
"一个按键, 操作可能比较繁琐, 但功能还都可以的.<br/>" "一个按键, 操作可能比较繁琐, 但功能还都可以的.<br/>"
"点按: 下一个/向下翻页<br/>双击: 上一个/向上翻页<br/>三连击: 返回/切换输入法<br/>长按: 确定/选择", "点按: 下一个/向下翻页<br/>双击: 确定/选择<br/>三连击: 返回/切换输入法<br/>长按: 上一个/向上翻页",
"两个按键, 操作可以满足需求.<br/>" "两个按键, 操作可以满足需求.<br/>"
"按键1点按: 下一个/向下翻页<br/>按键1长按: 上一个/向上翻页<br/>按键2点按: 确定/选择<br/>按键2长按: 返回/切换输入法", "按键1点按: 下一个/向下翻页<br/>按键1长按: 上一个/向上翻页<br/>按键2点按: 确定/选择<br/>按键2长按: 返回/切换输入法",
"三个按键, 操作非常流畅.<br/>" "三个按键, 操作非常流畅.<br/>"

View File

@@ -49,7 +49,7 @@ ReadguyDriver::ReadguyDriver(){
READGUY_sd_ok = 0; //初始默认SD卡未成功初始化 READGUY_sd_ok = 0; //初始默认SD卡未成功初始化
READGUY_buttons = 0; //初始情况下没有按钮 READGUY_buttons = 0; //初始情况下没有按钮
} //WiFiSet: 是否保持AP服务器一直处于打开状态 } //WiFiSet: 是否保持AP服务器一直处于打开状态
uint8_t ReadguyDriver::init(uint8_t WiFiSet,bool initepd/* ,int g_width,int g_height */){ uint8_t ReadguyDriver::init(uint8_t WiFiSet, bool initepd){
if(READGUY_cali==127) //已经初始化过了一次了, 为了防止里面一些volatile的东西出现问题....还是退出吧 if(READGUY_cali==127) //已经初始化过了一次了, 为了防止里面一些volatile的东西出现问题....还是退出吧
return 0; return 0;
#ifdef DYNAMIC_PIN_SETTINGS #ifdef DYNAMIC_PIN_SETTINGS
@@ -180,15 +180,14 @@ 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的倍数.
createSprite(guy_dev->drv_width(),(guy_dev->drv_height()+7)&0x7ffffff8); createSprite(guy_dev->drv_width(),guy_dev->drv_height());
//这里发现如果用自定义的内存分配方式会更好一些. 不会导致返回的height不对. 但是因为LovyanGFX库未更新 暂时不能这么用. //这里发现如果用自定义的内存分配方式会更好一些. 不会导致返回的height不对. 但是因为LovyanGFX库未更新 暂时不能这么用.
//setRotation(1); //旋转之后操作更方便 //setRotation(1); //旋转之后操作更方便
setRotation(0); setRotation(0);
@@ -280,18 +279,21 @@ void ReadguyDriver::setButtonDriver(){
if(READGUY_btn1) btn_rd[0].begin(abs(READGUY_btn1)-1,rd_btn_f,(READGUY_btn1>0)); if(READGUY_btn1) btn_rd[0].begin(abs(READGUY_btn1)-1,rd_btn_f,(READGUY_btn1>0));
if(READGUY_btn2) btn_rd[1].begin(abs(READGUY_btn2)-1,rd_btn_f,(READGUY_btn2>0)); if(READGUY_btn2) btn_rd[1].begin(abs(READGUY_btn2)-1,rd_btn_f,(READGUY_btn2>0));
if(READGUY_btn3) btn_rd[2].begin(abs(READGUY_btn3)-1,rd_btn_f,(READGUY_btn3>0)); if(READGUY_btn3) btn_rd[2].begin(abs(READGUY_btn3)-1,rd_btn_f,(READGUY_btn3>0));
//if(READGUY_buttons==1){
btn_rd[0].setLongRepeatMode(1); //允许连按
//}
if(READGUY_buttons==2){ if(READGUY_buttons==2){
btn_rd[0].setMultiBtn(1); //设置为多个按钮,不识别双击或三击 btn_rd[0].setMultiBtn(1); //设置为多个按钮,不识别双击或三击
btn_rd[0].setLongRepeatMode(1); //btn_rd[0].setLongRepeatMode(1);
btn_rd[1].setMultiBtn(1); //设置为多个按钮,不识别双击或三击 btn_rd[1].setMultiBtn(1); //设置为多个按钮,不识别双击或三击
btn_rd[1].setLongRepeatMode(0); btn_rd[1].setLongRepeatMode(0);
} }
else if(READGUY_buttons==3){ else if(READGUY_buttons==3){
btn_rd[0].setLongPressMs(1); //不识别双击三击, 只有按一下或者长按, 并且开启连按 btn_rd[0].long_press_ms = 150; //不识别双击三击, 只有按一下或者长按, 并且开启连按
btn_rd[0].setLongRepeatMode(1); //btn_rd[0].setLongRepeatMode(1);
btn_rd[1].setMultiBtn(1); //设置为多个按钮,不识别双击或三击 btn_rd[1].setMultiBtn(1); //设置为多个按钮,不识别双击或三击
btn_rd[1].setLongRepeatMode(0); btn_rd[1].setLongRepeatMode(0);
btn_rd[2].setLongPressMs(1); //不识别双击三击, 只有按一下或者长按, 并且开启连按 btn_rd[2].long_press_ms = 1; //不识别双击三击, 只有按一下或者长按, 并且开启连按
btn_rd[2].setLongRepeatMode(1); btn_rd[2].setLongRepeatMode(1);
} }
#ifdef ESP8266 //对于esp8266, 需要注册到ticker. 这是因为没freertos. #ifdef ESP8266 //对于esp8266, 需要注册到ticker. 这是因为没freertos.
@@ -370,32 +372,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::displayBuffer(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);
@@ -489,29 +500,47 @@ void ReadguyDriver::nvs_write(){
#endif #endif
uint8_t ReadguyDriver::getBtn_impl(){ //按钮不可用, 返回0. uint8_t ReadguyDriver::getBtn_impl(){ //按钮不可用, 返回0.
static uint32_t last=0;
uint8_t res1,res2,res3,res4=0; uint8_t res1,res2,res3,res4=0;
switch(READGUY_buttons){ switch(READGUY_buttons){
case 1: case 1:
res1=btn_rd[0].read(); res1=btn_rd[0].read();
if(res1 == 1) res4 |= 1; //点按 if(res1 == 1) res4 |= 1; //点按
else if(res1 == 2) res4 |= 2; //双击 else if(res1 == 2) res4 |= 4; //双击-确定
else if(res1 == 4) res4 |= 4; //长按-确定
else if(res1 == 3) res4 |= 8; //三击-返回 else if(res1 == 3) res4 |= 8; //三击-返回
else if(res1 == 4) res4 |= 2; //长按-向上翻页
else if(res1 == 5) res4 |= 3; //单击后长按-新增操作(可以连按)
break; break;
case 2: case 2:
res1=btn_rd[0].read(); //两个按钮引脚都读取 res1=btn_rd[0].read(); //两个按钮引脚都读取
res2=btn_rd[1].read(); res2=btn_rd[1].read();
if(res1 == 1) res4 |= 1; //左键点按-向下翻页 if(millis()-last>500){
else if(res1 == 4) res4 |= 2; //左键按-向翻页 if(res1 == 1) res4 |= 1; //左键按-向翻页
if(res2 == 1) res4 |= 4; //右键点按-确定 else if(res1 == 4) {
else if(res2 == 4) res4 |= 8; //键长按-返回 res4 |= 2; //键长按-向上翻页
//if(btn_rd[1].isPressedRaw()) res4 |= 1;
}
}
if(btn_rd[0].isPressedRaw() && res2){
res4 |= 3; //右键点按-确定
last=millis();
}
else{
if(res2 == 1) res4 |= 4; //右键点按-确定
else if(res2 == 4) res4 |= 8; //右键长按-返回
}
if(res4==5 || res4==6) res4=3;
break; break;
case 3: case 3:
res1=btn_rd[0].read(); res1=btn_rd[0].read();
res2=btn_rd[1].read(); res2=btn_rd[1].read();
res3=btn_rd[2].read(); res3=btn_rd[2].read();
if(res1 == 4) res4 |= 1; if(res1 && millis()-last >= btn_rd[1].long_repeat_ms && (!btn_rd[2].isPressedRaw())) res4 |= 2;
if(res3 == 4) res4 |= 2; if(res3) {
res4 |= ((btn_rd[0].isPressedRaw()<<1)|1);
last=millis();
}
//if(res3 && ((millis()-last)<btn_rd[0].long_repeat_ms)) res4 |=3;
if(res2 == 1) res4 |= 4; if(res2 == 1) res4 |= 4;
else if(res2 == 4) res4 |= 8; else if(res2 == 4) res4 |= 8;
break; break;

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
@@ -147,15 +154,18 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
/** @brief 初始化readguy /** @brief 初始化readguy
* @param WiFiSet 是否保持AP模式关闭. 0:配网完成自动关WiFi, 1:需要手动调用 WiFi.mode(WIFI_OFF) 关闭WiFi. * @param WiFiSet 是否保持AP模式关闭. 0:配网完成自动关WiFi, 1:需要手动调用 WiFi.mode(WIFI_OFF) 关闭WiFi.
* 2:自动连接到已存的WiFi, 但不等待连接成功 * 2:自动连接到已存的WiFi, 但不等待连接成功
* @param initepd 是否初始化墨水屏. 初始化后的首次刷屏必为慢刷. 如果是不断电复位, 可以不初始化墨水屏直接刷屏
* @return SD卡是否就绪 * @return SD卡是否就绪
*/ */
uint8_t init(uint8_t WiFiSet = 0,bool initepd = 1/* ,int g_width = 0,int g_height = 0 */); uint8_t init(uint8_t WiFiSet = 0, bool initepd = 1);
/// @brief 设置显示亮度 /// @brief 设置显示亮度
void setBright(int d); void setBright(int d);
/// @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 displayBuffer(const uint8_t *buf, uint8_t part);
/** @brief 刷新显示到屏幕上, 可以自定义读取指定位置像素的函数 /** @brief 刷新显示到屏幕上, 可以自定义读取指定位置像素的函数
* @param f 自定义的函数. 此函数将在读取像素并输出到墨水屏时被调用. * @param f 自定义的函数. 此函数将在读取像素并输出到墨水屏时被调用.
* 每次调用需要返回 "参数对应位置" 的8个像素的颜色信息(凑成一字节). 其中左侧应在高位,右侧应在低位. * 每次调用需要返回 "参数对应位置" 的8个像素的颜色信息(凑成一字节). 其中左侧应在高位,右侧应在低位.
@@ -170,7 +180,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);
/// @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);
@@ -240,6 +250,8 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
bool SDinside(bool check=true) { return check?setSDcardDriver():READGUY_sd_ok; }; bool SDinside(bool check=true) { return check?setSDcardDriver():READGUY_sd_ok; };
/// @brief 检查按钮. 当配置未完成时,按钮不可用, 返回0. /// @brief 检查按钮. 当配置未完成时,按钮不可用, 返回0.
uint8_t getBtn() { return (READGUY_cali==127)?getBtn_impl():0; } uint8_t getBtn() { return (READGUY_cali==127)?getBtn_impl():0; }
/// @brief 根据按钮ID来检查按钮. 注意这里如果按下返回0, 没按下或者按钮无效返回1
//uint8_t getBtn(unsigned int btnID){return btnID<getButtonsCount()?(!(btn_rd[0].isPressedRaw())):1;}
/** @brief 返回可用的文件系统. 当SD卡可用时, 返回SD卡. 否则根据情况返回最近的可用文件系统 /** @brief 返回可用的文件系统. 当SD卡可用时, 返回SD卡. 否则根据情况返回最近的可用文件系统
* @param initSD 2:总是重新初始化SD卡; 1:若SD卡不可用则初始化; 0:SD卡不可用则返回LittleFS. */ * @param initSD 2:总是重新初始化SD卡; 1:若SD卡不可用则初始化; 0:SD卡不可用则返回LittleFS. */
fs::FS &guyFS(uint8_t initSD = 0); fs::FS &guyFS(uint8_t initSD = 0);
@@ -328,14 +340,18 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
static uint8_t rd_btn_f(uint8_t btn); static uint8_t rd_btn_f(uint8_t btn);
uint8_t getBtn_impl(); //按钮不可用, 返回0. uint8_t getBtn_impl(); //按钮不可用, 返回0.
static void in_press(){ //SPI开始传输屏幕数据 static void in_press(){ //SPI开始传输屏幕数据
#ifndef ESP8266 #ifdef ESP8266
if(!spibz) SPI.beginTransaction(SPISettings(ESP8266_SPI_FREQUENCY, MSBFIRST, SPI_MODE0));
#else
if(!spibz) epd_spi->beginTransaction(SPISettings(ESP32_DISP_FREQUENCY, MSBFIRST, SPI_MODE0)); if(!spibz) epd_spi->beginTransaction(SPISettings(ESP32_DISP_FREQUENCY, MSBFIRST, SPI_MODE0));
#endif #endif
spibz ++; spibz ++;
} }
static void in_release(){//SPI结束传输屏幕数据 static void in_release(){//SPI结束传输屏幕数据
spibz --; spibz --;
#ifndef ESP8266 #ifdef ESP8266
if(!spibz) SPI.endTransaction();
#else
if(!spibz) epd_spi->endTransaction(); if(!spibz) epd_spi->endTransaction();
#endif #endif
} }
@@ -368,14 +384,23 @@ 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(); }
size_t getFreeMem() const { return
#ifdef ESP8266
ESP.getFreeHeap();
#else
esp_get_free_heap_size();
#endif
}
// 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. */