6 Commits
1.3.3 ... 1.3.5

Author SHA1 Message Date
fsender
7bb2ba77f0 1.3.5: add send-text example&fix bugs 2024-03-04 13:53:35 +08:00
fsender
8e825c862a 1.3.5: add more examples&fix bugs 2024-03-04 13:48:01 +08:00
fsender
d88f1a3c5c feat: add 5.83 inch support 2023-11-24 22:38:28 +08:00
fsender
771ac6db80 feat: initSD option. init without SD is fine 2023-11-12 07:10:23 +08:00
fsender
c4e848730c perf: better button preformance 2023-11-12 06:19:31 +08:00
fsender
78438e36a7 fix: pin preset order 2023-11-12 05:01:10 +08:00
31 changed files with 35362 additions and 119 deletions

View File

@@ -1,3 +1,19 @@
## Release 1.3.5 - 2024/3/4
1. 2024/2/25更新: 修复了按键bug, 双按键有时候识别不灵, 三按键不支持移植到拨轮硬件操作, 现在全修好了
2. 2024/2/26更新: 增加了新环境 : 针对无串口芯片的 ESP32C3 新增的选项
3. 2024/2/28更新: 增加了新的示例: WiFi传文本
4. 优化ESP32C3的配置体验
## Release 1.3.4 - 2023/11/24
1. 添加5.83寸屏幕驱动. 默认开启, 嫌flash占用大的可以手动关
2. 修复别的一些bug
## Release 1.3.3 - 2023/11/12
1. 添加了2.66寸三色和黑白的不同驱动程序.

View File

@@ -4,7 +4,7 @@
<img src="extra/artset/readguy_theme3.png" width="30%" height="auto">
**版本1.3.3正式发布欢迎分享、star和fork~** 上面的图是项目看板娘, 盖. 可爱的盖姐在等你哟~
**版本1.3.5正式发布欢迎分享、star和fork~** 上面的图是项目看板娘, 盖. 可爱的盖姐在等你哟~
**即将发布7个全新的屏幕驱动: 欢迎支持! (详见后面的驱动表格)**
@@ -70,7 +70,7 @@ Supported displays: 1.54-inch, 2.13-inch, 2.66-inch, 2.9-inch, 4.2-inch.
|14 |M5 Core.Ink 1.54寸 |即将支持|200*200|/|/|/|/|
|15 |3.7寸低DPI版墨水屏 |即将支持|416*240|/|/|/|/|
|16 |4.26寸高分辨率墨水屏|即将支持|800*480|/|/|/|/|
|17 |5.83寸墨水屏幕 |即将支持|600*448|/|/|/|/|
|17 |5.83寸墨水屏幕 |原创自研|600*448| 16阶 | 支持 | 1.7s | 0.8s |
|18 |5.83寸GDEQ0583T31 |即将支持|640*480|/|/|/|/|
|19 |7.5寸三色墨水屏幕 |即将支持|800*480|/|/|/|/|
|20 |10.2寸GDEQ102T90 |即将支持|960*640|/|/|/|/|
@@ -247,5 +247,5 @@ firmware.bin 0x10000
Copyright © 2022-2023 FriendshipEnder. All Rights reserved.
版权声明:需要经过作者@friendshipender的许可才能商用
版权声明:需要经过作者@friendshipender的许可才能商用 可以联系邮箱playyinzhe@qq.com询问商用事宜

View File

@@ -6,8 +6,9 @@
*
* @file ex03_buttons.ino
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
* @version 1.0
* @date 2023-10-20
* @version 1.1 增加了新的手势功能
*
* @date created: 2023-10-20 last modify: 2024-02-25
* @brief ReadGuy 按键功能演示. ReadGuy自带的按键驱动程序是非常好用的
* @attention
@@ -64,6 +65,11 @@ void loop(){
else if(c==2) guy.println("Left key long pressed!");
else if(c==3) guy.println("Right key clicked!");
break;
case 3:
if(c==1) guy.println("key triple clicked!");
else if(c==2) guy.println("Right clicked at left pressing!");
else if(c==3) guy.println("Centre key double clicked!");
break;
case 4:
if(c==1) guy.println("key long pressed!");
else if(c==2) guy.println("Right key clicked!");

View File

@@ -6,10 +6,13 @@
*
* @file 2_wifi_config.ino
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
* @version 1.0
* @date 2023-10-14
* @version 1.1
* @date create: 2023-10-14 last modify: 2024-02-26
* @note 本版本主要更新了NTP对时机制, 以及扫描wifi时可以在屏幕上显示到底扫描了多少wifi
* @brief ReadGuy配网服务器 配置并连接附近的WiFi网络演示程序.
编译烧录后, 本程序将使用AP方式配网并在连接到网络时访问NTP服务器来在墨水屏上显示时间.
*** 推荐文章 解决2038千年虫: (本程序未使用该文章内容)
*** https://blog.csdn.net/qdlyd/article/details/131199628
同时开启在STA上的服务器, 供这个WiFi上的用户访问此墨水屏阅读器.
// 注意, 为了避免此项目占用的flash空间过大, 故库内中不再提供配网的相关功能函数.
@@ -40,6 +43,7 @@
#include <Arduino.h> //arduino功能基础库. 在platformIO平台上此语句不可或缺
#include "readguy.h" //包含readguy_driver 基础驱动库
#include <lwip/apps/sntp.h>
ReadguyDriver guy;//新建一个readguy对象, 用于显示驱动.
@@ -48,7 +52,9 @@ typedef ReadguyDriver::serveFunc event_t ; //存储一个WiFi功能事
void f1(server_t sv); //服务器响应回调函数. 当启动AP配网服务器时, 这些函数将会被调用
void f2(server_t sv);
time_t getNTPTime(); //NTP获取时间的函数
/// @brief NTP获取时间的函数, 必须联网才能调用
time_t getNTPTime();
int conf_status = 0; //标记WiFi配网状态: 当此值为1时, 说明配网程序收到了WiFi SSID和密码信息, 尝试连接.
//此变量为2 说明配网成功了. 连接到了WiFi并显示当前时间.
@@ -81,8 +87,8 @@ void setup(){
scanres = WiFi.scanNetworks(); //开始扫描网络
Serial.println("[readguy] WiFi Scan OK."); //关闭服务器, 尝试连接, 连接成功之后将会在屏幕上显示
guy.println("WiFi Scan OK."); //连接失败则会重新进入循环
Serial.printf("[readguy] WiFi Scan %d OK.\n",scanres); //关闭服务器, 尝试连接, 连接成功之后将会在屏幕上显示
guy.printf("WiFi Scan %d OK.\n",scanres); //连接失败则会重新进入循环
guy.display();
IPAddress local_IP(192,168,4,1); //设置本地AP的IP地址, 网关和子网掩码.
@@ -135,9 +141,15 @@ void setup(){
Serial.println("[readguy] Getting NTP time..."); //连接成功之后尝试获取NTP时间
guy.display();
time_t now = getNTPTime(); //下方的函数演示了如何使用NTP来对时
guy.println(ctime(&now));
Serial.println(ctime(&now));
time_t now = getNTPTime(); //下方的函数演示了如何使用NTP来对时. 此函数必须连接上wifi才能调用
now=time(nullptr); //通过Unix API获取时间
struct tm now_tm;
gmtime_r(&now,&now_tm); //转换为GMT时间
guy.println(asctime(&now_tm));
Serial.println(asctime(&now_tm));
localtime_r(&now,&now_tm); //转换为本地时间(包含了时区数据的)
guy.println(asctime(&now_tm));
Serial.println(asctime(&now_tm));
guy.display();
guy.server_setup("现在是联网的STA模式."); //如果没有调用server_end函数 连续调用server_setup将自动结束之前的服务器
@@ -216,7 +228,6 @@ void f2(server_t sv){
PSTR("<html><body><meta charset=\"utf-8\">配置失败,缺少信息</body></html>"));
}
/*----------------- NTP code ------------------*/
WiFiUDP udp;
uint8_t packetBuffer[48];
@@ -271,25 +282,32 @@ time_t get_ntp_time_impl(uint8_t _server)
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
secsSince1900 |= (unsigned long)packetBuffer[43];
return secsSince1900 - 2208988800UL + timeZone * 3600;
return secsSince1900 - 2208988800UL; // + timeZone * 3600; //时区数据 舍弃即可
}
}
Serial.println("No NTP Response :-(");
return 0; // return 0 if unable to get the time
}
time_t getNTPTime(){
time_t _now = 0;
if(!WiFi.isConnected()) return 0;
udp.begin(localPort);
Serial.print("Local port: ");
Serial.println(localPort);
for(int i=0;i<4;i++){//最多尝试10次对时请求
_now=get_ntp_time_impl(i);
if(_now) break; //成功后立即退出
yield();
Serial.print("Local port: ");
Serial.println(localPort);
for(int i=0;i<4;i++){//最多尝试10次对时请求
_now=get_ntp_time_impl(i);
if(_now) break; //成功后立即退出
yield();
}
if(_now){
if(time(nullptr) < 1577836800){ //时区未设置 (比较时间为2020年1月1日 00:00:00)
setenv("TZ", "CST-8", 1); //设置时区变量 (当前设置为北京时间)
tzset();
}
return _now;
timeval tm_now={_now, 0};
settimeofday(&tm_now,nullptr);
}
return _now;
}
/* END OF FILE. ReadGuy project.

View File

@@ -0,0 +1,137 @@
/******************** F r i e n d s h i p E n d e r ********************
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
*
* @file 4_wifi_text_show.ino
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
* @version 1.0
* @date 2024-02-28
* @brief ReadGuy通过wifi传输文本并显示.
// 注意, 为了避免此项目占用的flash空间过大, 故库内中不再提供配网的相关功能函数.
// 此示例程序提供了文本传输的功能, 可以通过网页端输入文本并显示到墨水屏上. 自适应字体大小.
// ******** 在进行此示例之前, 不要将 DYNAMIC_PIN_SETTINGS 和 READGUY_ENABLE_WIFI 注释掉. ********
// ******************************** 此示例需要用到 WiFi 的特性. ********************************
*
* @attention
* Copyright (c) 2022-2023 FriendshipEnder
*
* Apache License, Version 2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//在这里包含程序需要用到的库函数
#include <Arduino.h> //arduino功能基础库. 在platformIO平台上此语句不可或缺
#include "readguy.h" //包含readguy_driver 基础驱动库
#include "ctg_u8g2_wqy12.h" //中文字体库
ReadguyDriver guy;//新建一个readguy对象, 用于显示驱动.
//extern const uint8_t ctg_u8g2_wqy12_chinese1[]; //声明中文字体文件, 本字体只包含很少的字, 不建议用
extern const uint8_t ctg_u8g2_wqy12_gb2312[]; //声明中文字体文件, 本字体包含常用字, 体积较大
//extern const uint8_t ctg_u8g2_wqy12[]; //声明中文字体文件, 本字体包含绝大多数的字, 但体积也更大
const lgfx::U8g2font cn_font(ctg_u8g2_wqy12_gb2312); //U8G2格式中文字体转化为LGFX格式字体
typedef ReadguyDriver::ReadguyWebServer* server_t; //类型名太长太繁琐, 使用typedef减短
typedef ReadguyDriver::serveFunc event_t ; //存储一个WiFi功能事件.
const PROGMEM char textShowHtml[]= R"EOF(<!DOCTYPE html>
<html lang=\"zh-cn\">
<head>
<meta charset=\"utf-8\">
<title>WiFi传文字</title>
</head>
<body>
<h1>WiFi传文字 </h1>
<p><br /></p>
<form action="/showtext" method="GET"><input type='text' name='txt' placeholder="ReadGuy" maxlength="63" />
<br /><input type='submit' value='!' /><br /></form><br />
<p>ReadGuy<br />Copyright © FriendshipEnder
<a href="https://github.com/fsender/readguy">GitHub</a>
<a href="https://space.bilibili.com/180327370/">Bilibili</a></p>
</body>
</html>
)EOF"; //网页文本
void textShow(server_t sv); //服务器响应回调函数. 当启动AP配网服务器时, 这些函数将会被调用
void textShowGet(server_t sv);
void setup(){
Serial.begin(115200); //初始化串口
guy.init(); //初始化readguy_driver 基础驱动库. 尽管初始化过程会刷屏, 但此示例不会用到屏幕.
if(guy.width()<guy.height()) guy.setRotation(1);
guy.setFont(&cn_font);
guy.println("Web一键传文本 正在启用热点...");
guy.display();
event_t server_event[2]={
{"一键传文字","/textshow",textShow},
{"","/showtext",textShowGet},
};
guy.ap_setup(); //初始化WiFi AP模式 (可以理解为路由器模式)
guy.server_setup(String(F("配网服务器演示:可以放置自己的链接和回调函数")),server_event,2); //初始化服务器.
//这些服务器响应回调函数会打包进入初始化参数列表中.
//上方的字符串可以在用户访问主页时, 显示在主页的第二行.(作为通知显示, 但并不是通知)
guy.println("名称:readguy 密码:12345678");
guy.display();
}
void loop(){
guy.server_loop(); //让服务器一直运行
}
// 以下演示了如何向配网服务器添加回调函数.
//其中, sv 参数指向了一个服务器类型的变量. 当有来自客户端的请求时, 需要通过sv来发送响应消息.
void textShow(server_t sv){ //点击链接即可出现发送文本框, 点击发送按钮即可将输入的文本显示到屏幕上
sv->send_P(200, PSTR("text/html"), textShowHtml);
}
void textShowGet(server_t sv){ //注册Web服务函数回调 (就是显示接口)
const String ok_str_1=F("<html><body><meta charset=\"utf-8\">"); //网页前半部分
const String ok_str_2=F("<a href=\"/textshow\">重新传文字</a></body></html>"); //网页后半部分
if(sv->hasArg("txt")){ //检查请求的报文 是否包含键值txt (详见前面的网页声明)
String txt=sv->arg("txt"); //找到字段
//-----------------showTextEpd(txt)------------------ //显示到墨水屏幕上
guy.setTextSize(1); //先设置为默认字体大小, 方便后续计算
int twidth = guy.textWidth(txt); //获取字符串在当前字体的宽度
if(!twidth) { //宽度数值必须为非0
sv->send(200, String(F("text/html")), ok_str_1+"只包含空格, 不显示. "+ok_str_2);
Serial.println("Arg width == 0."); //字符串为空 或者总宽度为零
return;
}
sv->send(200, String(F("text/html")), ok_str_1+"文字显示完成: "+txt+ok_str_2); //报告显示完成
float tsize = ((float)guy.width())/twidth; //计算字体大小, 此大小的目的是填满屏幕
float fsize = ((float)guy.height())/guy.fontHeight(); //计算垂直方向的字体大小, 制定合适的显示方法
if(tsize>fsize){ //字符太短, 字体大小取决于屏幕垂直高度
guy.setTextSize(fsize);
}
else{ //字符可以顶到宽度
guy.setTextSize(tsize, std::max(1.0f,tsize)); //显示的字体大小会根据文本动态变化
} //水平方向太小的话, 垂直方向大小设置为1.0倍(字体原高度)
guy.fillScreen(1);//清屏
guy.setTextDatum(MC_DATUM); //居中显示
guy.drawString(txt,guy.width()/2,guy.height()/2);//居中显示
guy.display(READGUY_SLOW); //慢刷
Serial.print("Show successful:"); //显示成功
Serial.println(txt);
}
else{
Serial.println("No arg."); //找不到txt字段参数
sv->send(200, String(F("text/html")), ok_str_1+"显示失败:缺少参数 "+ok_str_2);
}
}/* END OF FILE. ReadGuy project.
Copyright (C) 2023 FriendshipEnder. */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,43 @@
/******************** F r i e n d s h i p E n d e r ********************
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
*
* @file ctg_u8g2_wqy12.h
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
* @version 1.0
* @date 2023-09-24
* @brief ReadGuy示例字体文件
* @attention
* Copyright (c) 2022-2023 FriendshipEnder
*
* Apache License, Version 2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef _CTG_U8G2_WQY12_H_FILE
#define _CTG_U8G2_WQY12_H_FILE
#include <Arduino.h>
#include <pgmspace.h>
#ifdef __cplusplus
extern "C" {
#endif
extern const uint8_t ctg_u8g2_wqy12_chinese1[14241] ;
extern const uint8_t ctg_u8g2_wqy12_gb2312[208522] ;
extern const uint8_t ctg_u8g2_wqy12[626234] ;
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -35,6 +35,7 @@
extern "C" {
#endif
extern const uint8_t ctg_u8g2_wqy12_chinese1[14241] ;
extern const uint8_t ctg_u8g2_wqy12_gb2312[208522] ;
extern const uint8_t ctg_u8g2_wqy12[626234] ;
#ifdef __cplusplus
}

View File

@@ -40,17 +40,24 @@ namespace guydev_template{
void drv::drv_init(){ //初始化屏幕
//add driver code...
}
void drv::drv_fullpart(bool part){ //初始化慢刷功能
void drv::drv_fullpart(bool part){ //初始化慢刷/快刷功能
if(lastRefresh) return;
//add driver code...
}
void drv::drv_setDepth(uint8_t i){
epdFull=0; iLut = i?(i>15?15:i):15; //如果需要, 改成自己的代码
}
/* 关于这里的f函数指针: f(n)代表访问屏幕缓存的第n字节
若设N=(((屏幕宽度+7)/8)*屏幕高度), 则n的取值范围为 0<=n<N .
比如一个缓存buffer, 有N字节, 那么可以用f(n)=buffer[n]
函数语法为 drv_dispWriter([&](int n)->uint8_t{return buffer[n];},3);
呃 你就把里面的f(n)理解为buffer[n]就行.
*/
void drv::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷新
if(m&1){//stage 1
if(lastRefresh) drv_dispWriter(f,2);
//add driver code...
lastRefresh=millis();
}
if(m&2){//stage 2
uint32_t ms=millis()-lastRefresh;

View File

@@ -43,20 +43,45 @@ constexpr int fastRefTime =500; //驱动屏幕快刷时间, 单位毫秒
class drv : public readguyEpdBase {
public:
/** @brief 返回驱动程序ID. 此函数不需要在 cpp 文件内重写
* @return int 直接返回对应宏定义就可以 */
int drv_ID() const { return READGUY_DEV_template; }
void drv_init(); //初始化屏幕
void drv_fullpart(bool part); //切换慢刷/快刷功能
void drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m=3); //按照函数刷新
void drv_sleep() ; //开始屏幕睡眠
int drv_width() const { return GUY_D_WIDTH; }; //返回显示区域宽度
//int drv_panelwidth() const { return GUY_D_WIDTH; }; //返回缓存的数据宽度
int drv_height() const{ return GUY_D_HEIGHT; }; //返回显示区域高度
void drv_setDepth(uint8_t i); //设置显示颜色深度
/// @brief 初始化屏幕 不过大多数时候此函数只需要初始化启动变量就行
// 比如将模式设为慢刷, 设置为未上电状态 这样下次刷新必为全屏慢刷
void drv_init();
/// @brief 切换慢刷/快刷功能
/// @param part 为1则为快刷, 为0则为慢刷
void drv_fullpart(bool part);
/** @brief 刷屏函数. 程序接口按照此函数刷新
/ @param f 读取像素数据的函数. 这个函数用于替代屏幕缓存数组.
/ 因为有时候屏幕缓存数组不能满足一些显示场景, 比如存储空间复用, 缩放显示等
/ @param m 刷新模式:
/ 1-仅执行前半部分 执行前半部分之后将会向屏幕发送数据后立即退出. (不等busy信号)
/ 2-仅执行后半部分 执行后半部分之后会进行屏幕刷新完之后该执行的操作
/ 3-完整刷屏: 执行1部分->等待busy信号->执行2部分 */
void drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m=3);
/// @brief 开始屏幕睡眠/低功耗模式
void drv_sleep() ;
/// @brief 返回显示区域宽度
int drv_width() const { return GUY_D_WIDTH; };
/// @brief 返回显示区域高度
int drv_height() const{ return GUY_D_HEIGHT; };
/** @brief 设置显示颜色深度. 只有在受支持 屏幕上才可以设置灰度
/ @param i 有效值 1~16 0必须为无效 */
void drv_setDepth(uint8_t i);
/** @brief 设置屏幕是否支持连续灰度刷新.
/ @return 设置为 0 不支持灰度 16 支持灰度 -16 支持连续刷新灰度
/ 连续刷新灰度: 先刷深色部分 再刷浅色部分, 原来的深色部分每次刷新都会逐渐越来越深色.
/ 如果不提供连续刷新灰度接口 则使用setDepth函数 先刷浅色部分 再刷深色部分
/ 可以在支持连续刷新的屏幕上烧录范例程序查看效果. 通常都是好于非连续刷新的灰度 */
int drv_supportGreyscaling() const { return 16; }
// 在支持连续灰度刷新的屏幕上 还要额外实现一个函数用于连续刷新接口
/// @brief 设置连续刷新功能函数. 范例可以看guy_420a文件内的示例,分步执行连续刷灰度
//void drv_draw16grey_step(std::function<uint8_t(int)> f, int step);
private:
uint8_t epd_PowerOn=1; //是否上电. 睡眠则设为0
uint8_t epdFull=0; //是partical模式/快速刷新模式 0快刷, 1慢刷
uint8_t iLut=15; //颜色深度
uint8_t iLut=15; //颜色深度 1-15均为有效. 慢刷模式中 此数值为15.
};
}
#endif /* END OF FILE. ReadGuy project.

View File

@@ -45,9 +45,6 @@ default_envs = nodemcuv2
board_build.filesystem = littlefs ; SPIFFS mode
upload_speed = 921600 ; If using USB-JTAG, this selection is dummy
monitor_speed = 115200
build_flags =
-Wall
-Wextra
[env:esp32dev] ; 适用于ESP32的项目配置方案 注意是经典的ESP32...
platform = espressif32
@@ -60,6 +57,8 @@ framework = espidf, arduino
monitor_filters = esp32_exception_decoder
;build_type = debug
build_flags =
-Wall
-Wextra
; -DCORE_DEBUG_LEVEL=4
[env:nodemcuv2] ; 适用于ESP8266的项目配置方案
@@ -72,6 +71,8 @@ monitor_filters = esp8266_exception_decoder
;build_type = debug
build_flags =
-Wall
-Wextra
; -DNON32XFER_HANDLER ;不需要PROGMEM保留字也可以访问flash中的内容
; -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 ;增大可用的HEAP内存
; -fstack-protector ;打开栈溢出保护器
@@ -90,7 +91,9 @@ board_build.partitions = readguy_4MB.csv ; defined
monitor_filters = esp32_exception_decoder
;build_type = debug
build_flags =
build_flags =
-Wall
-Wextra
;-DARDUINO_USB_MODE=1
;-DARDUINO_USB_CDC_ON_BOOT=1 ; 是否需要使用USB串口调试如果需要调试则打开否则禁用
; 如果打开了这个选项但是不连接串口在有串口输出的地方会卡顿1秒左右
@@ -117,7 +120,9 @@ board_build.flash_mode = dio
board_build.partitions = readguy_16MB.csv
monitor_filters = esp32_exception_decoder
build_flags =
build_flags =
-Wall
-Wextra
;-DARDUINO_USB_MODE=1
;-DARDUINO_USB_CDC_ON_BOOT=1 ; 是否需要使用USB串口调试如果需要调试则打开否则禁用
; 如果打开了这个选项但是不连接串口在有串口输出的地方会卡顿1秒左右
@@ -142,6 +147,31 @@ board_build.f_flash = 80000000L
board_build.flash_mode = dio
board_build.partitions = readguy_4MB.csv ; 2MB的芯片就选readguy_2MB_noOTA.csv
build_flags =
-Wall
-Wextra
;-DARDUINO_USB_MODE=1
;-DARDUINO_USB_CDC_ON_BOOT=1 ; 是否需要使用USB串口调试如果需要调试则打开否则禁用
; 如果打开了这个选项但是不连接串口在有串口输出的地方会卡顿1秒左右
; 合宙无串口开发板请选择此选项为1.
-DCORE_DEBUG_LEVEL=1 ; None 0, Error 1, Warn 2, Info 3, Debug 4, Verbose 5
[env:esp32c3_no_uart] ;适用于ESP32C3 的项目配置方案.
platform = espressif32 ;注意在使用不带串口芯片的ESP32C3时, 尽量不要使用引脚18和19.
board = esp32-c3-devkitm-1 ;那俩是连接的板载USB串口 (USB-CDC, 可以下载程序或是当免驱串口)
framework = espidf, arduino ;合宙你真该死啊出这种没串口芯片的ESP32C3 甚至旧版本arduino无法编程!
board_build.f_cpu = 160000000L ;芯片速率默认160MHz, 不支持高频240MHz.
;board_build.flash_size=2MB ;2MB的芯片就选readguy_2MB_noOTA.csv
board_build.flash_size=4MB ;根据你自己的改, 不得小于4MB. 2MB的芯片就选readguy_2MB_noOTA.csv
board_build.f_flash = 80000000L
board_build.flash_mode = dio
board_build.partitions = readguy_4MB.csv ; 2MB的芯片就选readguy_2MB_noOTA.csv
build_flags =
-Wall
-Wextra
-DARDUINO_USB_MODE=1
-DARDUINO_USB_CDC_ON_BOOT=1 ; 是否需要使用USB串口调试如果需要调试则打开否则禁用
; 如果打开了这个选项但是不连接串口在有串口输出的地方会卡顿1秒左右
; 合宙无串口开发板请选择此选项为1.
-DCORE_DEBUG_LEVEL=1 ; None 0, Error 1, Warn 2, Info 3, Debug 4, Verbose 5
@@ -149,10 +179,14 @@ build_flags =
platform = espressif32
board = nodemcu-32s2
framework = espidf, arduino
board_build.f_cpu = 240000000L
build_type = debug
board_build.f_cpu = 160000000L
board_build.flash_size=4MB ;根据你自己的改, 不得小于4MB
board_build.f_flash = 80000000L
board_build.flash_mode = dio
board_build.partitions = readguy_4MB.csv ; defined
build_flags =
-Wall
-Wextra
-DCORE_DEBUG_LEVEL=1 ; None 0, Error 1, Warn 2, Info 3, Debug 4, Verbose 5
monitor_filters = esp32_exception_decoder

View File

@@ -0,0 +1,7 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x1E0000,
app1, app, ota_1, 0x1F0000,0x1E0000,
spiffs, data, spiffs, 0x3D0000,0x20000,
coredump, data, coredump,0x3F0000,0x10000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x1E0000
5 app1 app ota_1 0x1F0000 0x1E0000
6 spiffs data spiffs 0x3D0000 0x20000
7 coredump data coredump 0x3F0000 0x10000

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -51,6 +51,7 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷
if(m&1){//stage 1
if(lastRefresh) drv_dispWriter(f,2);
//add driver code...
lastRefresh=millis();
}
if(m&2){//stage 2
uint32_t ms=millis()-lastRefresh;

View File

@@ -46,6 +46,7 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷
if(m&1){//stage 1
if(lastRefresh) drv_dispWriter(f,2);
//add driver code...
lastRefresh=millis();
}
if(m&2){//stage 2
uint32_t ms=millis()-lastRefresh;

View File

@@ -51,6 +51,7 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷
if(m&1){//stage 1
if(lastRefresh) drv_dispWriter(f,2);
//add driver code...
lastRefresh=millis();
}
if(m&2){//stage 2
uint32_t ms=millis()-lastRefresh;

View File

@@ -51,6 +51,7 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷
if(m&1){//stage 1
if(lastRefresh) drv_dispWriter(f,2);
//add driver code...
lastRefresh=millis();
}
if(m&2){//stage 2
uint32_t ms=millis()-lastRefresh;

View File

@@ -35,34 +35,380 @@
#include "guy_583A.h"
#ifdef READGUY_DEV_583A
namespace guydev_583A{
//以下代码均为我 FriendshipEnder 原创, 呵呵哒~~
/*LUT格式
重复次数xnnnxnnn...(000=0,001=VSH,010=VSL,011=VSH_LV,100=VSL_LV,101=VSH_LVX,110=VSL_LVX,111=浮动),持续时间.......
0x01, 0x00, 0x00, 0x1B, 0x10, 0x0F, 0x0A, 0x0A, 0x0F, 0x10, 0x1B
0x01, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
0x01, 0x21, 0x21, 0x21, 0x21, 0x1B, 0x10, 0x0F, 0x0A, 0x0A, 0x0F, 0x10, 0x1B
0x01, 0x12, 0x12, 0x12, 0x10, 0x14, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x00
0x01, 0x11, 0x21, 0x21, 0x22, 0x1B, 0x10, 0x0F, 0x0A, 0x0A, 0x0F, 0x10, 0x1B
0x01, 0x21, 0x21, 0x21, 0x20, 0x14, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x00
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
0x01, 0x12, 0x12, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02
0x01, 0x21, 0x21, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
*/
const PROGMEM unsigned char drv::lut_20_LUTC[] =
{ 0x01, 0x00, 0x00, 0x1B, 0x10, 0x0F, 0x0A, 0x0A, 0x0F, 0x10, 0x1B};
const PROGMEM unsigned char drv::lut_20_LUTCFAST[] =
{ 0x01, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const PROGMEM unsigned char drv::lut_21_LUTB[] =//000
{ 0x01, 0x21, 0x21, 0x21, 0x21, 0x1B, 0x14, 0x13, 0x12, 0x00, 0x00, 0x10, 0x1E};
const PROGMEM unsigned char drv::lut_21_LUTBFAST[] =
{ 0x01, 0x12, 0x12, 0x12, 0x10, 0x1f, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x00};
const PROGMEM unsigned char drv::lut_22_LUTW[] =//011
{ 0x01, 0x11, 0x21, 0x21, 0x22, 0x1B, 0x14, 0x13, 0x12, 0x00, 0x00, 0x10, 0x1E};
const PROGMEM unsigned char drv::lut_22_LUTWFAST[] =
{ 0x01, 0x21, 0x21, 0x21, 0x20, 0x1f, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x00};
const PROGMEM unsigned char drv::lut_23_LUTG1[] =//001
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const PROGMEM unsigned char drv::lut_24_LUTG2[] =//010
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const PROGMEM unsigned char drv::lut_25_LUTR0[] =//100//WW
{ 0x01, 0x12, 0x12, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03};
const PROGMEM unsigned char drv::lut_26_LUTR1[] =//101//BB
{ 0x00/*0x01*/, 0x21, 0x21, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02};
const PROGMEM unsigned char drv::lut_27_LUTR2[] =//110
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const PROGMEM unsigned char drv::lut_28_LUTR3[] =//111//局刷
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const PROGMEM unsigned char drv::lut_29_LUTXON[] =
{ 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const PROGMEM unsigned char drv::customGrey[] =
{ 0x00, 0x01, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0a, 0x0c, 0x0e, 0x11, 0x14, 0x17, 0x1a, 0x1e,
0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01};
const PROGMEM unsigned char *drv::luts[10]={
lut_20_LUTC,lut_21_LUTB,lut_22_LUTW,lut_23_LUTG1,lut_24_LUTG2,
lut_25_LUTR0,lut_26_LUTR1,lut_27_LUTR2,lut_28_LUTR3,lut_29_LUTXON
};
const unsigned char *drv::luts_fast[10]={
lut_20_LUTCFAST,lut_21_LUTBFAST,lut_22_LUTWFAST,lut_23_LUTG1,lut_24_LUTG2,
lut_25_LUTR0,lut_26_LUTR1,lut_27_LUTR2,lut_28_LUTR3,lut_29_LUTXON
};
void drv::drv_init(){ //初始化屏幕
//add driver code...
#ifdef READGUY_583A_DUAL_BUFFER
drv::drv(){ //构造时, 分配内存.
buf_2nd=(uint8_t *)malloc(GUY_D_WIDTH*GUY_D_HEIGHT/8);
if(buf_2nd) {
Serial.println(F("[GUY MEM] allocate 33600B for 5.83' EPD."));
//memset(buf_2nd,0,GUY_D_WIDTH*GUY_D_HEIGHT/8);
}
}
void drv::drv_fullpart(bool part){ //初始化慢刷功能
drv::~drv(){ //构造时, 分配内存.
if(buf_2nd) free(buf_2nd);
Serial.println(F("[GUY MEM] unallocate 33600B."));
}
#endif
void drv::sendLut(int lutid){
int lutlen=13,lutlen2=247;
if(lutid==0){lutlen=11;lutlen2=209;}
else if(lutid==9){lutlen=10;lutlen2=190;}
guy_epdCmd(0x20+lutid);
if(epdFull){
for(int i=0;i<lutlen;i++){
guy_epdParam(pgm_read_byte(luts[lutid]+i));
}
}
else{
for(int i=0;i<lutlen;i++){
if(lutid==1 && i==5) guy_epdParam(pgm_read_byte(customGrey+iLut+greyscalingHighQuality));
else
guy_epdParam(pgm_read_byte(luts_fast[lutid]+i));
}
}
for(int i=0;i<lutlen2;i++){
guy_epdParam(0);
}
}
void drv::epd_init(){
if(!epd_PowerOn) Reset(); //设定为已上电
guy_epdCmd(0x01);
guy_epdParam(0x37);
guy_epdParam(0x00);
guy_epdParam(0x07);
guy_epdParam(0x07);
guy_epdCmd(0x00);
guy_epdParam(0xcf);
guy_epdParam(0x88);
guy_epdCmd(0x06);
guy_epdParam(0xc7);
guy_epdParam(0xcc);
guy_epdParam(0x28);
guy_epdCmd(0x30);
guy_epdParam(0x3a);
guy_epdCmd(0x41);
guy_epdParam(0x00);
guy_epdCmd(0x50);
guy_epdParam(0x77);
guy_epdCmd(0x60);
guy_epdParam(0x22);
guy_epdCmd(0x61);
guy_epdParam(0x02);
guy_epdParam(0x58);
guy_epdParam(0x01);
guy_epdParam(0xc0);
guy_epdCmd(0x82);
guy_epdParam(0x28);
for(int i=0;i<10;i++){
sendLut(i);
}
guy_epdCmd(0xe5);
guy_epdParam(0x03);
}
void drv::epd_sendZoneInfo(){
guy_epdCmd(0x91);
//send area info
guy_epdCmd(0x90);
guy_epdParam(0x00);
guy_epdParam(0x00);
guy_epdParam(0x02);
guy_epdParam(0x57);
guy_epdParam(0x00);
guy_epdParam(0x00);
guy_epdParam(0x01);
guy_epdParam(0xbf);
guy_epdParam(0x01);
}
void drv::epd_sendWriter(std::function<uint8_t(int)> f){
guy_epdCmd(0x10); //Then write image data 显示数据
#ifdef READGUY_583A_DUAL_BUFFER
if(epdFull || buf_2nd==nullptr || greyscalingHighQuality){
#endif
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/8;i++){ //fill 0x03 for test
uint8_t dat=0,dat_r=f(i);
dat |= ((dat_r&0x80)?0x30:0);
dat |= ((dat_r&0x40)?0x03:0);
guy_epdParam(dat);
dat&=0;
dat |= ((dat_r&0x20)?0x30:0);
dat |= ((dat_r&0x10)?0x03:0);
guy_epdParam(dat);
dat&=0;
dat |= ((dat_r&0x08)?0x30:0);
dat |= ((dat_r&0x04)?0x03:0);
guy_epdParam(dat);
dat&=0;
dat |= ((dat_r&0x02)?0x30:0);
dat |= ((dat_r&0x01)?0x03:0);
guy_epdParam(dat);
#ifdef READGUY_583A_DUAL_BUFFER
buf_2nd[i]=dat_r;
}
}
else{
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/8;i++){ //fill 0x03 for test
//guy_epdParam(0x03); //for data test
uint8_t dat=0,dat_r=f(i);
dat |= ((dat_r&0x80)?((buf_2nd[i]&0x80)?0x40:0x30):((buf_2nd[i]&0x80)?0x00:0x50));
//0x3?黑->白色, 0x0?白->黑色 0x4? 白->白色 0x5? 黑->黑色
dat |= ((dat_r&0x40)?((buf_2nd[i]&0x40)?0x4:0x3):((buf_2nd[i]&0x40)?0x0:0x5));
guy_epdParam(dat);
dat&=0;
dat |= ((dat_r&0x20)?((buf_2nd[i]&0x20)?0x40:0x30):((buf_2nd[i]&0x20)?0x00:0x50));
dat |= ((dat_r&0x10)?((buf_2nd[i]&0x10)?0x4:0x3):((buf_2nd[i]&0x10)?0x0:0x5));
guy_epdParam(dat);
dat&=0;
dat |= ((dat_r&0x8)?((buf_2nd[i]&0x8)?0x40:0x30):((buf_2nd[i]&0x8)?0x00:0x50));
dat |= ((dat_r&0x4)?((buf_2nd[i]&0x4)?0x4:0x3):((buf_2nd[i]&0x4)?0x0:0x5));
guy_epdParam(dat);
dat&=0;
dat |= ((dat_r&0x2)?((buf_2nd[i]&0x2)?0x40:0x30):((buf_2nd[i]&0x2)?0x00:0x50));
dat |= ((dat_r&0x1)?((buf_2nd[i]&0x1)?0x4:0x3):((buf_2nd[i]&0x1)?0x0:0x5));
guy_epdParam(dat);
buf_2nd[i]=dat_r;
}
#endif
}
}
void drv::drv_init(){ //初始化屏幕
epdFull=1;
epd_PowerOn=0;
}
void drv::drv_fullpart(bool part){ //初始化慢刷/快刷功能
if(lastRefresh) return;
//add driver code...
if(!epd_PowerOn) part=0;
epdFull=!part;
if(epdFull) iLut=15;
}
void drv::drv_setDepth(uint8_t i){
if(!epd_PowerOn) return; //不支持切换到快刷的情形
epdFull=0; iLut = i?(i>15?15:i):15; //如果需要, 改成自己的代码
}
void drv::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷新
if(m&1){//stage 1
if(lastRefresh) drv_dispWriter(f,2);
//add driver code...
BeginTransfer();
if(epdFull){
if(!epd_PowerOn){
epdFull=0; //发送快刷的lut
epd_init();
epdFull=1; //发送快刷的lut
guy_epdCmd(0x04); //power on
EndTransfer();
guy_epdBusy(-60);
BeginTransfer();
guy_epdCmd(0x10);
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/2;i++){ //fill 0x33
guy_epdParam(0x33);
}
epd_PowerOn=1; //设定为已上电
}
else{ //full refresh need power on
guy_epdCmd(0x04); //power on
EndTransfer();
guy_epdBusy(-60);
BeginTransfer();
}
epd_sendZoneInfo();
guy_epdCmd(0x10); //Then write image data
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/2;i++){ //fill 0x03 for test
guy_epdParam(0x33); //for test
}
guy_epdCmd(0x92);
epd_init();
//epd_init(); //repeat call in GxEPD2
epd_sendWriter(f); //write image data
}
else{
epd_init();
//Power on fx
guy_epdCmd(0x04);
EndTransfer();
guy_epdBusy(-60);
BeginTransfer();
epd_sendZoneInfo();
epd_sendWriter(f);
guy_epdCmd(0x92);
epd_sendZoneInfo();
}
guy_epdCmd(0x12); //开始刷屏
EndTransfer();
lastRefresh=millis();
}
if(m&2){//stage 2
uint32_t ms=millis()-lastRefresh;
uint32_t u=epdFull?slowRefTime:fastRefTime; //全刷:局刷 busy时间
if(ms<u) guy_epdBusy(u-ms); //对于busy电平为低电平忙碌,高电平正常的屏幕则改为ms-u
int ms=millis()-lastRefresh;
Serial.printf("epdFull? %d, epd_PowerOn? %d \n",epdFull,epd_PowerOn);
int u=epdFull?slowRefTime:fastRefTime; //全刷:局刷 busy时间
if(ms<u) guy_epdBusy(ms-u); //对于busy电平为低电平忙碌,高电平正常的屏幕则改为ms-u
lastRefresh=0;
//add driver code...
BeginTransfer();
if(epdFull){
epdFull=0; //发送快刷的lut
epd_init(); //repeat init in part mode
epdFull=1; //发送快刷的lut
epd_sendZoneInfo();
guy_epdCmd(0x10); //Then write image data
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/2;i++){ //fill 0x03 for test
guy_epdParam(0x33); //for test
}
guy_epdCmd(0x02); //power off for test...
//guy_epdBusy(-30);
}
else{
guy_epdCmd(0x92);
epd_sendZoneInfo();
guy_epdCmd(0x10); //Then write image data 显示数据
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/2;i++){ //fill 0x03 for test
guy_epdParam(0x33); //for test:全白
}
guy_epdCmd(0x92);
}
EndTransfer();
}
/* test code , with stageless ------------------------------------------------------
if(epdFull){ //慢刷
BeginTransfer();
if(!epd_PowerOn){
epdFull=0; //发送快刷的lut
epd_init();
epdFull=1; //发送快刷的lut
guy_epdCmd(0x04); //power on
EndTransfer();
guy_epdBusy(-60);
BeginTransfer();
guy_epdCmd(0x10);
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/2;i++){ //fill 0x33
guy_epdParam(0x33);
}
epd_PowerOn=1; //设定为已上电
}
else{ //full refresh need power on
guy_epdCmd(0x04); //power on
EndTransfer();
guy_epdBusy(-60);
BeginTransfer();
}
epd_sendZoneInfo();
guy_epdCmd(0x10); //Then write image data
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/2;i++){ //fill 0x03 for test
guy_epdParam(0x33); //for test
}
guy_epdCmd(0x92);
epd_init();
//epd_init(); //repeat call in GxEPD2
epd_sendWriter(f); //write image data
guy_epdCmd(0x12);
EndTransfer();
guy_epdBusy(-4000);
BeginTransfer();
epdFull=0; //发送快刷的lut
epd_init(); //repeat init in part mode
epdFull=1; //发送快刷的lut
epd_sendZoneInfo();
guy_epdCmd(0x10); //Then write image data
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/2;i++){ //fill 0x03 for test
guy_epdParam(0x33); //for test
}
guy_epdCmd(0x02); //power off for test...
EndTransfer();
//guy_epdBusy(-30);
}
else{ //partmode
BeginTransfer();
epd_init();
//Power on fx
guy_epdCmd(0x04);
EndTransfer();
guy_epdBusy(-60);
BeginTransfer();
epd_sendZoneInfo();
epd_sendWriter(f);
guy_epdCmd(0x92);
epd_sendZoneInfo();
guy_epdCmd(0x12); //快刷
EndTransfer();
guy_epdBusy(-1000); //1秒钟刷屏时间
BeginTransfer();
guy_epdCmd(0x92);
epd_sendZoneInfo();
guy_epdCmd(0x10); //Then write image data 显示数据
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/2;i++){ //fill 0x03 for test
guy_epdParam(0x33); //for test:全白
}
guy_epdCmd(0x92);
EndTransfer();
}
// test code , with stageless ------------------------------------------------------ */
}
void drv::drv_draw16grey_step(std::function<uint8_t(int)> f, int step){
if(_quality&1) return readguyEpdBase::drv_draw16grey_step(f,step);
if(step==1) drv_fullpart(1);//初始阶段,完成准备工作 //设置为快刷模式
greyscalingHighQuality=16; //开启高品质灰度模式
iLut=step;
drv_dispWriter(f);
//DelayMs(10); //未知原因()
if(step==15) greyscalingHighQuality=0;//初始阶段,完成准备工作 //设置为快刷模式
}
void drv::drv_sleep() { //开始屏幕睡眠
if(RST_PIN>=0){ //RST_PIN<0 无法唤醒
//add driver code...
guy_epdCmd(0x07); // deep sleep
guy_epdParam(0xA5); // check code
}
epd_PowerOn = 0;
epdFull = 1; //强制设置为慢刷新模式

View File

@@ -36,13 +36,17 @@
#define _GUY_EPD583A_H_FILE
namespace guydev_583A{
constexpr int GUY_D_WIDTH =200; //驱动屏幕宽度
constexpr int GUY_D_HEIGHT =200; //驱动屏幕高度
constexpr int slowRefTime =2000; //驱动屏幕慢刷时间, 单位毫秒
constexpr int fastRefTime =500; //驱动屏幕快刷时间, 单位毫秒
constexpr int GUY_D_WIDTH =600; //驱动屏幕宽度
constexpr int GUY_D_HEIGHT =448; //驱动屏幕高度
constexpr int slowRefTime =1600; //驱动屏幕慢刷时间, 单位毫秒
constexpr int fastRefTime =560; //驱动屏幕快刷时间, 单位毫秒
class drv : public readguyEpdBase {
public:
#ifdef READGUY_583A_DUAL_BUFFER
drv();
virtual ~drv();
#endif
int drv_ID() const { return READGUY_DEV_583A; }
void drv_init(); //初始化屏幕
void drv_fullpart(bool part); //切换慢刷/快刷功能
@@ -52,11 +56,36 @@ public:
//int drv_panelwidth() const { return GUY_D_WIDTH; }; //返回缓存的数据宽度
int drv_height() const{ return GUY_D_HEIGHT; }; //返回显示区域高度
void drv_setDepth(uint8_t i); //设置显示颜色深度
int drv_supportGreyscaling() const { return 16; }
int drv_supportGreyscaling() const { return (_quality&1)?16:-16; } //暂不支持灰度功能移植
void drv_draw16grey_step(std::function<uint8_t(int)> f, int step);
private:
uint8_t epd_PowerOn=1; //是否上电. 睡眠则设为0
uint8_t epdFull=0; //是partical模式/快速刷新模式 0快刷, 1慢刷
uint8_t iLut=15; //颜色深度
uint8_t greyscalingHighQuality = 0;
static const unsigned char *luts[10];
static const unsigned char *luts_fast[10];
static const unsigned char lut_20_LUTC[];
static const unsigned char lut_20_LUTCFAST[];
static const unsigned char lut_21_LUTB[];
static const unsigned char lut_21_LUTBFAST[];
static const unsigned char lut_22_LUTW[];
static const unsigned char lut_22_LUTWFAST[];
static const unsigned char lut_23_LUTG1[];
static const unsigned char lut_24_LUTG2[];
static const unsigned char lut_25_LUTR0[];
static const unsigned char lut_26_LUTR1[];
static const unsigned char lut_27_LUTR2[];
static const unsigned char lut_28_LUTR3[];
static const unsigned char lut_29_LUTXON[];
static const unsigned char customGrey[];
void sendLut(int lutid);
void epd_init();
void epd_sendZoneInfo();
void epd_sendWriter(std::function<uint8_t(int)> f);
#ifdef READGUY_583A_DUAL_BUFFER
uint8_t *buf_2nd=nullptr; //second Buffer for luts
#endif
};
}
#endif /* END OF FILE. ReadGuy project.

View File

@@ -51,6 +51,7 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷
if(m&1){//stage 1
if(lastRefresh) drv_dispWriter(f,2);
//add driver code...
lastRefresh=millis();
}
if(m&2){//stage 2
uint32_t ms=millis()-lastRefresh;

View File

@@ -51,6 +51,7 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷
if(m&1){//stage 1
if(lastRefresh) drv_dispWriter(f,2);
//add driver code...
lastRefresh=millis();
}
if(m&2){//stage 2
uint32_t ms=millis()-lastRefresh;

View File

@@ -59,7 +59,7 @@
//#define READGUY_DEV_154C 14 //(即将推出) 1.54寸M09墨水屏 (M5Stack Core-Ink 同款; GDEW0154M09)
//#define READGUY_DEV_370B 15 //(即将推出) 3.7寸低DPI墨水屏, 分辨率416*240, b站 @叫我武哒哒 的项目用
//#define READGUY_DEV_426A 16 //(即将推出) 4.26寸高分辨率墨水屏, 800*480. GDEQ0426T82 支持硬件四灰
//#define READGUY_DEV_583A 17 //(即将推出) 5.83寸墨水屏幕, 分辨率为600*448. 有黑白有三色
#define READGUY_DEV_583A 17 //(即将推出) 5.83寸墨水屏幕, 分辨率为600*448. 有黑白有三色
//#define READGUY_DEV_583B 18 //(即将推出) 5.83寸高分辨率, 640*480. GDEQ0583T31 只有黑白
//#define READGUY_DEV_750A 19 //(即将推出) 7.5 寸墨水屏幕, 800*480. 只有三色(买不到黑白)
//#define READGUY_DEV_1020A 20 //(即将推出) 10.2寸墨水屏GDEQ102T90, 芯片SSD1677. 黑白色分辨率960*640
@@ -68,5 +68,7 @@
#define EPD_DRIVERS_NUM_MAX 21 //此选项请不要取消注释掉, 有几个屏幕就写多少.
#define READGUY_583A_DUAL_BUFFER //对于单缓存的5.83屏幕, 启用双缓存支持
#endif /* END OF FILE. ReadGuy project.
Copyright (C) 2023 FriendshipEnder. */

View File

@@ -160,8 +160,8 @@ void readguyEpdBase::Reset(uint32_t minTime)
}
//void readguyEpdBase::drv_draw16grey(const uint8_t *d16bit){ //不支持的话什么都不做
void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_t x,uint16_t y,int o,
uint16_t fw, uint16_t fh){
void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,int32_t x,int32_t y,int o,
int32_t fw0, int32_t fh){
static const PROGMEM uint8_t bayer_tab [64]={
0, 32, 8, 40, 2, 34, 10, 42,
48, 16, 56, 24, 50, 18, 58, 26,
@@ -172,9 +172,11 @@ void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_
15, 47, 7, 39, 13, 45, 5, 37,
63, 31, 55, 23, 61, 29, 53, 21
};
if(!fw) fw=spr.width();
if(!fh) fh=spr.height();
if((!fw) || (!fh)) return;
if(!fw0) fw0=spr.width();
if(!fh) fh=spr.height();
if((!fw0) || (!fh)) return;
int32_t fw=(fw0>0?std::min(fw0,sprbase.width()):-fw0);
fw0=std::abs(fw0); //无视缩放优化, 0~3:常规的三种渲染模式, 4~7: 无视缩放优化
if(o==0 || o==1){
readBuff = new uint16_t[spr.width()];
floyd_tab[0] = new int16_t [fw];
@@ -188,7 +190,7 @@ void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_
spr.readRect(0,(i-y)*spr.height()/fh,spr.width(),1,readBuff);
if(_quality&2){
for(int32_t j=0;j<fw;j++){
int gv=greysc(readBuff[j*spr.width()/fw]);
int gv=greysc(readBuff[j*spr.width()/fw0]);
int32_t flodelta = floyd_tab[i&1][j]+(int32_t)((gv<<8)|gv);
if(flodelta>=0x8000) {
//spr.drawPixel(j,i,1);
@@ -221,7 +223,7 @@ void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_
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);
<greysc(readBuff[((j<<3)+b)*spr.width()/fw0]))<<(7-b);
writeBuff[j]=buff8bit;
}
}
@@ -236,12 +238,14 @@ void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_
}
}
//不支持的话使用单色抖动刷屏
void readguyEpdBase::drv_draw16grey(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_t x,uint16_t y,
uint16_t fw, uint16_t fh){
void readguyEpdBase::drv_draw16grey(LGFX_Sprite &sprbase,LGFX_Sprite &spr,int32_t x,int32_t y,
int32_t fw0, int32_t fh){
//Serial.println("drv_draw16grey fx");
if(!fw) fw=spr.width();
if(!fh) fh=spr.height();
if((!fw) || (!fh)) return;
if(!fw0) fw0=spr.width();
if(!fh) fh=spr.height();
if((!fw0) || (!fh)) return;
int32_t fw=(fw0>0?std::min(fw0,sprbase.width()):-fw0);
fw0=std::abs(fw0); //无视缩放优化, 0~3:常规的三种渲染模式, 4~7: 无视缩放优化
readBuff = new uint16_t[spr.width()];
if(_quality&2){
floyd_tab[0] = new int16_t [fw];
@@ -263,7 +267,7 @@ void readguyEpdBase::drv_draw16grey(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16
//for(uint_fast8_t b=0;b<8;b++){
uint_fast8_t cg=0;
if(_quality&2){
int gv=greysc(readBuff[j*spr.width()/fw]);
int gv=greysc(readBuff[j*spr.width()/fw0]);
int32_t fd = floyd_tab[i&1][j]+((gv<<8)|gv);
while(fd>=0x800) {
cg++;
@@ -275,8 +279,8 @@ void readguyEpdBase::drv_draw16grey(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16
{ floyd_tab[!(i&1)][j ] += (fd*5)>>4; }
if(j!=fw-1) { floyd_tab[!(i&1)][j+1] += (fd )>>4; }
}
else{ cg=greysc(readBuff[j*spr.width()/fw])>>4; }
//uint_fast8_t cg=greysc(readBuff[j*spr.width()/fw])>>4;
else{ cg=greysc(readBuff[j*spr.width()/fw0])>>4; }
//uint_fast8_t cg=greysc(readBuff[j*spr.width()/fw0])>>4;
if(negativeOrder)
buff8bit |= (cg<k)<<((~j)&7);
else{
@@ -288,7 +292,7 @@ void readguyEpdBase::drv_draw16grey(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16
buff8bit=0;
}
//}
//sprbase.drawPixel(x+j,i,(greysc(readBuff[j*spr.width()/fw])/16)==(15-k));
//sprbase.drawPixel(x+j,i,(greysc(readBuff[j*spr.width()/fw0])/16)==(15-k));
}
if(_quality&2) for(int floi=0;floi<fw;floi++) floyd_tab[i&1][floi]=0;
sprbase.drawBitmap(x,i,writeBuff,fw,1,1,0);

View File

@@ -48,9 +48,9 @@ protected:
int8_t CS_PIN ;
int8_t BUSY_PIN;
uint8_t in_trans=0;
uint8_t _quality=2; //灰度显示品质 0(默认)-高品质 1-低品质 部分屏幕支持高品质的连续刷灰度.
uint8_t _quality=2;//灰度显示品质 默认2 0,2-高品质 1,3-低品质高兼容性. 0,1使用bayer灰度二值表 2,3使用floyd算法
#ifdef MEPD_DEBUG_WAVE
uint16_t dat_combo = 0; //dc引脚状态 0 command, 1 data
int dat_combo = 0; //dc引脚状态 0 command, 1 data
#endif
uint16_t *readBuff;// = new uint16_t[spr.width()];
uint8_t *writeBuff;// = new uint8_t[w];
@@ -88,17 +88,19 @@ public:
virtual int drv_height()const=0; //返回显示区域高度, 即使旋转了也不能影响此函数输出
virtual int drv_supportGreyscaling() const { return 0; }
virtual void drv_setDepth(uint8_t i){} //设置显示颜色深度, 不支持的话什么都不做
virtual void drv_setDepth(uint8_t i){ (void)i; } //设置显示颜色深度, 不支持的话什么都不做
/** @brief 获取某一像素颜色, 并转化为256阶灰度
* @param x, y 坐标
* @param gamma_on 是否对灰度值进行gamma校正(速度慢)
* @return uint32_t 颜色的灰度值
*/
IRAM_ATTR static int greysc(int c){return(((c>>3)&0x1F)*79+(((c<<3)+(c>>13))&0x3F)*76+((c>>8)&0x1F)*30)>>5;}
void drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_t x,uint16_t y,int o=0,
uint16_t fw=0, uint16_t fh=0); //分步完成灰度刷新
void drv_draw16grey(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_t x,uint16_t y,
uint16_t fw=0, uint16_t fh=0);//省内存方式
/// @brief 显示sprite图像, 使用floyd算法
/// @param o 无视缩放优化, 0~3:分步的三种渲染模式, 0完整 1开始 2中间 3结束
void drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,int32_t x,int32_t y,int o=0,
int32_t fw0=0, int32_t fh=0); //分步完成灰度刷新
void drv_draw16grey(LGFX_Sprite &sprbase,LGFX_Sprite &spr,int32_t x,int32_t y,
int32_t fw0=0, int32_t fh=0);//省内存方式
void drv_draw16grey_step(const uint8_t *buf, int step){ //分步完成灰度刷新
drv_draw16grey_step([&](int n)->uint8_t{return buf[n];},step);
}

View File

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

View File

@@ -400,7 +400,7 @@ void ReadguyDriver::handlePinSetup(){
args_name[15],args_name[17],args_name[19],args_name[21],args_name[12],args_name[13]
};
static const PROGMEM int dem_args_val[DRIVER_TEMPLATE_N][DRIVER_TEMPLATE_ARRAY_L]={
{ 6,15, 0, 2, 4, 5, 2, 3, 0,-1,-1,13,14},
{ 6,15, 0, 2, 4, 5, 2, 0, 3,-1,-1,13,14},
//{ 0,10, 9, 8, 7, 4, 3, 2, 3, 5, 6,SDA,SCL},
//{ 0,15, 4, 2, 5,-1, 1, 0,-1,-1,-1,-1,-1} //微雪官方例程板子不支持SD卡, 也不支持I2C. 按钮为boot按钮
};
@@ -516,12 +516,16 @@ void ReadguyDriver::handlePinSetup(){
#if defined(ESP8266)
for(int i=2;i<12;i++){
if(i>=6 && i<=8) continue;
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
for(int i=2;i<12;i++){
#else
for(int i=0;i<12;i++){
#endif
s += F("<br/>");
#if defined(CONFIG_IDF_TARGET_ESP32C3)
if(i==7) {
i+=2; //优化ESP32C3的SPI配置体验 (C3只能共线)
s += F("(ESP32C3不支持SD卡独立SPI总线! SD_MOSI和SD_SCLK沿用EPDMOSI和EPDSCLK)<br/>");
}
#endif
#endif
s += FPSTR(args_name[i+2]);
s += F("<input type=\"number\" id=\"");
s += FPSTR(args_name[i+2]);

View File

@@ -79,7 +79,7 @@ ReadguyDriver::ReadguyDriver(){
READGUY_sd_ok = 0; //初始默认SD卡未成功初始化
READGUY_buttons = 0; //初始情况下没有按钮
} //WiFiSet: 是否保持AP服务器一直处于打开状态
uint8_t ReadguyDriver::init(uint8_t WiFiSet, bool initepd){
uint8_t ReadguyDriver::init(uint8_t WiFiSet, bool initepd, bool initSD){
if(READGUY_cali==127) //已经初始化过了一次了, 为了防止里面一些volatile的东西出现问题....还是退出吧
return 0;
#ifdef DYNAMIC_PIN_SETTINGS
@@ -109,7 +109,7 @@ uint8_t ReadguyDriver::init(uint8_t WiFiSet, bool initepd){
else if(WiFiSet==1) ap_setup();
if(checkEpdDriver()!=127) setEpdDriver(initepd/* ,g_width,g_height */); //初始化屏幕
else for(;;); //此处可能添加程序rollback等功能操作(比如返回加载上一个程序)
setSDcardDriver();
if(initSD) setSDcardDriver();
setButtonDriver();
}
#endif
@@ -118,7 +118,7 @@ uint8_t ReadguyDriver::init(uint8_t WiFiSet, bool initepd){
nvs_init();
if(checkEpdDriver()!=127) setEpdDriver(initepd/* ,g_width,g_height */); //初始化屏幕
else for(;;); //此处可能添加程序rollback等功能操作(比如返回加载上一个程序)
setSDcardDriver();
if(initSD) setSDcardDriver();
setButtonDriver();
if(!nvs_read()){
nvs_write(); //全部成功之后, 写入引脚信息到NVS.
@@ -409,16 +409,16 @@ void ReadguyDriver::setButtonDriver(){
//}
if(READGUY_buttons==2){
btn_rd[0].setMultiBtn(1); //设置为多个按钮,不识别双击或三击
//btn_rd[0].setLongRepeatMode(1);
//btn_rd[0].setLongRepeatMode(1); //双按键 选择按键 设置为允许连按
btn_rd[1].setMultiBtn(1); //设置为多个按钮,不识别双击或三击
btn_rd[1].setLongRepeatMode(0);
btn_rd[1].setLongRepeatMode(0); //双按键 确定按键 设置为不允许连按
}
else if(READGUY_buttons==3){
btn_rd[0].long_press_ms = 50; //不识别双击三击, 只有按一下或者长按, 并且开启连按
btn_rd[0].long_press_ms = 20; //不识别双击三击, 只有按一下或者长按, 并且开启连按
//btn_rd[0].setLongRepeatMode(1);
btn_rd[1].setMultiBtn(1); //设置为多个按钮,不识别双击或三击
btn_rd[1].setLongRepeatMode(0);
btn_rd[2].long_press_ms = 50; //不识别双击三击, 只有按一下或者长按, 并且开启连按
//btn_rd[1].setMultiBtn(1); //设置为多个按钮,不识别双击或三击 2024/2/25更新:需要支持连按适配拨轮
btn_rd[1].setLongRepeatMode(0); //三按键 确定按键 设置为不允许连按
btn_rd[2].long_press_ms = 20; //不识别双击三击, 只有按一下或者长按, 并且开启连按
btn_rd[2].setLongRepeatMode(1);
}
#ifdef ESP8266 //对于esp8266, 需要注册到ticker. 这是因为没freertos.
@@ -535,11 +535,11 @@ void ReadguyDriver::display(std::function<uint8_t(int)> f, uint8_t part){
//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,int32_t x,int32_t y,int32_t zoomw, int32_t zoomh) {
if(READGUY_cali==127) guy_dev->drv_drawImage(base, spr, x, y, 0, zoomw, zoomh);
}
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) {
void ReadguyDriver::drawImageStage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,int32_t x,int32_t y,uint8_t stage,
uint8_t totalstage,int32_t zoomw,int32_t zoomh) {
if(READGUY_cali!=127 || stage>=totalstage) return;
//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);
@@ -547,7 +547,7 @@ void ReadguyDriver::drawImageStage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_
void ReadguyDriver::setDepth(uint8_t d){
if(READGUY_cali==127 && guy_dev->drv_supportGreyscaling()) guy_dev->drv_setDepth(d);
}
void ReadguyDriver::draw16grey(LGFX_Sprite &spr,uint16_t x,uint16_t y,uint16_t zoomw,uint16_t zoomh){
void ReadguyDriver::draw16grey(LGFX_Sprite &spr,int32_t x,int32_t y,int32_t zoomw,int32_t zoomh){
if(READGUY_cali!=127) return;
if(guy_dev->drv_supportGreyscaling() && (spr.getColorDepth()&0xff)>1)
return guy_dev->drv_draw16grey(*this,spr,x,y,zoomw,zoomh);
@@ -646,7 +646,8 @@ void ReadguyDriver::nvs_write(){
#endif
uint8_t ReadguyDriver::getBtn_impl(){ //按钮不可用, 返回0.
static uint32_t last=0;
static unsigned long last=0;
static unsigned long last2=0;
uint8_t res1,res2,res3,res4=0;
switch(READGUY_buttons){
case 1:
@@ -658,22 +659,41 @@ uint8_t ReadguyDriver::getBtn_impl(){ //按钮不可用, 返回0.
else if(res1 == 5) res4 |= 3; //单击后长按-新增操作(可以连按)
break;
case 2:
res1=btn_rd[0].read(); //两个按钮引脚都读取
res2=btn_rd[1].read();
if(millis()-last>500){
if(res1 == 1) res4 |= 1; //左键点按-向下翻页
else if(res1 == 4) {
res4 |= 2; //左键长按-向上翻页
//if(btn_rd[1].isPressedRaw()) res4 |= 1;
res1=btn_rd[0].read(); //选项上下键 两个按钮引脚都读取
res2=btn_rd[1].read(); //确定/返回键
//#if 1
{
bool newval=btn_rd[0].isPressedRaw();
if(newval && last2) last2=0;
else if(!(newval || last2)) last2=millis(); //捕获按钮松开的行为
if(res1 && (millis()-last>=btn_rd[1].long_press_ms) && (!btn_rd[1].isPressedRaw())){
//Serial.printf("[%9d] res 1 state: %d %d\n",millis(),longpresstest,pressedRawtest);
res4 = (res1 == 1)?1:2; //左键点按-向下翻页
}
}
if(btn_rd[0].isPressedRaw() && res2){
res4 |= 3; //右键点按-确定
last=millis();
//#endif
/*
uint32_t nowm = millis();
if(res1 && nowm-last >= btn_rd[1].long_press_ms && (!btn_rd[1].isPressedRaw())){
res4 = (res1 == 1)?1:2; //左键点按-向下翻页
last=nowm;
}
else{
if(res2 == 1) res4 |= 4; //右键点按-确定
if(res2) {
if(btn_rd[0].isPressedRaw()) res4 |= 3; //避免GCC警告(我常年喜欢-Werror=all
else if(res2 == 1 && nowm>last) res4 |= 4; //右键点按-确定
else if(res2 == 4 && nowm>last) res4 |= 8; //右键长按-返回
last=nowm;
}
*/
if(res2) {
unsigned long ts=millis();
//Serial.printf("[%9lu] now last2: %lu, threshold %lu\n",ts,last2,ts-last2);
if(btn_rd[0].isPressedRaw() || ts-last2<=20) { //2024.2.25新增: 20毫秒的去抖时间 防误判
res4 |= 3; //避免GCC警告(我常年喜欢-Werror=all
}
else if(res2 == 1) res4 |= 4; //右键点按-确定
else if(res2 == 4) res4 |= 8; //右键长按-返回
last=ts;
}
if(res4==5 || res4==6) res4=3;
break;
@@ -689,6 +709,7 @@ uint8_t ReadguyDriver::getBtn_impl(){ //按钮不可用, 返回0.
//if(res3 && ((millis()-last)<btn_rd[0].long_repeat_ms)) res4 |=3;
if(res2 == 1) res4 |= 4;
else if(res2 == 4) res4 |= 8;
else if(res2 == 2) res4 |= 3; //新增: 双击进入操作5
break;
}
return res4;

View File

@@ -179,9 +179,10 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
* @param WiFiSet 是否保持AP模式关闭. 0:配网完成自动关WiFi, 1:需要手动调用 WiFi.mode(WIFI_OFF) 关闭WiFi.
* 2:自动连接到已存的WiFi, 但不等待连接成功
* @param initepd 是否初始化墨水屏. 初始化后的首次刷屏必为慢刷. 如果是不断电复位, 可以不初始化墨水屏直接刷屏
* @param initSD 是否初始化文件系统. 选是-初始化SD失败则初始化LittleFs; 选否-不初始化SD也不初始化littlefs.
* @return SD卡是否就绪
*/
uint8_t init(uint8_t WiFiSet = 0, bool initepd = 1);
uint8_t init(uint8_t WiFiSet = 0, bool initepd = 1, bool initSD = 1);
/// @brief 设置显示亮度
void setBright(int d);
/// @brief 返回显示亮度
@@ -206,11 +207,11 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
*/
void display(std::function<uint8_t(int)> f, uint8_t part);
/// @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,int32_t x,int32_t y,int32_t zoomw=0, int32_t zoomh=0){
if(READGUY_cali==127) drawImage(*this,spr,x,y,zoomw,zoomh);
}
/// @brief 显示图片, 将图片(任意颜色格式)显示到一个黑白色的sprite(必须是黑白二值型)上 (未经测试)
void drawImage(LGFX_Sprite &base,LGFX_Sprite &spr,uint16_t x,uint16_t y,uint16_t zoomw=0,uint16_t zoomh=0);
void drawImage(LGFX_Sprite &base,LGFX_Sprite &spr,int32_t x,int32_t y,int32_t zoomw=0,int32_t zoomh=0);
/// @brief 设置显示对比度(灰度)
void setDepth(uint8_t d);
/** @brief 返回目标屏幕是否支持16级灰度 返回非0代表支持.
@@ -222,7 +223,7 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
* 2-关闭连续刷屏 关闭16阶灰度抖动 3-开启连续刷屏 关闭16阶灰度抖动 */
void setGreyQuality(uint8_t q) { if(READGUY_cali==127) guy_dev->setGreyQuality(q); }
/// @brief 显示灰度图片,如果支持,否则就不显示灰度图片了. 可以用省内存的方法显示
void draw16grey(LGFX_Sprite &spr,uint16_t x,uint16_t y,uint16_t zoomw=0,uint16_t zoomh=0);
void draw16grey(LGFX_Sprite &spr,int32_t x,int32_t y,int32_t zoomw=0,int32_t zoomh=0);
/** @brief 按照自定义分步显示灰度图片,如果支持,否则就不显示灰度图片了. 可以用省内存的方法显示
* @param step 步骤代号. 从1开始到15,依次调用此函数来自定义的灰度显示显存内容. 没有0和16.
* @note 必须按照 "慢刷全屏->绘图->设置参数1->绘图->设置参数2... 调用15次 来完成一次自定义灰度刷屏
@@ -281,7 +282,7 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
/// @brief 检查按钮. 当配置未完成时,按钮不可用, 返回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;}
//uint8_t getBtn(int btnID){return btnID<getButtonsCount()?(!(btn_rd[btnID].isPressedRaw())):1;}
/** @brief 返回可用的文件系统. 当SD卡可用时, 返回SD卡. 否则根据情况返回最近的可用文件系统
* @param initSD 2:总是重新初始化SD卡; 1:若SD卡不可用则初始化; 0:SD卡不可用则返回LittleFS. */
fs::FS &guyFS(uint8_t initSD = 0);
@@ -426,10 +427,10 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
void implBeginTransfer() { guy_dev->BeginTransfer(); } //此函数用于开启SPI传输, 只能在自定义刷屏函数中使用!!
void implEndTransfer() { guy_dev->EndTransfer(); } //此函数用于开启SPI传输, 只能在自定义刷屏函数中使用!!
/// @brief 分阶段显示图片, 使用抖动算法. 更加的省内存.目前函数
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){ 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);
void drawImageStage(LGFX_Sprite &spr,int32_t x,int32_t y,uint8_t stage,uint8_t totalstage,
int32_t zoomw=0,int32_t zoomh=0){ drawImageStage(*this,spr,x,y,stage,totalstage,zoomw,zoomh); }
void drawImageStage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,int32_t x,int32_t y,
uint8_t stage,uint8_t totalstage,int32_t zoomw=0,int32_t zoomh=0);
};
#endif /* END OF FILE. ReadGuy project.
Copyright (C) 2023 FriendshipEnder. */