mirror of
https://github.com/fsender/readguy.git
synced 2026-03-25 21:39:49 +08:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6fe0269ccf | ||
|
|
f289938a65 | ||
|
|
a69456a09c | ||
|
|
b8d7310236 | ||
|
|
86de2fb12a | ||
|
|
558b847a3d | ||
|
|
7bb2ba77f0 | ||
|
|
8e825c862a | ||
|
|
d88f1a3c5c | ||
|
|
771ac6db80 | ||
|
|
c4e848730c | ||
|
|
78438e36a7 | ||
|
|
3ae6156886 | ||
|
|
2aca106448 | ||
|
|
d24639a962 | ||
|
|
85a785eabd |
128
CHANGELOG.md
128
CHANGELOG.md
@@ -1,3 +1,131 @@
|
||||
## Release 1.4.0 - 2024/12/1
|
||||
|
||||
### 新增内容
|
||||
|
||||
1. 新增用户引脚配置数据字段的读取和写入接口
|
||||
|
||||
2. 附加了时间管理库, 位于 `extra/ctg_timelib` 文件夹内. 本库可用于替代 [Arduino TimeLib](https://github.com/PaulStoffregen/Time), 使ESPxxxx系列主控可以与GNU C time库使用同一个时间访问接口, 并显著减小代码体积.
|
||||
|
||||
3. 新增 `getDepth` 函数, 用于获得当前墨水屏的显示颜色深度
|
||||
|
||||
4. 新增 `setAutoFullRefresh` 函数, 可用于设置自动慢刷, 防止连续快刷导致屏幕对比度降低甚至刷坏屏幕
|
||||
|
||||
5. 新增 `screenshot` 函数, 可截屏并保存在SD卡中.
|
||||
|
||||
6. 新增 `SDdeinit` 函数, 调用后SD卡将会不可用, 用于安全卸载SD卡或者重新检测SD卡的可用性.
|
||||
|
||||
7. 新增 `recoverI2C` 函数, 在I2C引脚被复用的情形下, 使用I2C功能会影响其他引脚的复用功能. 该函数可以在I2C用完之后还原这些复用引脚的功能设置
|
||||
|
||||
8. 新增 `setSDbusy` 函数, 在SD卡的CS引脚被复用作按键时, 调用 `setSDbusy(1)` 标记此时SD卡正在被占用, `setSDbusy(0)` 来释放. **该函数仅建议在需要兼容SD卡被复用作按键的硬件上使用. 其他情况用处不大. 前往** `guy_driver_config.h` **文件并禁用宏** `READGUY_ALLOW_SDCS_AS_BUTTON` **是最佳选择**
|
||||
|
||||
9. 新增实验性功能 `READGUY_ALLOW_DC_AS_BUTTON`, `READGUY_ALLOW_EPDCS_AS_BUTTON`, `READGUY_ALLOW_SDCS_AS_BUTTON`, 详见文件 `guy_driver_config.h` .
|
||||
|
||||
10. 内置服务器功能现在支持设置请求类型为 UPLOAD, HEAD, POST, PUT, PATCH, DELETE 和 OPTIONS 的服务函数, 以及请求返回 404 Not Found 的响应.
|
||||
|
||||
### 优化
|
||||
|
||||
1. 优化了大部分代码结构 (给一些函数加上const和inline标志, 提高效率) , 并修复了部分变量未初始化就调用的bug
|
||||
|
||||
2. 优化了配置网页的结构, 现在配置引脚的按钮在网页最下方了
|
||||
|
||||
3. 优化部分示例程序, 增加并更新部分注释, 更易读 更易用
|
||||
|
||||
4. 完全移除了内部对 RTC 的支持.
|
||||
|
||||
5. 为 1.54 寸 LilyGo 屏幕, 2.9 寸前置光屏幕和 2.7 寸屏幕提供了睡眠模式下快速唤醒的支持.
|
||||
|
||||
6. 为 LCD 墨水屏模拟器提供了快速但不支持同屏灰度的模拟模式.
|
||||
|
||||
### Bug 修复
|
||||
|
||||
1. 修复在禁用 dynamic_pin_settings 时, 数组访问越界的bug
|
||||
|
||||
2. 修复了禁用 WiFi 功能但未配置引脚时, 程序会异常继续运行的bug
|
||||
|
||||
3. 按键任务函数结构重构, 解决了按键被复用时, 无法设置按键为高电平触发的情况
|
||||
|
||||
## Release 1.3.7 - 2024/3/11
|
||||
|
||||
1. 配网页面, 增加了用户引脚数据 (可以配置其他功能的引脚. 此功能似乎是为了准备给esp32s3用sdmmc库驱动sd卡用的)
|
||||
|
||||
2. 增加 `guy_button` 按键库功能的接口函数
|
||||
|
||||
3. 修复部分bug
|
||||
|
||||
## Release 1.3.6 - 2024/3/11
|
||||
|
||||
1. 按键功能: 正式更新特殊操作按法, 此按法可用于切换输入法或菜单定位等功能. 同时更新ex03演示, 演示更清晰.
|
||||
|
||||
2. 修复其他bug, 比如示例wifi-text-show中, 中文网页无法在windows系统上呈现等...
|
||||
|
||||
## 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寸三色和黑白的不同驱动程序.
|
||||
|
||||
2. guy_epaper 文件夹内添加了一些文件. 为添加新版本驱动做准备.
|
||||
|
||||
3. 现在SD卡功能是可移除的. 可以自定义文件系统来初始化并使用. 但是对应的, SD卡引脚设定保留.
|
||||
|
||||
4. 优化按键手势的按动手感.
|
||||
|
||||
5. 重构了"固定引脚"(DYNAMIC_PIN_SETTINGS被注释)的宏定义逻辑代码. 现在如果在运行过"固定引脚"的程序之后, 再运行常规固件不需要二次配置.
|
||||
|
||||
6. 增大了S3的按钮任务栈空间, 避免因为stack overflow导致的任务终止.
|
||||
|
||||
7. 修复若干其他方面的bug, 比如配置引脚时, 屏幕没转向.
|
||||
|
||||
## 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
|
||||
|
||||
1. 增加了真.保姆级的教程 (详细到注释比代码多很多倍)
|
||||
|
||||
48
README.md
48
README.md
@@ -4,7 +4,9 @@
|
||||
|
||||
<img src="extra/artset/readguy_theme3.png" width="30%" height="auto">
|
||||
|
||||
**版本1.3.0正式发布!欢迎分享、star和fork~** 上面的图是项目看板娘, 盖. 可爱的盖姐在等你哟~
|
||||
**版本1.4,0正式发布!欢迎分享、star和fork~** 上面的图是项目看板娘, 盖. 可爱的盖姐在等你哟~
|
||||
|
||||
**即将发布7个全新的屏幕驱动: 欢迎支持! (详见后面的驱动表格)**
|
||||
|
||||
欢迎克隆, 项目交流QQ群: 926824162 (萌新可以进来问问题的哟), 项目的 Bilibili 主页: [BV1f94y187wz](https://www.bilibili.com/video/BV1f94y187wz/) 记得三连+关注我这个宝藏up主哦~
|
||||
|
||||
@@ -53,14 +55,23 @@ Supported displays: 1.54-inch, 2.13-inch, 2.66-inch, 2.9-inch, 4.2-inch.
|
||||
| 1 |1.54寸标准 |原创自研 |200*200| 16阶 | 不支持 | 1.3s | 0.35s |
|
||||
| 2 |1.54寸Lilygo |原创自研 |200*200| 16阶 | 支持 | 2.3s | 0.6s |
|
||||
| 3 |2.13寸汉朔价签 |原创自研 |122*250| 16阶 | 不支持 | 1.6s | 0.31s |
|
||||
| 4 |2.13寸三色 |原创自研 |104*212| 16阶 | 支持 | 2s | 0.2s |
|
||||
| 5 |2.66寸Vusion价签 |和4号相同|152*296| 16阶 | 支持 | 2s | 0.2s |
|
||||
| 4 |2.13寸低分辨率版 |原创自研 |104*212| 16阶 | 支持 | 1.12s | 0.17s |
|
||||
| 5 |2.66寸Vusion价签 |和4号相同|152*296| 16阶 | 支持 | 1.12s | 0.17s |
|
||||
| 6 |2.7寸佳显触摸屏 |和2号相同|176*264| 16阶 | 支持 | 2.3s | 0.6s |
|
||||
| 7 |2.9寸A01 |和1号相同|128*296| 16阶 | 不支持 | 1.8s | 0.55s |
|
||||
| 8 |2.9寸T94背光 |和2号相同|128*296| 16阶 | 支持 | 2.3s | 0.6s |
|
||||
| 9 |3.7寸高dpi墨水屏 |原创自研 |280*480| 16阶 | 不支持 | 1.3s | 0.5s |
|
||||
|10 |4.2寸HINK黑白价签 |原创自研 |400*300| 16阶 | 支持 | 1.72s | 0.38s |
|
||||
|11 |4.2寸WF丝印 |原创自研 |400*300| 16阶 | 不支持 | 3.6s | 0.8s |
|
||||
|12 |2.13寸三色 |和4号相同|122*250| 16阶 | 支持 | 未知 | 未知 |
|
||||
|13 |2.66寸三色价签 |和4号相同|152*296| 16阶 | 支持 | 2.48s | 0.65s |
|
||||
|14 |M5 Core.Ink 1.54寸 |即将支持|200*200|/|/|/|/|
|
||||
|15 |3.7寸低DPI版墨水屏 |即将支持|416*240|/|/|/|/|
|
||||
|16 |4.26寸高分辨率墨水屏|即将支持|800*480|/|/|/|/|
|
||||
|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|/|/|/|/|
|
||||
|
||||
可以自己在代码中加入你想要的屏幕型号
|
||||
|
||||
@@ -196,7 +207,7 @@ firmware.bin 0x10000
|
||||
|
||||
**如果想要使用纯arduino环境, 需要更改platformio.ini, 并将framework更改为`arduino`. 此时可以跳过 5~6 步骤**.
|
||||
|
||||
5. 编译目标是`ESP32`时, 需要单独安装[`LittleFS`](https://github.com/joltwallet/esp_littlefs)库来实现相关功能. 在项目内新建文件夹`components`, 在`components`文件夹内放入刚刚克隆的`LittleFS`库. *详见下图**上**方红框*. (使用纯arduino时跳过此步骤)
|
||||
5. 编译目标是`ESP32`且使用`ESP-IDF arduino component`时, 需要单独安装[`LittleFS`](https://github.com/joltwallet/esp_littlefs)库来实现相关功能. 在项目内新建文件夹`components`, 在`components`文件夹内放入刚刚克隆的`LittleFS`库. *详见下图**上**方红框*. (使用纯arduino时跳过此步骤)
|
||||
|
||||
<img src="extra/artset/build_dir_structure.png" width="20%" height="auto">
|
||||
|
||||
@@ -222,17 +233,38 @@ firmware.bin 0x10000
|
||||
|
||||
其中的WiFi功能, 其实是可以禁掉的. 只要你提前配置成功, 那么就可以摆脱WiFi配网配引脚功能.
|
||||
|
||||
使用方法: 打开文件[guy_driver_config.h](src/guy_driver_config.h), 随后便根据注释来选择性的开启或关闭一些系统功能.
|
||||
使用方法: 打开文件[`guy_driver_config.h`](src/guy_driver_config.h), 随后便根据注释来选择性的开启或关闭一些系统功能.
|
||||
|
||||
**不推荐的做法!**: 其中有些屏幕用不到, 也可以通过`guy_epaper_config`来配置.
|
||||
|
||||
使用方法: 打开文件[guy_epaper_config.h](src/guy_epaper/guy_epaper_config.h), 随后便可以设置不加载哪些屏幕的驱动程序.
|
||||
使用方法: 打开文件[`guy_epaper_config.h`](src/guy_epaper/guy_epaper_config.h), 随后便可以设置不加载哪些屏幕的驱动程序.
|
||||
|
||||
此操作可以节约flash和RAM消耗, **但是实际上此操作并不能节省太多的flash.** 为确保编译获得的程序兼容性, 应尽量不要更改这个文件.
|
||||
|
||||
- 还有一部分功能可以通过更改这两个文件来进行编辑 (如你想自己实现一个SD卡驱动)
|
||||
|
||||
- 但是如果自己更改了WiFi配置引脚的功能, ***这样编译出的程序就不能实现跨硬件运行了***
|
||||
|
||||
*有一些宏定义的组合是没有检验是否能够通过编译的. 如果有问题请提issue或者群里反馈*
|
||||
|
||||
## ESP32 项目配置 (使用 PlatformIO + Arduino as ESP-IDF component 环境)
|
||||
|
||||
menuconfig 内容:
|
||||
|
||||
``` ini
|
||||
FREERTOS_HZ = 1000
|
||||
ESP32_DEFAULT_CPU_FREQ_MHZ = 240
|
||||
ESP32_BROWNOUT_DET_LVL = 0
|
||||
ESP_PHY_REDUCE_TX_POWER=y
|
||||
FATFS_API_ENCODING_UTF_8 = true
|
||||
; SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS = true
|
||||
; SPI_MASTER_IN_IRAM = true ; 该选项能提高SPI传输速率
|
||||
; SPI_MASTER_ISR_IN_IRAM = true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Copyright © 2022-2023 FriendshipEnder. All Rights reserved.
|
||||
Copyright © 2022-2025 FriendshipEnder. All Rights reserved.
|
||||
|
||||
版权声明:需要经过作者@friendshipender的许可才能商用。
|
||||
版权声明:需要经过作者@friendshipender的许可才能商用。 可以联系邮箱playyinzhe@qq.com询问商用事宜
|
||||
|
||||
|
||||
@@ -157,8 +157,8 @@ void setup(){ //Arduino的setup函数. 这个函数在上电之后仅执行一
|
||||
//guy.setCursor(10,10); //设置显示的坐标
|
||||
//guy.print("Hello Readguy!"); //使用这个函数也能显示出字符串, 但是需要提前使用setCursor确定显示坐标
|
||||
|
||||
guy.display(true); // 快速刷新. 将屏幕缓存内的内容显示到墨水屏幕上. 可简写为 guy.display(), 效果一样.
|
||||
//guy.display(false); // 慢速刷新.
|
||||
guy.display(READGUY_FAST); // 快速刷新. 将屏幕缓存内的内容显示到墨水屏幕上. 可简写为 guy.display(), 效果一样.
|
||||
//guy.display(READGUY_SLOW); // 慢速刷新.
|
||||
|
||||
//想知道更多内容, 欢迎移步到其他示例.
|
||||
}
|
||||
|
||||
@@ -11,6 +11,25 @@
|
||||
* @brief ReadGuy功能演示.
|
||||
* 将根目录下的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都要用这种方法.
|
||||
*
|
||||
* 用于演示BMP格式图片灰度显示.
|
||||
*
|
||||
* @note 食用方法:
|
||||
@@ -69,62 +88,67 @@ void setup(){
|
||||
|
||||
// ------------------- 2 - 使用ReadGuy来显示字符串 ------<<
|
||||
|
||||
guy.setFont(&FreeMonoBold9pt7b); //设置显示的字体
|
||||
guy.setFont(&FreeMonoBold9pt7b); //设置显示的字体. 字体的更多信息可以查阅 Github 上的 Freefont
|
||||
|
||||
guy.setTextColor(0,1); //设置显示的颜色. 0代表黑色, 1代表白色
|
||||
guy.setTextColor(0,1); //设置显示的颜色. 0代表深色, 1代表白色
|
||||
//注意这个函数不是设定显示灰度的函数! 这只是设置像素显示到屏幕缓存里的颜色
|
||||
//屏幕缓存对于每个像素点只能保存黑白两种颜色信息. 若是显示到屏幕则为深色和白色
|
||||
//所有通过 setDepth 以外的函数设置的颜色都只有深色和白色
|
||||
//如果要实现灰度显示, 请参考后面的代码, 会提供相关说明的. 其中设置颜色灰度应当使用 setDepth() 函数
|
||||
|
||||
guy.drawString("Hello Readguy!",10,10); //用此函数将字符串显示到屏幕缓存内
|
||||
//guy.print("Hello Readguy!"); //使用这个函数也能显示出字符串, 但是需要提前使用setCursor确定显示坐标
|
||||
//guy.print("Hello Readguy!"); //使用这个函数也能显示出字符串, 但是需要提前使用setCursor确定显示坐标
|
||||
|
||||
guy.display(true); // 快速刷新. 将屏幕缓存内的内容显示到墨水屏幕上
|
||||
//guy.display(false); // 慢速刷新.
|
||||
guy.display(READGUY_FAST); // 快速刷新. 将屏幕缓存内的内容显示到墨水屏幕上
|
||||
// 但是, 上电初始化之后的首次刷新必为慢速刷新
|
||||
//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("with " _READGUY_PLATFORM ".",10,70); //检查readguy运行在ESP8266上还是ESP32上.
|
||||
|
||||
guy.display(); //不带参数时, 默认使用快速刷新
|
||||
guy.display(); //不带参数时, 默认使用快速刷新
|
||||
|
||||
|
||||
guy.setTextColor(0); //设置显示的颜色. 一个参数时,代表文本背景色为透明;
|
||||
//两个参数时, 代表文本背景色为后面的那个参数代表的颜色. 此次函数调用之后将显示为透明背景.
|
||||
guy.setTextColor(0); //设置显示的颜色. 一个参数时,代表文本背景色为透明;
|
||||
//两个参数时, 代表文本背景色为后面的那个参数代表的颜色. 此次函数调用之后将显示为透明背景.
|
||||
|
||||
guy.setCursor(10,80); //设置显示的坐标, 用于显示别的内容
|
||||
guy.setCursor(10,80); //设置显示的坐标, 用于显示别的内容
|
||||
|
||||
guy.setTextSize(2); //或者用此函数在屏幕上打印字符串.
|
||||
guy.setTextSize(2); //或者用此函数在屏幕上打印字符串.
|
||||
|
||||
guy.print('a'); //使用print打印字符.
|
||||
guy.print('a'); //使用print打印字符.
|
||||
|
||||
guy.display(); //快刷
|
||||
guy.display(); //快刷
|
||||
|
||||
|
||||
guy.setTextSize(1); //恢复常规大小字符
|
||||
guy.setTextSize(1); //恢复常规大小字符
|
||||
|
||||
guy.setFont(&fonts::Font0); //设置小字体 [字体设定部分参考lovyanGFX的示例]
|
||||
guy.setFont(&fonts::Font0); //设置小字体 [字体设定部分参考lovyanGFX等库的示例, 请查阅这些库的代码]
|
||||
|
||||
guy.setCursor(10,110); //设置显示的坐标, 用于显示别的内容
|
||||
guy.setCursor(10,110); //设置显示的坐标, 用于显示别的内容
|
||||
|
||||
guy.print(926824162); //使用print打印数字.
|
||||
guy.print(926824162); //使用print打印数字. (本数字为ReadGuy库的官方QQ交流群号)
|
||||
|
||||
guy.print(' '); //使用print打印字符.
|
||||
guy.print(' '); //使用print打印字符.
|
||||
|
||||
guy.print(1.61834,5); //使用print打印浮点数字, 5代表显示5位数
|
||||
guy.print(1.61834,5); //使用print打印浮点数字, 5代表显示5位数
|
||||
|
||||
guy.display(); //快刷
|
||||
guy.display(); //快刷
|
||||
|
||||
|
||||
guy.setCursor(10,130); //设置显示的坐标, 用于显示别的内容
|
||||
guy.setCursor(10,130); //设置显示的坐标, 用于显示别的内容
|
||||
|
||||
guy.printf("Small font using %s. It's a long string in the E-paper. "
|
||||
"Readguy always print it in a new line","printf");
|
||||
//使用 print 或者 printf 显示长串字符串时, 后面的字符会自动显示到下一行.而 drawString 不会这样
|
||||
//使用 print 或者 printf 显示长串字符串时, 后面的字符会自动显示到下一行.而 drawString 不会这样
|
||||
|
||||
guy.display(); //快刷
|
||||
|
||||
@@ -134,30 +158,30 @@ void setup(){
|
||||
|
||||
guy.fillScreen(1);
|
||||
|
||||
guy.display(false); // 慢速刷新. 慢刷的对比度显著高于快速刷新, 而且可以消除残影
|
||||
guy.display(READGUY_SLOW); // 慢速刷新. 慢刷的对比度显著高于快速刷新, 而且可以消除残影
|
||||
|
||||
for(int i=1;i<16;i++){ //灰度测试, 循环设置不同灰度
|
||||
for(int i=1;i<16;i++){ //灰度测试, 循环设置不同灰度
|
||||
|
||||
guy.setDepth(i); //设置灰度的颜色深度. 可接受的值为1~15.(从白到黑)
|
||||
//注意1. 在此函数内参数越接近0越白, 越接近15越黑. 输入参数为0或者>15时则自动设为15(最黑).
|
||||
//这和其他绘图函数中的 "0黑1白" 表示方法相反.
|
||||
//注意2. 此函数需要在程序中调用display()函数刷新屏幕之后才会生效, 且此次刷新必须是快刷.
|
||||
//若该函数在两次display()函数之间被多次调用, 则最终呈现的灰度依据最后一次调用的setDepth()函数.
|
||||
// OK: guy.setDepth(4); guy.print("hello"); guy.display();
|
||||
// guy.setDepth(8); guy.print("world"); guy.display();
|
||||
// NOT OK: guy.setDepth(4); guy.print("hello");
|
||||
// guy.setDepth(8); guy.print("world"); guy.display();
|
||||
// 最终呈现两个print函数等效于只调用一次 guy.setDepth(8);
|
||||
guy.setDepth(i); //设置灰度的颜色深度. 可接受的值为1~15.(从白到黑)
|
||||
//注意1. 在此函数内参数越接近0越白, 越接近15越黑. 输入参数为0或者>15时则自动设为15(最黑).
|
||||
//这和其他绘图函数中的 "0黑1白" 表示方法相反.
|
||||
//注意2. 此函数需要在程序中调用display()函数刷新屏幕之后才会生效, 且此次刷新必须是快刷.
|
||||
//若该函数在两次display()函数之间被多次调用, 则最终呈现的灰度依据最后一次调用的setDepth()函数.
|
||||
// OK: guy.setDepth(4); guy.print("hello"); guy.display();
|
||||
// guy.setDepth(8); guy.print("world"); guy.display();
|
||||
// NOT OK: guy.setDepth(4); guy.print("hello");
|
||||
// guy.setDepth(8); guy.print("world"); guy.display();
|
||||
// 最终呈现两个print函数等效于只调用一次 guy.setDepth(8);
|
||||
|
||||
guy.fillRect(10,i*10,20,10,0); //显示填充矩形.
|
||||
//注意, 此处最后一个参数0代表是黑色, 黑色的深度则是由前面的setDepth函数设定的.
|
||||
//即使您希望使用setDepth(1)之后显示一个浅灰色的矩形, 也需要将这个参数设为0(黑色)
|
||||
//注意, 此处最后一个参数0代表是深色, 深色的深度则是由前面的setDepth函数设定的.
|
||||
//即使您希望使用setDepth(1)之后显示一个浅灰色的矩形, 也需要将这个参数设为0(深色)
|
||||
|
||||
guy.setCursor(32,i*10);
|
||||
guy.setCursor(32,i*10); //设置文本显示坐标
|
||||
|
||||
guy.printf("Grey%d",i);
|
||||
guy.printf("Grey%d",i); //使用类似C语言的printf函数来显示带数字的格式化字符串
|
||||
|
||||
guy.display(); //快刷显示.
|
||||
guy.display(); //快刷显示.
|
||||
|
||||
}
|
||||
delay(2000);
|
||||
@@ -165,34 +189,34 @@ void setup(){
|
||||
// --------------------- 4 - 显示BMP格式图片文件 ----<<<<
|
||||
// [此部分更多可以参考lovyanGFX的示例]
|
||||
|
||||
guy.fillScreen(1); //清屏
|
||||
guy.fillScreen(1); //清屏
|
||||
|
||||
guy.display(); //显示白屏,用于将来显示图片.
|
||||
guy.display(); //显示白屏,用于将来显示图片.
|
||||
|
||||
LGFX_Sprite sp(&guy); //创建一个Sprite (可以存储一些像素, 快速读写)
|
||||
LGFX_Sprite sp(&guy); //创建一个Sprite (可以存储一些像素, 快速读写)
|
||||
|
||||
sp.createFromBmpFile(guy.guyFS(),"/test.bmp"); //从文件创建BMP图像信息.
|
||||
//使用guy.guyFS()函数返回可用的文件系统. 默认为SD卡. 当SD卡不可用时, 自动切换到内置的LittleFS.
|
||||
|
||||
//显示打开的图片信息(宽度和高度), 和剩余内存
|
||||
Serial.printf("[%lu] sp.w: %d, h: %d, res: %d.\n",millis(),sp.width(),sp.height(),ESP.getFreeHeap());
|
||||
Serial.printf("[%lu] sp.w: %d, h: %d, res: %d.\n",millis(),sp.width(),sp.height(),guy.getFreeMem());
|
||||
|
||||
guy.drawImage(sp,10,10); //使用抖动像素的方式显示图片(不是灰度, 只有黑点和白点的那种显示效果)
|
||||
guy.drawImage(sp,10,10); //使用抖动像素的方式显示图片(不是灰度, 只有黑点和白点的那种显示效果)
|
||||
|
||||
guy.display(); //自从1.2.0更新之后, drawImage不再刷屏, 此处需要额外调用display函数刷屏
|
||||
guy.display(); //自从1.2.0更新之后, drawImage不再刷屏, 此处需要额外调用display函数刷屏
|
||||
|
||||
Serial.printf("[%lu] drawn dithering bmp.\n",millis()); //显示信息
|
||||
|
||||
delay(2000);
|
||||
|
||||
|
||||
guy.setGreyQuality(1); //设置灰度刷新方式. 对于支持连续刷灰度的屏幕才有效.
|
||||
guy.setGreyQuality(1); //设置灰度刷新方式. 对于支持连续刷灰度的屏幕才有效.
|
||||
// 1(默认)为连续刷新, 0为循环调用 setDepth+display 来刷新 (可能会有白边)
|
||||
//如果连续刷新效果不好, 请将此处改为0再试一次.
|
||||
|
||||
guy.draw16grey(sp,10,10); //使用16级灰度的方式显示图片 需要的时间比较长
|
||||
|
||||
sp.deleteSprite(); //关闭图片文件, 释放图片占用的大量内存
|
||||
sp.deleteSprite(); //关闭图片文件, 释放图片占用的大量内存
|
||||
|
||||
Serial.printf("[%lu] drawn 16-layer greyscale bmp.\n",millis()); //显示信息
|
||||
|
||||
@@ -201,72 +225,72 @@ void setup(){
|
||||
// ---------------------- 5 - 其他屏幕功能测试 ---<<<<<
|
||||
|
||||
guy.setFont(&FreeMonoBold9pt7b); //设置文本字体
|
||||
guy.setTextColor(0); //设置文本颜色
|
||||
guy.fillScreen(1); //用白色清屏.
|
||||
guy.display(false); //慢刷. 注意, 进行慢刷操作之后, 所有之前显示的灰度内容均会被重新刷成纯黑色
|
||||
guy.setTextColor(0); //设置文本颜色
|
||||
guy.fillScreen(1); //用白色清屏.
|
||||
guy.display(READGUY_SLOW); //慢刷. 注意, 进行慢刷操作之后, 所有之前显示的灰度内容均会被重新刷成纯黑色
|
||||
//不管是浅灰色还是深灰色, 进行慢刷之后只有黑白色. 原来的非白色像素(浅灰色,深灰色和黑色等) 会全刷成白色.
|
||||
|
||||
guy.drawString("Rotation 0",10,12); //默认旋转方向为0. 实际的默认方向取决于屏幕IC. 大多数屏幕IC是竖屏.
|
||||
drawLines(); //调用 画线函数, 绘制屏幕上的一些线条.并显示.
|
||||
|
||||
guy.fillScreen(1); //用白色清屏.
|
||||
guy.fillScreen(1); //用白色清屏.
|
||||
guy.setRotation(1); //设置旋转方向, 旋转完成之后会对画面进行裁切.
|
||||
guy.drawString("setRotation 1",12,10); //设置旋转方向
|
||||
guy.drawString("Set Rot 1",12,10); //设置旋转方向
|
||||
drawLines();
|
||||
|
||||
guy.fillScreen(1); //用白色清屏.
|
||||
guy.setRotation(2); //方向2和方向0 的宽度和高度相同.旋转了180度.
|
||||
guy.drawString("Rot 2",12,10); //设置旋转方向
|
||||
guy.fillScreen(1); //用白色清屏.
|
||||
guy.setRotation(2); //方向2和方向0 的宽度和高度相同.旋转了180度.
|
||||
guy.drawString("Rot 2",12,10); //设置旋转方向
|
||||
drawLines();
|
||||
|
||||
guy.fillScreen(1); //用白色清屏.
|
||||
guy.setRotation(3); //方向3和方向1 的宽度和高度也是相同的.旋转了180度.
|
||||
guy.drawString("Rotate 3",15,10); //设置旋转方向
|
||||
guy.fillScreen(1); //用白色清屏.
|
||||
guy.setRotation(3); //方向3和方向1 的宽度和高度也是相同的.旋转了180度.
|
||||
guy.drawString("Rotate 3",15,10); //设置旋转方向
|
||||
drawLines();
|
||||
|
||||
|
||||
guy.drawString("Sleeping...",10,30); //此部分程序演示如何使用屏幕睡眠(降低耗电量)
|
||||
guy.drawString("Sleeping...",10,30);//此部分程序演示如何使用屏幕睡眠(降低耗电量)
|
||||
|
||||
guy.invertDisplay(); //对屏幕上的一切都进行反色处理
|
||||
guy.invertDisplay(); //对屏幕上的一切都进行反色处理
|
||||
|
||||
guy.display(); //即将进入睡眠状态
|
||||
guy.display(); //即将进入睡眠状态
|
||||
|
||||
guy.sleepEPD(); //进入睡眠模式
|
||||
guy.sleepEPD(); //进入睡眠模式. 睡眠模式下再次刷新屏幕必须使用慢速刷新
|
||||
//注意, 如果没有设置RST引脚, 则实际上不会进入睡眠模式. 睡眠模式依赖RST引脚的复位信号.
|
||||
|
||||
delay(3000);
|
||||
|
||||
guy.setTextColor(1); //设置文本颜色为白色,因为被反色的屏幕的当前像素颜色以黑色像素为主
|
||||
guy.setTextColor(1); //设置文本颜色为白色, 因为被反色的屏幕的当前像素颜色以黑色像素为主
|
||||
guy.drawString("Wake Up! ~\\(^_^)/~",10,50); //退出睡眠状态
|
||||
|
||||
guy.display(false); //使用慢刷 来唤醒处于低功耗状态下的屏幕.
|
||||
guy.display(READGUY_SLOW); //使用全屏慢刷 来唤醒处于低功耗状态下的屏幕.
|
||||
|
||||
// ------------------ 6 - 可以利用灰度来达到的一些显示效果 --<<<<<<
|
||||
|
||||
guy.fillScreen(1); //清屏
|
||||
guy.fillScreen(1); //清屏
|
||||
|
||||
guy.display(FILL_WHITE,false); //慢刷清屏. 左侧的FILL_WHITE表示 不写入屏幕缓存, 直接刷全白
|
||||
//可以改为FILL_BLACK来设置写入缓存全黑.
|
||||
//以上的方式均不会修改屏幕缓存中的内容. 右侧的false表示全屏慢刷.
|
||||
guy.display(FILL_WHITE,READGUY_SLOW); //慢刷清屏. 左侧的FILL_WHITE表示 不写入屏幕缓存, 直接刷全白
|
||||
//可以改为FILL_BLACK来设置写入缓存全黑.
|
||||
//以上的两种 guy.display(...) 方法均不会修改屏幕缓存中的内容.
|
||||
|
||||
guy.setTextColor(0); //设置显示的颜色. 0代表黑色, 一个参数代表黑白显示.
|
||||
//注意这个函数不是设定显示灰度的函数!
|
||||
guy.setTextColor(0); //设置显示的颜色. 0代表深色, 1代表白色. 一个参数代表黑白显示.
|
||||
//注意这个函数不是设定显示灰度的函数!
|
||||
|
||||
guy.setDepth(0); //恢复黑色显示, 此语句等效于setDepth(15)
|
||||
guy.setFont(&FreeMonoBold9pt7b); //设置文本字体
|
||||
guy.setDepth(0); //恢复黑色显示, 此语句等效于setDepth(15)
|
||||
guy.setFont(&FreeMonoBold9pt7b); //设置文本字体
|
||||
guy.drawString("I love Readguy!",10,10); //设置显示坐标并显示
|
||||
guy.display(); //setDepth()函数需要调用display()函数刷新屏幕之后才会生效
|
||||
guy.display(); //setDepth()函数需要调用display()函数刷新屏幕之后才会生效
|
||||
|
||||
guy.setDepth(4); //把灰度深度设为一个浅色, 方便勾勒阴影.
|
||||
guy.setDepth(4); //把灰度深度设为一个浅色, 方便勾勒阴影.
|
||||
guy.drawString("I love Readguy!",12,12); //错开2像素并减淡颜色灰度,可以实现阴影效果
|
||||
guy.display();
|
||||
|
||||
const char *st="Programmed by";
|
||||
guy.setDepth(7); //设置颜色深度
|
||||
guy.setDepth(7); //设置颜色深度
|
||||
guy.drawString(st,11,31); //设置显示坐标
|
||||
guy.display();
|
||||
guy.setDepth(4); //这里有一点需要注意: 如果显示的位置原本就已经显示过灰度数据了
|
||||
guy.drawString(st,10,31); //(其实这里的像素在内存里存储的还是黑色), 即使新设定的颜色深度比之前的颜色深,
|
||||
guy.drawString(st,10,31); //(其实这里的像素在内存里存储的还是深色), 即使新设定的颜色深度比之前的颜色深,
|
||||
guy.drawString(st,11,30); //也不会覆盖这里原来的浅灰色. 此处的灰度设定只对原来是纯白色的像素有效.
|
||||
guy.display(); //如果要更改这个像素点的颜色, 只能全部刷白屏之后再重新刷这些灰度颜色.
|
||||
guy.setDepth(15); //(最好是慢刷白屏,如果要坚持使用快刷,也需要把灰度设置为全黑色对应的15再刷)
|
||||
@@ -275,31 +299,31 @@ void setup(){
|
||||
guy.display();
|
||||
|
||||
const char str[]="FriendshipEnder"; //实现类似于渐变色的效果
|
||||
guy.setCursor(8,50);
|
||||
guy.setCursor(8,50); //设置显示字符的基础位置坐标
|
||||
for(int i=0;i<15;i++){ //在 for 循环内循环修改显示深度
|
||||
guy.setDepth(15-i);
|
||||
guy.print(str[i]);
|
||||
guy.display(); //注意每次使用 setDepth 之后需要再刷一次屏, 灰度设置才能生效
|
||||
}
|
||||
guy.setDepth(15-i); //设置显示颜色深度 (灰度), 越小越浅(白), 1为最浅, 15为纯黑色
|
||||
guy.print(str[i]); //显示单个字符
|
||||
guy.display(); //注意每次使用 setDepth 之后需要再刷一次屏, 灰度设置才能生效
|
||||
} //设置灰度显示之后必须刷屏才能设置不同的其他灰度, 一次刷出来的只能是一种颜色
|
||||
|
||||
guy.setDepth(6);
|
||||
guy.drawString("Follow me~~",14,68);
|
||||
guy.setDepth(6); //设置灰度显示的深度为6 (其实也是很浅的灰色了, 但对于一些屏幕来说这个颜色也很黑了)
|
||||
guy.drawString("Follow me~~",14,68); //指定坐标显示文本
|
||||
guy.display();
|
||||
|
||||
guy.setDepth(2);
|
||||
guy.drawString("Follow me~~",16,70);
|
||||
guy.setDepth(2); //设置灰度显示的深度为2 (几乎是白色了)
|
||||
guy.drawString("Follow me~~",16,70); //指定坐标显示文本
|
||||
guy.display();
|
||||
|
||||
guy.setDepth(5);
|
||||
guy.setTextColor(0);
|
||||
guy.drawString("on Bilibili!",14,90);
|
||||
guy.setDepth(5); //设置灰度显示的深度为5
|
||||
guy.setTextColor(0); //设置文本为深色 (所有通过 setDepth 以外的函数设置的颜色都只有深色和白色)
|
||||
guy.drawString("on Bilibili!",14,90); //指定坐标显示文本
|
||||
guy.display();
|
||||
|
||||
guy.setDepth(6); //绘制外框
|
||||
guy.setDepth(6); //绘制外框, 浅灰色
|
||||
guy.drawRoundRect(8,86,guy.textWidth("on Bilibili!")+14,28,7,0);
|
||||
guy.display();
|
||||
|
||||
guy.setDepth(15); //恢复到正常黑色
|
||||
guy.setDepth(15); //恢复到正常黑色
|
||||
guy.fillRoundRect(10,88,guy.textWidth("on Bilibili!")+10,24,5,0);
|
||||
guy.setTextColor(1);
|
||||
guy.drawString("on Bilibili!",16,92);
|
||||
@@ -307,30 +331,51 @@ void setup(){
|
||||
|
||||
delay(5000);
|
||||
|
||||
guy.sleepEPD(); //进入睡眠模式
|
||||
// guy.sleepEPD(); //进入睡眠模式, 屏幕不再刷新.
|
||||
guy.setTextColor(0); //重新将文本颜色恢复到黑色.
|
||||
|
||||
// ------------------ 7 - 屏幕以外的功能: 比如wifi和按钮 -<<<<<<<
|
||||
|
||||
guy.ap_setup(); //启动ESP芯片内置 WiFi 热点, 启动后即可在wifi列表上查看readguy
|
||||
guy.ap_setup(); //启动ESP芯片内置 WiFi 热点, 启动后即可在wifi列表上查看readguy
|
||||
|
||||
guy.server_setup(); //启动服务器功能, 默认地址为192.168.4.1
|
||||
guy.server_setup(); //启动服务器功能, 默认地址为192.168.4.1
|
||||
|
||||
}
|
||||
|
||||
int bright=128; //设置亮度
|
||||
int bright=128; //设置亮度
|
||||
|
||||
int showTextPlace=10; //设置文本显示位置
|
||||
|
||||
void loop(){
|
||||
guy.server_loop(); //让服务器保持服务
|
||||
delay(10);
|
||||
if(bright%7==0){
|
||||
Serial.printf("getBtn: %d\n",guy.getBtn()); //每隔一段时间, 检测一下按键.
|
||||
|
||||
guy.server_loop(); //让服务器保持服务
|
||||
|
||||
int buttonValue = guy.getBtn(); //程序会自动检测按键. 使用 guy.getBtn() 可以实时查看当前按键的状态.
|
||||
|
||||
if (buttonValue != 0){ //0 代表没有按键被按下
|
||||
|
||||
guy.fillScreen(1); //白色清屏
|
||||
guy.setCursor(4,showTextPlace);//设置显示文本位置. showTextPlace 可以让每次按下按钮刷屏位置不一样.
|
||||
guy.print("Button: "); //显示先导字符串
|
||||
guy.print(buttonValue); //按下不同的按键, 或者不同的按法, 会显示不同的数字. 自己按以下试试吧.
|
||||
guy.display(); //显示出来
|
||||
|
||||
if(showTextPlace != 10)
|
||||
showTextPlace = 10; //在这里显示过文本了, 下一次在另一个地方显示
|
||||
else showTextPlace = 20; //没在这里显示过文本, 下一次回到上次的地方显示
|
||||
|
||||
Serial.printf("Button: %d\n", buttonValue); //在串口上也显示按键按下的内容.
|
||||
}
|
||||
|
||||
//以下的语句用于让背光闪烁呼吸灯.
|
||||
if(bright==511) bright=0;
|
||||
else bright++;
|
||||
guy.setBright(bright>=256?511-bright:bright);
|
||||
delay(10);
|
||||
}
|
||||
|
||||
void drawLines(){ //声明一个函数, 用于显示一些线条. 此函数在后面的程序中会用到的
|
||||
//具体都有哪些绘图函数可以用, 请参考以下 LovyanGFX 或者 TFT_eSPI 或者 Adafruit_GFX 这几个库的的说明吧
|
||||
|
||||
guy.drawFastHLine(0,0,20); //使用 drawFastHLine 绘制横向线段
|
||||
guy.drawFastVLine(0,0,20); //使用 drawFastVLine 绘制纵向线段
|
||||
|
||||
@@ -6,9 +6,15 @@
|
||||
*
|
||||
* @file ex03_buttons.ino
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @version 1.0
|
||||
* @date 2023-10-20
|
||||
* @version 1.2 增加了新的手势功能
|
||||
*
|
||||
* @date created: 2023-10-20 modify: 2024-02-25 last modify: 2024-03-11
|
||||
* @brief ReadGuy 按键功能演示. ReadGuy自带的按键驱动程序是非常好用的
|
||||
以下内容为按键个数与手势操作的对应关系.
|
||||
//行为 下一个 上一个 确定 返回/退出 特殊操作(如切换输入法)
|
||||
//1个按键 返回 1=点按 2=双击 4=长按 8=三击 3=点按后接长按
|
||||
//2个按键 返回 1=左键点按 2=左键长按 4=右键点按 8=右键长按 3=按住左键点按右键
|
||||
//3个按键 返回 1=右键点按 2=左键点按 4=中键点按 8=中键长按 3=中间按键双击(需手动开启)
|
||||
|
||||
* @attention
|
||||
* Copyright (c) 2022-2023 FriendshipEnder
|
||||
@@ -43,33 +49,36 @@ void setup(){
|
||||
Serial.println(F("[readguy] Button demo")); //显示文本 默认是不支持中文显示的.
|
||||
guy.println("Button demo"); //显示文本 默认是不支持中文显示的.
|
||||
guy.display();//刷新墨水屏.
|
||||
guy.setButtonSpecial(true);//对于三按键系统,打开此模式将会允许双击进行特殊操作(如切换键盘)
|
||||
}
|
||||
|
||||
void loop(){
|
||||
int val = guy.getBtn(); //此函数用于获取按键状态 没有按键按下时 返回0.
|
||||
//1个按键 返回 1=点按 2=双击 3=长按 4=三击
|
||||
//2个按键 返回 1=左键点按 2=左键长按 3=右键点按 4=右键长按
|
||||
//3个按键 返回 1=左键点按 2=右键点按 3=中键点按 4=中键长按
|
||||
|
||||
if(val>0){
|
||||
int c = guy.getButtonsCount(); //此函数用于返回设备有多少个按键. [最近更新的函数]
|
||||
switch (val){
|
||||
case 1:
|
||||
case 1: //下一个 手势
|
||||
if(c==1) guy.println("key single clicked!");
|
||||
else if(c==2) guy.println("Left key clicked!");
|
||||
else if(c==3) guy.println("Left key clicked!");
|
||||
break;
|
||||
case 2:
|
||||
if(c==1) guy.println("key double clicked!");
|
||||
else if(c==2) guy.println("Left key long pressed!");
|
||||
else if(c==3) guy.println("Right key clicked!");
|
||||
break;
|
||||
case 4:
|
||||
case 2: //上一个 手势
|
||||
if(c==1) guy.println("key long pressed!");
|
||||
else if(c==2) guy.println("Left key long pressed!");
|
||||
else if(c==3) guy.println("Left key clicked!");
|
||||
break;
|
||||
case 3: //特殊 手势
|
||||
if(c==1) guy.println("key clicked and pressed!");
|
||||
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 double clicked!");
|
||||
else if(c==2) guy.println("Right key clicked!");
|
||||
else if(c==3) guy.println("Centre key clicked!");
|
||||
break;
|
||||
case 8:
|
||||
case 8: //返回 手势
|
||||
if(c==1) guy.println("key triple clicked!");
|
||||
else if(c==2) guy.println("Right key long pressed!");
|
||||
else if(c==3) guy.println("Centre key long pressed!");
|
||||
|
||||
@@ -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> // settimeofday 函数 需要
|
||||
|
||||
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地址, 网关和子网掩码.
|
||||
@@ -129,15 +135,21 @@ void setup(){
|
||||
|
||||
}while(conf_status!=2); // conf_status==2说明连接上了
|
||||
|
||||
WiFi.mode(WIFI_STA); //从WIFI_AP_STA模式切换到WIFI_STA模式, 不再提供readguy热点.
|
||||
// WiFi.mode(WIFI_STA); //从WIFI_AP_STA模式切换到WIFI_STA模式, 不再提供readguy热点.
|
||||
|
||||
guy.println("Getting NTP time..."); //连接成功之后尝试获取NTP时间
|
||||
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将自动结束之前的服务器
|
||||
@@ -151,6 +163,11 @@ void loop(){
|
||||
//其中, sv 参数指向了一个服务器类型的变量. 当有来自客户端的请求时, 需要通过sv来发送响应消息.
|
||||
|
||||
void f1(server_t sv){ //使用PSTR来减少对内存的消耗(不加PSTR()或者F()则字符串会存到.rodata,占用宝贵的内存)
|
||||
if(WiFi.status() == WL_CONNECTED) {
|
||||
sv->send_P(200, PSTR("text/html"),PSTR(
|
||||
"<html><body><meta charset=\"utf-8\">已连接, 不需要再配网了。</body></html>"));
|
||||
return;
|
||||
}
|
||||
String webpage_html = F(
|
||||
"<!DOCTYPE html>"
|
||||
"<html lang='zh-cn'>"
|
||||
@@ -216,80 +233,84 @@ void f2(server_t sv){
|
||||
PSTR("<html><body><meta charset=\"utf-8\">配置失败,缺少信息</body></html>"));
|
||||
}
|
||||
|
||||
|
||||
/*----------------- NTP code ------------------*/
|
||||
#define NTP_SERVERS 4
|
||||
WiFiUDP udp;
|
||||
uint8_t packetBuffer[48];
|
||||
const int16_t timeZone = 8; //Beijing
|
||||
const int16_t localPort = 1337;
|
||||
time_t get_ntp_time_impl(uint8_t _server)
|
||||
{
|
||||
const char * ntpServerName[4] = {
|
||||
time_t getNTPTime(){
|
||||
const char * ntpServerName[NTP_SERVERS] = {
|
||||
"ntp1.aliyun.com","time.windows.com","cn.ntp.org.cn","cn.pool.ntp.org"
|
||||
};
|
||||
char ntpHost[32];
|
||||
IPAddress ntpServerIP; // NTP server's ip address
|
||||
|
||||
while (udp.parsePacket() > 0) ; // discard any previously received packets
|
||||
Serial.println(F("Transmit NTP Request"));
|
||||
// get a random server from the pool
|
||||
strncpy_P(ntpHost,ntpServerName[_server],31);
|
||||
ntpHost[31] = '\0';
|
||||
WiFi.hostByName(ntpHost, ntpServerIP);
|
||||
Serial.print(FPSTR(ntpServerName[_server]));
|
||||
Serial.write(':');
|
||||
Serial.println(ntpServerIP);
|
||||
|
||||
// set all bytes in the buffer to 0
|
||||
memset(packetBuffer, 0, 48);
|
||||
// Initialize values needed to form NTP request
|
||||
// (see URL above for details on the packets)
|
||||
packetBuffer[0] = 0b11100011; // LI, Version, Mode
|
||||
packetBuffer[1] = 0; // Stratum, or type of clock
|
||||
packetBuffer[2] = 6; // Polling Interval
|
||||
packetBuffer[3] = 0xEC; // Peer Clock Precision
|
||||
// 8 bytes of zero for Root Delay & Root Dispersion
|
||||
packetBuffer[12] = 49;
|
||||
packetBuffer[13] = 0x4E;
|
||||
packetBuffer[14] = 49;
|
||||
packetBuffer[15] = 52;
|
||||
// all NTP fields have been given values, now
|
||||
// you can send a packet requesting a timestamp:
|
||||
udp.beginPacket(ntpServerIP, 123); //NTP requests are to port 123
|
||||
udp.write(packetBuffer, 48);
|
||||
udp.endPacket();
|
||||
|
||||
uint32_t beginWait = millis();
|
||||
while (millis() - beginWait < 1500) {
|
||||
int size = udp.parsePacket();
|
||||
if (size >= 48) {
|
||||
Serial.println("Receive NTP Response");
|
||||
udp.read(packetBuffer, 48); // read packet into the buffer
|
||||
unsigned long secsSince1900;
|
||||
// convert four bytes starting at location 40 to a long integer
|
||||
secsSince1900 = (unsigned long)packetBuffer[40] << 24;
|
||||
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
|
||||
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
|
||||
secsSince1900 |= (unsigned long)packetBuffer[43];
|
||||
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<NTP_SERVERS;i++){//最多尝试10次对时请求
|
||||
_now=0;
|
||||
char ntpHost[32];
|
||||
IPAddress ntpServerIP; // NTP server's ip address
|
||||
|
||||
while (udp.parsePacket() > 0) ; // discard any previously received packets
|
||||
Serial.println(F("Transmit NTP Request"));
|
||||
// get a random server from the pool
|
||||
strncpy_P(ntpHost,ntpServerName[i],31);
|
||||
ntpHost[31] = '\0';
|
||||
WiFi.hostByName(ntpHost, ntpServerIP);
|
||||
Serial.print(FPSTR(ntpServerName[i]));
|
||||
Serial.write(':');
|
||||
Serial.println(ntpServerIP);
|
||||
|
||||
// set all bytes in the buffer to 0
|
||||
memset(packetBuffer, 0, 48);
|
||||
// Initialize values needed to form NTP request
|
||||
// (see URL above for details on the packets)
|
||||
packetBuffer[0] = 0b11100011; // LI, Version, Mode
|
||||
packetBuffer[1] = 0; // Stratum, or type of clock
|
||||
packetBuffer[2] = 6; // Polling Interval
|
||||
packetBuffer[3] = 0xEC; // Peer Clock Precision
|
||||
// 8 bytes of zero for Root Delay & Root Dispersion
|
||||
packetBuffer[12] = 49;
|
||||
packetBuffer[13] = 0x4E;
|
||||
packetBuffer[14] = 49;
|
||||
packetBuffer[15] = 52;
|
||||
// all NTP fields have been given values, now
|
||||
// you can send a packet requesting a timestamp:
|
||||
udp.beginPacket(ntpServerIP, 123); //NTP requests are to port 123
|
||||
udp.write(packetBuffer, 48);
|
||||
udp.endPacket();
|
||||
|
||||
uint32_t beginWait = millis();
|
||||
while (millis() - beginWait < 1500) {
|
||||
int size = udp.parsePacket();
|
||||
if (size >= 48) {
|
||||
Serial.println("Receive NTP Response");
|
||||
udp.read(packetBuffer, 48); // read packet into the buffer
|
||||
unsigned long secsSince1900;
|
||||
// convert four bytes starting at location 40 to a long integer
|
||||
secsSince1900 = (unsigned long)packetBuffer[40] << 24;
|
||||
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
|
||||
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
|
||||
secsSince1900 |= (unsigned long)packetBuffer[43];
|
||||
_now = secsSince1900 - 2208988800UL; // + timeZone * 3600;
|
||||
break;
|
||||
}
|
||||
}// return 0 if unable to get the time
|
||||
if(_now) break; //成功后立即退出
|
||||
else Serial.println("No NTP Response :-(");
|
||||
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.
|
||||
|
||||
@@ -70,8 +70,8 @@ void setup(){
|
||||
//guy.setCursor(10,10); //设置显示的坐标
|
||||
//guy.print("Hello Readguy!"); //使用这个函数也能显示出字符串, 但是需要提前使用setCursor确定显示坐标
|
||||
|
||||
guy.display(true); // 快速刷新. 将屏幕缓存内的内容显示到墨水屏幕上
|
||||
//guy.display(false); // 慢速刷新.
|
||||
guy.display(READGUY_FAST); // 快速刷新. 将屏幕缓存内的内容显示到墨水屏幕上
|
||||
//guy.display(READGUY_SLOW); // 慢速刷新.
|
||||
|
||||
//想知道更多内容, 欢迎移步到其他示例.
|
||||
}
|
||||
|
||||
138
examples/ex04_wifi/4_wifi_text_show/4_wifi_text_show.ino
Normal file
138
examples/ex04_wifi/4_wifi_text_show/4_wifi_text_show.ino
Normal file
@@ -0,0 +1,138 @@
|
||||
/******************** 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.println("连接后浏览器访问: 192.168.4.1");
|
||||
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("<br/><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+"文字显示完成:<br/>"+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. */
|
||||
26582
examples/ex04_wifi/4_wifi_text_show/ctg_u8g2_wqy12.c
Normal file
26582
examples/ex04_wifi/4_wifi_text_show/ctg_u8g2_wqy12.c
Normal file
File diff suppressed because it is too large
Load Diff
43
examples/ex04_wifi/4_wifi_text_show/ctg_u8g2_wqy12.h
Normal file
43
examples/ex04_wifi/4_wifi_text_show/ctg_u8g2_wqy12.h
Normal 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
|
||||
@@ -55,9 +55,9 @@
|
||||
|
||||
ReadguyDriver guy;//新建一个readguy对象, 用于显示驱动.
|
||||
|
||||
extern const uint8_t ctg_wqy9pt_chinese1[]; //声明中文字体文件
|
||||
extern const uint8_t ctg_u8g2_wqy12_chinese1[]; //声明中文字体文件
|
||||
|
||||
const lgfx::U8g2font cn_font(ctg_wqy9pt_chinese1); //U8G2格式中文字体转化为LGFX格式字体
|
||||
const lgfx::U8g2font cn_font(ctg_u8g2_wqy12_chinese1); //U8G2格式中文字体转化为LGFX格式字体
|
||||
|
||||
void setup(){
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
}
|
||||
|
||||
@@ -15,6 +15,29 @@
|
||||
* - 运行的会很缓慢, 因为示例的图片文件比较大.
|
||||
* 1. 在运行过ex01或者ex02的开发板上 编译烧录本程序.
|
||||
* 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} 代码食用注意事项:
|
||||
* 这一部分的代码很难读, 或者按维莫斯小姐的说法, 很 "抽象" .
|
||||
@@ -174,13 +197,13 @@ void setup(){
|
||||
delay(2000);
|
||||
|
||||
|
||||
guy.display(FILL_WHITE,true); //在保持屏幕缓存不变的时候快速刷新白屏.
|
||||
guy.display(FILL_WHITE,READGUY_FAST); //在保持屏幕缓存不变的时候快速刷新白屏.
|
||||
guy.drawImage(sp,0,0,guy.width(),guy.height()); //绘画的画布可以被放大或者缩小到任意宽度和高度.
|
||||
//此处的参数调用表示将会在屏幕坐标(0,0)开始显示, 显示的画布宽度缩放到屏幕宽度, 画布高度缩放到屏幕高度.
|
||||
guy.display(); //调用display函数刷屏.
|
||||
delay(2000);
|
||||
|
||||
guy.display(FILL_WHITE,true); //在保持屏幕缓存不变的时候快速刷新白屏
|
||||
guy.display(FILL_WHITE,READGUY_FAST); //在保持屏幕缓存不变的时候快速刷新白屏
|
||||
guy.fillScreen(1); //白屏清屏(清屏幕缓存)
|
||||
guy.drawImage(sp,10,10,65,50); //缩放: 缩小到65X50
|
||||
guy.display(); //调用display函数刷屏.
|
||||
@@ -244,7 +267,7 @@ void setup(){
|
||||
|
||||
im.filename=BMP_FILE; //在此直接设置文件路径和文件名.
|
||||
|
||||
guy.display(FILL_WHITE,false); //将屏幕全刷成白屏. 为了即将的图片刷新.
|
||||
guy.display(FILL_WHITE,READGUY_SLOW); //将屏幕全刷成白屏. 为了即将的图片刷新.
|
||||
//建议在使用drawImageFile函数之前, 使用慢刷刷白屏, 可以保证显示效果清晰可见.
|
||||
|
||||
im.drawImageFile(); //显示BMP格式.图片. im会自动识别文件扩展名并绘制.
|
||||
@@ -265,7 +288,7 @@ void setup(){
|
||||
|
||||
im.background=0; //设置背景颜色, 0黑1白, 此处设为背景色为黑色.
|
||||
|
||||
guy.display(FILL_WHITE,false); //将屏幕全刷成白屏. 为了即将的图片刷新.
|
||||
guy.display(FILL_WHITE,READGUY_SLOW); //将屏幕全刷成白屏. 为了即将的图片刷新.
|
||||
|
||||
im.drawImageFile(); //显示JPG格式.图片. im会自动识别文件扩展名并绘制.
|
||||
delay(2000);
|
||||
@@ -279,7 +302,7 @@ void setup(){
|
||||
im.scalex=400.0f/1280.0f;
|
||||
im.scaley=300.0f/576.0f;
|
||||
|
||||
guy.display(FILL_WHITE, false);//显示. 此处的功能就是将显示缓存输出到屏幕上
|
||||
guy.display(FILL_WHITE, READGUY_SLOW);//显示. 此处的功能就是将显示缓存输出到屏幕上
|
||||
|
||||
im.drawImageFile(); //显示PNG格式.图片. ESP8266可能不会绘制.
|
||||
delay(2000);
|
||||
@@ -308,7 +331,7 @@ void setup(){
|
||||
im.exPoolSize=MEM_POOL; //设置外部缓存内存大小
|
||||
|
||||
guy.setGreyQuality(1); //设置灰度模式为默认灰度显示模式
|
||||
guy.display(FILL_WHITE,false); //将屏幕全刷成白屏. 为了即将显示灰度图.
|
||||
guy.display(FILL_WHITE,READGUY_SLOW); //将屏幕全刷成白屏. 为了即将显示灰度图.
|
||||
|
||||
im.enableFloyd=0; //禁用掉抖动算法.
|
||||
|
||||
@@ -316,7 +339,7 @@ void setup(){
|
||||
|
||||
delay(2000);
|
||||
|
||||
guy.display(FILL_WHITE,false); //将屏幕全刷成白屏. 为了即将显示灰度图.
|
||||
guy.display(FILL_WHITE,READGUY_SLOW); //将屏幕全刷成白屏. 为了即将显示灰度图.
|
||||
|
||||
im.enableFloyd=1; // 重新启用抖动算法.
|
||||
|
||||
@@ -351,7 +374,7 @@ void setup(){
|
||||
}
|
||||
guy.drawLine(guy.width(),0,0,guy.height(),0);
|
||||
|
||||
guy.display(false); //刷新屏幕, 显示绘画的线段
|
||||
guy.display(READGUY_SLOW); //刷新屏幕, 显示绘画的线段
|
||||
|
||||
//im.baseFs=&guy.guyFS(); //直接更改im内的数据即可设置绘制参数. 在此处就是设置文件系统.
|
||||
im.filename=BMP_FILE; //在此直接设置文件路径和文件名.
|
||||
|
||||
@@ -61,16 +61,16 @@ uint8_t readguyImage::drawImgHandler(int r, LGFX_Sprite *spr){
|
||||
//_x=y-r/stage*_h; yd=0;
|
||||
//_y=x;//(widthDiv8<<3)-x-1;
|
||||
_x=x-r/stage*_h;
|
||||
_y=y; yd=0;
|
||||
_y=y+w-guy->drvWidth(); yd=0;
|
||||
if(_x<0){ xd=-_x; _x=0; }
|
||||
break;
|
||||
case 2:
|
||||
_x=x; xd=0;
|
||||
_y=y-(GUY_STAGES-r/stage-1)*_h;
|
||||
_x=x+w-guy->drvWidth(); xd=0;
|
||||
_y=y+(r/stage+1)*_h-h;
|
||||
if(_y<0){ yd=-_y; _y=0; }
|
||||
break;
|
||||
case 3:
|
||||
_x=x-(GUY_STAGES-r/stage-1)*_h;
|
||||
_x=x+(r/stage+1)*_h-h;
|
||||
_y=y; yd=0;
|
||||
if(_x<0){ xd=-_x; _x=0; }
|
||||
break;
|
||||
@@ -234,7 +234,7 @@ void readguyImage::drawImageFile(bool use16grey){
|
||||
_pool=exPool;
|
||||
}
|
||||
if(_pool==nullptr) {
|
||||
_h=(h+7)>>3; //设置缓存区的高度. 更多内存将可以更快显示
|
||||
_h=h>>3; //设置缓存区的高度. 更多内存将可以更快显示
|
||||
_pool=(uint8_t *)guy->getBuffer();
|
||||
}
|
||||
//(guy->guyMemoryHeight()+7)>>3 返回高度,并补齐后右移三位 (等效于除以2³, 分成8份)
|
||||
@@ -275,7 +275,7 @@ void readguyImage::drawImageFile(bool use16grey){
|
||||
}
|
||||
else{
|
||||
// ************* 提示: 编写此示例时的最新版本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);
|
||||
// 此函数过不了编译 需要改库.
|
||||
}
|
||||
|
||||
|
||||
@@ -41,21 +41,21 @@
|
||||
|
||||
class readguyImage{
|
||||
public:
|
||||
readguyImage(ReadguyDriver &_guy):guy(&_guy){}
|
||||
|
||||
readguyImage(ReadguyDriver &_guy):guy(&_guy){
|
||||
w=guy->width(); h=guy->height();
|
||||
}
|
||||
/** @brief 显示图像. use16grey: 为true则使用16灰度,false则不用
|
||||
* @note 需要提前设置绘制参数, 直接在类的外部 设置此类的成员函数即可.
|
||||
* 对于不会C++的朋友们, 可以看示例.
|
||||
* @note 需要提前设置绘制参数, 直接在类的外部 设置此类的成员函数即可. 对于不会C++的朋友们, 可以看示例.
|
||||
* 注意该函数会调用 guy.display 来刷屏, 因此
|
||||
* @param baseFs, filename 文件系统和文件名. 必须指定.
|
||||
* @param x, y 显示在屏幕的什么地方
|
||||
*
|
||||
* @param use16grey 0: 使用单色抖动 1:使用16灰度 2:使用16灰度但不抖动
|
||||
* @param use16grey 0: 使用单色抖动 1:使用16灰度 (如果要开关抖动则需要用setGreyQuality设置)
|
||||
* */
|
||||
void drawImageFile(bool use16grey = 0);
|
||||
|
||||
/** @brief 将图像绘制到系统缓存内. 必须预分配内存, 并且需要知道分配的大小.
|
||||
* @note 需要提前设置绘制参数, 直接在类的外部 设置此类的成员函数即可.
|
||||
* 对于不会C++的朋友们, 可以看示例.
|
||||
* @note 需要提前设置绘制参数, 直接在类的外部 设置此类的成员函数即可. 对于不会C++的朋友们, 可以看示例.
|
||||
* 注意该函数会调用 guy.display 来刷屏
|
||||
* @param baseFs, filename 文件系统和文件名. 必须指定.
|
||||
* @param x, y 显示在屏幕缓存的什么地方
|
||||
* @param w, h 开辟的缓存宽度和高度. 最好是和图片的大小相匹配.
|
||||
|
||||
9
extra/ctg_timelib/TimeLib.h
Normal file
9
extra/ctg_timelib/TimeLib.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef _TIMELIB_H_FILE
|
||||
#define _TIMELIB_H_FILE
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "ctg_timelib.hpp"
|
||||
using namespace CTG_TimeLib;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
104
extra/ctg_timelib/ctg_timelib.cpp
Normal file
104
extra/ctg_timelib/ctg_timelib.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "ctg_timelib.hpp"
|
||||
|
||||
namespace CTG_TimeLib {
|
||||
|
||||
time_t tOffset = 0;
|
||||
struct tm m;
|
||||
|
||||
#if (defined ( CTG_USE_tmElements_t ) || defined (CTG_USE_ALL_TimeLib_features))
|
||||
|
||||
void setTime(int16_t hr,int16_t min,int16_t sec,int16_t dy, int16_t mnth, int16_t yr){
|
||||
// year can be given as full four digit year or two digts (2010 or 10 for 2010);
|
||||
//it is converted to years since 1970
|
||||
tmElements_t tem;
|
||||
if( yr >= 1900) yr -= 1970;
|
||||
else yr += 30;
|
||||
tem.Year = yr;
|
||||
tem.Month = mnth;
|
||||
tem.Day = dy;
|
||||
tem.Wday = 0;
|
||||
tem.Hour = hr;
|
||||
tem.Minute = min;
|
||||
tem.Second = sec;
|
||||
setTime(makeTime(tem));
|
||||
}
|
||||
|
||||
#define LEAP_YEAR(Y) ( ((1970+(Y))>0) && !((1970+(Y))%4) && ( ((1970+(Y))%100) || !((1970+(Y))%400) ) )
|
||||
static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31};
|
||||
|
||||
void breakTime(time_t timeInput, tmElements_t &tm){
|
||||
// break the given time_t into time components
|
||||
// this is a more compact version of the C library localtime function
|
||||
// note that year is offset from 1970 !!!
|
||||
|
||||
uint8_t year;
|
||||
uint8_t month, monthLength;
|
||||
uint32_t time;
|
||||
unsigned long days;
|
||||
// API starts months from 1, this array starts from 0
|
||||
time = (uint32_t)timeInput;
|
||||
tm.Second = time % 60;
|
||||
time /= 60; // now it is minutes
|
||||
tm.Minute = time % 60;
|
||||
time /= 60; // now it is hours
|
||||
tm.Hour = time % 24;
|
||||
time /= 24; // now it is days
|
||||
tm.Wday = ((time + 4) % 7) + 1; // Sunday is day 1
|
||||
|
||||
year = 0;
|
||||
days = 0;
|
||||
while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) {
|
||||
year++;
|
||||
}
|
||||
tm.Year = year; // year is offset from 1970
|
||||
|
||||
days -= LEAP_YEAR(year) ? 366 : 365;
|
||||
time -= days; // now it is days in this year, starting at 0
|
||||
|
||||
days=0;
|
||||
month=0;
|
||||
monthLength=0;
|
||||
for (month=0; month<12; month++) {
|
||||
monthLength = monthDays[month];
|
||||
if(LEAP_YEAR(year) && month==1) monthLength++;// february
|
||||
if (time >= monthLength)
|
||||
time -= monthLength;
|
||||
else break;
|
||||
}
|
||||
tm.Month = month + 1; // jan is month 1
|
||||
tm.Day = time + 1; // day of month
|
||||
}
|
||||
|
||||
time_t makeTime(const tmElements_t &tm){
|
||||
// assemble time elements into time_t
|
||||
// note year argument is offset from 1970 (see macros in time.h to convert to other formats)
|
||||
// previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9
|
||||
|
||||
int i;
|
||||
uint32_t seconds;
|
||||
|
||||
// seconds from 1970 till 1 jan 00:00:00 of the given year
|
||||
seconds= tm.Year*(86400 * 365);
|
||||
for (i = 0; i < tm.Year; i++) {
|
||||
if (LEAP_YEAR(i)) {
|
||||
seconds += 86400; // add extra days for leap years
|
||||
}
|
||||
}
|
||||
|
||||
// add days for this year, months start from 1
|
||||
for (i = 1; i < tm.Month; i++) {
|
||||
if ( (i == 2) && LEAP_YEAR(tm.Year)) {
|
||||
seconds += 86400 * 29;
|
||||
} else {
|
||||
seconds += 86400 * monthDays[i-1]; //monthDay array starts from 0
|
||||
}
|
||||
}
|
||||
seconds+= (tm.Day-1) * 86400;
|
||||
seconds+= tm.Hour * 3600;
|
||||
seconds+= tm.Minute * 60;
|
||||
seconds+= tm.Second;
|
||||
return (time_t)seconds;
|
||||
}
|
||||
#endif // CTG_USE_tmElements_t
|
||||
|
||||
} //namespace
|
||||
158
extra/ctg_timelib/ctg_timelib.hpp
Normal file
158
extra/ctg_timelib/ctg_timelib.hpp
Normal file
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* @file ctg_timelib.h
|
||||
* @author FriendshipEnder (Q:3253342798)
|
||||
* @brief 时间兼容库文件. 旨在替代原有的, 过时的 TimeLib.h 文件(用于AVR设备)
|
||||
* 本库依赖 GLibC 的 time.h 文件.
|
||||
* 本库兼容 TimeLib.h 文件
|
||||
* 为了确保名称无冲突, 使用名称空间命名避免函数名冲突
|
||||
* @version 1.0.0
|
||||
* @date 2024-11-16
|
||||
*
|
||||
* @copyright Copyright (c) 2024
|
||||
*
|
||||
*/
|
||||
#ifndef _CTG_TimeLib_H_FILE
|
||||
#define _CTG_TimeLib_H_FILE
|
||||
|
||||
#define CTG_DEFAULT_LOCAL_TIMEZONE ("CST-8") //默认时区
|
||||
#define CTG_DEFAULT_LOCAL_OFFSET (8*3600) //默认时区偏移值
|
||||
#define CTG_USE_tmElements_t //使用 tmElements_t (强兼容, 但是没什么用)
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <lwip/apps/sntp.h> //settimeofday
|
||||
|
||||
namespace CTG_TimeLib {
|
||||
|
||||
extern time_t tOffset;
|
||||
extern struct tm m;
|
||||
|
||||
/// @brief return the current local time as seconds since Jan 1 1970
|
||||
inline time_t now() {return time(NULL)+tOffset;}
|
||||
/// @brief the hour for the given time
|
||||
inline int hour(time_t t){gmtime_r(&t, &m);return m.tm_hour;}
|
||||
/// @brief the hour now
|
||||
inline int hour(){return hour(now());}
|
||||
/// @brief the minute for the given time
|
||||
inline int minute(time_t t){gmtime_r(&t, &m);return m.tm_min;}
|
||||
/// @brief the minute now
|
||||
inline int minute(){return minute(now());}
|
||||
/// @brief the second for the given time
|
||||
inline int second(time_t t){gmtime_r(&t, &m);return m.tm_sec;}
|
||||
/// @brief the second now
|
||||
inline int second(){return second(now());}
|
||||
/// @brief the day for the given time
|
||||
inline int day(time_t t){gmtime_r(&t, &m);return m.tm_mday;}
|
||||
/// @brief the day now
|
||||
inline int day(){return day(now());}
|
||||
/// @brief the weekday for the given time (Sunday is day 1)
|
||||
inline int weekday(time_t t){gmtime_r(&t, &m);return m.tm_wday+1;}
|
||||
/// @brief the weekday now (Sunday is day 1)
|
||||
inline int weekday(){return weekday(now());}
|
||||
/// @brief the month for the given time (Jan is month 1)
|
||||
inline int month(time_t t){gmtime_r(&t, &m);return m.tm_mon+1;}
|
||||
/// @brief the month now (Jan is month 1)
|
||||
inline int month(){return month(now());}
|
||||
/// @brief the year for the given time
|
||||
inline int year(time_t t){gmtime_r(&t, &m);return m.tm_year+1900;}
|
||||
/// @brief the full four digit year: (2009, 2010 etc)
|
||||
inline int year(){return year(now());}
|
||||
/// @brief set the time-zone
|
||||
/// @param z (string) timezone name (like 'CST-8', 'EST+5', etc)
|
||||
/// @param offset (time_t) how many seconds offset (+8 == 8*3600)
|
||||
inline void setTimezone(const char *z, time_t offset){
|
||||
tOffset = offset;
|
||||
setenv("TZ", z, 1); //设置时区变量 (当前设置为北京时间)
|
||||
tzset();
|
||||
}
|
||||
|
||||
/// @brief set the time (input UTC time,not local time)
|
||||
/// @param t (time_t): correct UTC time
|
||||
/// @param fit_zone_cn (bool): Set timezone to UTC+8 (Beijing)
|
||||
inline void setUTCTime(time_t t, bool fit_local = true){
|
||||
if(tOffset != CTG_DEFAULT_LOCAL_OFFSET && fit_local)
|
||||
setTimezone(CTG_DEFAULT_LOCAL_TIMEZONE, CTG_DEFAULT_LOCAL_OFFSET);
|
||||
timeval tm_now={t, 0};
|
||||
settimeofday(&tm_now,nullptr);// need #include <lwip/apps/sntp.h>
|
||||
}
|
||||
|
||||
/// @brief set the time (input local time)
|
||||
/// @param t (time_t): correct local time (UTC+8 = Beijing)
|
||||
inline void setTime(time_t t){
|
||||
if(tOffset != CTG_DEFAULT_LOCAL_OFFSET)
|
||||
setTimezone(CTG_DEFAULT_LOCAL_TIMEZONE, CTG_DEFAULT_LOCAL_OFFSET);
|
||||
timeval tm_now={t-CTG_DEFAULT_LOCAL_OFFSET, 0};
|
||||
settimeofday(&tm_now,nullptr);// need #include <lwip/apps/sntp.h>
|
||||
}
|
||||
|
||||
#ifdef CTG_USE_tmElements_t
|
||||
typedef enum {timeNotSet, timeNeedsSync, timeSet
|
||||
} timeStatus_t ;
|
||||
|
||||
typedef enum {
|
||||
dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday
|
||||
} timeDayOfWeek_t;
|
||||
|
||||
typedef enum {
|
||||
tmSecond, tmMinute, tmHour, tmWday, tmDay,tmMonth, tmYear, tmNbrFields
|
||||
} tmByteFields;
|
||||
typedef struct {
|
||||
uint8_t Second;
|
||||
uint8_t Minute;
|
||||
uint8_t Hour;
|
||||
uint8_t Wday; // day of week, sunday is day 1
|
||||
uint8_t Day;
|
||||
uint8_t Month;
|
||||
int16_t Year; // offset from 1970;
|
||||
} tmElements_t;
|
||||
|
||||
#define tmYearToCalendar(Y) ((Y) + 1970) // full four digit year
|
||||
#define CalendarYrToTm(Y) ((Y) - 1970)
|
||||
#define tmYearToY2k(Y) ((Y) - 30) // offset is from 2000
|
||||
#define y2kYearToTm(Y) ((Y) + 30)
|
||||
|
||||
/* Useful Constants */
|
||||
#define SECS_PER_MIN ((time_t)(60UL))
|
||||
#define SECS_PER_HOUR ((time_t)(3600UL))
|
||||
#define SECS_PER_DAY ((time_t)(SECS_PER_HOUR * 24UL))
|
||||
#define DAYS_PER_WEEK ((time_t)(7UL))
|
||||
#define SECS_PER_WEEK ((time_t)(SECS_PER_DAY * DAYS_PER_WEEK))
|
||||
#define SECS_PER_YEAR ((time_t)(SECS_PER_DAY * 365UL)) // TODO: ought to handle leap years
|
||||
#define SECS_YR_2000 ((time_t)(946684800UL)) // the time at the start of y2k
|
||||
|
||||
/* Useful Macros for getting elapsed time */
|
||||
#define numberOfSeconds(_time_) ((_time_) % SECS_PER_MIN)
|
||||
#define numberOfMinutes(_time_) (((_time_) / SECS_PER_MIN) % SECS_PER_MIN)
|
||||
#define numberOfHours(_time_) (((_time_) % SECS_PER_DAY) / SECS_PER_HOUR)
|
||||
#define dayOfWeek(_time_) ((((_time_) / SECS_PER_DAY + 4) % DAYS_PER_WEEK)+1) // 1 = Sunday
|
||||
#define elapsedDays(_time_) ((_time_) / SECS_PER_DAY) // this is number of days since Jan 1 1970
|
||||
#define elapsedSecsToday(_time_) ((_time_) % SECS_PER_DAY) // the number of seconds since last midnight
|
||||
// The following macros are used in calculating alarms and assume the clock is set to a date later than Jan 1 1971
|
||||
// Always set the correct time before settting alarms
|
||||
#define previousMidnight(_time_) (((_time_) / SECS_PER_DAY) * SECS_PER_DAY) // time at the start of the given day
|
||||
#define nextMidnight(_time_) (previousMidnight(_time_) + SECS_PER_DAY) // time at the end of the given day
|
||||
#define elapsedSecsThisWeek(_time_) (elapsedSecsToday(_time_) + ((dayOfWeek(_time_)-1) * SECS_PER_DAY)) // note that week starts on day 1
|
||||
#define previousSunday(_time_) ((_time_) - elapsedSecsThisWeek(_time_)) // time at the start of the week for the given time
|
||||
#define nextSunday(_time_) (previousSunday(_time_)+SECS_PER_WEEK) // time at the end of the week for the given time
|
||||
|
||||
|
||||
/* Useful Macros for converting elapsed time to a time_t */
|
||||
#define minutesToTime_t ((M)) ( (M) * SECS_PER_MIN)
|
||||
#define hoursToTime_t ((H)) ( (H) * SECS_PER_HOUR)
|
||||
#define daysToTime_t ((D)) ( (D) * SECS_PER_DAY) // fixed on Jul 22 2011
|
||||
#define weeksToTime_t ((W)) ( (W) * SECS_PER_WEEK)
|
||||
|
||||
/// @brief set the time (input local time)
|
||||
/// @param hr,min,sec,day,month,yr: correct local time (UTC+8 = Beijing)
|
||||
void setTime(int16_t hr,int16_t min,int16_t sec,int16_t day,int16_t month,int16_t yr);
|
||||
|
||||
/// @brief break time_t into elements
|
||||
void breakTime(time_t time, tmElements_t &tm);
|
||||
|
||||
/// @brief convert time elements into time_t
|
||||
time_t makeTime(const tmElements_t &tm);
|
||||
|
||||
#endif // CTG_USE_tmElements_t
|
||||
} //namespace
|
||||
#endif // _CTG_TimeLib_H_FILE
|
||||
81
extra/guy_driver_template/guy_template/guy_template.cpp
Normal file
81
extra/guy_driver_template/guy_template/guy_template.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/******************** F r i e n d s h i p E n d e r ********************
|
||||
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
||||
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
||||
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
||||
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
||||
* @file guy_template.cpp
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief 墨水屏 驱动库函数 源代码模板
|
||||
* 使用前, 先查找替换 template 改为你需要的驱动名称
|
||||
* 比如3英寸的屏幕驱动程序应该叫 guy_dev_300a
|
||||
* 此时需要将 template 替换为300A.
|
||||
* 替换好之后, 改文件名, 大小写也要注意改 (文件名最好不要出现大写)
|
||||
* 最后把这个brief替换掉
|
||||
* @version 1.0
|
||||
* @date 2023-11-11
|
||||
|
||||
* @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 <stdlib.h>
|
||||
#include "guy_template.h"
|
||||
#ifdef READGUY_DEV_template
|
||||
namespace guydev_template{
|
||||
//以下代码均为我 FriendshipEnder 原创, 呵呵哒~~
|
||||
|
||||
void drv::drv_init(){ //初始化屏幕
|
||||
//add driver code...
|
||||
}
|
||||
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;
|
||||
uint32_t u=epdFull?slowRefTime:fastRefTime; //全刷:局刷 busy时间
|
||||
if(ms<u) guy_epdBusy(u-ms); //对于busy电平为低电平忙碌,高电平正常的屏幕则改为ms-u
|
||||
lastRefresh=0;
|
||||
//add driver code...
|
||||
}
|
||||
}
|
||||
void drv::drv_sleep() { //开始屏幕睡眠
|
||||
if(RST_PIN>=0){ //RST_PIN<0 无法唤醒
|
||||
//add driver code...
|
||||
}
|
||||
epd_PowerOn = 0;
|
||||
epdFull = 1; //强制设置为慢刷新模式
|
||||
}
|
||||
}
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
|
||||
|
||||
88
extra/guy_driver_template/guy_template/guy_template.h
Normal file
88
extra/guy_driver_template/guy_template/guy_template.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/******************** F r i e n d s h i p E n d e r ********************
|
||||
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
||||
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
||||
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
||||
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
||||
* @file guy_template.h
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief 墨水屏 驱动库函数 头文件模板
|
||||
* 使用前, 先查找替换 template 改为你需要的驱动名称
|
||||
* 比如3英寸的屏幕驱动程序应该叫 guy_dev_300a
|
||||
* 此时需要将 template 替换为300A.
|
||||
* 替换好之后, 改文件名, 大小写也要注意改 (文件名最好不要出现大写)
|
||||
* 最后把这个brief替换掉
|
||||
* @version 1.0
|
||||
* @date 2023-11-11
|
||||
|
||||
* @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 "../guy_epdbase.h"
|
||||
#if (!defined(_GUY_EPDtemplate_H_FILE) && (defined(READGUY_DEV_template)))
|
||||
#define _GUY_EPDtemplate_H_FILE
|
||||
|
||||
namespace guydev_template{
|
||||
constexpr int GUY_D_WIDTH =200; //驱动屏幕宽度
|
||||
constexpr int GUY_D_HEIGHT =200; //驱动屏幕高度
|
||||
constexpr int slowRefTime =2000; //驱动屏幕慢刷时间, 单位毫秒
|
||||
constexpr int fastRefTime =500; //驱动屏幕快刷时间, 单位毫秒
|
||||
|
||||
class drv : public readguyEpdBase {
|
||||
public:
|
||||
/** @brief 返回驱动程序ID. 此函数不需要在 cpp 文件内重写
|
||||
* @return int 直接返回对应宏定义就可以 */
|
||||
int drv_ID() const { return READGUY_DEV_template; }
|
||||
/// @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; //颜色深度 1-15均为有效. 慢刷模式中 此数值为15.
|
||||
};
|
||||
}
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
23
extra/guy_driver_template/readme.md
Normal file
23
extra/guy_driver_template/readme.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# 添加新驱动程序
|
||||
|
||||
1. 将文件夹 guy_template 整个拷贝到 guy_epaper 文件夹下
|
||||
|
||||
2. 根据里面的模板文件, 添加自定义驱动.
|
||||
|
||||
3. 使用查找工具搜索 src 下的以下文本.
|
||||
|
||||
```
|
||||
//添加新屏幕型号 add displays here
|
||||
```
|
||||
|
||||
然后把新加入的屏幕驱动 define 给加上
|
||||
|
||||
4. 更新 `EPD_DRIVERS_NUM_MAX` 变量, 表明一共有多少个驱动可用.
|
||||
|
||||
5. 加好了之后, 应该就可以使用这个驱动了.
|
||||
|
||||
6. 记得更改项目根目录的 readme 文件
|
||||
|
||||
# 禁用驱动程序
|
||||
|
||||
前往 guy_epaper_config.h 文件, 注释掉不需要编译的驱动文件即可
|
||||
@@ -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
|
||||
|
||||
7
extra/platformio/readguy_4MB_largeAPP.csv
Normal file
7
extra/platformio/readguy_4MB_largeAPP.csv
Normal 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,
|
||||
|
@@ -971,7 +971,11 @@ CONFIG_MBEDTLS_TLS_ENABLED=y
|
||||
#
|
||||
# TLS Key Exchange Methods
|
||||
#
|
||||
# CONFIG_MBEDTLS_PSK_MODES is not set
|
||||
CONFIG_MBEDTLS_PSK_MODES=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_PSK=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_PSK=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_PSK=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y
|
||||
|
||||
1434
extra/platformio/sdkconfig.esp32c3_no_uart
Normal file
1434
extra/platformio/sdkconfig.esp32c3_no_uart
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1012,7 +1012,11 @@ CONFIG_MBEDTLS_TLS_ENABLED=y
|
||||
#
|
||||
# TLS Key Exchange Methods
|
||||
#
|
||||
# CONFIG_MBEDTLS_PSK_MODES is not set
|
||||
CONFIG_MBEDTLS_PSK_MODES=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_PSK=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_PSK=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_PSK=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y
|
||||
|
||||
@@ -978,7 +978,11 @@ CONFIG_MBEDTLS_TLS_ENABLED=y
|
||||
#
|
||||
# TLS Key Exchange Methods
|
||||
#
|
||||
# CONFIG_MBEDTLS_PSK_MODES is not set
|
||||
CONFIG_MBEDTLS_PSK_MODES=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_PSK=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_PSK=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_PSK=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/fsender/readguy"
|
||||
},
|
||||
"version": "1.3.0",
|
||||
"version": "1.4.0",
|
||||
"frameworks": "arduino",
|
||||
"platforms": ["espressif32", "espressif8266"],
|
||||
"headers": "readguy.h",
|
||||
@@ -19,7 +19,7 @@
|
||||
"libArchive": false
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"homepage": "b站视频",
|
||||
"homepage": "https://www.bilibili.com/video/BV1f94y187wz/",
|
||||
"dependencies": {
|
||||
"name": "lovyan03/LovyanGFX",
|
||||
"version": ">=1.1.9"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name=readguy
|
||||
version=1.3.0
|
||||
version=1.4.0
|
||||
author=fsender <f_ender@163.com>
|
||||
maintainer=fsender <f_ender@163.com>
|
||||
sentence=A free E-paper display driver library supports 16-level greyscale.
|
||||
|
||||
@@ -59,6 +59,7 @@ SOFTWARE.
|
||||
|
||||
*/
|
||||
#include "guy_button.h"
|
||||
#include "guy_driver_config.h"
|
||||
|
||||
// initalize static counter
|
||||
|
||||
@@ -67,7 +68,7 @@ guy_button::guy_button() {
|
||||
//id = _nextID++;
|
||||
}
|
||||
|
||||
void guy_button::begin(uint8_t _pin, std_U8_function_U8 f, bool activeLow /* = true */) {
|
||||
void guy_button::begin(uint8_t _pin, std_U8_function_U8 f, bool activeLow/*=true*/) {
|
||||
//pin = attachTo;
|
||||
//id = _nextID++;
|
||||
_pressedState = activeLow ? LOW : HIGH;
|
||||
@@ -75,14 +76,22 @@ void guy_button::begin(uint8_t _pin, std_U8_function_U8 f, bool activeLow /* = t
|
||||
prev_state = state ;
|
||||
get_state_cb = f;
|
||||
pin = _pin;
|
||||
state = get_state_cb(pin);
|
||||
min_debounce =25; //去抖时间
|
||||
long_press_ms =300; //长按持续时间+双击识别间隔最大时间
|
||||
long_repeat_ms =150; //长按连按间隔时间
|
||||
multibtn =0;
|
||||
state = get_state_cb(pin, activeLow);
|
||||
min_debounce =READGUY_DEFAULT_MIN_DEBOUNCE_MS; //去抖时间
|
||||
long_press_ms =READGUY_LONG_PRESS_MS; //长按持续时间
|
||||
double_press_ms =READGUY_DOUBLE_PRESS_MS; //双击识别间隔最大时间
|
||||
long_repeat_ms =READGUY_LONG_REPEAT_MS; //长按连按间隔时间
|
||||
scanDT =1; // =1识别双击或三击, =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) == _pressedState);
|
||||
lk=0;
|
||||
return willreturn;
|
||||
}
|
||||
uint8_t guy_button::read() { //注意ticker不能在此触发
|
||||
int mi=millis();
|
||||
while(lk) if(millis()-mi>GUYBTN_READ_TIMEOUT) return 0; //等待数据读完
|
||||
@@ -91,13 +100,14 @@ uint8_t guy_button::read() { //注意ticker不能在此触发
|
||||
if(state == _pressedState && n - down_ms>= long_press_ms && long_clicked < n){
|
||||
long_clicked = trig_mode?(n+long_repeat_ms):0xfffffffful;
|
||||
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;
|
||||
last_click_type = GUYBUTTON_empty;
|
||||
was_pressed = false;
|
||||
lk=0;
|
||||
return (res==GUYBUTTON_long_click)?GUYBUTTON_empty:res;
|
||||
return (res>=GUYBUTTON_long_click)?GUYBUTTON_empty:res;
|
||||
}
|
||||
|
||||
void guy_button::loop() {
|
||||
@@ -107,7 +117,7 @@ void guy_button::loop() {
|
||||
lk=1;
|
||||
unsigned long now = millis();
|
||||
prev_state = state;
|
||||
state = get_state_cb(pin);
|
||||
state = get_state_cb(pin, !_pressedState);
|
||||
|
||||
// is button pressed?
|
||||
if (state == _pressedState) {
|
||||
@@ -136,29 +146,27 @@ void guy_button::loop() {
|
||||
longclick_detected = true;
|
||||
}
|
||||
// is the button released and the time has passed for multiple clicks?
|
||||
} else if (now - click_ms > (multibtn?min_debounce:long_press_ms)) {
|
||||
} else if (now - click_ms > (scanDT?double_press_ms:min_debounce)) {
|
||||
// was there a longclick?
|
||||
if (longclick_detected) {
|
||||
// was it part of a combination?
|
||||
if (click_count == 1) {
|
||||
last_click_type = GUYBUTTON_long_click;
|
||||
if (click_count) {
|
||||
last_click_type = (click_count>=3)?GUYBUTTON_xxlong_click:\
|
||||
((click_count==2)?GUYBUTTON_xlong_click:GUYBUTTON_long_click);
|
||||
was_pressed = true;
|
||||
}
|
||||
longclick_detected = false;
|
||||
|
||||
// determine the number of single clicks
|
||||
} else if (click_count > 0) {
|
||||
switch (click_count) {
|
||||
case 1:
|
||||
last_click_type = GUYBUTTON_single_click;
|
||||
break;
|
||||
case 2:
|
||||
last_click_type = GUYBUTTON_double_click;
|
||||
break;
|
||||
case 3:
|
||||
last_click_type = GUYBUTTON_triple_click;
|
||||
break;
|
||||
if(scanDT){
|
||||
switch (click_count) {
|
||||
case 1: last_click_type = GUYBUTTON_single_click; break;
|
||||
case 2: last_click_type = GUYBUTTON_double_click; break;
|
||||
case 3: last_click_type = GUYBUTTON_triple_click;
|
||||
}
|
||||
}
|
||||
else last_click_type = GUYBUTTON_single_click; //此时若click_count>1 视为抖动
|
||||
was_pressed = true;
|
||||
}
|
||||
// clean up
|
||||
|
||||
@@ -71,25 +71,29 @@ SOFTWARE.
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#define GUYBUTTON_empty 0
|
||||
#define GUYBUTTON_single_click 1
|
||||
#define GUYBUTTON_double_click 2
|
||||
#define GUYBUTTON_triple_click 3
|
||||
#define GUYBUTTON_long_click 4
|
||||
#define GUYBTN_READ_TIMEOUT 100
|
||||
#define GUYBTN_LOOP_TIMEOUT 10
|
||||
#define GUYBUTTON_empty 0 //没按下
|
||||
#define GUYBUTTON_single_click 1 //单击
|
||||
#define GUYBUTTON_double_click 2 //双击
|
||||
#define GUYBUTTON_triple_click 3 //三击
|
||||
#define GUYBUTTON_long_click 4 //长按
|
||||
#define GUYBUTTON_xlong_click 5 //点击后接长按
|
||||
#define GUYBUTTON_xxlong_click 6 //双击后接长按
|
||||
#define GUYBTN_READ_TIMEOUT 100 //读取延时
|
||||
#define GUYBTN_LOOP_TIMEOUT 10 //循环扫描延时
|
||||
|
||||
class guy_button{
|
||||
protected:
|
||||
public:
|
||||
uint16_t min_debounce ; //去抖时间
|
||||
uint16_t long_press_ms ; //长按持续时间+双击识别间隔最大时间
|
||||
uint16_t long_press_ms ; //长按持续时间
|
||||
uint16_t double_press_ms ; //双击识别间隔最大时间
|
||||
uint16_t long_repeat_ms ; //长按连按间隔时间
|
||||
protected:
|
||||
uint8_t pin = 255; //未定义引脚
|
||||
uint8_t state;
|
||||
uint8_t prev_state;
|
||||
uint8_t click_count = 0;
|
||||
uint8_t _pressedState;
|
||||
uint8_t multibtn; //是否为多个按钮, 可自己设置
|
||||
uint8_t scanDT; //是否为多个按钮, 可自己设置
|
||||
uint8_t last_click_type = GUYBUTTON_empty;
|
||||
volatile uint8_t lk = 255;
|
||||
//int id;
|
||||
@@ -105,25 +109,51 @@ class guy_button{
|
||||
bool pressed_triggered = false;
|
||||
bool trig_mode = false; //长按连按触发模式
|
||||
|
||||
typedef uint8_t (*std_U8_function_U8)(uint8_t);
|
||||
typedef uint8_t (*std_U8_function_U8)(uint8_t, bool);
|
||||
std_U8_function_U8 get_state_cb = NULL;
|
||||
|
||||
public:
|
||||
guy_button();
|
||||
/// @brief 初始化
|
||||
/// @param _pin 引脚ID. 传入的引脚在内部将会使用digitalRead函数实现
|
||||
/// @param activeLow 设置为true时, 当读取到低电平视为按下
|
||||
void begin(uint8_t _pin, bool activeLow = true){
|
||||
begin(_pin,[](uint8_t p, bool)->uint8_t { return digitalRead(p); },activeLow);
|
||||
}
|
||||
/// @brief 初始化
|
||||
/// @param _pin 引脚ID. 传入的引脚在内部将会使用digitalRead函数实现
|
||||
/// @param f 触发函数: 当activeLow为false时, 返回1表示按下, 0表示没按下 为true时相反
|
||||
/// @note 默认的 f 是 匿名函数 [](uint8_t p)->uint8_t { return digitalRead(p); }
|
||||
/// 如果自己指定了函数而且没有用到内置的参数, 那么 _pin 参数可能是没有任何用处的
|
||||
void begin(uint8_t _pin, std_U8_function_U8 f, bool activeLow = true);
|
||||
/// @brief 设置长按连按触发模式
|
||||
/// @param trigMode 0:单次长按 1:连续长按
|
||||
void setLongRepeatMode(bool trigMode) { trig_mode = trigMode; }
|
||||
/// @brief 长按了多久按钮
|
||||
unsigned int wasPressedFor() const { return down_time_ms; }
|
||||
/// @brief 返回是否处于被按下的状态 受loop扫描的限制, 如果没loop扫描则可以先手动调用扫描后使用
|
||||
bool isPressed() const { return (state == _pressedState); }
|
||||
bool isPressedRaw() { return (get_state_cb(pin) == _pressedState); }
|
||||
/// @brief 读取原始的按钮状态 (不去抖动), 此函数不受loop扫描的限制
|
||||
bool isPressedRaw(); // { return (get_state_cb(pin) == _pressedState); }
|
||||
/// @brief 曾经按下的状态 是否是点击后立即松开
|
||||
bool wasPressed(){ if(was_pressed){ was_pressed = false; return true; } return false; }
|
||||
/// @brief 连击了几下
|
||||
uint8_t getNumberOfClicks() const{ return click_count;}
|
||||
/// @brief [已经弃用] 获取上次按钮的按下数据. 返回按钮状态(按钮状态参考read函数的说明)
|
||||
uint8_t getType() const { return last_click_type; }
|
||||
/// @brief 读取按钮的按下数据. 返回按钮状态 0没按 1单击 2双击 3三击 4长按 5点击后长按 6双击后长按
|
||||
uint8_t read();
|
||||
/// @brief 连续循环扫描按钮. 必须多次反复调用, 最好是单独开一个task来实现
|
||||
void loop();
|
||||
void setMultiBtn(uint8_t btns) { multibtn = btns; }
|
||||
void setMinDebounce(short n) { min_debounce =n;} //去抖时间
|
||||
/// @brief 设置是否识别双击 三连击等高级手势
|
||||
/// @param scan =1识别双击或三击, =0则不识别双击或三击等需要延时返回的情况
|
||||
void enScanDT(uint8_t scan) { scanDT = scan; }
|
||||
/* void setMinDebounce(short n) { min_debounce =n;} //去抖时间
|
||||
void setLongPressMs(short n) { long_press_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. */
|
||||
@@ -6,11 +6,16 @@
|
||||
* @file guy_driver_config.h
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief readguy 基础配置文件. 用户可以根据自己对库的编译需求来修改此文件.
|
||||
*
|
||||
* 如果你希望在程序代码内包含引脚定义, 请参考此文件下方的注释来确定并编译
|
||||
* !!!但是这样编译得到的程序不具备跨平台特性.!!!
|
||||
* 可以禁用WiFi功能来减少ESP32的flash消耗
|
||||
* @version 1.0
|
||||
* @date 2023-09-21
|
||||
* 这样就可以只针对你设计的这一个硬件来设定引脚功能.
|
||||
* 关于屏幕配置, 请参考 guy_epaper/guy_epaper_config.h 文件来配置到底哪些屏幕型号的屏幕会被包含进来
|
||||
|
||||
* 可以禁用WiFi功能来减少程序的flash消耗
|
||||
|
||||
* @version 1.1
|
||||
* @date create: 2023-09-21
|
||||
* last modify: 2023-11-11
|
||||
|
||||
* @attention
|
||||
* Copyright (c) 2022-2023 FriendshipEnder
|
||||
@@ -47,9 +52,10 @@
|
||||
//对于甘草酸不酸的新版本板子:
|
||||
//busy 4 rst 2 dc 0 cs 15 sck / mosi / sdcs 5 btnL rx(3) btnM 0
|
||||
|
||||
//对于四个按钮的4.2屏开发板:
|
||||
//对于四个按钮的4.2屏开发板: @十里画廊
|
||||
//(https://oshwhub.com/shilihualang/han-jia-qian-gai-zhuang-ji-jian-kai-fa-ban)
|
||||
//clk 14 cs 15 mosi 13 dc 27 rst 26 busy 25
|
||||
//sd cs 4 miso 12 (共线) 按键 k1 5 k2 17 k3 16 k4 0 前置光 19/18/23
|
||||
//sd cs 4 miso 12 (共线) 按键 k1 5 k2 17 k3 16 k4 0 前置光 19/18/23 (RGB)
|
||||
|
||||
//对于lilygo t-watch epaper 开发板:
|
||||
//cs 5 dc 19 rst 27 busy 38 clk 18 mosi 23
|
||||
@@ -59,21 +65,71 @@
|
||||
|
||||
// ------------------ definations - 定义 -
|
||||
|
||||
/// @brief 使用静态的数据 !!!注意:注释此选项编写的程序是不支持跨平台运行的!!!
|
||||
/// @note 相比于禁用WiFi配网功能, 禁用此功能减少的flash并不多, 为保证程序可在不同屏幕上运行, 请不要注释此选项
|
||||
/** @brief 使用静态的数据 !!!注意:注释此选项编写的程序是不支持跨平台运行的!!!
|
||||
/ @note 相比于禁用WiFi配网功能, 禁用此功能减少的flash并不多, 为保证程序可在不同屏幕上运行, 请不要注释此选项
|
||||
/ 关闭此选项自动禁用wifi功能. 如需wifi功能需要自己在程序里加. 但也可以大幅减少flash的占用 */
|
||||
#define DYNAMIC_PIN_SETTINGS
|
||||
|
||||
/// @brief 启用WIFI配网功能.必须先启用 #define DYNAMIC_PIN_SETTINGS. 此选项对 ESP32xx 会减少大量flash.
|
||||
/// @brief 启用WIFI配网功能.必须先启用 #define DYNAMIC_PIN_SETTINGS. 此选项对 ESP32xx 会减少大量可用flash.
|
||||
#define READGUY_ENABLE_WIFI
|
||||
|
||||
/// @brief 启用I2C功能. 可用于联网时钟, 温度计, 陀螺仪等外设. 目前暂不支持库内使用类似函数. 仅可以提供引脚定义
|
||||
#define READGUY_ENABLE_I2C
|
||||
/** @brief 启用I2C功能. 可用于联网时钟, 温度计, 陀螺仪等外设. 目前暂不支持库内使用类似函数. 仅可以提供引脚定义
|
||||
/ @note 现在库提供了获取已存的I2C引脚的接口, 使用时请使用 getI2cSda() 和 getI2cScl() 函数获取I2C的引脚.
|
||||
/ 本库内不提供任何I2C驱动, 只提供引脚定义的存储和读取, 这几乎不增加多少代码. 因此本宏不再使用 */
|
||||
//#define READGUY_ENABLE_I2C
|
||||
|
||||
/** @brief 启用SD卡功能. 开启此功能将会使用内置SD卡管理功能. 关闭后仅可保存SD卡用到的引脚.
|
||||
/ @note 会破坏兼容性. 若没有启用通用的SD卡驱动程序, 那么那些跨屏台编译的程序将无法用guyFS读取到SD卡.
|
||||
/ 若用户程序希望能从外部加载SD卡, 可以使用getSdMiso()等函数获取SD卡的Miso等引脚, 再由用户程序初始化SD卡. */
|
||||
#define READGUY_ENABLE_SD
|
||||
|
||||
/// @brief 使用LittleFS作为片上文件系统, 注释此行则用SPIFFS(功能少, 不好用)
|
||||
#define READGUY_USE_LITTLEFS 1
|
||||
|
||||
/** @brief 使用esp8266时, EEPROM(类似NVS)的存储位置起点 (从起点开始的40字节被readguy所使用) 可选值: 0~4045
|
||||
/ @note 对于单一项目来说, 此选项不建议更改, 请在项目初期就确定此变量的值. */
|
||||
#define READGUY_ESP8266_EEPROM_OFFSET 2
|
||||
|
||||
/** @brief (实验性) 允许 EPD_DC 引脚复用作按键引脚. 当DC引脚直连主控且直连按键时 (按下按键后DC引脚电平被锁定)
|
||||
/ 启用此项可以允许这样的按键复用 (如用于早期版本甘草酸不酸2.9阅读器板子) 但复用的引脚作为按钮长按时体验会变差
|
||||
/ @note 即使注释此选项依旧可以允许DC引脚复用, 但需要在主控直连屏幕DC引脚, 并在按键一端和主控引脚之间接入一个
|
||||
/ 220Ω~1kΩ的电阻 (推荐470Ω), 按键另一端接地, 这样才可以. 注释该选项后, 即使按键和DC引脚复用了, 也不会影响功
|
||||
/ 能和长按体验. 注意如果按键有内阻(不按时按键两端电阻为∞, 按下后按键电阻较高) 可以酌情减小一些按键接入电阻.
|
||||
/ 对于新版的甘草酸不酸2.9阅读器板子就可以注释此选项.
|
||||
/ 没有需要兼容「复用DC引脚的硬件」的需求的用户, 建议注释此项. 一般仅建议ESP8266启用此选项*/
|
||||
//#define READGUY_ALLOW_DC_AS_BUTTON
|
||||
|
||||
/** @brief (实验性) 允许复用 EPD 的 CS 引脚作为按钮. 这会让读取按钮电平的速度些许减慢.
|
||||
/ @note 需要在按键一端和主控引脚之间接入一个220Ω~1kΩ的电阻 (推荐470Ω), 并要求EPD的CS引脚直连主控对应引脚. */
|
||||
//#define READGUY_ALLOW_EPDCS_AS_BUTTON
|
||||
|
||||
/** @brief (不建议, 实验性) 允许复用 SD 卡的 CS 引脚作为按钮.
|
||||
/ @details 这不仅会减慢读按钮速度, 而且十分不建议对「确定」按钮 (通常为按钮2) 启用此功能函数. 因为一些程序会
|
||||
/ 在你按下「确定」后立即读取 SD 卡 (与按键循环读取功能冲突) 导致总线紊乱! 在ESP32上会引起无法预知的崩溃复位!
|
||||
/ @attention 启用后每次读写SD卡时,都必须调用 setSDbusy(1) 来锁定引脚, 屏蔽按键读取, 调用 setSDbusy(0)解锁.
|
||||
/ @note 需要在按键一端和主控引脚之间接入一个220Ω~1kΩ的电阻 (推荐470Ω), 并要求SD卡的CS引脚直连主控对应引脚.
|
||||
/ 所有示例程序未针对此选项重写, 建议重新规划硬件再使用示例. 若硬件无法更改, 请手动对需要用 ReadGuy 库未提供的
|
||||
/ SD卡IO操作的部分, 手动添加 setSDbusy() 函数. 由 ReadGuy 提供的函数已适配好了, 如ReadGuy::Screenshot() */
|
||||
//#define READGUY_ALLOW_SDCS_AS_BUTTON
|
||||
|
||||
/// @brief 按键去抖时间
|
||||
#define READGUY_DEFAULT_MIN_DEBOUNCE_MS 25
|
||||
|
||||
/// @brief 按键长按持续时间
|
||||
#define READGUY_LONG_PRESS_MS 300
|
||||
|
||||
/// @brief 按键双击识别间隔最大时间
|
||||
#define READGUY_DOUBLE_PRESS_MS 300
|
||||
|
||||
/// @brief 按键长按连按间隔时间
|
||||
#define READGUY_LONG_REPEAT_MS 200
|
||||
|
||||
/// @brief ESP32按键服务任务的栈空间大小, 不建议普通用户更改. 默认值1024字节. 小于此大小会使程序栈溢出.
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S3
|
||||
#define BTN_LOOPTASK_STACK 1536
|
||||
#else
|
||||
#define BTN_LOOPTASK_STACK 1024
|
||||
#endif
|
||||
|
||||
/// @brief ESP32按键服务任务运行在哪个核心. 通常运行在核心0上.
|
||||
#define BTN_LOOPTASK_CORE_ID 0
|
||||
@@ -94,7 +150,10 @@
|
||||
#define ESP32_SD_SPI_FREQUENCY 20000000
|
||||
|
||||
/// @brief debug专用, 请保持处于注释状态. 正常开机从NVS读取引脚配置数据, 取消注释则每次开机需要重新配置
|
||||
//#define INDEV_DEBUG 1
|
||||
//#define READGUY_INDEV_DEBUG 1
|
||||
|
||||
/// @brief 串口显示刷屏功能等的信息. 建议开启, 如果是对flash要求十分敏感 可以关闭
|
||||
#define READGUY_SERIAL_DEBUG
|
||||
|
||||
#ifndef DYNAMIC_PIN_SETTINGS
|
||||
#ifdef ESP8266
|
||||
@@ -116,12 +175,23 @@
|
||||
#define READGUY_i2c_scl -1 // 目标i2c总线的SCL引脚, 当且仅当启用i2c总线时才生效
|
||||
//按键驱动部分, 为负代表高触发, 否则低触发,
|
||||
//注意, 这里的io编号是加1的, 即 1或-1 代表 gpio0 的低触发/高触发
|
||||
#define READGUY_btn1 ( 5+1) //按键1,注意需要+1,这里示例已经加了 设置为负的来允许高电平触发
|
||||
#define READGUY_btn1 ( 5+1) //按键1,注意需要+1,这里示例已经加了 设置为负的来允许高电平触发 如 (-(5+1))
|
||||
#define READGUY_btn2 (12+1) //按键2,注意需要+1
|
||||
#define READGUY_btn3 ( 2+1) //按键3,注意需要+1
|
||||
#define READGUY_bl_pin 4 //前置光接口引脚IO
|
||||
|
||||
#else //对于非ESP8266
|
||||
#define READGUY_user1 -1 //useless
|
||||
#define READGUY_user2 -1 //useless
|
||||
#define READGUY_user3 -1 //useless
|
||||
#define READGUY_user4 -1 //useless
|
||||
#define READGUY_user5 -1 //useless
|
||||
#define READGUY_user6 -1 //useless
|
||||
#define READGUY_user7 -1 //useless
|
||||
#define READGUY_user8 -1 //useless
|
||||
#define READGUY_user9 -1 //useless
|
||||
#define READGUY_user10 -1 //useless
|
||||
|
||||
#else //对于非ESP8266 (如 ESP32xx)
|
||||
#define READGUY_shareSpi 0 //EPD和SD卡是否共享SPI, 此处不共享
|
||||
#define READGUY_epd_type READGUY_DEV_154B // 对应的epd驱动程序代号, -1为未指定
|
||||
|
||||
@@ -147,9 +217,20 @@
|
||||
#define READGUY_btn2 -(32+1) //按键2,注意需要+1,此处前面的负号表示允许高电平触发
|
||||
#define READGUY_btn3 0 //按键3,注意需要+1, 不用的按钮应当设置为0
|
||||
#define READGUY_bl_pin 12 //前置光接口引脚IO
|
||||
|
||||
#define READGUY_user1 -1 //useful with ESP32S3 SDMMC sd mode DAT2 pin
|
||||
#define READGUY_user2 -1 //useful with ESP32S3 SDMMC sd mode DAT3 pin
|
||||
#define READGUY_user3 -1 //useless
|
||||
#define READGUY_user4 -1 //useless
|
||||
#define READGUY_user5 -1 //useless
|
||||
#define READGUY_user6 -1 //useless
|
||||
#define READGUY_user7 -1 //useless
|
||||
#define READGUY_user8 -1 //useless
|
||||
#define READGUY_user9 -1 //useless
|
||||
#define READGUY_user10 -1 //useless
|
||||
#endif
|
||||
|
||||
#define READGUY_rtc_type 0 //使用的RTC型号(待定, 还没用上)
|
||||
#define READGUY_rtc_type 0 //使用的RTC型号. 现已弃用 RTC 功能. 保留是为了兼容性 让代码更简单维护
|
||||
#elif defined(READGUY_ENABLE_WIFI)
|
||||
#define READGUY_ESP_ENABLE_WIFI //使用WIFI进行配网等功能
|
||||
#endif
|
||||
|
||||
75
src/guy_epaper/guy_1020A/guy_1020A.cpp
Normal file
75
src/guy_epaper/guy_1020A/guy_1020A.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/******************** F r i e n d s h i p E n d e r ********************
|
||||
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
||||
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
||||
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
||||
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
||||
* @file guy_1020A.cpp
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief 墨水屏 驱动库函数 源代码模板
|
||||
* 使用前, 先查找替换 1020A 改为你需要的驱动名称
|
||||
* 比如3英寸的屏幕驱动程序应该叫 guy_dev_300a
|
||||
* 此时需要将 1020A 替换为300A.
|
||||
* 替换好之后, 改文件名, 大小写也要注意改 (文件名最好不要出现大写)
|
||||
* 最后把这个brief替换掉
|
||||
* @version 1.0
|
||||
* @date 2023-11-11
|
||||
|
||||
* @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 <stdlib.h>
|
||||
#include "guy_1020A.h"
|
||||
#ifdef READGUY_DEV_1020A
|
||||
namespace guydev_1020A{
|
||||
//以下代码均为我 FriendshipEnder 原创, 呵呵哒~~
|
||||
|
||||
void drv::drv_init(){ //初始化屏幕
|
||||
//add driver code...
|
||||
}
|
||||
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; //如果需要, 改成自己的代码
|
||||
}
|
||||
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;
|
||||
uint32_t u=epdFull?slowRefTime:fastRefTime; //全刷:局刷 busy时间
|
||||
if(ms<u) guy_epdBusy(u-ms); //对于busy电平为低电平忙碌,高电平正常的屏幕则改为ms-u
|
||||
lastRefresh=0;
|
||||
//add driver code...
|
||||
}
|
||||
}
|
||||
void drv::drv_sleep() { //开始屏幕睡眠
|
||||
if(RST_PIN>=0){ //RST_PIN<0 无法唤醒
|
||||
//add driver code...
|
||||
}
|
||||
epd_PowerOn = 0;
|
||||
epdFull = 1; //强制设置为慢刷新模式
|
||||
}
|
||||
}
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
|
||||
|
||||
63
src/guy_epaper/guy_1020A/guy_1020A.h
Normal file
63
src/guy_epaper/guy_1020A/guy_1020A.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/******************** F r i e n d s h i p E n d e r ********************
|
||||
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
||||
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
||||
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
||||
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
||||
* @file guy_1020A.h
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief 墨水屏 驱动库函数 头文件模板
|
||||
* 使用前, 先查找替换 1020A 改为你需要的驱动名称
|
||||
* 比如3英寸的屏幕驱动程序应该叫 guy_dev_300a
|
||||
* 此时需要将 1020A 替换为300A.
|
||||
* 替换好之后, 改文件名, 大小写也要注意改 (文件名最好不要出现大写)
|
||||
* 最后把这个brief替换掉
|
||||
* @version 1.0
|
||||
* @date 2023-11-11
|
||||
|
||||
* @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 "../guy_epdbase.h"
|
||||
#if (!defined(_GUY_EPD1020A_H_FILE) && (defined(READGUY_DEV_1020A)))
|
||||
#define _GUY_EPD1020A_H_FILE
|
||||
|
||||
namespace guydev_1020A{
|
||||
constexpr int GUY_D_WIDTH =200; //驱动屏幕宽度
|
||||
constexpr int GUY_D_HEIGHT =200; //驱动屏幕高度
|
||||
constexpr int slowRefTime =2000; //驱动屏幕慢刷时间, 单位毫秒
|
||||
constexpr int fastRefTime =500; //驱动屏幕快刷时间, 单位毫秒
|
||||
|
||||
class drv : public readguyEpdBase {
|
||||
public:
|
||||
int drv_ID() const { return READGUY_DEV_1020A; }
|
||||
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); //设置显示颜色深度
|
||||
int drv_supportGreyscaling() const { return 16; }
|
||||
private:
|
||||
uint8_t epd_PowerOn=1; //是否上电. 睡眠则设为0
|
||||
uint8_t epdFull=0; //是partical模式/快速刷新模式 0快刷, 1慢刷
|
||||
uint8_t iLut=15; //颜色深度
|
||||
};
|
||||
}
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
70
src/guy_epaper/guy_154C/guy_154C.cpp
Normal file
70
src/guy_epaper/guy_154C/guy_154C.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
/******************** F r i e n d s h i p E n d e r ********************
|
||||
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
||||
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
||||
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
||||
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
||||
* @file guy_154c.cpp
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief 1.54英寸墨水屏 驱动库函数
|
||||
* @version 1.0
|
||||
* @date 2023-11-11
|
||||
|
||||
* @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 <stdlib.h>
|
||||
#include "guy_154C.h"
|
||||
#ifdef READGUY_DEV_154C
|
||||
namespace guydev_154C{
|
||||
//以下代码均为我 FriendshipEnder 原创, 呵呵哒~~
|
||||
|
||||
void drv::drv_init(){ //初始化屏幕
|
||||
//add driver code...
|
||||
}
|
||||
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; //如果需要, 改成自己的代码
|
||||
}
|
||||
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;
|
||||
uint32_t u=epdFull?slowRefTime:fastRefTime; //全刷:局刷 busy时间
|
||||
if(ms<u) guy_epdBusy(u-ms); //对于busy电平为低电平忙碌,高电平正常的屏幕则改为ms-u
|
||||
lastRefresh=0;
|
||||
//add driver code...
|
||||
}
|
||||
}
|
||||
void drv::drv_sleep() { //开始屏幕睡眠
|
||||
if(RST_PIN>=0){ //RST_PIN<0 无法唤醒
|
||||
//add driver code...
|
||||
}
|
||||
epd_PowerOn = 0;
|
||||
epdFull = 1; //强制设置为慢刷新模式
|
||||
}
|
||||
}
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
|
||||
|
||||
58
src/guy_epaper/guy_154C/guy_154C.h
Normal file
58
src/guy_epaper/guy_154C/guy_154C.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/******************** F r i e n d s h i p E n d e r ********************
|
||||
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
||||
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
||||
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
||||
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
||||
* @file guy_154c.h
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief 1.54英寸墨水屏 驱动库函数 头文件
|
||||
* @version 1.0
|
||||
* @date 2023-11-11
|
||||
|
||||
* @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 "../guy_epdbase.h"
|
||||
#if (!defined(_GUY_EPD154C_H_FILE) && (defined(READGUY_DEV_154C)))
|
||||
#define _GUY_EPD154C_H_FILE
|
||||
|
||||
namespace guydev_154C{
|
||||
constexpr int GUY_D_WIDTH =200; //驱动屏幕宽度
|
||||
constexpr int GUY_D_HEIGHT =200; //驱动屏幕高度
|
||||
constexpr int slowRefTime =2000; //驱动屏幕慢刷时间, 单位毫秒
|
||||
constexpr int fastRefTime =500; //驱动屏幕快刷时间, 单位毫秒
|
||||
|
||||
class drv : public readguyEpdBase {
|
||||
public:
|
||||
int drv_ID() const { return READGUY_DEV_154C; }
|
||||
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); //设置显示颜色深度
|
||||
int drv_supportGreyscaling() const { return 16; }
|
||||
private:
|
||||
uint8_t epd_PowerOn=1; //是否上电. 睡眠则设为0
|
||||
uint8_t epdFull=0; //是partical模式/快速刷新模式 0快刷, 1慢刷
|
||||
uint8_t iLut=15; //颜色深度
|
||||
};
|
||||
}
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
@@ -98,6 +98,7 @@ void drvBase::drv_init(){ //new init method can init without freshing.
|
||||
//drv_color(0xffu); //睡眠模式下始终需要慢刷
|
||||
}
|
||||
void drvBase::drv_fullpart(bool part){ //切换慢刷/快刷功能
|
||||
if(lastRefresh) return;
|
||||
if(!part) iLut=15;
|
||||
if(sleeping) iLut=15;
|
||||
else Init(part?lut_fast:lut_slow);
|
||||
@@ -110,7 +111,9 @@ void drvBase::drv_fullpart(bool part){ //切换慢刷/快刷功能
|
||||
if(!part) iLut=15; //恢复默认的灰度模式
|
||||
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);
|
||||
BeginTransfer();
|
||||
SetMemory(); // bit set = white, bit reset = black
|
||||
@@ -123,14 +126,22 @@ void drvBase::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新等
|
||||
guy_epdCmd(0x20);
|
||||
guy_epdCmd(0xff);
|
||||
EndTransfer();
|
||||
guy_epdBusy((this->lut == (const uint8_t*)lut_fast)?idleFastRf:idleSlowRf);
|
||||
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();
|
||||
lastRefresh=millis();
|
||||
}
|
||||
|
||||
if(m&2){//stage 2
|
||||
uint32_t ms=millis()-lastRefresh;
|
||||
uint32_t u=(this->lut == (const uint8_t*)lut_fast)?idleFastRf:idleSlowRf;
|
||||
if(ms<u) guy_epdBusy(u-ms);
|
||||
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() { //开始屏幕睡眠
|
||||
if(RST_PIN>=0) { //未定义RST_PIN时无法唤醒
|
||||
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
virtual int drv_ID() const=0;
|
||||
void drv_init(); //初始化屏幕
|
||||
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() ; //开始屏幕睡眠
|
||||
int drv_width() const { return epdWidth; }; //返回显示区域宽度
|
||||
int drv_height() const{ return epdHeight; }; //返回显示区域高度
|
||||
|
||||
@@ -144,11 +144,14 @@ void drvSSD168x::drv_init(){
|
||||
//drv_color(0xffu);
|
||||
}
|
||||
void drvSSD168x::drv_fullpart(bool part){ //切换慢刷/快刷功能
|
||||
if(!epd_PowerOn) part=0; //未上电 无法局刷
|
||||
if(lastRefresh) return;
|
||||
//if(!epd_PowerOn) part=0; //未上电 无法局刷
|
||||
if(!part) { iLut=15; greyScaling=0; }
|
||||
_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();
|
||||
if(_part){
|
||||
//Reset();
|
||||
@@ -196,7 +199,15 @@ void drvSSD168x::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
|
||||
guy_epdParam(_part?0x0f:0xc7);
|
||||
guy_epdCmd(0x20);
|
||||
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() { //开始屏幕睡眠
|
||||
if(RST_PIN>=0){ //无法唤醒
|
||||
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
virtual int drv_ID() const =0;
|
||||
void drv_init(); //初始化屏幕
|
||||
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() ; //开始屏幕睡眠
|
||||
int drv_width() const { return epdWidth; }; //返回显示区域宽度
|
||||
int drv_height() const{ return epdHeight; }; //返回显示区域高度
|
||||
|
||||
@@ -113,13 +113,16 @@ void drv::drv_init(){ //初始化屏幕
|
||||
//drv_color(0xff);
|
||||
}
|
||||
void drv::drv_fullpart(bool part){ //初始化慢刷功能
|
||||
if(lastRefresh) return;
|
||||
if(!epd_PowerOn) part=0; //未上电 无法局刷
|
||||
//if(part==epdFull) return;
|
||||
if(!part) iLut=15; //恢复默认的灰度模式
|
||||
epdFull = !part;
|
||||
//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();
|
||||
if(epdFull) { //当刷新模式从快刷切换为慢刷时, 需要发送一次init
|
||||
epdFull=0;
|
||||
@@ -143,7 +146,15 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
|
||||
guy_epdParam(epdFull?0xc4:0x04);
|
||||
guy_epdCmd(0x20);
|
||||
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() { //开始屏幕睡眠
|
||||
if(RST_PIN>=0){ //RST_PIN<0 无法唤醒
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
int drv_ID() const { return READGUY_DEV_213A; }
|
||||
void drv_init(); //初始化屏幕
|
||||
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() ; //开始屏幕睡眠
|
||||
int drv_width() const { return EPD_REAL_WIDTH; }; //返回显示区域宽度
|
||||
//int drv_panelwidth() const { return GUY_D_WIDTH; }; //返回缓存的数据宽度
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
#include <stdlib.h>
|
||||
#include "guy_213b_266a.h"
|
||||
// #define MEPD_DEBUG_WAVE
|
||||
#ifdef READGUY_DEV_266A
|
||||
#if (defined(READGUY_DEV_213B) || defined(READGUY_DEV_213B3C) \
|
||||
|| defined(READGUY_DEV_266A) || defined(READGUY_DEV_266A3C))
|
||||
namespace guydev_213B_266A{
|
||||
static const PROGMEM unsigned char lutSlow_vcom0[] ={
|
||||
0x00, 0x08, 0x00, 0x00, 0x00, 0x02,
|
||||
@@ -68,21 +69,30 @@ static const PROGMEM unsigned char lutSlow_b_b[] ={
|
||||
static const PROGMEM unsigned char lutFast_[]={
|
||||
0x00,0x18,0x5a,0xa5,0x24
|
||||
};
|
||||
static const PROGMEM unsigned char greyLutLevel[]={
|
||||
0, 3, 6, 9,12,15,18,21,24,28,31,34,37,42,48,54, //for BWR displays
|
||||
0, 3, 5, 7,10,13,16,19,22,25,29,32,35,38,43,49,
|
||||
0, 3, 5, 6, 8,11,14,17,20,23,26,29,32,35,39,44,
|
||||
0, 2, 4, 5, 6, 8,10,13,15,18,21,24,27,31,35,39,
|
||||
0, 2, 3, 5, 6, 7, 8,10,12,15,17,19,22,24,27,30,
|
||||
0, 2, 3, 4, 5, 6, 7, 8,10,12,14,16,18,20,22,24,
|
||||
|
||||
0, 3, 3, 3, 4, 4, 5, 6, 7, 9,12,16,21,28,36,48,
|
||||
};
|
||||
drv_base::drv_base(){
|
||||
guy_lutArray[0] = lutSlow_vcom0;
|
||||
guy_lutArray[1] = lutSlow_w_w;
|
||||
guy_lutArray[2] = lutSlow_b_w;
|
||||
guy_lutArray[3] = lutSlow_w_b;
|
||||
guy_lutArray[4] = lutSlow_b_b;
|
||||
guy_lutArray[5] = lutFast_;
|
||||
}
|
||||
void drv_base::epd_init(){
|
||||
//if(!Power_is_on) Reset();
|
||||
guy_epdCmd(0x01);
|
||||
guy_epdParam(0x03);
|
||||
guy_epdParam(0x00);
|
||||
guy_epdParam(0x2b);
|
||||
guy_epdParam(0x2b);
|
||||
guy_epdParam(0x10);
|
||||
guy_epdParam(isBWR?0x3f:0x2b);
|
||||
guy_epdParam(isBWR?0x3f:0x2b);
|
||||
guy_epdParam(0x03);
|
||||
guy_epdCmd(0x06);
|
||||
guy_epdParam(0x17);
|
||||
@@ -92,7 +102,7 @@ void drv_base::epd_init(){
|
||||
guy_epdParam(0xbf);
|
||||
guy_epdParam(0x0d);
|
||||
guy_epdCmd(0x30);
|
||||
guy_epdParam(0x29); //0x3a:100Hz, 0x29:150Hz
|
||||
guy_epdParam(isBWR?0x3b:0x29); //0x3a:100Hz, 0x29:150Hz
|
||||
guy_epdCmd(0x61);
|
||||
guy_epdParam(0x98);
|
||||
guy_epdParam(0x01);
|
||||
@@ -118,9 +128,9 @@ void drv_base::SendLuts(bool part_lut){
|
||||
guy_epdCmd(i+0x20);
|
||||
for(int j=0;j<(i==0?44:42);j++){
|
||||
if(part_lut){
|
||||
if(j==4 && ((i==2) || (greyHQ==3 && i==4))) guy_epdParam(15);
|
||||
else if(j==greyHQ) guy_epdParam(greyLut);
|
||||
else if(j==0) guy_epdParam(pgm_read_byte(guy_lutArray[5]+(i)));
|
||||
if(j==4 && ((i==2) || (greyHQ==3 && i==4))) guy_epdParam(isBWR?0x2f:0x0f); //刷黑->白
|
||||
else if(j==greyHQ) guy_epdParam(isBWR?pgm_read_byte(greyLutLevel+(greyLut+refTime*16)):greyLut);
|
||||
else if(j==0) guy_epdParam(pgm_read_byte(lutFast_+(i)));
|
||||
else if(j==5) guy_epdParam(1);
|
||||
else guy_epdParam(0x0);
|
||||
}
|
||||
@@ -141,6 +151,7 @@ void drv_base::drv_init(){
|
||||
//drv_color(0xff);
|
||||
}
|
||||
void drv_base::drv_fullpart(bool part){ //切换慢刷/快刷功能
|
||||
if(lastRefresh) return;
|
||||
if(!Power_is_on) part=0;
|
||||
if(!part) greyLut=15; //恢复默认的灰度模式
|
||||
part_mode = part;
|
||||
@@ -152,7 +163,9 @@ void drv_base::drv_setDepth(uint8_t i){
|
||||
SendLuts(1);
|
||||
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();
|
||||
epd_init();
|
||||
SendLuts(part_mode);
|
||||
@@ -165,21 +178,30 @@ void drv_base::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
|
||||
guy_epdCmd(0x92);
|
||||
if(part_mode){
|
||||
guy_epdCmd(0x30);
|
||||
guy_epdParam(0x3a); //0x3a:100Hz, 0x29:150Hz
|
||||
//guy_epdParam(0x3a); //黑白色用此行, 三色用下一行
|
||||
guy_epdParam(isBWR?0x19:(refTime?0x21:0x3a)); //0x3a:100Hz, 0x29:150Hz
|
||||
send_zoneInfo();
|
||||
guy_epdCmd(0x12);
|
||||
EndTransfer();
|
||||
guy_epdBusy(-200);
|
||||
}
|
||||
else{
|
||||
guy_epdCmd(0x12);
|
||||
EndTransfer();
|
||||
guy_epdBusy(-2000);
|
||||
BeginTransfer();
|
||||
epd_init();
|
||||
SendLuts(1);
|
||||
guy_epdCmd(0x92);
|
||||
EndTransfer();
|
||||
guy_epdCmd(0x12);
|
||||
EndTransfer();
|
||||
lastRefresh=millis();
|
||||
}
|
||||
if(m&2){//stage 2
|
||||
uint32_t ms=millis()-lastRefresh;
|
||||
if(part_mode){
|
||||
if((int32_t)ms<fastRefTime) guy_epdBusy((int32_t)ms-fastRefTime);
|
||||
refTime+=(refTime<5);
|
||||
}
|
||||
else{
|
||||
if((int32_t)ms<slowRefTime) guy_epdBusy((int32_t)ms-slowRefTime);
|
||||
BeginTransfer();
|
||||
epd_init();
|
||||
SendLuts(1);
|
||||
guy_epdCmd(0x92);
|
||||
EndTransfer();
|
||||
refTime=0;
|
||||
}
|
||||
lastRefresh=0;
|
||||
}
|
||||
}
|
||||
void drv_base::drv_sleep() { //开始屏幕睡眠
|
||||
@@ -199,6 +221,7 @@ void drv_base::drv_draw16grey_step(std::function<uint8_t(int)> f, int step){
|
||||
if(_quality&1) return readguyEpdBase::drv_draw16grey_step(f,step);
|
||||
if(step==1){
|
||||
greyHQ=3;
|
||||
refTime=6;
|
||||
drv_setDepth(3);
|
||||
drv_fullpart(1); //开始快刷
|
||||
}
|
||||
@@ -207,6 +230,7 @@ void drv_base::drv_draw16grey_step(std::function<uint8_t(int)> f, int step){
|
||||
drv_dispWriter(f);
|
||||
if(step==15){
|
||||
greyHQ=4;
|
||||
refTime=5;
|
||||
drv_setDepth(15);
|
||||
}
|
||||
} //据说可以设置灰度渲染方式. 好像是调用setGreyQuality函数就行来着
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
* @file guy_213b_266a.h
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief 2.13英寸B型墨水屏和 2.66英寸墨水屏 驱动库函数 头文件
|
||||
* @version 1.0
|
||||
* @date 2023-09-21
|
||||
* 增加了对三色屏幕的支持
|
||||
* @version 1.1
|
||||
* @date create: 2023-09-21
|
||||
* last modify: 2023-11-11
|
||||
|
||||
* @attention
|
||||
* Copyright (c) 2022-2023 FriendshipEnder
|
||||
@@ -29,7 +31,8 @@
|
||||
|
||||
#include "../guy_epdbase.h"
|
||||
#if (!defined(_GUY_EPD213B_266A_H_FILE) && \
|
||||
(defined(READGUY_DEV_266A) || defined(READGUY_DEV_213B)))
|
||||
(defined(READGUY_DEV_213B) || defined(READGUY_DEV_213B3C) \
|
||||
|| defined(READGUY_DEV_266A) || defined(READGUY_DEV_266A3C)))
|
||||
#define _GUY_EPD213B_266A_H_FILE
|
||||
|
||||
namespace guydev_213B_266A{
|
||||
@@ -39,7 +42,7 @@ public:
|
||||
virtual int drv_ID() const=0;
|
||||
void drv_init(); //初始化屏幕
|
||||
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() ; //开始屏幕睡眠
|
||||
int drv_width() const { return epdWidth; }; //返回显示区域宽度
|
||||
int drv_height() const{ return epdHeight; }; //返回显示区域高度
|
||||
@@ -49,7 +52,6 @@ public:
|
||||
protected:
|
||||
int epdWidth;
|
||||
int epdHeight;
|
||||
private:
|
||||
void epd_init();
|
||||
void send_zoneInfo();
|
||||
void SendLuts(bool part_lut);
|
||||
@@ -57,22 +59,40 @@ private:
|
||||
uint8_t Power_is_on = 2; //初始为未上电
|
||||
uint8_t greyLut=15;
|
||||
uint8_t greyHQ=4; // greyHQ==3 时 为高品质刷新灰度 否则为常规方式刷新灰度
|
||||
const uint8_t *guy_lutArray[6];
|
||||
uint8_t refTime=0;
|
||||
uint8_t isBWR=0; //三色2.66将此屏幕数值改为1.
|
||||
int16_t slowRefTime;
|
||||
int16_t fastRefTime;
|
||||
const uint8_t *guy_lutArray[5];
|
||||
};
|
||||
#ifdef READGUY_DEV_213B
|
||||
class dev213B : public drv_base {
|
||||
public:
|
||||
dev213B(){ epdWidth=104; epdHeight=212; }
|
||||
dev213B(){ epdWidth=104; epdHeight=212; slowRefTime=1300; fastRefTime=200; }
|
||||
int drv_ID() const { return READGUY_DEV_213B; }
|
||||
};
|
||||
#endif
|
||||
#ifdef READGUY_DEV_213B3C
|
||||
class dev213B3C : public drv_base {
|
||||
public:
|
||||
dev213B3C(){ epdWidth=104; epdHeight=212; isBWR=1; slowRefTime=2800; fastRefTime=800; }
|
||||
int drv_ID() const { return READGUY_DEV_213B3C; }
|
||||
};
|
||||
#endif
|
||||
#ifdef READGUY_DEV_266A
|
||||
class dev266A : public drv_base {
|
||||
public:
|
||||
dev266A(){ epdWidth=152; epdHeight=296; }
|
||||
dev266A(){ epdWidth=152; epdHeight=296; slowRefTime=1300; fastRefTime=200; }
|
||||
int drv_ID() const { return READGUY_DEV_266A; }
|
||||
};
|
||||
#endif
|
||||
#ifdef READGUY_DEV_266A3C
|
||||
class dev266A3C : public drv_base {
|
||||
public:
|
||||
dev266A3C(){ epdWidth=152; epdHeight=296; isBWR=1; slowRefTime=2800; fastRefTime=800; }
|
||||
int drv_ID() const { return READGUY_DEV_266A3C; }
|
||||
};
|
||||
#endif
|
||||
}
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
|
||||
75
src/guy_epaper/guy_370B/guy_370B.cpp
Normal file
75
src/guy_epaper/guy_370B/guy_370B.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/******************** F r i e n d s h i p E n d e r ********************
|
||||
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
||||
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
||||
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
||||
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
||||
* @file guy_370B.cpp
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief 墨水屏 驱动库函数 源代码模板
|
||||
* 使用前, 先查找替换 370B 改为你需要的驱动名称
|
||||
* 比如3英寸的屏幕驱动程序应该叫 guy_dev_300a
|
||||
* 此时需要将 370B 替换为300A.
|
||||
* 替换好之后, 改文件名, 大小写也要注意改 (文件名最好不要出现大写)
|
||||
* 最后把这个brief替换掉
|
||||
* @version 1.0
|
||||
* @date 2023-11-11
|
||||
|
||||
* @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 <stdlib.h>
|
||||
#include "guy_370B.h"
|
||||
#ifdef READGUY_DEV_370B
|
||||
namespace guydev_370B{
|
||||
//以下代码均为我 FriendshipEnder 原创, 呵呵哒~~
|
||||
|
||||
void drv::drv_init(){ //初始化屏幕
|
||||
//add driver code...
|
||||
}
|
||||
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; //如果需要, 改成自己的代码
|
||||
}
|
||||
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;
|
||||
uint32_t u=epdFull?slowRefTime:fastRefTime; //全刷:局刷 busy时间
|
||||
if(ms<u) guy_epdBusy(u-ms); //对于busy电平为低电平忙碌,高电平正常的屏幕则改为ms-u
|
||||
lastRefresh=0;
|
||||
//add driver code...
|
||||
}
|
||||
}
|
||||
void drv::drv_sleep() { //开始屏幕睡眠
|
||||
if(RST_PIN>=0){ //RST_PIN<0 无法唤醒
|
||||
//add driver code...
|
||||
}
|
||||
epd_PowerOn = 0;
|
||||
epdFull = 1; //强制设置为慢刷新模式
|
||||
}
|
||||
}
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
|
||||
|
||||
63
src/guy_epaper/guy_370B/guy_370B.h
Normal file
63
src/guy_epaper/guy_370B/guy_370B.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/******************** F r i e n d s h i p E n d e r ********************
|
||||
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
||||
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
||||
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
||||
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
||||
* @file guy_370B.h
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief 墨水屏 驱动库函数 头文件模板
|
||||
* 使用前, 先查找替换 370B 改为你需要的驱动名称
|
||||
* 比如3英寸的屏幕驱动程序应该叫 guy_dev_300a
|
||||
* 此时需要将 370B 替换为300A.
|
||||
* 替换好之后, 改文件名, 大小写也要注意改 (文件名最好不要出现大写)
|
||||
* 最后把这个brief替换掉
|
||||
* @version 1.0
|
||||
* @date 2023-11-11
|
||||
|
||||
* @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 "../guy_epdbase.h"
|
||||
#if (!defined(_GUY_EPD370B_H_FILE) && (defined(READGUY_DEV_370B)))
|
||||
#define _GUY_EPD370B_H_FILE
|
||||
|
||||
namespace guydev_370B{
|
||||
constexpr int GUY_D_WIDTH =200; //驱动屏幕宽度
|
||||
constexpr int GUY_D_HEIGHT =200; //驱动屏幕高度
|
||||
constexpr int slowRefTime =2000; //驱动屏幕慢刷时间, 单位毫秒
|
||||
constexpr int fastRefTime =500; //驱动屏幕快刷时间, 单位毫秒
|
||||
|
||||
class drv : public readguyEpdBase {
|
||||
public:
|
||||
int drv_ID() const { return READGUY_DEV_370B; }
|
||||
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); //设置显示颜色深度
|
||||
int drv_supportGreyscaling() const { return 16; }
|
||||
private:
|
||||
uint8_t epd_PowerOn=1; //是否上电. 睡眠则设为0
|
||||
uint8_t epdFull=0; //是partical模式/快速刷新模式 0快刷, 1慢刷
|
||||
uint8_t iLut=15; //颜色深度
|
||||
};
|
||||
}
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
@@ -110,7 +110,7 @@ void drv::drv_init(){ //初始化屏幕
|
||||
//drv_color(0xff);
|
||||
}
|
||||
void drv::drv_fullpart(bool part){ //切换慢刷/快刷功能
|
||||
if(sleeping) return;
|
||||
if(lastRefresh || sleeping) return;
|
||||
if(!part) {
|
||||
greyScaling=15; //恢复默认的灰度模式
|
||||
BeginTransfer();
|
||||
@@ -120,7 +120,9 @@ void drv::drv_fullpart(bool 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();
|
||||
BeginTransfer();
|
||||
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);
|
||||
guy_epdCmd(0x20);
|
||||
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() { //开始屏幕睡眠
|
||||
if(RST_PIN>=0){
|
||||
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
int drv_ID() const { return READGUY_DEV_370A; }
|
||||
void drv_init(); //初始化屏幕
|
||||
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() ; //开始屏幕睡眠
|
||||
int drv_width() const { return GUY_D_WIDTH; }; //返回显示区域宽度
|
||||
int drv_height() const{ return GUY_D_HEIGHT; }; //返回显示区域高度
|
||||
|
||||
@@ -182,10 +182,13 @@ void drv::drv_init(){ //初始化屏幕
|
||||
//drv_color(0xff);
|
||||
}
|
||||
void drv::drv_fullpart(bool part){ //初始化慢刷功能
|
||||
if(lastRefresh) return;
|
||||
if(epdFull<=1) epdFull = !part; //epdFull==2代表睡眠中, 不能快刷
|
||||
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();
|
||||
epd_Init();
|
||||
SetMemory();
|
||||
@@ -211,9 +214,7 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
|
||||
SetLut(lut_213_B72_Full);
|
||||
guy_epdCmd(0x22);
|
||||
guy_epdParam(0xc4);
|
||||
guy_epdCmd(0x20);
|
||||
EndTransfer();
|
||||
guy_epdBusy(1600); //等待刷完
|
||||
//guy_epdBusy(1600); //等待刷完
|
||||
}
|
||||
else{ //快刷
|
||||
guy_epdCmd(0x2c); //may a mistake? 此处不需要设置vcom
|
||||
@@ -221,17 +222,24 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
|
||||
SetLut(GreyScalingHighQuality?lut_213_B72_16grey:lut_213_B72);
|
||||
guy_epdCmd(0x22);
|
||||
guy_epdParam(0x04);
|
||||
guy_epdCmd(0x20);
|
||||
EndTransfer();
|
||||
guy_epdBusy(260); //等待屏幕刷新完成
|
||||
}
|
||||
BeginTransfer(); //write again
|
||||
SetMemory();
|
||||
guy_epdCmd(0x26);
|
||||
for (int i = 0; i < GUY_D_HEIGHT*GUY_D_WIDTH/8; i++)
|
||||
SpiTransfer(f(i)); //按照给定的RAM写入数据
|
||||
guy_epdCmd(0x20);
|
||||
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){
|
||||
if(_quality&1) return readguyEpdBase::drv_draw16grey_step(f,step);
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
int drv_ID() const { return READGUY_DEV_420A; }
|
||||
void drv_init(); //初始化屏幕
|
||||
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() ; //开始屏幕睡眠
|
||||
int drv_width() const { return GUY_D_WIDTH; }; //返回显示区域宽度
|
||||
int drv_height() const{ return GUY_D_HEIGHT; }; //返回显示区域高度
|
||||
|
||||
@@ -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_b_b[] ={ 0x01,2,0,48,0,1 };
|
||||
//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();
|
||||
Init(part_mode);
|
||||
if(part_mode){
|
||||
@@ -181,7 +183,13 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
|
||||
}
|
||||
guy_epdCmd(0x12);
|
||||
EndTransfer();
|
||||
guy_epdBusy(part_mode?-800:-3600);
|
||||
lastRefresh=millis();
|
||||
}
|
||||
if(m&2){//stage 2
|
||||
uint32_t ms=millis()-lastRefresh;
|
||||
int32_t u=part_mode?800:3600;
|
||||
if((int32_t)ms<u) guy_epdBusy((int32_t)ms-u);
|
||||
lastRefresh=0;
|
||||
BeginTransfer();
|
||||
if(part_mode){
|
||||
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++)
|
||||
SpiTransfer(f(i));
|
||||
guy_epdCmd(0x92);
|
||||
EndTransfer();
|
||||
}
|
||||
else{
|
||||
Init(2);
|
||||
@@ -199,6 +206,7 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
|
||||
SpiTransfer(f(i));
|
||||
guy_epdCmd(0x92);
|
||||
guy_epdCmd(0x02);
|
||||
}
|
||||
EndTransfer();
|
||||
guy_epdBusy(-20);
|
||||
}
|
||||
@@ -216,6 +224,7 @@ void drv::drv_init(){
|
||||
//drv_color(0xffu);
|
||||
}
|
||||
void drv::drv_fullpart(bool part){ //切换慢刷/快刷功能
|
||||
if(lastRefresh) return;
|
||||
if(Power_is_on) {
|
||||
if(!part) customLut = CUSTOM_LUT_DISABLE;
|
||||
part_mode = part;
|
||||
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
void drv_init(); //初始化屏幕
|
||||
//void drv_draw16grey(uint8_t *d16bit);
|
||||
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() ; //开始屏幕睡眠
|
||||
int drv_width() const { return GUY_D_WIDTH; }; //返回显示区域宽度
|
||||
int drv_height() const{ return GUY_D_HEIGHT; }; //返回显示区域高度
|
||||
|
||||
75
src/guy_epaper/guy_426A/guy_426A.cpp
Normal file
75
src/guy_epaper/guy_426A/guy_426A.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/******************** F r i e n d s h i p E n d e r ********************
|
||||
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
||||
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
||||
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
||||
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
||||
* @file guy_426A.cpp
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief 墨水屏 驱动库函数 源代码模板
|
||||
* 使用前, 先查找替换 426A 改为你需要的驱动名称
|
||||
* 比如3英寸的屏幕驱动程序应该叫 guy_dev_300a
|
||||
* 此时需要将 426A 替换为300A.
|
||||
* 替换好之后, 改文件名, 大小写也要注意改 (文件名最好不要出现大写)
|
||||
* 最后把这个brief替换掉
|
||||
* @version 1.0
|
||||
* @date 2023-11-11
|
||||
|
||||
* @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 <stdlib.h>
|
||||
#include "guy_426A.h"
|
||||
#ifdef READGUY_DEV_426A
|
||||
namespace guydev_426A{
|
||||
//以下代码均为我 FriendshipEnder 原创, 呵呵哒~~
|
||||
|
||||
void drv::drv_init(){ //初始化屏幕
|
||||
//add driver code...
|
||||
}
|
||||
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; //如果需要, 改成自己的代码
|
||||
}
|
||||
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;
|
||||
uint32_t u=epdFull?slowRefTime:fastRefTime; //全刷:局刷 busy时间
|
||||
if(ms<u) guy_epdBusy(u-ms); //对于busy电平为低电平忙碌,高电平正常的屏幕则改为ms-u
|
||||
lastRefresh=0;
|
||||
//add driver code...
|
||||
}
|
||||
}
|
||||
void drv::drv_sleep() { //开始屏幕睡眠
|
||||
if(RST_PIN>=0){ //RST_PIN<0 无法唤醒
|
||||
//add driver code...
|
||||
}
|
||||
epd_PowerOn = 0;
|
||||
epdFull = 1; //强制设置为慢刷新模式
|
||||
}
|
||||
}
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
|
||||
|
||||
63
src/guy_epaper/guy_426A/guy_426A.h
Normal file
63
src/guy_epaper/guy_426A/guy_426A.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/******************** F r i e n d s h i p E n d e r ********************
|
||||
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
||||
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
||||
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
||||
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
||||
* @file guy_426A.h
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief 墨水屏 驱动库函数 头文件模板
|
||||
* 使用前, 先查找替换 426A 改为你需要的驱动名称
|
||||
* 比如3英寸的屏幕驱动程序应该叫 guy_dev_300a
|
||||
* 此时需要将 426A 替换为300A.
|
||||
* 替换好之后, 改文件名, 大小写也要注意改 (文件名最好不要出现大写)
|
||||
* 最后把这个brief替换掉
|
||||
* @version 1.0
|
||||
* @date 2023-11-11
|
||||
|
||||
* @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 "../guy_epdbase.h"
|
||||
#if (!defined(_GUY_EPD426A_H_FILE) && (defined(READGUY_DEV_426A)))
|
||||
#define _GUY_EPD426A_H_FILE
|
||||
|
||||
namespace guydev_426A{
|
||||
constexpr int GUY_D_WIDTH =200; //驱动屏幕宽度
|
||||
constexpr int GUY_D_HEIGHT =200; //驱动屏幕高度
|
||||
constexpr int slowRefTime =2000; //驱动屏幕慢刷时间, 单位毫秒
|
||||
constexpr int fastRefTime =500; //驱动屏幕快刷时间, 单位毫秒
|
||||
|
||||
class drv : public readguyEpdBase {
|
||||
public:
|
||||
int drv_ID() const { return READGUY_DEV_426A; }
|
||||
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); //设置显示颜色深度
|
||||
int drv_supportGreyscaling() const { return 16; }
|
||||
private:
|
||||
uint8_t epd_PowerOn=1; //是否上电. 睡眠则设为0
|
||||
uint8_t epdFull=0; //是partical模式/快速刷新模式 0快刷, 1慢刷
|
||||
uint8_t iLut=15; //颜色深度
|
||||
};
|
||||
}
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
420
src/guy_epaper/guy_583A/guy_583A.cpp
Normal file
420
src/guy_epaper/guy_583A/guy_583A.cpp
Normal file
@@ -0,0 +1,420 @@
|
||||
/******************** F r i e n d s h i p E n d e r ********************
|
||||
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
||||
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
||||
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
||||
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
||||
* @file guy_583A.cpp
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief 墨水屏 驱动库函数 源代码模板
|
||||
* 使用前, 先查找替换 583A 改为你需要的驱动名称
|
||||
* 比如3英寸的屏幕驱动程序应该叫 guy_dev_300a
|
||||
* 此时需要将 583A 替换为300A.
|
||||
* 替换好之后, 改文件名, 大小写也要注意改 (文件名最好不要出现大写)
|
||||
* 最后把这个brief替换掉
|
||||
* @version 1.0
|
||||
* @date 2023-11-11
|
||||
|
||||
* @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 <stdlib.h>
|
||||
#include "guy_583A.h"
|
||||
#ifdef READGUY_DEV_583A
|
||||
namespace guydev_583A{
|
||||
/*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
|
||||
};
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
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;
|
||||
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
|
||||
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; //强制设置为慢刷新模式
|
||||
}
|
||||
}
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
|
||||
|
||||
92
src/guy_epaper/guy_583A/guy_583A.h
Normal file
92
src/guy_epaper/guy_583A/guy_583A.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/******************** F r i e n d s h i p E n d e r ********************
|
||||
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
||||
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
||||
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
||||
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
||||
* @file guy_583A.h
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief 墨水屏 驱动库函数 头文件模板
|
||||
* 使用前, 先查找替换 583A 改为你需要的驱动名称
|
||||
* 比如3英寸的屏幕驱动程序应该叫 guy_dev_300a
|
||||
* 此时需要将 583A 替换为300A.
|
||||
* 替换好之后, 改文件名, 大小写也要注意改 (文件名最好不要出现大写)
|
||||
* 最后把这个brief替换掉
|
||||
* @version 1.0
|
||||
* @date 2023-11-11
|
||||
|
||||
* @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 "../guy_epdbase.h"
|
||||
#if (!defined(_GUY_EPD583A_H_FILE) && (defined(READGUY_DEV_583A)))
|
||||
#define _GUY_EPD583A_H_FILE
|
||||
|
||||
namespace guydev_583A{
|
||||
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); //切换慢刷/快刷功能
|
||||
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); //设置显示颜色深度
|
||||
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.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
75
src/guy_epaper/guy_583B/guy_583B.cpp
Normal file
75
src/guy_epaper/guy_583B/guy_583B.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/******************** F r i e n d s h i p E n d e r ********************
|
||||
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
||||
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
||||
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
||||
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
||||
* @file guy_583B.cpp
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief 墨水屏 驱动库函数 源代码模板
|
||||
* 使用前, 先查找替换 583B 改为你需要的驱动名称
|
||||
* 比如3英寸的屏幕驱动程序应该叫 guy_dev_300a
|
||||
* 此时需要将 583B 替换为300A.
|
||||
* 替换好之后, 改文件名, 大小写也要注意改 (文件名最好不要出现大写)
|
||||
* 最后把这个brief替换掉
|
||||
* @version 1.0
|
||||
* @date 2023-11-11
|
||||
|
||||
* @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 <stdlib.h>
|
||||
#include "guy_583B.h"
|
||||
#ifdef READGUY_DEV_583B
|
||||
namespace guydev_583B{
|
||||
//以下代码均为我 FriendshipEnder 原创, 呵呵哒~~
|
||||
|
||||
void drv::drv_init(){ //初始化屏幕
|
||||
//add driver code...
|
||||
}
|
||||
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; //如果需要, 改成自己的代码
|
||||
}
|
||||
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;
|
||||
uint32_t u=epdFull?slowRefTime:fastRefTime; //全刷:局刷 busy时间
|
||||
if(ms<u) guy_epdBusy(u-ms); //对于busy电平为低电平忙碌,高电平正常的屏幕则改为ms-u
|
||||
lastRefresh=0;
|
||||
//add driver code...
|
||||
}
|
||||
}
|
||||
void drv::drv_sleep() { //开始屏幕睡眠
|
||||
if(RST_PIN>=0){ //RST_PIN<0 无法唤醒
|
||||
//add driver code...
|
||||
}
|
||||
epd_PowerOn = 0;
|
||||
epdFull = 1; //强制设置为慢刷新模式
|
||||
}
|
||||
}
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
|
||||
|
||||
63
src/guy_epaper/guy_583B/guy_583B.h
Normal file
63
src/guy_epaper/guy_583B/guy_583B.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/******************** F r i e n d s h i p E n d e r ********************
|
||||
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
||||
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
||||
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
||||
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
||||
* @file guy_583B.h
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief 墨水屏 驱动库函数 头文件模板
|
||||
* 使用前, 先查找替换 583B 改为你需要的驱动名称
|
||||
* 比如3英寸的屏幕驱动程序应该叫 guy_dev_300a
|
||||
* 此时需要将 583B 替换为300A.
|
||||
* 替换好之后, 改文件名, 大小写也要注意改 (文件名最好不要出现大写)
|
||||
* 最后把这个brief替换掉
|
||||
* @version 1.0
|
||||
* @date 2023-11-11
|
||||
|
||||
* @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 "../guy_epdbase.h"
|
||||
#if (!defined(_GUY_EPD583B_H_FILE) && (defined(READGUY_DEV_583B)))
|
||||
#define _GUY_EPD583B_H_FILE
|
||||
|
||||
namespace guydev_583B{
|
||||
constexpr int GUY_D_WIDTH =200; //驱动屏幕宽度
|
||||
constexpr int GUY_D_HEIGHT =200; //驱动屏幕高度
|
||||
constexpr int slowRefTime =2000; //驱动屏幕慢刷时间, 单位毫秒
|
||||
constexpr int fastRefTime =500; //驱动屏幕快刷时间, 单位毫秒
|
||||
|
||||
class drv : public readguyEpdBase {
|
||||
public:
|
||||
int drv_ID() const { return READGUY_DEV_583B; }
|
||||
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); //设置显示颜色深度
|
||||
int drv_supportGreyscaling() const { return 16; }
|
||||
private:
|
||||
uint8_t epd_PowerOn=1; //是否上电. 睡眠则设为0
|
||||
uint8_t epdFull=0; //是partical模式/快速刷新模式 0快刷, 1慢刷
|
||||
uint8_t iLut=15; //颜色深度
|
||||
};
|
||||
}
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
75
src/guy_epaper/guy_750A/guy_750A.cpp
Normal file
75
src/guy_epaper/guy_750A/guy_750A.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/******************** F r i e n d s h i p E n d e r ********************
|
||||
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
||||
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
||||
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
||||
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
||||
* @file guy_750A.cpp
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief 墨水屏 驱动库函数 源代码模板
|
||||
* 使用前, 先查找替换 750A 改为你需要的驱动名称
|
||||
* 比如3英寸的屏幕驱动程序应该叫 guy_dev_300a
|
||||
* 此时需要将 750A 替换为300A.
|
||||
* 替换好之后, 改文件名, 大小写也要注意改 (文件名最好不要出现大写)
|
||||
* 最后把这个brief替换掉
|
||||
* @version 1.0
|
||||
* @date 2023-11-11
|
||||
|
||||
* @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 <stdlib.h>
|
||||
#include "guy_750A.h"
|
||||
#ifdef READGUY_DEV_750A
|
||||
namespace guydev_750A{
|
||||
//以下代码均为我 FriendshipEnder 原创, 呵呵哒~~
|
||||
|
||||
void drv::drv_init(){ //初始化屏幕
|
||||
//add driver code...
|
||||
}
|
||||
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; //如果需要, 改成自己的代码
|
||||
}
|
||||
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;
|
||||
uint32_t u=epdFull?slowRefTime:fastRefTime; //全刷:局刷 busy时间
|
||||
if(ms<u) guy_epdBusy(u-ms); //对于busy电平为低电平忙碌,高电平正常的屏幕则改为ms-u
|
||||
lastRefresh=0;
|
||||
//add driver code...
|
||||
}
|
||||
}
|
||||
void drv::drv_sleep() { //开始屏幕睡眠
|
||||
if(RST_PIN>=0){ //RST_PIN<0 无法唤醒
|
||||
//add driver code...
|
||||
}
|
||||
epd_PowerOn = 0;
|
||||
epdFull = 1; //强制设置为慢刷新模式
|
||||
}
|
||||
}
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
|
||||
|
||||
63
src/guy_epaper/guy_750A/guy_750A.h
Normal file
63
src/guy_epaper/guy_750A/guy_750A.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/******************** F r i e n d s h i p E n d e r ********************
|
||||
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
||||
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
||||
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
||||
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
||||
* @file guy_750A.h
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief 墨水屏 驱动库函数 头文件模板
|
||||
* 使用前, 先查找替换 750A 改为你需要的驱动名称
|
||||
* 比如3英寸的屏幕驱动程序应该叫 guy_dev_300a
|
||||
* 此时需要将 750A 替换为300A.
|
||||
* 替换好之后, 改文件名, 大小写也要注意改 (文件名最好不要出现大写)
|
||||
* 最后把这个brief替换掉
|
||||
* @version 1.0
|
||||
* @date 2023-11-11
|
||||
|
||||
* @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 "../guy_epdbase.h"
|
||||
#if (!defined(_GUY_EPD750A_H_FILE) && (defined(READGUY_DEV_750A)))
|
||||
#define _GUY_EPD750A_H_FILE
|
||||
|
||||
namespace guydev_750A{
|
||||
constexpr int GUY_D_WIDTH =200; //驱动屏幕宽度
|
||||
constexpr int GUY_D_HEIGHT =200; //驱动屏幕高度
|
||||
constexpr int slowRefTime =2000; //驱动屏幕慢刷时间, 单位毫秒
|
||||
constexpr int fastRefTime =500; //驱动屏幕快刷时间, 单位毫秒
|
||||
|
||||
class drv : public readguyEpdBase {
|
||||
public:
|
||||
int drv_ID() const { return READGUY_DEV_750A; }
|
||||
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); //设置显示颜色深度
|
||||
int drv_supportGreyscaling() const { return 16; }
|
||||
private:
|
||||
uint8_t epd_PowerOn=1; //是否上电. 睡眠则设为0
|
||||
uint8_t epdFull=0; //是partical模式/快速刷新模式 0快刷, 1慢刷
|
||||
uint8_t iLut=15; //颜色深度
|
||||
};
|
||||
}
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
@@ -44,7 +44,7 @@
|
||||
#define READGUY_DEV_154A 0 //1.54寸标准, 甘草酸不酸使用的1.54默认屏幕型号. 1.54汉朔价签也选这个
|
||||
#define READGUY_DEV_154B 1 //1.54寸Lilygo, lilygo的1.54触摸和1.54背光墨水屏. GDEH0154D67
|
||||
#define READGUY_DEV_213A 2 //2.13寸汉朔价签, 价格便宜, 兼容性好. 夏襄居士单词卡用 GDE0213B1
|
||||
#define READGUY_DEV_213B 3 //2.13寸三色, 分辨率低212x104, 部分价签也用这个屏 易老化
|
||||
#define READGUY_DEV_213B 3 //2.13寸, 分辨率低212x104, 部分2.13驱动不了的情况下用这个屏驱动
|
||||
#define READGUY_DEV_266A 4 //2.66寸Vusion价签, 黑白双色.
|
||||
#define READGUY_DEV_270B 5 //2.7寸佳显触摸墨水屏, 佳显官方店有售: 2.7寸触摸墨水屏.
|
||||
#define READGUY_DEV_290A 6 //2.9寸A01, 甘草酸不酸2.9寸A01型号. 显示性能一般
|
||||
@@ -53,6 +53,22 @@
|
||||
#define READGUY_DEV_420A 9 //4.2寸HINK黑白价签, 汉朔价签, 汉朔三色价签通用. 速度快, 但效果一般
|
||||
#define READGUY_DEV_420B 10 //4.2寸WF丝印, 部分价签也用此型号屏, 排线有WF开头的丝印
|
||||
#define MEPD_DEBUG_DISPLAY 11 //使用LCD显示屏幕来debug. 前往ctg_stack_c_defines.h修改兼容的屏幕.
|
||||
#define READGUY_DEV_213B3C 12 //2.13寸三色, 分辨率低212x104, 部分价签也用这个屏 易老化
|
||||
#define READGUY_DEV_266A3C 13 //2.66寸三色. 驱动只能支持黑白色, 分辨率 296x152,
|
||||
|
||||
//#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_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
|
||||
|
||||
//添加新屏幕型号 add displays here
|
||||
|
||||
#define EPD_DRIVERS_NUM_MAX 21 //此选项请不要取消注释掉, 有几个屏幕就写多少.
|
||||
|
||||
#define READGUY_583A_DUAL_BUFFER //对于单缓存的5.83屏幕,启用双缓存支持. 相当不建议注释掉,否则不能刷白色
|
||||
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
@@ -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);
|
||||
if(BUSY_PIN>=0) pinMode(BUSY_PIN, INPUT);
|
||||
_spi = &c;
|
||||
lastRefresh=0;
|
||||
|
||||
//_spi->begin();
|
||||
//_spi->beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
|
||||
@@ -159,10 +160,9 @@ 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){
|
||||
#ifndef FLOYD_STEINBERG_DITHERING
|
||||
static const uint8_t bayer_tab [64]={
|
||||
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,
|
||||
12, 44, 4, 36, 14, 46, 6, 38,
|
||||
@@ -172,26 +172,25 @@ 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
|
||||
};
|
||||
#endif
|
||||
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()];
|
||||
#ifdef FLOYD_STEINBERG_DITHERING
|
||||
floyd_tab[0] = 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; }
|
||||
#endif
|
||||
writeBuff = new uint8_t[(fw+7)>>3];
|
||||
}
|
||||
sprbase.fillRect(x,y,fw,fh,1);
|
||||
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;
|
||||
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);
|
||||
@@ -218,39 +217,39 @@ void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_
|
||||
{ floyd_tab[!(i&1)][j+1] += (flodelta )>>4; }
|
||||
}
|
||||
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()/fw0]))<<(7-b);
|
||||
writeBuff[j]=buff8bit;
|
||||
}
|
||||
}
|
||||
sprbase.drawBitmap(x,i,writeBuff,fw,1,1,0);
|
||||
}
|
||||
//_display((const uint8_t*)sprbase.getBuffer()); //显示
|
||||
if(o==0 || o==3){
|
||||
delete []readBuff;
|
||||
delete []writeBuff;
|
||||
#ifdef FLOYD_STEINBERG_DITHERING
|
||||
delete [] floyd_tab[0] ;
|
||||
delete [] floyd_tab[1] ;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
//不支持的话使用单色抖动刷屏
|
||||
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){
|
||||
#ifdef FLOYD_DITHERING_16GREY
|
||||
floyd_tab[0] = new int16_t [fw];
|
||||
floyd_tab[1] = new int16_t [fw];
|
||||
#endif
|
||||
}
|
||||
writeBuff = new uint8_t[(fw+7)>>3];
|
||||
sprbase.fillRect(x,y,fw,fh,1);
|
||||
@@ -260,18 +259,15 @@ void readguyEpdBase::drv_draw16grey(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16
|
||||
drv_dispWriter(FILL_WHITE);
|
||||
drv_fullpart(1);
|
||||
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; }
|
||||
#endif
|
||||
for(int i=y;i<(int32_t)fh+y;i++){
|
||||
uint_fast8_t buff8bit=0;
|
||||
spr.readRect(0,(i-y)*spr.height()/fh,spr.width(),1,readBuff);
|
||||
for(int32_t j=0;j<fw;j++){
|
||||
//for(uint_fast8_t b=0;b<8;b++){
|
||||
#ifdef FLOYD_DITHERING_16GREY
|
||||
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++;
|
||||
@@ -283,10 +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; }
|
||||
#else
|
||||
uint_fast8_t cg=greysc(readBuff[j*spr.width()/fw])>>4;
|
||||
#endif
|
||||
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{
|
||||
@@ -298,11 +292,9 @@ 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));
|
||||
}
|
||||
#ifdef FLOYD_DITHERING_16GREY
|
||||
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);
|
||||
}
|
||||
drv_draw16grey_step((const uint8_t*)sprbase.getBuffer(),k); //使用灰度显示函数
|
||||
@@ -310,10 +302,8 @@ void readguyEpdBase::drv_draw16grey(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16
|
||||
delete []readBuff;
|
||||
delete []writeBuff;
|
||||
if(_quality&2){
|
||||
#ifdef FLOYD_DITHERING_16GREY
|
||||
delete [] floyd_tab[0] ;
|
||||
delete [] floyd_tab[1] ;
|
||||
#endif
|
||||
}
|
||||
} /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
@@ -36,7 +36,6 @@
|
||||
#define LGFX_USE_V1
|
||||
#include <LovyanGFX.hpp>
|
||||
#include "guy_epaper_config.h"
|
||||
#define EPD_DRIVERS_NUM_MAX 12 //此选项请不要取消注释掉
|
||||
|
||||
#define FILL_WHITE ([](int)->uint8_t{return 0xff;})
|
||||
#define FILL_BLACK ([](int)->uint8_t{return 0x00;})
|
||||
@@ -49,15 +48,14 @@ 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];
|
||||
#if (defined(FLOYD_DITHERING_16GREY) || defined(FLOYD_STEINBERG_DITHERING))
|
||||
int16_t *floyd_tab[2];
|
||||
#endif
|
||||
uint32_t lastRefresh;
|
||||
|
||||
public:
|
||||
readguyEpdBase(void);
|
||||
@@ -82,25 +80,27 @@ public:
|
||||
virtual int drv_ID() const =0; //返回驱动代号
|
||||
virtual void drv_init()=0; //初始化屏幕
|
||||
virtual void drv_fullpart(bool part)=0; //初始化慢刷功能
|
||||
void _display(const uint8_t *d){ drv_dispWriter([&](int n)->uint8_t{return d[n];}); }
|
||||
virtual void drv_dispWriter(std::function<uint8_t(int)>)=0; //按照显示函数刷新
|
||||
void drv_color(uint8_t c){ drv_dispWriter([=](int)->uint8_t{return c;}); } //单色刷新
|
||||
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)>,uint8_t m=3)=0; //按照显示函数刷新
|
||||
void drv_color(uint8_t c,uint8_t m=3){ drv_dispWriter([=](int)->uint8_t{return c;},m); } //单色刷新
|
||||
virtual void drv_sleep() =0; //开始屏幕睡眠
|
||||
virtual int drv_width() const=0; //返回显示区域宽度, 即使旋转了也不能影响此函数输出
|
||||
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);
|
||||
}
|
||||
@@ -115,8 +115,6 @@ public:
|
||||
#ifdef MEPD_DEBUG_DISPLAY
|
||||
friend class LGFX;
|
||||
#endif
|
||||
private:
|
||||
int16_t guy_width=0,guy_height=0;
|
||||
};
|
||||
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
|
||||
@@ -73,7 +73,11 @@
|
||||
//#define _DEFINA_SD_CS_PIN 0
|
||||
|
||||
// * for NodeMcu ctg stack LCF board
|
||||
#define WHITE_GAP 8
|
||||
#define WHITE_GAP 2 //白边像素数
|
||||
#define SIMULATE_BLINK 1 //额外的闪屏次数
|
||||
#define SIMULATE_SLOW_REFRESH_DELAY 250 //慢刷延时
|
||||
#define SIMULATE_FAST_REFRESH_DELAY 50 //快刷延时
|
||||
#define SIMULATE_GREYSCALE_COLOUR //仿真灰度时, 读取屏幕像素决定色彩 (更逼真但更慢)
|
||||
|
||||
#ifdef ESP8266
|
||||
#define DISPLAY_TYPE_ST7789_240320 //2.0寸的ST7789 IPS TFT模块
|
||||
|
||||
@@ -38,30 +38,49 @@ void drv::drv_init(){
|
||||
ips.fillScreen(0xffff);
|
||||
}
|
||||
void drv::drv_fullpart(bool part){
|
||||
if(lastRefresh) return;
|
||||
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];
|
||||
unsigned short xbits=(drv_width()+7)/8;
|
||||
ips.startWrite();
|
||||
if(partMode==0){
|
||||
ips.invertDisplay(1);
|
||||
DelayMs(250);
|
||||
DelayMs(SIMULATE_SLOW_REFRESH_DELAY);
|
||||
#if ((SIMULATE_BLINK) > 1)
|
||||
ips.invertDisplay(0);
|
||||
DelayMs(250);
|
||||
DelayMs(SIMULATE_SLOW_REFRESH_DELAY);
|
||||
ips.invertDisplay(1);
|
||||
DelayMs(250);
|
||||
DelayMs(SIMULATE_SLOW_REFRESH_DELAY);
|
||||
#endif
|
||||
#if ((SIMULATE_BLINK) > 0)
|
||||
ips.invertDisplay(0);
|
||||
DelayMs(SIMULATE_SLOW_REFRESH_DELAY);
|
||||
ips.invertDisplay(1);
|
||||
DelayMs(SIMULATE_SLOW_REFRESH_DELAY);
|
||||
#endif
|
||||
ips.invertDisplay(0);
|
||||
}
|
||||
for(int j=0;j<drv_height();j++){
|
||||
for(int i=0;i<xbits;i++){
|
||||
uint_fast8_t readf=f(j*xbits+i);
|
||||
#ifdef SIMULATE_GREYSCALE_COLOUR
|
||||
if(readf == 0xff && i!=xbits-1)
|
||||
#endif
|
||||
ips.drawFastHLine(WHITE_GAP+i*8,WHITE_GAP+j,8,0xffff);
|
||||
else {
|
||||
#ifdef SIMULATE_GREYSCALE_COLOUR
|
||||
else
|
||||
#endif
|
||||
{
|
||||
int lineOK=0;
|
||||
#ifdef SIMULATE_GREYSCALE_COLOUR
|
||||
if(partMode)//注意这里 readrect函数已经自动化实现边界处理了
|
||||
ips.readRect(WHITE_GAP+i*8,WHITE_GAP+j,8,1,dat);
|
||||
else memset(dat,0xff,sizeof(dat));
|
||||
else
|
||||
#endif
|
||||
memset(dat,0xff,sizeof(dat));
|
||||
if(readf == 0x00 && i!=xbits-1){
|
||||
for(int k=0;k<8;k++)
|
||||
if((dat[k]&0x1f)==0x1f) lineOK++;
|
||||
@@ -72,15 +91,23 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
|
||||
}
|
||||
for(int k=0;k<8;k++){
|
||||
if(i==xbits-1 && i*8+k>=drv_width()) break;
|
||||
#ifdef SIMULATE_GREYSCALE_COLOUR
|
||||
if((readf&(0x80>>k)))
|
||||
ips.drawPixel(WHITE_GAP+i*8+k,WHITE_GAP+j,0xffff);
|
||||
else if((dat[k]&0x1f)==0x1f)
|
||||
ips.drawPixel(WHITE_GAP+i*8+k,WHITE_GAP+j,0x1082*(15-depth));
|
||||
#else
|
||||
if(!(readf&(0x80>>k))) {
|
||||
ips.drawPixel(WHITE_GAP+i*8+k,WHITE_GAP+j,0x1082*(15-depth));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
yield();
|
||||
}
|
||||
ips.endWrite();
|
||||
DelayMs(SIMULATE_FAST_REFRESH_DELAY);
|
||||
}
|
||||
void drv::drv_sleep() {}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
int drv_ID() const { return MEPD_DEBUG_DISPLAY; }
|
||||
void drv_init(); //初始化屏幕
|
||||
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() ; //开始屏幕睡眠
|
||||
int drv_width() const { return ips.width()-2*WHITE_GAP; } //返回显示区域宽度
|
||||
int drv_height() const{ return ips.height()-2*WHITE_GAP; } //返回显示区域高度
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @file guy_version.h
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief readguy 版本控制文件.
|
||||
* @version 1.0
|
||||
* @version 1.3.2
|
||||
* @date 2023-09-21
|
||||
|
||||
* @attention
|
||||
@@ -40,10 +40,10 @@
|
||||
//务必保证这些版本号是一致的.
|
||||
//另外, 在提交新版本之前, 不要忘记在github上创建release, 否则Arduino IDE会读不到
|
||||
#define READGUY_V_MAJOR 1
|
||||
#define READGUY_V_MINOR 3
|
||||
#define READGUY_V_MINOR 4
|
||||
#define READGUY_V_PATCH 0
|
||||
#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.4.0"
|
||||
|
||||
#ifdef ESP8266
|
||||
#define _READGUY_PLATFORM "ESP8266"
|
||||
@@ -61,8 +61,8 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define _GITHUB_LINK "github.com/fsender/readguy"
|
||||
#define _BILIBILI_LINK "www.bilibili.com/video/BV1f94y187wz"
|
||||
#define _GITHUB_LINK "https://github.com/fsender/readguy"
|
||||
#define _BILIBILI_LINK "https://www.bilibili.com/video/BV1f94y187wz"
|
||||
|
||||
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
|
||||
@@ -28,15 +28,24 @@
|
||||
*/
|
||||
|
||||
#include "readguy.h"
|
||||
/* #if (!defined(ESP8266)) //for ESP32, ESP32S2, ESP32S3, ESP32C3
|
||||
#include "esp_flash.h"
|
||||
#endif */
|
||||
|
||||
#ifdef READGUY_ESP_ENABLE_WIFI
|
||||
static const PROGMEM char NOT_SUPPORTED[] = "(不支持此屏幕)";
|
||||
static const PROGMEM char TEXT_HTML[] = "text/html";
|
||||
static const PROGMEM char TEXT_PLAIN [] = "text/plain";
|
||||
static const PROGMEM char args_name[23][8]={
|
||||
static const PROGMEM char text_http_methods[8][8]={
|
||||
"UPLOAD", "404", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"
|
||||
};
|
||||
static const HTTPMethod val_http_methods[6]={
|
||||
HTTP_HEAD, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS
|
||||
};
|
||||
static const PROGMEM char args_name[24][8]={
|
||||
"share","epdtype","EpdMOSI","EpdSCLK","Epd_CS","Epd_DC","Epd_RST","EpdBusy",
|
||||
"SD_MISO","SD_MOSI","SD_SCLK","SD_CS","I2C_SDA","I2C_SCL",
|
||||
"btn_cnt","btn1","btn1c","btn2","btn2c","btn3","btn3c","bklight","rtc"
|
||||
"btn_cnt","btn1","btn1c","btn2","btn2c","btn3","btn3c","bklight","rtc","user"
|
||||
};
|
||||
#ifdef READGUY_DEV_154A
|
||||
static const PROGMEM char NAME_guyDev154[]="1.54寸标准";
|
||||
@@ -59,7 +68,7 @@ static const PROGMEM char args_name[23][8]={
|
||||
static const char *NAME_guyDev266=NOT_SUPPORTED;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_213B
|
||||
static const PROGMEM char NAME_guyDev213M21[]="2.13寸三色";
|
||||
static const PROGMEM char NAME_guyDev213M21[]="2.13寸低分辨率版";
|
||||
#else
|
||||
static const char *NAME_guyDev213M21=NOT_SUPPORTED;
|
||||
#endif
|
||||
@@ -98,6 +107,53 @@ static const PROGMEM char args_name[23][8]={
|
||||
#else
|
||||
static const char *NAME_guyDev270_V2=NOT_SUPPORTED;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_213B3C
|
||||
static const PROGMEM char NAME_guyDev213B3C[]="2.13寸三色";
|
||||
#else
|
||||
static const char *NAME_guyDev213B3C=NOT_SUPPORTED;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_266A3C
|
||||
static const PROGMEM char NAME_guyDev266A3C[]="2.66寸三色价签";
|
||||
#else
|
||||
static const char *NAME_guyDev266A3C=NOT_SUPPORTED;
|
||||
#endif
|
||||
|
||||
#ifdef READGUY_DEV_154C
|
||||
static const PROGMEM char NAME_guyDev154M5CoreInk[]="1.54寸Core.Ink";
|
||||
#else
|
||||
static const char *NAME_guyDev154M5CoreInk=NOT_SUPPORTED;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_370B
|
||||
static const PROGMEM char NAME_guyDev370LoRes[]="3.7寸低分版本416x240";
|
||||
#else
|
||||
static const char *NAME_guyDev370LoRes=NOT_SUPPORTED;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_426A
|
||||
static const PROGMEM char NAME_guyDev426HiRes[]="4.26寸GDEQ0426T82高分辨率";
|
||||
#else
|
||||
static const char *NAME_guyDev426HiRes=NOT_SUPPORTED;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_583A
|
||||
static const PROGMEM char NAME_guyDev583Normal[]="5.83寸黑白/三色价签";
|
||||
#else
|
||||
static const char *NAME_guyDev583Normal=NOT_SUPPORTED;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_583B
|
||||
static const PROGMEM char NAME_guyDev583HiResBW[]="5.83寸高分辨率版本";
|
||||
#else
|
||||
static const char *NAME_guyDev583HiResBW=NOT_SUPPORTED;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_750A
|
||||
static const PROGMEM char NAME_guyDev750A3C[]="7.5寸三色价签";
|
||||
#else
|
||||
static const char *NAME_guyDev750A3C=NOT_SUPPORTED;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_1020A
|
||||
static const PROGMEM char NAME_guyDev1020BW[]="10.2寸黑白";
|
||||
#else
|
||||
static const char *NAME_guyDev1020BW=NOT_SUPPORTED;
|
||||
#endif
|
||||
//添加新屏幕型号 add displays here
|
||||
const char *ReadguyDriver::epd_drivers_list[EPD_DRIVERS_NUM_MAX]={
|
||||
NAME_guyDev154, //此处的顺序必须和 guy_epaper_config.h 里面的一样
|
||||
NAME_guyDev154_V2,
|
||||
@@ -110,7 +166,18 @@ const char *ReadguyDriver::epd_drivers_list[EPD_DRIVERS_NUM_MAX]={
|
||||
NAME_guyDev370,
|
||||
NAME_guyDev420Hink,
|
||||
NAME_guyDev420WF,
|
||||
NAME_epdLcd
|
||||
NAME_epdLcd,
|
||||
NAME_guyDev213B3C,
|
||||
NAME_guyDev266A3C,
|
||||
|
||||
NAME_guyDev154M5CoreInk,
|
||||
NAME_guyDev370LoRes,
|
||||
NAME_guyDev426HiRes,
|
||||
NAME_guyDev583Normal,
|
||||
NAME_guyDev583HiResBW,
|
||||
NAME_guyDev750A3C,
|
||||
NAME_guyDev1020BW
|
||||
//添加新屏幕型号 add displays here
|
||||
};
|
||||
//static const char *index_cn_html;
|
||||
//static const uint8_t faviconData[1150];
|
||||
@@ -119,14 +186,19 @@ const char *ReadguyDriver::epd_drivers_list[EPD_DRIVERS_NUM_MAX]={
|
||||
//x==62 -> _
|
||||
//#define R2CHAR(x) (((x)==63)?42:(((x)==62)?95:(((x)>=36)?((x)+61):(((x)>=10)?((x)+55):((x)+48)))))
|
||||
void ReadguyDriver::ap_setup(){
|
||||
return ap_setup("readguy","12345678");
|
||||
}
|
||||
void ReadguyDriver::ap_setup(const char *ssid, const char *pass, int m){
|
||||
//初始化WiFi AP模式, 用于将来的连接WiFi 处于已连接状态下会断开原本的连接
|
||||
WiFi.mode(WIFI_AP);
|
||||
if(m>=0 && m<=3) WiFi.mode((WiFiMode_t)m); //有时候还需要STA+AP或者是一开始就确定好了wifi模式
|
||||
IPAddress local_IP(192,168,4,1);
|
||||
IPAddress gateway(192,168,4,1);
|
||||
IPAddress subnet(255,255,255,0);
|
||||
WiFi.softAPConfig(local_IP, gateway, subnet);
|
||||
WiFi.softAP("readguy","12345678");
|
||||
Serial.println(F("[Guy AP] ap_setup SSID: readguy, Pass: 12345678"));
|
||||
WiFi.softAP(ssid,pass);
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.printf_P(PSTR("[Guy AP] ap_setup SSID: %s, Pass: %s\n"),ssid,pass);
|
||||
#endif
|
||||
}
|
||||
void ReadguyDriver::server_setup(const String ¬ify, const serveFunc *serveFuncs, int funcs){
|
||||
//启动WiFi服务器端, 这样就可以进行配网工作
|
||||
@@ -137,6 +209,7 @@ void ReadguyDriver::server_setup(const String ¬ify, const serveFunc *serveFun
|
||||
sv.on("/pinsetup", HTTP_GET, std::bind(&ReadguyDriver::handlePinSetup ,this));
|
||||
sv.on("/final", HTTP_POST, std::bind(&ReadguyDriver::handleFinalPost,this)); //此时验证已经正确
|
||||
//sv.on("/wifi", HTTP_GET, std::bind(&ReadguyDriver::handleWiFi ,this)); //此时验证已经正确
|
||||
sv.onNotFound(std::bind(&ReadguyDriver::handleNotFound,this)); //处理404的情况
|
||||
guy_notify=notify;
|
||||
sfuncs=funcs; //设置服务函数列表
|
||||
if(sfnames!=nullptr) { delete [] sfnames; delete [] sfevents; } //严防内存泄露
|
||||
@@ -144,7 +217,14 @@ void ReadguyDriver::server_setup(const String ¬ify, const serveFunc *serveFun
|
||||
sfnames=new String[sfuncs];
|
||||
sfevents=new String[sfuncs];
|
||||
for(int i=0;i<sfuncs;i++){ //set-up 第三方库内容, 初始化后即可使用
|
||||
sv.on(serveFuncs[i].event,HTTP_GET,std::bind(serveFuncs[i].func,&sv));
|
||||
int spec = -1;
|
||||
for(int ij=0;ij<8;ij++){ //处理一些HTTP不同类型请求.
|
||||
if(!strcmp_P(serveFuncs[i].linkname.c_str(),text_http_methods[ij])) spec = ij;
|
||||
}
|
||||
if(spec>1) sv.on(serveFuncs[i].event,val_http_methods[spec-2],std::bind(serveFuncs[i].func,&sv));
|
||||
else if(spec==1) sv.onNotFound(std::bind(serveFuncs[i].func,&sv)); //404
|
||||
else if(spec==0) sv.onFileUpload(std::bind(serveFuncs[i].func,&sv)); //文件上传
|
||||
else sv.on(serveFuncs[i].event,HTTP_GET,std::bind(serveFuncs[i].func,&sv));
|
||||
sfnames[i] = serveFuncs[i].linkname;
|
||||
sfevents[i] = serveFuncs[i].event;
|
||||
}
|
||||
@@ -159,13 +239,14 @@ void ReadguyDriver::server_setup(const String ¬ify, const serveFunc *serveFun
|
||||
"Connection: close\r\n\r\n"),89);
|
||||
sv.client().write_P((const char *)faviconData,sizeof(faviconData));
|
||||
});*/
|
||||
sv.onNotFound(std::bind(&ReadguyDriver::handleNotFound,this)); //处理404的情况
|
||||
sv.begin();
|
||||
MDNS.begin("readguy");
|
||||
//MDNS.addService("http","tcp",80);
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.print(F("[Guy server] Done! visit "));
|
||||
if(WiFi.getMode() == WIFI_AP) Serial.println(F("192.168.4.1"));
|
||||
else Serial.println(WiFi.localIP());
|
||||
#endif
|
||||
}
|
||||
bool ReadguyDriver::server_loop(){ //此时等待网页操作完成响应...
|
||||
sv.handleClient();
|
||||
@@ -190,10 +271,16 @@ bool ReadguyDriver::server_loop(){ //此时等待网页操作完成响应...
|
||||
refFlag=3;
|
||||
}
|
||||
if(refFlag!=127) {
|
||||
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);
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.printf_P(PSTR("randch: %d %c\n"),randomch[refFlag],(char)(randomch[refFlag]));
|
||||
#endif
|
||||
drawChar((guy_dev->drv_width()>>1)-46+refFlag*24,(guy_dev->drv_height()>>1)-14,randomch[refFlag],true,false,4);
|
||||
refresh_begin(0);
|
||||
guy_dev->drv_fullpart(1);
|
||||
guy_dev->_display((const uint8_t*)getBuffer());
|
||||
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
|
||||
refresh_end();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
delay(1); //防止触发看门狗
|
||||
@@ -218,29 +305,43 @@ void ReadguyDriver::handleInitPost(){
|
||||
// 此时返回一个文本输入框, 定位到 handleFinalPost 函数
|
||||
uint8_t btn_count_=0;
|
||||
if(READGUY_cali){ //再次初始化已经初始化的东西, 此时需要关闭一些外设什么的
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.println(F("[Guy Pin] Reconfig pins and hardwares..."));
|
||||
#endif
|
||||
READGUY_cali=0;
|
||||
READGUY_sd_ok=0;
|
||||
#if defined(ESP8266)
|
||||
//Esp8266无视SPI的设定, 固定为唯一的硬件SPI (D5=SCK, D6=MISO, D7=MOSI)
|
||||
#ifdef READGUY_ENABLE_SD
|
||||
SDFS.end();//关闭SD卡
|
||||
#endif
|
||||
btnTask.detach();
|
||||
#else
|
||||
#ifdef READGUY_ENABLE_SD
|
||||
SD.end();//关闭SD卡
|
||||
if(sd_spi != epd_spi) { //共线时, 不要删除SD
|
||||
delete sd_spi;
|
||||
sd_spi=nullptr;
|
||||
}
|
||||
#endif
|
||||
vTaskDelete(btn_handle);
|
||||
#endif
|
||||
}
|
||||
config_data[0]=1; //默认只要运行到此处, 就已经初始化好了的
|
||||
for(int i=0;i<23;i++){
|
||||
for(int i=0;i<33;i++){
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.print(F("Argument "));
|
||||
Serial.print(FPSTR(args_name[i]));
|
||||
#endif
|
||||
String a_name = String(FPSTR(args_name[23])) + (i-22);
|
||||
if(i<=22) a_name = FPSTR(args_name[i]);
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.print(a_name);
|
||||
Serial.write(':');
|
||||
if(sv.hasArg(FPSTR(args_name[i]))) {
|
||||
Serial.println(sv.arg(FPSTR(args_name[i])));
|
||||
#endif
|
||||
if(sv.hasArg(a_name)) {
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.println(sv.arg(a_name));
|
||||
#endif
|
||||
if(i<14){ //这12个引脚是不可以重复的, 如果有重复, config_data[0]设为0
|
||||
config_data[i+1] = sv.arg(FPSTR(args_name[i])).toInt();
|
||||
}
|
||||
@@ -252,10 +353,15 @@ void ReadguyDriver::handleInitPost(){
|
||||
else if(i==19&&btn_count_>2) config_data[17]=sv.arg(FPSTR(args_name[19])).toInt()+1;
|
||||
else if(i==20&&btn_count_>2) config_data[17]=-config_data[17];
|
||||
else if(i==21) config_data[18] = sv.arg(FPSTR(args_name[21])).toInt();
|
||||
else if(i==22) config_data[19] = sv.arg(FPSTR(args_name[22])).toInt(); //保留RTC功能
|
||||
else if(i==22) config_data[19] = sv.arg(FPSTR(args_name[22])).toInt(); //现已弃用 RTC 功能.
|
||||
else if(i>22){ //用户数据
|
||||
config_data[i-1] = sv.arg(a_name).toInt();
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.write('\n');
|
||||
#endif
|
||||
if(i==0) READGUY_shareSpi = 0; //有的html响应是没有的.共享SPI默认值为true.
|
||||
else if(i<14) config_data[i+1] = -1;//这12个引脚是不可以重复的, 如果有重复, config_data[0]设为0
|
||||
}
|
||||
@@ -280,7 +386,9 @@ void ReadguyDriver::handleInitPost(){
|
||||
uint8_t ck=checkEpdDriver();
|
||||
if(btn_count_<2) config_data[16]=0;
|
||||
if(btn_count_<3) config_data[17]=0;
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.println(F("[Guy Pin] Config OK. Now init devices."));
|
||||
#endif
|
||||
if(ck>=125) {
|
||||
const char *pNotify[3]={ PSTR("Necessary pin NOT connected."),\
|
||||
PSTR("Pin conflicted."),PSTR("Display not supported.") };
|
||||
@@ -304,25 +412,34 @@ void ReadguyDriver::handleInitPost(){
|
||||
randomch[1] = 48+((rdm>>12)%10);//R2CHAR((rdm>>12)%10);
|
||||
randomch[2] = 48+((rdm>> 6)%10);//R2CHAR((rdm>> 6)%10);
|
||||
randomch[3] = 48+((rdm )%10);//R2CHAR((rdm )%10);
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.print(F("[Guy] rand string: "));
|
||||
for(int i=0;i<4;i++) Serial.write(randomch[i]);
|
||||
Serial.write('\n');
|
||||
Serial.println(F("[Guy] Init EPD...")); //此时引脚io数据已经录入, 如果没有问题, 此处屏幕应当可以显示
|
||||
#endif
|
||||
setEpdDriver(); //尝试初始化屏幕
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.println(F("[Guy] Init details..."));
|
||||
#endif
|
||||
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(); //初始化按钮..
|
||||
//} //尝试初始化按键, 调用后, 若SD卡初始化成功, READGUY_sd_ok的值会变成1
|
||||
drawRect((width()>>1)-46 ,(height()>>1)-14,20,28,0);
|
||||
drawRect((width()>>1)-46+24,(height()>>1)-14,20,28,0);
|
||||
drawRect((width()>>1)-46+48,(height()>>1)-14,20,28,0);
|
||||
drawRect((width()>>1)-46+72,(height()>>1)-14,20,28,0);
|
||||
spibz++;
|
||||
drawRect((guy_dev->drv_width()>>1)-46 ,(guy_dev->drv_height()>>1)-14,20,28,0);
|
||||
drawRect((guy_dev->drv_width()>>1)-46+24,(guy_dev->drv_height()>>1)-14,20,28,0);
|
||||
drawRect((guy_dev->drv_width()>>1)-46+48,(guy_dev->drv_height()>>1)-14,20,28,0);
|
||||
drawRect((guy_dev->drv_width()>>1)-46+72,(guy_dev->drv_height()>>1)-14,20,28,0);
|
||||
refresh_begin(0);
|
||||
guy_dev->drv_fullpart(1);
|
||||
guy_dev->_display((const uint8_t*)getBuffer());
|
||||
spibz--;
|
||||
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
|
||||
refresh_end();
|
||||
#endif
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.println(F("[Guy] Display done!"));
|
||||
#endif
|
||||
READGUY_cali=1; //显示初始化完成
|
||||
}
|
||||
void ReadguyDriver::handlePinSetup(){
|
||||
@@ -453,18 +570,23 @@ 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++){
|
||||
s += F("<br/>");
|
||||
#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]);
|
||||
s += FPSTR(index_cn_html3);
|
||||
s += FPSTR(args_name[i+2]);
|
||||
s += ("\" min=\"-1\" max=\"99\" step=\"1\" value=\"");
|
||||
s += F("\" min=\"-1\" max=\"99\" step=\"1\" value=\"");
|
||||
s += (READGUY_cali?(int)config_data[i+3] :-1);
|
||||
s += F("\"/>");
|
||||
}
|
||||
@@ -491,6 +613,17 @@ void ReadguyDriver::handlePinSetup(){
|
||||
if(i==3) s += (READGUY_cali?(int)READGUY_bl_pin :-1);
|
||||
else s += ((READGUY_cali && config_data[15+i])?(int)abs(config_data[15+i])-1:-1);
|
||||
}
|
||||
for(int i=0;i<10;i++){
|
||||
s += F("\"/><br/>用户数据 ");
|
||||
s += (i+1);
|
||||
s += F("<input type=\"number\" id=\"user");
|
||||
s += (i+1);
|
||||
s += FPSTR(index_cn_html3);
|
||||
s += ("user");
|
||||
s += (i+1);
|
||||
s += F("\" min=\"-1\" max=\"99\" step=\"1\" value=\"");
|
||||
s += (READGUY_cali?(int)config_data[i+22] :-1);
|
||||
} //---------------------------------此部分代码需要配合硬件测试 + 查看网页源代码 才可以实现
|
||||
s += FPSTR(index_cn_html16); //s += (READGUY_cali?(int)0 :-1);
|
||||
sv.send_P(200, TEXT_HTML, (s+FPSTR(end_html)).c_str());
|
||||
}
|
||||
@@ -506,7 +639,12 @@ void ReadguyDriver::handleFinal(){
|
||||
s += F("</h3><hr/>");
|
||||
if(sfuncs>0){
|
||||
s+=F("以下链接来自<b>应用程序</b><br/>"); //换行
|
||||
for(int i=0;i<sfuncs && sfnames[i]!=emptyString;i++){
|
||||
for(int i=0;i<sfuncs;i++){
|
||||
int spec = -1;
|
||||
for(int ij=0;ij<8;ij++){
|
||||
if(!strcmp_P(sfnames[i].c_str(),text_http_methods[ij])) spec = ij;
|
||||
}
|
||||
if(spec != -1 || sfnames[i]==emptyString) continue;
|
||||
s+=F("<a href=\"");
|
||||
s+=sfevents[i];
|
||||
s+=F("\">");
|
||||
@@ -515,6 +653,7 @@ void ReadguyDriver::handleFinal(){
|
||||
}
|
||||
s+=F("<br/><hr/>"); //换行
|
||||
}
|
||||
#ifdef READGUY_ENABLE_SD
|
||||
if(!READGUY_sd_ok) s+=F("SD卡不可用!!!<br/>");
|
||||
#if (defined(ESP8266)) //此函数速度太慢了, 因此删掉不用了
|
||||
/*else{
|
||||
@@ -544,9 +683,10 @@ void ReadguyDriver::handleFinal(){
|
||||
s+=(uint32_t)(SD.usedBytes()/1024);
|
||||
s+=F("KB.<br/>");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
s+=F("当前WiFi模式: ");
|
||||
s+=(WiFi.getMode()==WIFI_STA)?F("正常联网模式"):F("AP配网模式");
|
||||
s+=(WiFi.getMode()==WIFI_AP_STA)?F("热点联网模式"):((WiFi.getMode()==WIFI_STA)?F("正常联网模式"):F("热点配置模式"));
|
||||
s+=F(", IP地址: ");
|
||||
s+=WiFi.localIP().toString();
|
||||
s+=F("<br/>芯片型号: ");
|
||||
@@ -593,7 +733,9 @@ void ReadguyDriver::handleFinal(){
|
||||
//s+=F("<br/>"); //换行
|
||||
sv.send_P(200, TEXT_HTML, (s+FPSTR(end_html)).c_str());
|
||||
if(READGUY_cali == 63){
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.println(F("[Guy NVS] Data saved to NVS."));
|
||||
#endif
|
||||
READGUY_cali = 127;
|
||||
nvs_init();
|
||||
nvs_write();
|
||||
@@ -642,13 +784,13 @@ const PROGMEM char ReadguyDriver::verify_html[] =
|
||||
const PROGMEM char ReadguyDriver::verify2_html[] =
|
||||
"<br/><hr/>完成上述4个操作之后屏幕上将会展现出验证码,输入验证码即可完成硬件配置.<br/></p><form action=\"/fin"
|
||||
"al\" method=\"POST\"><input type=\'text\' name=\'t_verify\' maxlength=\"6";
|
||||
const PROGMEM char ReadguyDriver::verifybtn_html[3][200] = {
|
||||
"一个按键, 操作可能比较繁琐, 但功能还都可以的.<br/>"
|
||||
"点按: 下一个/向下翻页<br/>双击: 上一个/向上翻页<br/>三连击: 返回/切换输入法<br/>长按: 确定/选择",
|
||||
"两个按键, 操作可以满足需求.<br/>"
|
||||
"按键1点按: 下一个/向下翻页<br/>按键1长按: 上一个/向上翻页<br/>按键2点按: 确定/选择<br/>按键2长按: 返回/切换输入法",
|
||||
"三个按键, 操作非常流畅.<br/>"
|
||||
"按键1: 上一个/向上翻页<br/>按键2点按: 确定/选择<br/>按键2长按: 返回/切换输入法<br/>按键3: 下一个/向下翻页"
|
||||
const PROGMEM char ReadguyDriver::verifybtn_html[3][224] = {
|
||||
"一个按键, 功能全保留, 操作可能比较繁琐.<br/>点按:下一个/向下翻页<br/>双击:确定/选择<br/>三连击:返回/退格<br/>"
|
||||
"长按半秒:上一个/向上翻页<br/>点按紧接着长按: 特殊操作",
|
||||
"两个按键, 操作可以满足需求.<br/>按键1点按:下一个/向下翻页<br/>按键1长按:上一个/向上翻页<br/>按键2点按:确定/选"
|
||||
"择<br/>按键2长按:返回/退格<br/>按住按键1点按2:特殊操作",
|
||||
"三个按键, 操作非常方便流畅.<br/>按键1:上一个/向上翻页<br/>按键2点按:确定/选择<br/>按键2长按: 返回/退格<br/>按"
|
||||
"键3:下一个/向下翻页<br/>双击点按2:切换输入法等特殊操作"
|
||||
};
|
||||
const PROGMEM char ReadguyDriver::final_html[] =
|
||||
"欢迎使用 readguy</title></head><body><h1>readguy ";
|
||||
@@ -656,7 +798,7 @@ const PROGMEM char ReadguyDriver::afterConfig_html[] =
|
||||
"配置完成</h1><p>您已完成了初始化工作.现在可以配置WiFi和天气密钥相关内容.<br/></p>"
|
||||
"返回<a href=\"/pinsetup\">引脚设置</a><h3>";
|
||||
const PROGMEM char ReadguyDriver::home_html[]=
|
||||
"欢迎页面</h1>在这里您可以配置属于应用app的内容. <a href=\"/pinsetup\">重新配置引脚</a><h3>";
|
||||
"欢迎页面</h1>在这里您可以配置属于应用app的内容.<h3>";
|
||||
/*
|
||||
const PROGMEM char ReadguyDriver::final2_html[] =
|
||||
"<form action=\"/wifi\" method=\"POST\">WiFi 名称<input type=\'text\' name=\'ssid\' "
|
||||
@@ -665,9 +807,9 @@ const PROGMEM char ReadguyDriver::final2_html[] =
|
||||
"钥<input type=\'text\' name=\'psk\' maxlength=\"63";
|
||||
*/
|
||||
const PROGMEM char ReadguyDriver::end_html[] =
|
||||
"<p>ReadGuy on device " _READGUY_PLATFORM "<br/>Copyright © FriendshipEnder <a href=\""
|
||||
_GITHUB_LINK "\">GitHub</a> <a href=\"" _BILIBILI_LINK "\">Bilibili</"
|
||||
"a><br/>版本: " READGUY_VERSION " ,编译日期: " __DATE__ " " __TIME__ "</p></body></html>";
|
||||
"<p>ReadGuy on device " _READGUY_PLATFORM " <a href=\"/pinsetup\">重新配置引脚</a> <a href=\"/update\">固件更新"
|
||||
"</a><br/>Copyright © FriendshipEnder <a href=\"" _GITHUB_LINK "\">GitHub</a> <a href=\"" _BILIBILI_LINK "\">"
|
||||
"Bilibili</a><br/>版本: " READGUY_VERSION " ,编译日期: " __DATE__ " " __TIME__ "</p></body></html>";
|
||||
/*const PROGMEM uint8_t ReadguyDriver::faviconData[1150]={
|
||||
0x0,0x0,0x1,0x0,0x1,0x0,0x10,0x10,0x0,0x0,0x1,0x0,0x20,0x0,0x68,0x4,0x0,0x0,0x16,0x0,0x0,0x0,0x28,0x0,
|
||||
0x0,0x0,0x10,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x1,0x0,0x20,0x0,0x0,0x0,0x0,0x0,0x40,0x4,0x0,0x0,0x0,0x0,
|
||||
|
||||
680
src/readguy.cpp
680
src/readguy.cpp
@@ -7,7 +7,7 @@
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief readguy 基础功能源代码文件.
|
||||
* @version 1.0
|
||||
* @date 2023-09-21
|
||||
* @date created: 2023-09-21 last modify: 2024-03-11
|
||||
|
||||
* @attention
|
||||
* Copyright (c) 2022-2023 FriendshipEnder
|
||||
@@ -28,16 +28,63 @@
|
||||
*/
|
||||
|
||||
#include "readguy.h"
|
||||
#if (!defined(INPUT_PULLDOWN))
|
||||
/* #if (!defined(ESP8266)) //for ESP32, ESP32S2, ESP32S3, ESP32C3
|
||||
#include "esp32-hal.h"
|
||||
#endif */
|
||||
#if (!defined(INPUT_PULLDOWN)) //not supported pinMode
|
||||
#define INPUT_PULLDOWN INPUT
|
||||
#endif
|
||||
|
||||
guy_button ReadguyDriver::btn_rd[3];
|
||||
int8_t ReadguyDriver::pin_cmx=-1;
|
||||
int8_t ReadguyDriver::pin_cmx=-1;
|
||||
#ifdef READGUY_ALLOW_DC_AS_BUTTON
|
||||
bool ReadguyDriver::refresh_state=1; //1: free; 0: busy(refreshing)
|
||||
uint8_t ReadguyDriver::refresh_press=0x7f; //0x7f: no button pressed other:button pressed pin
|
||||
#endif
|
||||
#ifdef READGUY_ALLOW_EPDCS_AS_BUTTON
|
||||
uint8_t ReadguyDriver::static_epd_cs=0x7f;
|
||||
#endif
|
||||
#ifdef READGUY_ALLOW_SDCS_AS_BUTTON
|
||||
uint8_t ReadguyDriver::static_sd_cs=0x7f;
|
||||
volatile uint8_t ReadguyDriver::sd_cs_busy=0;
|
||||
#endif
|
||||
|
||||
const PROGMEM char ReadguyDriver::projname[8] = "readguy";
|
||||
const PROGMEM char ReadguyDriver::tagname[7] = "hwconf";
|
||||
volatile uint8_t ReadguyDriver::spibz=0;
|
||||
#ifndef DYNAMIC_PIN_SETTINGS
|
||||
const int8_t ReadguyDriver::config_data[32] = {
|
||||
127 , //READGUY_cali
|
||||
READGUY_shareSpi ,
|
||||
READGUY_epd_type ,// 对应的epd驱动程序代号, -1为未指定
|
||||
//显示驱动部分, 显示默认使用vspi (vspi也是默认SPI库的通道)
|
||||
READGUY_epd_mosi ,// 目标显示器的 MOSI 引脚
|
||||
READGUY_epd_sclk ,// 目标显示器的 SCLK 引脚
|
||||
READGUY_epd_cs ,// 目标显示器的 CS 引脚
|
||||
READGUY_epd_dc ,// 目标显示器的 DC 引脚
|
||||
READGUY_epd_rst ,// 目标显示器的 RST 引脚
|
||||
READGUY_epd_busy ,// 目标显示器的 BUSY 引脚
|
||||
//sd卡驱动部分, 默认使用hspi (sd卡建议用hspi)
|
||||
READGUY_sd_miso ,// 目标sd卡的 MISO 引脚, 或esp32s3使用SDIO的 DAT0 引脚, sd_share_spi == 1 时无效
|
||||
READGUY_sd_mosi ,// 目标sd卡的 MOSI 引脚, 或esp32s3使用SDIO的 CMD 引脚, sd_share_spi == 1 时无效
|
||||
READGUY_sd_sclk ,// 目标sd卡的 SCLK 引脚, 或esp32s3使用SDIO的 CLK 引脚, sd_share_spi == 1 时无效
|
||||
READGUY_sd_cs ,// 目标sd卡的 CS 引脚, 或esp32s3使用SDIO的 DAT3 引脚,
|
||||
READGUY_i2c_sda ,// 目标i2c总线的SDA引脚, 当且仅当启用i2c总线时才生效
|
||||
READGUY_i2c_scl ,// 目标i2c总线的SCL引脚, 当且仅当启用i2c总线时才生效
|
||||
//按键驱动部分, 为负代表高触发, 否则低触发,
|
||||
//注意, 这里的io编号是加1的, 即 1或-1 代表 gpio0 的低触发/高触发
|
||||
READGUY_btn1 ,
|
||||
READGUY_btn2 ,
|
||||
READGUY_btn3 ,
|
||||
READGUY_bl_pin ,//前置光接口引脚IO
|
||||
READGUY_rtc_type ,//使用的RTC型号. 现已弃用 RTC 功能. 保留是为了兼容性 让代码更简单维护
|
||||
0 ,//READGUY_sd_ok SD卡已经成功初始化
|
||||
0 ,//READGUY_buttons 按钮个数, 0-3都有可能
|
||||
-1, //用户自定义变量 同时用于esp32s3使用SDIO卡数据的DAT1 为-1代表不使用SDIO
|
||||
-1, //用户自定义变量 同时用于esp32s3使用SDIO卡数据的DAT2
|
||||
-1,-1,-1,-1,-1,-1,-1,-1 //user data 区域, 此功能没啥用就暂时全设定为-1了
|
||||
};
|
||||
#endif
|
||||
#ifndef ESP8266
|
||||
SPIClass *ReadguyDriver::sd_spi =nullptr;
|
||||
SPIClass *ReadguyDriver::epd_spi=nullptr;
|
||||
@@ -46,15 +93,18 @@ TaskHandle_t ReadguyDriver::btn_handle;
|
||||
|
||||
ReadguyDriver::ReadguyDriver(){
|
||||
READGUY_cali = 0; // config_data[0] 的初始值为0
|
||||
#ifdef DYNAMIC_PIN_SETTINGS
|
||||
for(unsigned int i=1;i<sizeof(config_data);i++) config_data[i] = -1;
|
||||
#endif
|
||||
READGUY_sd_ok = 0; //初始默认SD卡未成功初始化
|
||||
READGUY_buttons = 0; //初始情况下没有按钮
|
||||
} //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, bool initSD){
|
||||
if(READGUY_cali==127) //已经初始化过了一次了, 为了防止里面一些volatile的东西出现问题....还是退出吧
|
||||
return 0;
|
||||
return READGUY_sd_ok;
|
||||
#ifdef DYNAMIC_PIN_SETTINGS
|
||||
nvs_init();
|
||||
#if (!defined(INDEV_DEBUG))
|
||||
#if (!defined(READGUY_INDEV_DEBUG))
|
||||
if(!nvs_read()){ //如果NVS没有录入数据, 需要打开WiFiAP模式初始化录入引脚数据
|
||||
#endif
|
||||
#ifdef READGUY_ESP_ENABLE_WIFI
|
||||
@@ -71,26 +121,46 @@ uint8_t ReadguyDriver::init(uint8_t WiFiSet,bool initepd/* ,int g_width,int g_he
|
||||
server_end();
|
||||
if(!WiFiSet) WiFi.mode(WIFI_OFF);
|
||||
fillScreen(1);
|
||||
#else //DYNAMIC_PIN_SETTINGS 已定义 and READGUY_ESP_ENABLE_WIFI 已定义 but NVS无数据, 此时无法配置引脚. 视为halt
|
||||
(void)WiFiSet; //avoid warning
|
||||
nvs_deinit(); //invalid
|
||||
Serial.printf_P(PSTR("[Guy NVS] INVALID pin settings on " _READGUY_PLATFORM " (Readguy lib version " READGUY_VERSION ")!\n"\
|
||||
"Please open guy_driver_config.h and uncomment #define READGUY_ESP_ENABLE_WIFI!\n"\
|
||||
"You can also flash example binary with Wi-Fi, configure pins and re-flash this program.\n"\
|
||||
"System will restart in 5 seconds..."));
|
||||
delay(5000);
|
||||
ESP.restart();
|
||||
#endif
|
||||
#if (!defined(INDEV_DEBUG))
|
||||
#if (!defined(READGUY_INDEV_DEBUG))
|
||||
}
|
||||
else{ //看来NVS有数据, //从NVS加载数据, 哪怕前面的数据刚刚写入, 还没读取
|
||||
#ifdef READGUY_ESP_ENABLE_WIFI
|
||||
if(WiFiSet>=2) WiFi.begin(); //连接到上次存储在flash NVS中的WiFi.
|
||||
else if(WiFiSet==1) ap_setup();
|
||||
else
|
||||
#endif
|
||||
if(WiFiSet==1) ap_setup();
|
||||
if(checkEpdDriver()!=127) setEpdDriver(initepd/* ,g_width,g_height */); //初始化屏幕
|
||||
else for(;;); //此处可能添加程序rollback等功能操作(比如返回加载上一个程序)
|
||||
setSDcardDriver();
|
||||
if(initSD) setSDcardDriver();
|
||||
setButtonDriver();
|
||||
}
|
||||
#endif
|
||||
nvs_deinit();
|
||||
#else
|
||||
(void)WiFiSet; //avoid warning
|
||||
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.
|
||||
}
|
||||
nvs_deinit();
|
||||
#endif
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.println(F("[Guy init] init done."));
|
||||
#endif
|
||||
READGUY_cali=127;
|
||||
return READGUY_sd_ok;
|
||||
}
|
||||
@@ -101,7 +171,9 @@ uint8_t ReadguyDriver::checkEpdDriver(){
|
||||
#else
|
||||
#define TEST_ONLY_VALUE 3
|
||||
#endif
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.printf_P(PSTR("[Guy SPI] shareSpi? %d\n"),READGUY_shareSpi);
|
||||
#endif
|
||||
for(int i=TEST_ONLY_VALUE;i<8;i++){
|
||||
if(i<7 && config_data[i]<0) return 125;//必要的引脚没连接
|
||||
for(int j=1;j<=8-i;j++)
|
||||
@@ -111,47 +183,126 @@ uint8_t ReadguyDriver::checkEpdDriver(){
|
||||
#endif
|
||||
if(guy_dev != nullptr && READGUY_epd_type!=guy_dev->drv_ID()) delete guy_dev; //释放多余的内存
|
||||
//Serial.printf("initing epd %s...\n",epd_drivers_list[READGUY_epd_type]);
|
||||
#ifdef DYNAMIC_PIN_SETTINGS
|
||||
switch (READGUY_epd_type){
|
||||
#ifdef READGUY_DEV_154A
|
||||
case READGUY_DEV_154A: guy_dev = new guydev_154A_290A ::dev154A; break; //适用于一般的价签黑白屏
|
||||
case READGUY_DEV_154A: guy_dev = new guydev_154A_290A ::dev154A; break; //适用于一般的价签黑白屏
|
||||
#endif
|
||||
#ifdef READGUY_DEV_154B
|
||||
case READGUY_DEV_154B: guy_dev = new guydev_154B_270B_290B ::dev154B; break; //适用于
|
||||
case READGUY_DEV_154B: guy_dev = new guydev_154B_270B_290B ::dev154B; break; //适用于
|
||||
#endif
|
||||
#ifdef READGUY_DEV_213A
|
||||
case READGUY_DEV_213A: guy_dev = new guydev_213A ::drv; break;
|
||||
case READGUY_DEV_213A: guy_dev = new guydev_213A ::drv; break;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_266A
|
||||
case READGUY_DEV_266A: guy_dev = new guydev_213B_266A ::dev266A; break;
|
||||
case READGUY_DEV_266A: guy_dev = new guydev_213B_266A ::dev266A; break;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_213B
|
||||
case READGUY_DEV_213B: guy_dev = new guydev_213B_266A ::dev213B; break;
|
||||
case READGUY_DEV_213B: guy_dev = new guydev_213B_266A ::dev213B; break;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_290A
|
||||
case READGUY_DEV_290A: guy_dev = new guydev_154A_290A ::dev290A; break;
|
||||
case READGUY_DEV_290A: guy_dev = new guydev_154A_290A ::dev290A; break;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_290B
|
||||
case READGUY_DEV_290B: guy_dev = new guydev_154B_270B_290B ::dev290B; break;
|
||||
case READGUY_DEV_290B: guy_dev = new guydev_154B_270B_290B ::dev290B; break;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_420A
|
||||
case READGUY_DEV_420A: guy_dev = new guydev_420A ::drv; break;
|
||||
case READGUY_DEV_420A: guy_dev = new guydev_420A ::drv; break;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_420B
|
||||
case READGUY_DEV_420B: guy_dev = new guydev_420B ::drv; break;
|
||||
case READGUY_DEV_420B: guy_dev = new guydev_420B ::drv; break;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_370A
|
||||
case READGUY_DEV_370A: guy_dev = new guydev_370A ::drv; break;
|
||||
case READGUY_DEV_370A: guy_dev = new guydev_370A ::drv; break;
|
||||
#endif
|
||||
#ifdef MEPD_DEBUG_DISPLAY
|
||||
case MEPD_DEBUG_DISPLAY:guy_dev = new EpdLcdDebug ::drv; break;
|
||||
case MEPD_DEBUG_DISPLAY: guy_dev = new EpdLcdDebug ::drv; break;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_270B
|
||||
case READGUY_DEV_270B: guy_dev = new guydev_154B_270B_290B ::dev270B; break;
|
||||
case READGUY_DEV_270B: guy_dev = new guydev_154B_270B_290B ::dev270B; break;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_213B3C
|
||||
case READGUY_DEV_213B3C: guy_dev = new guydev_213B_266A ::dev213B3C; break;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_266A3C
|
||||
case READGUY_DEV_266A3C: guy_dev = new guydev_213B_266A ::dev266A3C; break;
|
||||
#endif
|
||||
|
||||
#ifdef READGUY_DEV_154C
|
||||
case READGUY_DEV_154C: guy_dev = new guydev_154C ::drv; break;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_370B
|
||||
case READGUY_DEV_370B: guy_dev = new guydev_370B ::drv; break;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_426A
|
||||
case READGUY_DEV_426A: guy_dev = new guydev_426A ::drv; break;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_583A
|
||||
case READGUY_DEV_583A: guy_dev = new guydev_583A ::drv; break;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_583B
|
||||
case READGUY_DEV_583B: guy_dev = new guydev_583B ::drv; break;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_750A
|
||||
case READGUY_DEV_750A: guy_dev = new guydev_750A ::drv; break;
|
||||
#endif
|
||||
#ifdef READGUY_DEV_1020A
|
||||
case READGUY_DEV_1020A: guy_dev = new guydev_1020A ::drv; break;
|
||||
#endif
|
||||
//添加新屏幕型号 add displays here
|
||||
default:
|
||||
Serial.println(F("[GUY ERR] EPD DRIVER IC NOT SUPPORTED!\n"));
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.println(F("[Guy Error] EPD DRIVER IC NOT SUPPORTED!\n"));
|
||||
#endif
|
||||
return 127;
|
||||
}
|
||||
#else
|
||||
#if (defined(READGUY_DEV_154A) && (READGUY_epd_type==READGUY_DEV_154A))
|
||||
guy_dev = new guydev_154A_290A ::dev154A; //适用于一般的价签黑白屏
|
||||
#elif (defined(READGUY_DEV_154B) && (READGUY_epd_type==READGUY_DEV_154B))
|
||||
guy_dev = new guydev_154B_270B_290B ::dev154B; //适用于
|
||||
#elif (defined(READGUY_DEV_213A) && (READGUY_epd_type==READGUY_DEV_213A))
|
||||
guy_dev = new guydev_213A ::drv;
|
||||
#elif (defined(READGUY_DEV_266A) && (READGUY_epd_type==READGUY_DEV_266A))
|
||||
guy_dev = new guydev_213B_266A ::dev266A;
|
||||
#elif (defined(READGUY_DEV_213B) && (READGUY_epd_type==READGUY_DEV_213B))
|
||||
guy_dev = new guydev_213B_266A ::dev213B;
|
||||
#elif (defined(READGUY_DEV_290A) && (READGUY_epd_type==READGUY_DEV_290A))
|
||||
guy_dev = new guydev_154A_290A ::dev290A;
|
||||
#elif (defined(READGUY_DEV_290B) && (READGUY_epd_type==READGUY_DEV_290B))
|
||||
guy_dev = new guydev_154B_270B_290B ::dev290B;
|
||||
#elif (defined(READGUY_DEV_420A) && (READGUY_epd_type==READGUY_DEV_420A))
|
||||
guy_dev = new guydev_420A ::drv;
|
||||
#elif (defined(READGUY_DEV_420B) && (READGUY_epd_type==READGUY_DEV_420B))
|
||||
guy_dev = new guydev_420B ::drv;
|
||||
#elif (defined(READGUY_DEV_370A) && (READGUY_epd_type==READGUY_DEV_370A))
|
||||
guy_dev = new guydev_370A ::drv;
|
||||
#elif (defined(MEPD_DEBUG_DISPLAY) && (READGUY_epd_type==MEPD_DEBUG_DISPLAY))
|
||||
guy_dev = new EpdLcdDebug ::drv;
|
||||
#elif (defined(READGUY_DEV_270B) && (READGUY_epd_type==READGUY_DEV_270B))
|
||||
guy_dev = new guydev_154B_270B_290B ::dev270B;
|
||||
#elif (defined(READGUY_DEV_213B3C) && (READGUY_epd_type==READGUY_DEV_213B3C))
|
||||
guy_dev = new guydev_213B_266A ::dev213B3C;
|
||||
#elif (defined(READGUY_DEV_266A3C) && (READGUY_epd_type==READGUY_DEV_266A3C))
|
||||
guy_dev = new guydev_213B_266A ::dev266B3C;
|
||||
|
||||
#elif (defined(READGUY_DEV_154C) && (READGUY_epd_type==READGUY_DEV_154C))
|
||||
guy_dev = new guydev_154C ::drv;
|
||||
#elif (defined(READGUY_DEV_370B) && (READGUY_epd_type==READGUY_DEV_370B))
|
||||
guy_dev = new guydev_370B ::drv;
|
||||
#elif (defined(READGUY_DEV_426A) && (READGUY_epd_type==READGUY_DEV_426A))
|
||||
guy_dev = new guydev_426A ::drv;
|
||||
#elif (defined(READGUY_DEV_583A) && (READGUY_epd_type==READGUY_DEV_583A))
|
||||
guy_dev = new guydev_583A ::drv;
|
||||
#elif (defined(READGUY_DEV_583B) && (READGUY_epd_type==READGUY_DEV_583B))
|
||||
guy_dev = new guydev_583B ::drv;
|
||||
#elif (defined(READGUY_DEV_750A) && (READGUY_epd_type==READGUY_DEV_750A))
|
||||
guy_dev = new guydev_750A ::drv;
|
||||
#elif (defined(READGUY_DEV_1020A) && (READGUY_epd_type==READGUY_DEV_1020A))
|
||||
guy_dev = new guydev_1020A ::drv;
|
||||
#endif
|
||||
//添加新屏幕型号 add displays here
|
||||
#endif
|
||||
#if (defined(ESP8266))
|
||||
SPI.begin();
|
||||
SPI.setFrequency(ESP8266_SPI_FREQUENCY); ///< 1MHz
|
||||
@@ -169,10 +320,12 @@ uint8_t ReadguyDriver::checkEpdDriver(){
|
||||
epd_spi->begin(READGUY_epd_sclk,READGUY_shareSpi?READGUY_sd_miso:-1,READGUY_epd_mosi);
|
||||
guy_dev->IfInit(*epd_spi, READGUY_epd_cs, READGUY_epd_dc, READGUY_epd_rst, READGUY_epd_busy);
|
||||
#endif
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.println(F("[Guy SPI] drvBase Init OK"));
|
||||
#endif
|
||||
return READGUY_epd_type;
|
||||
}
|
||||
void ReadguyDriver::setEpdDriver(bool initepd/* ,int g_width,int g_height */){
|
||||
void ReadguyDriver::setEpdDriver(bool initepd, bool initGFX){
|
||||
guy_dev->spi_tr_release = in_release;
|
||||
guy_dev->spi_tr_press = in_press;
|
||||
if(initepd) guy_dev->drv_init(); //初始化epd驱动层
|
||||
@@ -180,23 +333,26 @@ void ReadguyDriver::setEpdDriver(bool initepd/* ,int g_width,int g_height */){
|
||||
//else guy_width = guy_dev->drv_width(); //宽度必须是8的倍数, 但这个可以由GFX自动计算
|
||||
//if(g_height) guy_height = g_height;
|
||||
//else guy_height = guy_dev->drv_height();
|
||||
Serial.println(F("[Guy EPD] EPD init OK"));
|
||||
//以下依赖于你的图形驱动
|
||||
setColorDepth(1); //单色模式
|
||||
createPalette(); //初始化颜色系统
|
||||
Serial.printf_P(PSTR("[Guy EPD] mono set: w: %d, h: %d\n"),guy_dev->drv_width(),guy_dev->drv_height());
|
||||
//创建画布. 根据LovyanGFX的特性, 如果以前有画布会自动重新生成新画布
|
||||
//此外, 即使画布宽度不是8的倍数(如2.13寸单色),也支持自动补全8的倍数 ( 250x122 => 250x128 )
|
||||
//为了保证图片显示功能的正常使用, 高度也必须是8的倍数.
|
||||
createSprite(guy_dev->drv_width(),(guy_dev->drv_height()+7)&0x7ffffff8);
|
||||
//这里发现如果用自定义的内存分配方式会更好一些. 不会导致返回的height不对. 但是因为LovyanGFX库未更新 暂时不能这么用.
|
||||
//setRotation(1); //旋转之后操作更方便
|
||||
setRotation(0);
|
||||
setFont(&fonts::Font0);
|
||||
setCursor(0,0);
|
||||
setTextColor(0);
|
||||
fillScreen(1); //开始先全屏白色
|
||||
if(initGFX){
|
||||
setColorDepth(1); //单色模式
|
||||
createPalette(); //初始化颜色系统
|
||||
//创建画布. 根据LovyanGFX的特性, 如果以前有画布会自动重新生成新画布
|
||||
//此外, 即使画布宽度不是8的倍数(如2.13寸单色),也支持自动补全8的倍数 ( 250x122 => 250x128 )
|
||||
//为了保证图片显示功能的正常使用, 高度也必须是8的倍数.
|
||||
createSprite(guy_dev->drv_width(),guy_dev->drv_height());
|
||||
//这里发现如果用自定义的内存分配方式会更好一些. 不会导致返回的height不对. 但是因为LovyanGFX库未更新 暂时不能这么用.
|
||||
setRotation(0); //默认的旋转方向就是0咯
|
||||
setFont(&fonts::Font0);
|
||||
setCursor(0,0);
|
||||
setTextColor(0);
|
||||
fillScreen(1); //开始先全屏白色
|
||||
}
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.printf_P(PSTR("[Guy EPD] EPD init OK(%d): w: %d, h: %d\n"),guy_dev->drv_ID(),guy_dev->drv_width(),guy_dev->drv_height());
|
||||
#endif
|
||||
}
|
||||
#ifdef READGUY_ENABLE_SD
|
||||
bool ReadguyDriver::setSDcardDriver(){
|
||||
/*重要信息: 有些引脚冲突是难以避免的, 比如8266 尤其需要重写这部分代码
|
||||
对于esp32也要注意这个引脚是否是一个合法的引脚
|
||||
@@ -209,8 +365,11 @@ bool ReadguyDriver::setSDcardDriver(){
|
||||
#endif
|
||||
&& READGUY_sd_cs!=READGUY_epd_cs && READGUY_sd_cs!=READGUY_epd_dc && READGUY_sd_cs!=READGUY_epd_rst && READGUY_sd_cs!=READGUY_epd_busy
|
||||
){ //SD卡的CS检测程序和按键检测程序冲突, 故删掉 (可能引发引脚无冲突但是显示冲突的bug)
|
||||
#if defined(ESP8266)
|
||||
//Esp8266无视SPI的设定, 固定为唯一的硬件SPI (D5=SCK, D6=MISO, D7=MOSI)
|
||||
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON))
|
||||
setSDbusy(1);
|
||||
#endif
|
||||
#if defined(ESP8266) //Esp8266无视SPI的设定, 固定为唯一的硬件SPI (D5=SCK, D6=MISO, D7=MOSI)
|
||||
SDFS.end();
|
||||
SDFS.setConfig(SDFSConfig(READGUY_sd_cs));
|
||||
READGUY_sd_ok = SDFS.begin();
|
||||
#else
|
||||
@@ -223,11 +382,16 @@ bool ReadguyDriver::setSDcardDriver(){
|
||||
sd_spi->begin(READGUY_sd_sclk,READGUY_sd_miso,READGUY_sd_mosi); //初始化SPI
|
||||
}
|
||||
READGUY_sd_ok = SD.begin(READGUY_sd_cs,*sd_spi,ESP32_SD_SPI_FREQUENCY); //初始化频率为20MHz
|
||||
#endif
|
||||
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON))
|
||||
setSDbusy(0);
|
||||
#endif
|
||||
}
|
||||
else READGUY_sd_ok=0; //引脚不符合规则,或冲突或不可用
|
||||
if(!READGUY_sd_ok){
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.println(F("[Guy SD] SD Init Failed!"));
|
||||
#endif
|
||||
//guyFS().begin(); //初始化内部FS
|
||||
#ifdef READGUY_USE_LITTLEFS
|
||||
LittleFS.begin();
|
||||
@@ -237,9 +401,20 @@ bool ReadguyDriver::setSDcardDriver(){
|
||||
}
|
||||
return READGUY_sd_ok;
|
||||
}
|
||||
#else
|
||||
bool ReadguyDriver::setSDcardDriver(){
|
||||
READGUY_sd_ok=0;
|
||||
#ifdef READGUY_USE_LITTLEFS
|
||||
LittleFS.begin();
|
||||
#else
|
||||
SPIFFS.begin();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
void ReadguyDriver::setButtonDriver(){
|
||||
if(READGUY_btn1) { //初始化按键. 注意高电平触发的引脚在初始化时要设置为下拉
|
||||
int8_t btn_pin=abs(READGUY_btn1)-1;
|
||||
int8_t btn_pin=abs((int)READGUY_btn1)-1;
|
||||
#if defined(ESP8266) //只有ESP8266是支持16引脚pulldown功能的, 而不支持pullup
|
||||
if(btn_pin == 16) pinMode(16,(READGUY_btn1>0)?INPUT:INPUT_PULLDOWN_16);
|
||||
else if(btn_pin < 16 && btn_pin != D5 && btn_pin != D6 && btn_pin != D7)
|
||||
@@ -276,23 +451,38 @@ void ReadguyDriver::setButtonDriver(){
|
||||
|| abs(READGUY_btn3)-1==READGUY_epd_dc ) {
|
||||
pin_cmx=READGUY_epd_dc; //DC引脚复用
|
||||
}
|
||||
#if ((defined (READGUY_ALLOW_EPDCS_AS_BUTTON)) || ((defined(READGUY_ALLOW_SDCS_AS_BUTTON)) && (defined(READGUY_ENABLE_SD))))
|
||||
for(int j=15;j<=17;j++){ //btn1~3
|
||||
#ifdef READGUY_ALLOW_EPDCS_AS_BUTTON
|
||||
if(READGUY_epd_cs == abs(config_data[j])-1) static_epd_cs = READGUY_epd_cs;
|
||||
#endif
|
||||
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON) && defined(READGUY_ENABLE_SD))
|
||||
if(READGUY_sd_cs == abs(config_data[j])-1 && READGUY_sd_cs!=-1) static_sd_cs = READGUY_sd_cs;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
//初始化按钮, 原计划要使用Button2库, 后来发现实在是太浪费内存, 于是决定自己写
|
||||
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_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){
|
||||
btn_rd[0].setMultiBtn(1); //设置为多个按钮,不识别双击或三击
|
||||
btn_rd[0].setLongRepeatMode(1);
|
||||
btn_rd[1].setMultiBtn(1); //设置为多个按钮,不识别双击或三击
|
||||
btn_rd[1].setLongRepeatMode(0);
|
||||
btn_rd[0].enScanDT(0); //不识别双击或三击
|
||||
//btn_rd[0].setLongRepeatMode(1); //双按键 选择按键 设置为允许连按
|
||||
btn_rd[1].enScanDT(0); //不识别双击或三击
|
||||
btn_rd[1].setLongRepeatMode(0); //双按键 确定按键 设置为不允许连按
|
||||
}
|
||||
else if(READGUY_buttons==3){
|
||||
btn_rd[0].setLongPressMs(1); //不识别双击三击, 只有按一下或者长按, 并且开启连按
|
||||
btn_rd[0].setLongRepeatMode(1);
|
||||
btn_rd[1].setMultiBtn(1); //设置为多个按钮,不识别双击或三击
|
||||
btn_rd[1].setLongRepeatMode(0);
|
||||
btn_rd[2].setLongPressMs(1); //不识别双击三击, 只有按一下或者长按, 并且开启连按
|
||||
btn_rd[2].setLongRepeatMode(1);
|
||||
btn_rd[0].long_press_ms = 20; //只有长按, 按一下也是长按,
|
||||
btn_rd[0].double_press_ms = 20; //不识别双击三击,
|
||||
btn_rd[0].setLongRepeatMode(1); //并且开启连按
|
||||
btn_rd[1].enScanDT(0); //不识别双击或三击(默认) 2024/2/25更新:需要支持连按适配拨轮
|
||||
btn_rd[1].setLongRepeatMode(0); //三按键 确定按键 设置为不允许连按
|
||||
btn_rd[2].long_press_ms = 20; //只有长按, 按一下也是长按, 并且开启连按
|
||||
btn_rd[2].double_press_ms = 20; //不识别双击三击,
|
||||
btn_rd[2].setLongRepeatMode(1); //并且开启连按
|
||||
}
|
||||
#ifdef ESP8266 //对于esp8266, 需要注册到ticker. 这是因为没freertos.
|
||||
btnTask.attach_ms(BTN_LOOPTASK_DELAY,looptask);
|
||||
@@ -307,7 +497,7 @@ void ReadguyDriver::setButtonDriver(){
|
||||
btn_rd[0].setLongPressMs(1); //不识别双击三击, 只有按一下或者长按, 并且开启连按
|
||||
btn_rd[0].begin(33,rd_btn_f);
|
||||
btn_rd[0].setLongRepeatMode(1);
|
||||
btn_rd[1].setMultiBtn(1); //设置为多个按钮,不识别双击或三击
|
||||
btn_rd[1].enScanDT(1); //设置为多个按钮,不识别双击或三击
|
||||
btn_rd[1].begin(32,rd_btn_f);
|
||||
btn_rd[1].setLongRepeatMode(0);
|
||||
btn_rd[2].setLongPressMs(1); //不识别双击三击, 只有按一下或者长按, 并且开启连按
|
||||
@@ -341,6 +531,7 @@ void ReadguyDriver::setButtonDriver(){
|
||||
}
|
||||
} //关于按键策略, 我们在此使用多个Button2的类, 然后在一个task共享变量来确定上一个按键状态
|
||||
}
|
||||
#ifdef READGUY_ENABLE_SD
|
||||
fs::FS &ReadguyDriver::guyFS(uint8_t initSD){
|
||||
if(initSD==2 || (!READGUY_sd_ok && initSD)) setSDcardDriver();
|
||||
if(READGUY_sd_ok){
|
||||
@@ -356,6 +547,16 @@ fs::FS &ReadguyDriver::guyFS(uint8_t initSD){
|
||||
return SPIFFS;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
fs::FS &ReadguyDriver::guyFS(uint8_t initSD){
|
||||
(void)initSD; //avoid GCC warning
|
||||
#ifdef READGUY_USE_LITTLEFS
|
||||
return LittleFS;
|
||||
#else
|
||||
return SPIFFS;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
void ReadguyDriver::setBright(int d){
|
||||
if(currentBright>=0 && d>=0 && d<=255){
|
||||
currentBright=d;
|
||||
@@ -370,52 +571,110 @@ void ReadguyDriver::setBright(int d){
|
||||
digitalWrite(READGUY_bl_pin,d?HIGH:LOW);
|
||||
}
|
||||
}
|
||||
void ReadguyDriver::display(bool part){
|
||||
void ReadguyDriver::display(uint8_t part){
|
||||
//真的是我c++的盲区了啊....搜索了半天才找到可以这么玩的
|
||||
//......可惜'dynamic_cast' not permitted with -fno-rtti
|
||||
// static bool _part = 0; 记忆上次到底是full还是part, 注意启动时默认为full
|
||||
if(READGUY_cali==127){
|
||||
part = refresh_begin(part);
|
||||
//in_press(); //暂停, 然后读取按键状态 spibz
|
||||
guy_dev->drv_fullpart(part);
|
||||
guy_dev->_display((const uint8_t*)getBuffer());
|
||||
guy_dev->drv_fullpart(part&1);
|
||||
guy_dev->_display((const uint8_t*)getBuffer(),((part>>1)?part>>1:3));
|
||||
//in_release(); //恢复
|
||||
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
|
||||
refresh_end();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
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){
|
||||
part = refresh_begin(part);
|
||||
//in_press(); //暂停, 然后读取按键状态 spibz
|
||||
guy_dev->drv_fullpart(part);
|
||||
guy_dev->drv_dispWriter(f);
|
||||
guy_dev->drv_fullpart(part&1);
|
||||
epdPartRefresh++;
|
||||
guy_dev->_display(buf,((part>>1)?part>>1:3));
|
||||
//in_release(); //恢复
|
||||
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
|
||||
refresh_end();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
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);
|
||||
void ReadguyDriver::display(std::function<uint8_t(int)> f, uint8_t part){
|
||||
if(READGUY_cali==127){
|
||||
part = refresh_begin(part);
|
||||
//in_press(); //暂停, 然后读取按键状态 spibz
|
||||
guy_dev->drv_fullpart(part&1);
|
||||
guy_dev->drv_dispWriter(f,((part>>1)?part>>1:3));
|
||||
//in_release(); //恢复
|
||||
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
|
||||
refresh_end();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
void ReadguyDriver::drawImageStage(LGFX_Sprite &spr,uint16_t x,uint16_t y,uint8_t stage,
|
||||
uint8_t totalstage,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) {
|
||||
refresh_begin(0);
|
||||
guy_dev->drv_drawImage(base, spr, x, y, 0, zoomw, zoomh);
|
||||
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
|
||||
refresh_end();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
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;
|
||||
guy_dev->drv_drawImage(*this, spr, x, y, (totalstage<=1)?0:(stage==0?1:(stage==(totalstage-1)?3:2)),zoomw,zoomh);
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.printf_P(PSTR("[Guy Draw] stage: %d/%d\n"),stage+1,totalstage);
|
||||
#endif
|
||||
refresh_begin(0);
|
||||
guy_dev->drv_drawImage(sprbase, spr, x, y, (totalstage<=1)?0:(stage==0?1:(stage==(totalstage-1)?3:2)),zoomw,zoomh);
|
||||
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
|
||||
refresh_end();
|
||||
#endif
|
||||
}
|
||||
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()) {
|
||||
// refresh_begin(0);
|
||||
if(d==0 || d>15) { d=15; } //invalid. set to default value 15.
|
||||
guy_dev->drv_setDepth(d);
|
||||
current_depth = d;
|
||||
//#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
|
||||
// refresh_end();
|
||||
//#endif
|
||||
}
|
||||
}
|
||||
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;
|
||||
refresh_begin(0);
|
||||
if(guy_dev->drv_supportGreyscaling() && (spr.getColorDepth()&0xff)>1)
|
||||
return guy_dev->drv_draw16grey(*this,spr,x,y,zoomw,zoomh);
|
||||
guy_dev->drv_drawImage(*this, spr, x, y, 0, zoomw, zoomh);
|
||||
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
|
||||
refresh_end();
|
||||
#endif
|
||||
}
|
||||
void ReadguyDriver::draw16greyStep(int step){
|
||||
if(READGUY_cali==127 && guy_dev->drv_supportGreyscaling() && step>0 && step<16 ){
|
||||
if(step==1) guy_dev->drv_fullpart(1);
|
||||
if(step==1) {
|
||||
refresh_begin(0);
|
||||
guy_dev->drv_fullpart(1);
|
||||
}
|
||||
guy_dev->drv_draw16grey_step((const uint8_t *)this->getBuffer(),step);
|
||||
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
|
||||
if(step>=15) refresh_end();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
void ReadguyDriver::draw16greyStep(std::function<uint8_t(int)> f, int step){
|
||||
if(READGUY_cali==127 && guy_dev->drv_supportGreyscaling() && step>0 && step<16 ){
|
||||
if(step==1) guy_dev->drv_fullpart(1);
|
||||
if(step==1) {
|
||||
refresh_begin(0);
|
||||
guy_dev->drv_fullpart(1);
|
||||
}
|
||||
guy_dev->drv_draw16grey_step(f,step);
|
||||
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
|
||||
if(step>=15) refresh_end();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
void ReadguyDriver::invertDisplay(){
|
||||
@@ -426,11 +685,100 @@ void ReadguyDriver::invertDisplay(){
|
||||
}
|
||||
}
|
||||
void ReadguyDriver::sleepEPD(){
|
||||
if(READGUY_cali==127) guy_dev->drv_sleep();
|
||||
if(READGUY_cali==127) {
|
||||
if(READGUY_bl_pin>=0) digitalWrite(READGUY_bl_pin, LOW); //关闭背光灯, 节省电量
|
||||
guy_dev->drv_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
#if (!defined(DYNAMIC_PIN_SETTINGS)) //do nothing here.
|
||||
#elif (defined(INDEV_DEBUG))
|
||||
uint8_t ReadguyDriver::refresh_begin(uint8_t freshType){
|
||||
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
|
||||
if(refresh_state){
|
||||
refresh_state=0;
|
||||
refresh_press = 0x7f; //clear state
|
||||
for(uint8_t i=0;i<3;i++){ //修复老旧硬件 按键和DC引脚冲突
|
||||
bool flag = 0;
|
||||
if(config_data[15+i] == 0) break;
|
||||
int ipin = abs((int)config_data[15+i])-1;
|
||||
if(ipin == (int)READGUY_epd_dc){ //旨在解决部分老旧硬件共用DC引脚
|
||||
while(btn_rd[i].isPressedRaw() == ((int)config_data[15+i] > 0)) { //这里需要按下的状态
|
||||
flag = 1;
|
||||
yield();
|
||||
}
|
||||
if(flag) {
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.printf_P(PSTR("[Guy Pin] refresh_begin pin %d mode output\n"), READGUY_epd_dc);
|
||||
#endif //等待恢复到按键空闲电平 btn>0 代表低电平按下, 此时右边为1 btn<0 代表高电平按下
|
||||
delay(btn_rd[i].min_debounce); //去抖动
|
||||
//#ifdef ESP8266
|
||||
// btnTask.detach();//暂时关闭任务, 避免引脚被设置为非法模式
|
||||
//#else
|
||||
// vTaskSuspend(btn_handle);//暂时关闭任务, 避免引脚被设置为非法模式
|
||||
//#endif
|
||||
spibz|=0x40; //set bit at 0x40
|
||||
refresh_press = i;
|
||||
//pinMode((uint8_t)READGUY_epd_dc, OUTPUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if((freshType&1)==1){ //隶属于快刷的范畴, 计数+1
|
||||
if(epdPartRefresh >= epdForceFull) {
|
||||
epdPartRefresh = 0;
|
||||
return (freshType & 0xfe);
|
||||
}
|
||||
else {
|
||||
if(!epdPartRefresh) guy_dev->drv_setDepth(current_depth); //慢刷完成后的首次快刷, 保存上次的刷新颜色深度
|
||||
if(epdPartRefresh<0x7ffe) epdPartRefresh++;
|
||||
}
|
||||
}
|
||||
else epdPartRefresh = 0; //全刷, 重置计数器
|
||||
return freshType;
|
||||
}
|
||||
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
|
||||
void ReadguyDriver::refresh_end(){
|
||||
#ifdef READGUY_ALLOW_DC_AS_BUTTON
|
||||
//for(uint8_t i=15;i<=17;i++){ //修复老旧硬件 按键和DC引脚冲突
|
||||
// if(config_data[i] == 0) break;
|
||||
// int ipin = abs((int)config_data[i])-1;
|
||||
if(refresh_press != 0x7f && !refresh_state){ //旨在解决部分老旧硬件共用DC引脚的bug
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.printf_P(PSTR("[Guy Pin] refresh_end pin %d\n"), READGUY_epd_dc);
|
||||
#endif //pinMode((uint8_t)READGUY_epd_dc, INPUT_PULLUP);
|
||||
spibz&=0x3f; //reset bit at 0x40
|
||||
//#ifdef ESP8266
|
||||
// btnTask.attach_ms(BTN_LOOPTASK_DELAY,looptask);
|
||||
//#else
|
||||
// vTaskResume(btn_handle);
|
||||
//#endif //开启任务后, 延时确保按键任务可以活跃而不是一直处于被暂停又刷屏的无限循环
|
||||
delay((BTN_LOOPTASK_DELAY+btn_rd[refresh_press].min_debounce)*2);
|
||||
}
|
||||
refresh_state = 1;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
void ReadguyDriver::setAutoFullRefresh(int16_t frames){
|
||||
//epdPartRefresh = frames<0?-frames:0;
|
||||
if(frames<0) epdPartRefresh = -frames;
|
||||
if(frames) {
|
||||
epdForceFull = (frames<0?-frames:frames);
|
||||
}
|
||||
else {
|
||||
epdForceFull = 0x7fff;
|
||||
}
|
||||
}
|
||||
#ifdef ESP8266
|
||||
void ReadguyDriver::recoverI2C(){
|
||||
if(READGUY_cali!=127) return;
|
||||
for(int i=13;i<=14;i++){ // READGUY_i2c_scl == config_data[14]; READGUY_i2c_sda == config_data[13];
|
||||
if(config_data[i] == 12 || config_data[i] == 13 || config_data[i] == 14) pinMode(config_data[i], SPECIAL);
|
||||
for(int j=15;j<=17;j++){ // READGUY_btn1 == config_data[15]; b2 == config_data[15]; b3== config_data[17];
|
||||
if(config_data[i] == abs((int)config_data[j])-1) pinMode(config_data[i], config_data[j]>0?INPUT_PULLUP:INPUT_PULLDOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if (defined(READGUY_INDEV_DEBUG))
|
||||
void ReadguyDriver::nvs_init(){
|
||||
}
|
||||
void ReadguyDriver::nvs_deinit(){
|
||||
@@ -442,7 +790,7 @@ void ReadguyDriver::nvs_write(){
|
||||
}
|
||||
#elif (defined(ESP8266))
|
||||
void ReadguyDriver::nvs_init(){
|
||||
EEPROM.begin(32);
|
||||
EEPROM.begin(sizeof(config_data)+8+READGUY_ESP8266_EEPROM_OFFSET);
|
||||
}
|
||||
void ReadguyDriver::nvs_deinit(){
|
||||
EEPROM.commit();
|
||||
@@ -450,17 +798,26 @@ void ReadguyDriver::nvs_deinit(){
|
||||
}
|
||||
bool ReadguyDriver::nvs_read(){
|
||||
char s[8];
|
||||
for(unsigned int i=0;i<sizeof(config_data)+8;i++){
|
||||
int8_t rd=(int8_t)EEPROM.read(2+i);
|
||||
for(unsigned int i=0;i<
|
||||
#ifdef DYNAMIC_PIN_SETTINGS
|
||||
sizeof(config_data)+
|
||||
#endif
|
||||
8;i++){
|
||||
int8_t rd=(int8_t)EEPROM.read(READGUY_ESP8266_EEPROM_OFFSET+i);
|
||||
#ifdef DYNAMIC_PIN_SETTINGS
|
||||
if(i>=8) config_data[i-8] = rd;
|
||||
else s[i]=(char)rd;
|
||||
else
|
||||
#endif
|
||||
s[i]=(char)rd;
|
||||
}
|
||||
Serial.printf("[Guy NVS] Get NVS...%d\n", config_data[0]);
|
||||
#ifdef READGUY_SERIAL_DEBUG
|
||||
Serial.printf_P(PSTR("[Guy NVS] ReadGuy Ver " READGUY_VERSION " on " _READGUY_PLATFORM " Get EEPROM...%d\n"), config_data[0]);
|
||||
#endif
|
||||
return !(strcmp_P(s,projname));
|
||||
}
|
||||
void ReadguyDriver::nvs_write(){
|
||||
for(unsigned int i=0;i<sizeof(config_data)+8;i++){
|
||||
EEPROM.write(2+i,(uint8_t)(i<8?pgm_read_byte(projname+i):config_data[i-8]));
|
||||
EEPROM.write(READGUY_ESP8266_EEPROM_OFFSET+i,(uint8_t)(i<8?pgm_read_byte(projname+i):config_data[i-8]));
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -472,6 +829,7 @@ void ReadguyDriver::nvs_deinit(){
|
||||
}
|
||||
bool ReadguyDriver::nvs_read(){ //此处需要处理一些有关I2C的内容
|
||||
if(!nvsData.isKey(tagname)) return 0; //没有这个键值
|
||||
#ifdef DYNAMIC_PIN_SETTINGS
|
||||
size_t len=nvsData.getBytes(tagname,config_data,sizeof(config_data)); //读取的数据长度
|
||||
/*if(len<sizeof(config_data)){ //旧版本格式无法获取I2C相关数据, 设置为-1.
|
||||
for(int i=sizeof(config_data)-1;i>=15;i--) //使用新版本格式来存储相关数据
|
||||
@@ -481,6 +839,9 @@ bool ReadguyDriver::nvs_read(){ //此处需要处理一些有关I2C的内容
|
||||
nvsData.putBytes(tagname,config_data,sizeof(config_data)); //用新版本格式保存
|
||||
}*/
|
||||
return len==sizeof(config_data);
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
void ReadguyDriver::nvs_write(){
|
||||
if(nvsData.isKey(tagname)) nvsData.remove(tagname);
|
||||
@@ -489,31 +850,70 @@ void ReadguyDriver::nvs_write(){
|
||||
#endif
|
||||
|
||||
uint8_t ReadguyDriver::getBtn_impl(){ //按钮不可用, 返回0.
|
||||
static unsigned long last=0;
|
||||
static unsigned long last2=0;
|
||||
uint8_t res1,res2,res3,res4=0;
|
||||
switch(READGUY_buttons){
|
||||
case 1:
|
||||
res1=btn_rd[0].read();
|
||||
if(res1 == 1) res4 |= 1; //点按
|
||||
else if(res1 == 2) res4 |= 2; //双击
|
||||
else if(res1 == 4) res4 |= 4; //长按-确定
|
||||
else if(res1 == 2) res4 |= 4; //双击-确定
|
||||
else if(res1 == 3) res4 |= 8; //三击-返回
|
||||
else if(res1 == 4) res4 |= 2; //长按-向上翻页
|
||||
else if(res1 == 5) res4 |= 3; //单击后长按-新增操作(可以连按)
|
||||
break;
|
||||
case 2:
|
||||
res1=btn_rd[0].read(); //两个按钮引脚都读取
|
||||
res2=btn_rd[1].read();
|
||||
if(res1 == 1) res4 |= 1; //左键点按-向下翻页
|
||||
else if(res1 == 4) res4 |= 2; //左键长按-向上翻页
|
||||
if(res2 == 1) res4 |= 4; //右键点按-确定
|
||||
else if(res2 == 4) res4 |= 8; //右键长按-返回
|
||||
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; //左键点按-向下翻页
|
||||
}
|
||||
}
|
||||
//#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;
|
||||
}
|
||||
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;
|
||||
case 3:
|
||||
res1=btn_rd[0].read();
|
||||
res2=btn_rd[1].read();
|
||||
res3=btn_rd[2].read();
|
||||
if(res1 == 4) res4 |= 1;
|
||||
if(res3 == 4) res4 |= 2;
|
||||
if(res1 && millis()-last >= btn_rd[1].long_repeat_ms && (!btn_rd[2].isPressedRaw())) 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;
|
||||
else if(res2 == 4) res4 |= 8;
|
||||
else if(res2 == 2) res4 |= 3; //新增: 双击进入操作5
|
||||
break;
|
||||
}
|
||||
return res4;
|
||||
@@ -523,19 +923,109 @@ void ReadguyDriver::looptask(){ //均为类内静态数据
|
||||
btn_rd[1].loop();
|
||||
btn_rd[2].loop();
|
||||
}
|
||||
bool ReadguyDriver::screenshot(const char *filename){
|
||||
#ifdef READGUY_ENABLE_SD
|
||||
if(!SDinside(false)) return 0;
|
||||
uint16_t ibytes = ((width()+31)>>3)&0x7ffcu; //必须是4的倍数
|
||||
uint16_t bmpHeader[] = { //0x3e == 62 字节
|
||||
0x4d42, //[ 0]字符BM, 固定文件头
|
||||
0x0f7e,0,0,0, //[ 1]File Size 文件总大小 文件大小0x0f7e == 3966; 位图数据大小32*122 == 3904
|
||||
0x003e,0, //[ 5]Bitmap Data Offset (BDO) 信息头到数据段的字节数 (索引到0x3e后的第一个数据就是位图字节数据)
|
||||
0x0028,0, //[ 7]Bitmap Header Size (BHS) 信息头长度
|
||||
0x00fa,0, //[ 9]宽度 0xfa == 250
|
||||
0x007a,0, //[11]高度 0x7a == 122
|
||||
0x01, //[13]Planes 位面数(图层数) 锁定为1
|
||||
0x01, //[14]Bits Per Pixel (BPP) 每像素位数 (1bit/pixel)
|
||||
0,0, //[15]Compression 压缩方法 压缩说明:0-无压缩
|
||||
0x0f40,0, //[17]Bitmap Data Size 位图数据的字节数。该数必须是4的倍数 0x0f40 == 3904 == 32*122
|
||||
0x0ec4,0, //[19]Horizontal Resolution 水平分辨率 0x0ec4==3780 (pixel/metre)==96.012 (pixel/inch)
|
||||
0x0ec4,0, //[21]Vertical Resolution 水平分辨率 0x0ec4==3780 (pixel/metre)==96.012 (pixel/inch)
|
||||
0,0, //[23]Colours 位图使用的所有颜色数。为0表示使用 2^比特数 种颜色 如8-比特/像素表示为100h或者 256.
|
||||
0,0, //[25]Important Colours 指定重要的色彩数。当该域的值等于色彩数或者等于0时,表示所有色彩都一样重要
|
||||
0,0, //[27]重要颜色 0: 黑色 (#000000) R0 G0 B0 X0
|
||||
0xffff,0xff //[29]重要颜色 1: 白色 (#ffffff) R255 G255 B255 X0
|
||||
};
|
||||
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON))
|
||||
setSDbusy(1);
|
||||
#endif
|
||||
File bmpf = guyFS().open(filename,"w");
|
||||
if(!bmpf) {
|
||||
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON))
|
||||
setSDbusy(0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
uint32_t datsz = ibytes * height();
|
||||
bmpHeader[ 1] = (datsz + sizeof(bmpHeader)) & 0xffffu;
|
||||
bmpHeader[ 2] = (datsz + sizeof(bmpHeader)) >> 16;
|
||||
bmpHeader[ 9] = width();
|
||||
bmpHeader[11] = height();
|
||||
bmpHeader[17] = datsz & 0xffffu;
|
||||
bmpHeader[18] = datsz >> 16;
|
||||
bmpf.write((uint8_t*)bmpHeader,sizeof(bmpHeader));
|
||||
uint8_t *byteWrite = new uint8_t [ibytes];
|
||||
for(int h=bmpHeader[11]-1;h>=0;h--){ //bmpHeader[11] == tft->height()
|
||||
for(uint16_t i=0;i<ibytes;i++) byteWrite[i] = 0; //ibytes == (tft->width()+7)>>3
|
||||
for(uint16_t w=0;w<=bmpHeader[9];w++){ //bmpHeader[ 9] == tft->width()
|
||||
byteWrite[w>>3] |= !!(readPixel(w,h))<<((w&7)^7);
|
||||
}
|
||||
bmpf.write(byteWrite,ibytes);
|
||||
yield();
|
||||
}
|
||||
bmpf.close();
|
||||
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON))
|
||||
setSDbusy(0);
|
||||
#endif
|
||||
delete [] byteWrite; //释放内存
|
||||
//bmpf = guyFS().open(filename,"r");
|
||||
//if(!bmpf || bmpf.size()!=datsz + sizeof(bmpHeader) || bmpf.peek() != 0x42) return 0; //检查
|
||||
//bmpf.close();
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t ReadguyDriver::rd_btn_f(uint8_t btn){
|
||||
uint8_t ReadguyDriver::rd_btn_f(uint8_t btn, bool activeLow){
|
||||
static uint8_t lstate=0; //上次从dc引脚读到的电平
|
||||
#ifdef ESP8266
|
||||
if(btn==ReadguyDriver::pin_cmx && spibz) return lstate;
|
||||
if(btn==D5||btn==D6||btn==D7||btn==ReadguyDriver::pin_cmx)
|
||||
pinMode(btn,INPUT_PULLUP);//针对那些复用引脚做出的优化
|
||||
if(btn==ReadguyDriver::pin_cmx && ReadguyDriver::spibz) return lstate;
|
||||
#ifdef READGUY_ALLOW_EPDCS_AS_BUTTON
|
||||
static uint8_t epdcsstate=0; //上次从epd_cs引脚读到的电平
|
||||
if(btn==ReadguyDriver::static_epd_cs && ReadguyDriver::spibz) return epdcsstate;
|
||||
#endif
|
||||
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON) && defined(READGUY_ENABLE_SD))
|
||||
static uint8_t sdcsstate=0; //上次从sd_cs引脚读到的电平
|
||||
if(btn==ReadguyDriver::static_sd_cs && ReadguyDriver::sd_cs_busy) return sdcsstate;
|
||||
#endif
|
||||
if(btn==D5||btn==D6||btn==D7||btn==ReadguyDriver::pin_cmx
|
||||
#ifdef READGUY_ALLOW_EPDCS_AS_BUTTON
|
||||
|| btn==ReadguyDriver::static_epd_cs
|
||||
#endif
|
||||
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON) && defined(READGUY_ENABLE_SD))
|
||||
|| btn==ReadguyDriver::static_sd_cs
|
||||
#endif
|
||||
)
|
||||
pinMode(btn,activeLow?INPUT_PULLUP:INPUT_PULLDOWN);//针对那些复用引脚做出的优化
|
||||
uint8_t readb = digitalRead(btn);
|
||||
if(btn==ReadguyDriver::pin_cmx) {
|
||||
if(btn==ReadguyDriver::pin_cmx
|
||||
#ifdef READGUY_ALLOW_EPDCS_AS_BUTTON
|
||||
|| btn==ReadguyDriver::static_epd_cs
|
||||
#endif
|
||||
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON) && defined(READGUY_ENABLE_SD))
|
||||
|| btn==ReadguyDriver::static_sd_cs
|
||||
#endif
|
||||
) {
|
||||
//Serial.printf("rd D1.. %d\n",spibz);
|
||||
pinMode(btn,OUTPUT); //如果有复用引脚, 它们的一部分默认需要保持输出状态, 比如复用的DC引脚
|
||||
digitalWrite(btn,HIGH); //这些引脚的默认电平都是高电平
|
||||
lstate = readb;
|
||||
if(btn==ReadguyDriver::pin_cmx) lstate = readb;
|
||||
#ifdef READGUY_ALLOW_EPDCS_AS_BUTTON
|
||||
else if(btn==ReadguyDriver::static_epd_cs) epdcsstate = readb;
|
||||
#endif
|
||||
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON) && defined(READGUY_ENABLE_SD))
|
||||
else if(btn==ReadguyDriver::static_sd_cs) sdcsstate = readb;
|
||||
#endif
|
||||
}
|
||||
else if(btn==D5||btn==D6||btn==D7) pinMode(btn,SPECIAL); //针对SPI引脚进行专门的优化
|
||||
return readb;
|
||||
@@ -543,7 +1033,7 @@ uint8_t ReadguyDriver::rd_btn_f(uint8_t btn){
|
||||
if(btn!=ReadguyDriver::pin_cmx)
|
||||
return digitalRead(btn);
|
||||
if(spibz) return lstate;
|
||||
pinMode(btn,INPUT_PULLUP);
|
||||
pinMode(btn,activeLow?INPUT_PULLUP:INPUT_PULLDOWN);
|
||||
uint8_t readb = digitalRead(btn);
|
||||
pinMode(btn,OUTPUT);
|
||||
digitalWrite(btn,HIGH);
|
||||
|
||||
309
src/readguy.h
309
src/readguy.h
@@ -49,7 +49,8 @@
|
||||
#ifdef READGUY_DEV_213A
|
||||
#include "guy_epaper/guy_213a/guy_213a.h"
|
||||
#endif
|
||||
#if (defined(READGUY_DEV_213B) || defined(READGUY_DEV_266A))
|
||||
#if (defined(READGUY_DEV_213B) || defined(READGUY_DEV_213B3C) \
|
||||
|| defined(READGUY_DEV_266A) || defined(READGUY_DEV_266A3C))
|
||||
#include "guy_epaper/guy_213b_266a/guy_213b_266a.h"
|
||||
#endif
|
||||
#ifdef READGUY_DEV_370A
|
||||
@@ -65,6 +66,29 @@
|
||||
#include "guy_epaper/lcdDebug/lcdDebug.h"
|
||||
#endif
|
||||
|
||||
#ifdef READGUY_DEV_154C
|
||||
#include "guy_epaper/guy_154C/guy_154C.h"
|
||||
#endif
|
||||
#ifdef READGUY_DEV_370B
|
||||
#include "guy_epaper/guy_370B/guy_370B.h"
|
||||
#endif
|
||||
#ifdef READGUY_DEV_426A
|
||||
#include "guy_epaper/guy_426A/guy_426A.h"
|
||||
#endif
|
||||
#ifdef READGUY_DEV_583A
|
||||
#include "guy_epaper/guy_583A/guy_583A.h"
|
||||
#endif
|
||||
#ifdef READGUY_DEV_583B
|
||||
#include "guy_epaper/guy_583B/guy_583B.h"
|
||||
#endif
|
||||
#ifdef READGUY_DEV_750A
|
||||
#include "guy_epaper/guy_750A/guy_750A.h"
|
||||
#endif
|
||||
#ifdef READGUY_DEV_1020A
|
||||
#include "guy_epaper/guy_1020A/guy_1020A.h"
|
||||
#endif
|
||||
//添加新屏幕型号 add displays here
|
||||
|
||||
#include "guy_button.h" //改自Button2精简而来
|
||||
#include "guy_version.h"
|
||||
#include "guy_driver_config.h" //config
|
||||
@@ -77,28 +101,28 @@
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266) //for ESP8266
|
||||
#ifdef DYNAMIC_PIN_SETTINGS
|
||||
#include <EEPROM.h> //ESP32需要NVS才可以读取引脚信息
|
||||
#endif
|
||||
#include <EEPROM.h> //ESP32需要NVS才可以读取引脚信息,
|
||||
#ifdef READGUY_ESP_ENABLE_WIFI
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#include <ESP8266mDNS.h>
|
||||
#include "ESP8266HTTPUpdateServer.h"
|
||||
#endif
|
||||
#ifdef READGUY_ENABLE_SD
|
||||
#include <SDFS.h>
|
||||
#endif
|
||||
#include <Ticker.h>
|
||||
#else //for ESP32
|
||||
#ifdef DYNAMIC_PIN_SETTINGS
|
||||
#include <Preferences.h> //ESP32需要NVS才可以读取引脚信息
|
||||
#endif
|
||||
#ifdef READGUY_ESP_ENABLE_WIFI
|
||||
#include <WiFi.h>
|
||||
#include <WebServer.h>
|
||||
#include <ESPmDNS.h>
|
||||
#include "HTTPUpdateServer.h"
|
||||
#endif
|
||||
#ifdef READGUY_ENABLE_SD
|
||||
#include <SD.h>
|
||||
#endif
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#endif
|
||||
@@ -115,10 +139,10 @@
|
||||
#define READGUY_epd_rst (config_data[7]) // 目标显示器的 RST 引脚
|
||||
#define READGUY_epd_busy (config_data[8]) // 目标显示器的 BUSY 引脚
|
||||
//sd卡驱动部分, 默认使用hspi (sd卡建议用hspi)
|
||||
#define READGUY_sd_miso (config_data[9]) // 目标sd卡的 MISO 引脚, sd_share_spi == 1 时无效
|
||||
#define READGUY_sd_mosi (config_data[10])// 目标sd卡的 MOSI 引脚, sd_share_spi == 1 时无效
|
||||
#define READGUY_sd_sclk (config_data[11])// 目标sd卡的 SCLK 引脚, sd_share_spi == 1 时无效
|
||||
#define READGUY_sd_cs (config_data[12])// 目标sd卡的 CS 引脚.
|
||||
#define READGUY_sd_miso (config_data[9]) // 目标sd卡的 MISO 引脚, 或esp32s3使用SDIO的 DAT0 引脚, sd_share_spi == 1 时无效
|
||||
#define READGUY_sd_mosi (config_data[10])// 目标sd卡的 MOSI 引脚, 或esp32s3使用SDIO的 CMD 引脚, sd_share_spi == 1 时无效
|
||||
#define READGUY_sd_sclk (config_data[11])// 目标sd卡的 SCLK 引脚, 或esp32s3使用SDIO的 CLK 引脚, sd_share_spi == 1 时无效
|
||||
#define READGUY_sd_cs (config_data[12])// 目标sd卡的 CS 引脚, 或esp32s3使用SDIO的 DAT3 引脚
|
||||
#define READGUY_i2c_sda (config_data[13])// 目标i2c总线的SDA引脚, 当且仅当启用i2c总线时才生效
|
||||
#define READGUY_i2c_scl (config_data[14])// 目标i2c总线的SCL引脚, 当且仅当启用i2c总线时才生效
|
||||
//按键驱动部分, 为负代表高触发, 否则低触发,
|
||||
@@ -127,11 +151,39 @@
|
||||
#define READGUY_btn2 (config_data[16])
|
||||
#define READGUY_btn3 (config_data[17])
|
||||
#define READGUY_bl_pin (config_data[18])//前置光接口引脚IO
|
||||
#define READGUY_rtc_type (config_data[19])//使用的RTC型号(待定, 还没用上)
|
||||
#define READGUY_rtc_type (config_data[19])//现已弃用 RTC 功能. 保留是为了兼容性 让代码更简单维护
|
||||
#define READGUY_sd_ok (config_data[20]) //SD卡已经成功初始化
|
||||
#define READGUY_buttons (config_data[21]) //按钮个数, 0-3都有可能
|
||||
|
||||
#define READGUY_user1 (config_data[22]) //用户自定义变量 同时用于esp32s3使用SDIO卡数据的DAT1 为-1代表不使用SDIO
|
||||
#define READGUY_user2 (config_data[23]) //用户自定义变量 同时用于esp32s3使用SDIO卡数据的DAT2
|
||||
#define READGUY_user3 (config_data[24]) //用户自定义变量
|
||||
#define READGUY_user4 (config_data[25]) //用户自定义变量
|
||||
#define READGUY_user5 (config_data[26]) //用户自定义变量
|
||||
#define READGUY_user6 (config_data[27]) //用户自定义变量
|
||||
#define READGUY_user7 (config_data[28]) //用户自定义变量
|
||||
#define READGUY_user8 (config_data[29]) //用户自定义变量
|
||||
#define READGUY_user9 (config_data[30]) //用户自定义变量
|
||||
#define READGUY_user10 (config_data[31]) //用户自定义变量
|
||||
#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
|
||||
|
||||
//按键行为 下一个 上一个 确定 返回/退出 特殊操作(如切换输入法)
|
||||
//1个按键 返回 1=点按 2=双击 4=长按 8=三击 3=点按后接长按
|
||||
//2个按键 返回 1=左键点按 2=左键长按 4=右键点按 8=右键长按 3=按住左键点按右键
|
||||
//3个按键 返回 1=右键点按 2=左键点按 4=中键点按 8=中键长按 3=中间按键双击(需手动开启)
|
||||
#define GUY_BTN_PREV 1 //上一个
|
||||
#define GUY_BTN_NEXT 2 //下一个
|
||||
#define GUY_BTN_SPECIAL 3 //确定 选择
|
||||
#define GUY_BTN_OK 4 //返回/退出
|
||||
#define GUY_BTN_BACK 8 //特殊操作(如切换输入法)
|
||||
|
||||
class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
|
||||
public:
|
||||
#ifdef READGUY_ESP_ENABLE_WIFI
|
||||
@@ -147,15 +199,19 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
|
||||
/** @brief 初始化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/* ,int g_width = 0,int g_height = 0 */);
|
||||
uint8_t init(uint8_t WiFiSet = 0, bool initepd = 1, bool initSD = 1);
|
||||
/// @brief 设置显示亮度
|
||||
void setBright(int d);
|
||||
/// @brief 返回显示亮度
|
||||
int getBright() const { return currentBright; }
|
||||
/// @brief 刷新显示到屏幕上
|
||||
void display(bool part = true);
|
||||
void display(uint8_t part = READGUY_FAST);
|
||||
/// @brief 刷新显示到屏幕上
|
||||
void displayBuffer(const uint8_t *buf, uint8_t part);
|
||||
/** @brief 刷新显示到屏幕上, 可以自定义读取指定位置像素的函数
|
||||
* @param f 自定义的函数. 此函数将在读取像素并输出到墨水屏时被调用.
|
||||
* 每次调用需要返回 "参数对应位置" 的8个像素的颜色信息(凑成一字节). 其中左侧应在高位,右侧应在低位.
|
||||
@@ -170,15 +226,17 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
|
||||
* @endcode
|
||||
* 该函数会将参数从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 显示图片, 使用抖动算法. 可以用省内存的方法显示, 可以缩放到指定的宽度和高度
|
||||
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 返回上次设置的显示对比度(灰度)
|
||||
int16_t getDepth() const {return current_depth;}
|
||||
/** @brief 返回目标屏幕是否支持16级灰度 返回非0代表支持.
|
||||
* @note 返回负整数则代表调用draw16greyStep需要从深色到浅色刷新, 而不是从浅色到深色刷新 */
|
||||
int supportGreyscaling() const{return READGUY_cali==127?guy_dev->drv_supportGreyscaling():0;}
|
||||
@@ -188,39 +246,57 @@ 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次 来完成一次自定义灰度刷屏
|
||||
* 连续调用多次此函数之间, 可以修改显存内的像素颜色, 但只能从白色改为黑色.
|
||||
* @attention 需要先调用 supportGreyscaling() 来确定是否支持灰度分步刷新.为负数时需要从深到浅刷新. 参见示例.
|
||||
*/
|
||||
* @attention 先调用 supportGreyscaling() 来确定是否支持灰度分步刷新. 为负时需要从深到浅刷新. 参见示例.
|
||||
* 方法较为复杂用法参见示例. */
|
||||
void draw16greyStep(int step);
|
||||
/** @brief 分步刷新显示灰度, 详见 display(f,part) 和 draw16grey(spr,x,y) 的注释.
|
||||
* @note 此函数不读取显存,而是通过调用该函数来确定像素颜色. */
|
||||
* @note 此函数不读取显存,而是通过调用该函数来确定像素颜色, 不建议新手使用该函数. */
|
||||
void draw16greyStep(std::function<uint8_t(int)> f, int step);
|
||||
/// @brief 对缓冲区内所有像素进行反色.只对现在的缓冲区有效,之后的颜色该怎样就怎样. 灰度信息会被扔掉.
|
||||
void invertDisplay();
|
||||
/// @brief 进入EPD的低功耗模式
|
||||
void sleepEPD(void);
|
||||
/// @brief 设置自动全刷慢刷(连续快刷一定次数之后自动调用慢刷, 保护屏幕
|
||||
/// @param frames 连续快刷多少次之后自动慢刷, 传入0来禁用自动慢刷
|
||||
void setAutoFullRefresh(int16_t frames);
|
||||
/// @brief 截屏并保存到SD卡上. 不支持灰度. 当SD卡不可用或者截屏失败时返回false
|
||||
bool screenshot(const char *filename);
|
||||
#ifdef READGUY_ESP_ENABLE_WIFI
|
||||
/// @brief ap配网设置页面
|
||||
typedef struct {
|
||||
String linkname;
|
||||
String event; //链接名称 事件URI
|
||||
std::function<void(ReadguyWebServer*)> func; //触发时执行的函数
|
||||
} serveFunc;
|
||||
#ifdef READGUY_ESP_ENABLE_WIFI
|
||||
/// @brief 初始化WiFi AP模式, 用于将来的连接WiFi 处于已连接状态下会断开原本的连接
|
||||
void ap_setup();
|
||||
/*** @brief 初始化WiFi AP模式, 用于将来的连接WiFi 可以自定义模式切换的函数
|
||||
* @param ssid 设置ap的名称
|
||||
* @param pass 设置ap的密码
|
||||
* @param m WiFi模式 */
|
||||
void ap_setup(const char *ssid, const char *pass, int m=(int)WIFI_AP);
|
||||
/// @brief 初始化WiFi AP模式, 用于将来的连接WiFi 处于已连接状态下会断开原本的连接
|
||||
void server_setup(const String ¬ify=emptyString, const serveFunc *serveFuncs = nullptr, int funcs = 0);
|
||||
bool server_loop();
|
||||
void server_end();
|
||||
#else
|
||||
/// @brief ap配网设置页面
|
||||
typedef struct {
|
||||
String linkname;
|
||||
String event; //链接名称 事件URI
|
||||
std::function<void(void*)> func; //触发时执行的函数
|
||||
} serveFunc;
|
||||
/// @brief 初始化WiFi AP模式, 用于将来的连接WiFi 处于已连接状态下会断开原本的连接
|
||||
void ap_setup(){}
|
||||
void ap_setup(const char *ssid, const char *pass, int m=2){(void)ssid; (void)pass; (void)m;} //avoid warning
|
||||
/// @brief 初始化服务器模式, 用于将来的连接WiFi 处于已连接状态下会断开原本的连接
|
||||
void server_setup(const String ¬ify=emptyString, const serveFunc *serveFuncs = nullptr, int funcs = 0){}
|
||||
void server_setup(const String ¬ify=emptyString, const serveFunc *serveFuncs = nullptr, int funcs = 0)
|
||||
{(void)notify;(void)serveFuncs;(void)funcs;} //avoid warning
|
||||
bool server_loop(){ return true; }
|
||||
void server_end(){}
|
||||
#endif
|
||||
@@ -229,7 +305,7 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
|
||||
/** @brief 初始化屏幕, 设置驱动代号, 引脚排列顺序. 过程会检验引脚可用性.
|
||||
* @param g_width, g_height 显示区域的宽度和高度. 为0表示直接使用屏幕的宽度和高度
|
||||
* @note 这两个参数转专为指定分辨率的程序画面设计, 其他分辨率的画面会自动拉伸. [1.2新增] */
|
||||
void setEpdDriver(bool initepd = 1/* ,int g_width = 0,int g_height = 0 */);
|
||||
void setEpdDriver(bool initepd = 1, bool initGFX = 1);
|
||||
/** @brief 初始化SD卡, 设置驱动代号, 引脚排列顺序. 过程会检验引脚可用性.
|
||||
* @return SD卡初始化成功与否 */
|
||||
bool setSDcardDriver();
|
||||
@@ -238,12 +314,48 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
|
||||
/** @brief 检查SD卡是否插入
|
||||
* @param check 为true时, 如果SD卡不可用则初始化SD卡. 为false时, 当SD卡不可用则返回LittleFS. */
|
||||
bool SDinside(bool check=true) { return check?setSDcardDriver():READGUY_sd_ok; };
|
||||
void SDdeinit() { READGUY_sd_ok = 0; }; //当SD卡被检测到拔出或不可用时, 调用此函数标记
|
||||
/// @brief 检查按钮. 当配置未完成时,按钮不可用, 返回0.
|
||||
uint8_t getBtn() { return (READGUY_cali==127)?getBtn_impl():0; }
|
||||
/// @brief [此函数已弃用 非常不建议使用] 根据按钮ID来检查按钮. 注意这里如果按下返回0, 没按下或者按钮无效返回1
|
||||
//uint8_t getBtn(int btnID){return btnID<getButtonsCount()?(!(btn_rd[btnID].isPressedRaw())):1;}
|
||||
/// @brief 该函数用于设置按键是否允许扫描连按
|
||||
void setButtonSpecial(bool en = 1) { if(READGUY_buttons==3) btn_rd[1].enScanDT(en); }
|
||||
/** @brief 返回可用的文件系统. 当SD卡可用时, 返回SD卡. 否则根据情况返回最近的可用文件系统
|
||||
* @param initSD 2:总是重新初始化SD卡; 1:若SD卡不可用则初始化; 0:SD卡不可用则返回LittleFS. */
|
||||
fs::FS &guyFS(uint8_t initSD = 0);
|
||||
#ifdef ESP8266
|
||||
/// @brief 恢复I2C复用SPI时的引脚功能, 仅ESP8266可用
|
||||
void recoverI2C();
|
||||
#else
|
||||
/// @brief 恢复I2C引脚功能
|
||||
void recoverI2C(){}
|
||||
#endif
|
||||
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON) && defined(READGUY_ENABLE_SD))
|
||||
/// @brief 设置SD卡为忙状态或空闲状态
|
||||
void setSDbusy(bool busy){ if(static_sd_cs!=0x7f) sd_cs_busy += (busy?1:(sd_cs_busy?-1:0)); }
|
||||
#else
|
||||
void setSDbusy(bool busy){ (void)busy; } //sd_cs as a btn pin
|
||||
#endif
|
||||
|
||||
#if 0 // disabled because of useless
|
||||
/// @brief 暂停按键扫描 (比如即将要开启中断或者中断, 定时器等硬件外设资源不足)
|
||||
void stopKeyScan(){
|
||||
#ifdef ESP8266
|
||||
btnTask.detach();//暂时关闭任务, 避免引脚被设置为非法模式
|
||||
#else
|
||||
vTaskSuspend(btn_handle);//暂时关闭任务, 避免引脚被设置为非法模式
|
||||
#endif
|
||||
}
|
||||
/// @brief 恢复按键扫描 (中断...等需要定时器的硬件外设用完了)
|
||||
void keyScan(){
|
||||
#ifdef ESP8266
|
||||
btnTask.attach_ms(BTN_LOOPTASK_DELAY,looptask);
|
||||
#else
|
||||
vTaskResume(btn_handle); //开启任务后, 延时确保按键任务可以活跃而不是一直处于被暂停又刷屏的无限循环
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
//friend class EpdIf; //这样EpdIf就可以随意操作这个类的成员了
|
||||
private:
|
||||
//以下是支持的所有屏幕型号 Add devices here!
|
||||
@@ -251,20 +363,27 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
|
||||
static const char projname[8];
|
||||
static const char tagname[7];
|
||||
//uint8_t config_wifi=0; //是否强行在初始化期间设置WiFi.
|
||||
#ifdef DYNAMIC_PIN_SETTINGS//数据是否已经校准
|
||||
int8_t config_data[22];
|
||||
char randomch[4]; //校验用字符串
|
||||
void nvs_init(); //初始化持久存储器.
|
||||
void nvs_deinit();//保存持久存储器的内容
|
||||
bool nvs_read(); //从持久存储器读取, 返回是否读取成功
|
||||
void nvs_write(); //写入到持久存储器
|
||||
#ifdef DYNAMIC_PIN_SETTINGS//数据是否已经校准
|
||||
int8_t config_data[32];
|
||||
char randomch[4]; //校验用字符串
|
||||
#else
|
||||
static const int8_t config_data[32];
|
||||
int8_t READGUY_sd_ok = 0;
|
||||
int8_t READGUY_cali = 0;
|
||||
int8_t READGUY_buttons = 0; //按钮个数, 0-3都有可能
|
||||
#endif
|
||||
int epd_OK=0; //墨水屏可用
|
||||
int currentBright = -3; //初始亮度
|
||||
int16_t epdPartRefresh = 0; //连续快刷次数
|
||||
int16_t epdForceFull = 0x7fff; //连续快刷达到指定次数后, 强制全刷, 内部变量
|
||||
int16_t currentBright = -3; //初始亮度
|
||||
int16_t current_depth = 15; //初始灰度
|
||||
uint8_t refresh_begin(uint8_t freshType); //设置快速刷新 频率调控
|
||||
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
|
||||
void refresh_end();
|
||||
#endif
|
||||
|
||||
//LGFX_Sprite gfx; // 图形引擎类指针, 可以用这个指针去操作屏幕缓冲区
|
||||
readguyEpdBase *guy_dev = nullptr;
|
||||
@@ -277,10 +396,8 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
|
||||
//对于esp8266, 需要注册到ticker
|
||||
Ticker btnTask;
|
||||
#else
|
||||
#ifdef DYNAMIC_PIN_SETTINGS
|
||||
//NVS数据操作函数, 无NVS的使用EEProm的最后几个字节块
|
||||
Preferences nvsData;
|
||||
#endif
|
||||
static SPIClass *sd_spi;
|
||||
static SPIClass *epd_spi;
|
||||
static TaskHandle_t btn_handle;
|
||||
@@ -304,9 +421,19 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
|
||||
static guy_button btn_rd[3];
|
||||
/// @brief 复用输出引脚1: 适用于按键引脚与屏幕DC引脚复用的情形
|
||||
/// @note 只能解决屏幕DC引脚复用的情况, 其他引脚最好不要复用, 复用了我也解决不了
|
||||
static int8_t pin_cmx;
|
||||
static int8_t pin_cmx;
|
||||
#ifdef READGUY_ALLOW_DC_AS_BUTTON
|
||||
static bool refresh_state; //1: free; 0: busy(refreshing)
|
||||
static uint8_t refresh_press; //0x7f: epd_dc btn released; others: epd_dc btn pressed
|
||||
#endif
|
||||
#ifdef READGUY_ALLOW_EPDCS_AS_BUTTON
|
||||
static uint8_t static_epd_cs; //epd_cs as a btn pin
|
||||
#endif
|
||||
#ifdef READGUY_ALLOW_SDCS_AS_BUTTON
|
||||
static uint8_t static_sd_cs; //sd_cs as a btn pin
|
||||
static volatile uint8_t sd_cs_busy; //sd_cs as a btn pin
|
||||
#endif
|
||||
static volatile uint8_t spibz;
|
||||
private:
|
||||
#ifdef READGUY_ESP_ENABLE_WIFI
|
||||
//static constexpr size_t EPD_DRIVERS_NUM_MAX = READGUY_SUPPORT_DEVICES;
|
||||
static const char *epd_drivers_list[EPD_DRIVERS_NUM_MAX];
|
||||
@@ -317,7 +444,7 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
|
||||
static const PROGMEM char index_cn_html16[];
|
||||
static const PROGMEM char verify_html[];
|
||||
static const PROGMEM char verify2_html[];
|
||||
static const PROGMEM char verifybtn_html[3][200];
|
||||
static const PROGMEM char verifybtn_html[3][224];
|
||||
static const PROGMEM char final_html[];
|
||||
static const PROGMEM char afterConfig_html[];
|
||||
static const PROGMEM char home_html[];
|
||||
@@ -325,57 +452,115 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
|
||||
//static const PROGMEM uint8_t faviconData[1150];
|
||||
#endif
|
||||
static void looptask(); //按键服务函数
|
||||
static uint8_t rd_btn_f(uint8_t btn);
|
||||
static uint8_t rd_btn_f(uint8_t btn, bool activeLow);
|
||||
uint8_t getBtn_impl(); //按钮不可用, 返回0.
|
||||
static void in_press(){ //SPI开始传输屏幕数据
|
||||
#ifndef ESP8266
|
||||
if(!spibz) epd_spi->beginTransaction(SPISettings(ESP32_DISP_FREQUENCY, MSBFIRST, SPI_MODE0));
|
||||
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
|
||||
if(!(spibz&0x3f))
|
||||
#else
|
||||
if(!spibz)
|
||||
#endif
|
||||
#ifdef ESP8266
|
||||
SPI.beginTransaction(SPISettings(ESP8266_SPI_FREQUENCY, MSBFIRST, SPI_MODE0));
|
||||
#else
|
||||
epd_spi->beginTransaction(SPISettings(ESP32_DISP_FREQUENCY, MSBFIRST, SPI_MODE0));
|
||||
#endif
|
||||
spibz ++;
|
||||
}
|
||||
static void in_release(){//SPI结束传输屏幕数据
|
||||
spibz --;
|
||||
#ifndef ESP8266
|
||||
if(!spibz) epd_spi->endTransaction();
|
||||
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
|
||||
if(!(spibz&0x3f))
|
||||
#else
|
||||
if(!spibz)
|
||||
#endif
|
||||
#ifdef ESP8266
|
||||
SPI.endTransaction();
|
||||
#else
|
||||
epd_spi->endTransaction();
|
||||
#endif
|
||||
}
|
||||
public: //增加了一些返回系统状态变量的函数, 它们是静态的, 而且不会对程序造成任何影响.
|
||||
constexpr int getShareSpi() const { return config_data[1]; }
|
||||
constexpr int getEpdType () const { return config_data[2]; } // 对应的epd驱动程序代号, -1为未指定
|
||||
constexpr int getShareSpi() const { return READGUY_shareSpi; }
|
||||
constexpr int getEpdType () const { return READGUY_epd_type; } // 对应的epd驱动程序代号, -1为未指定
|
||||
//显示驱动部分, 显示默认使用vspi (vspi也是默认SPI库的通道)
|
||||
constexpr int getEpdMosi () const { return config_data[3]; } // 目标显示器的 MOSI 引脚
|
||||
constexpr int getEpdSclk () const { return config_data[4]; } // 目标显示器的 SCLK 引脚
|
||||
constexpr int getEpdCs () const { return config_data[5]; } // 目标显示器的 CS 引脚
|
||||
constexpr int getEpdDc () const { return config_data[6]; } // 目标显示器的 DC 引脚
|
||||
constexpr int getEpdRst () const { return config_data[7]; } // 目标显示器的 RST 引脚
|
||||
constexpr int getEpdBusy () const { return config_data[8]; } // 目标显示器的 BUSY 引脚
|
||||
constexpr int getEpdMosi () const { return READGUY_epd_mosi; } // 目标显示器的 MOSI 引脚
|
||||
constexpr int getEpdSclk () const { return READGUY_epd_sclk; } // 目标显示器的 SCLK 引脚
|
||||
constexpr int getEpdCs () const { return READGUY_epd_cs; } // 目标显示器的 CS 引脚
|
||||
constexpr int getEpdDc () const { return READGUY_epd_dc; } // 目标显示器的 DC 引脚
|
||||
constexpr int getEpdRst () const { return READGUY_epd_rst; } // 目标显示器的 RST 引脚
|
||||
constexpr int getEpdBusy () const { return READGUY_epd_busy; } // 目标显示器的 BUSY 引脚
|
||||
//sd卡驱动部分, 默认使用hspi (sd卡建议用hspi)
|
||||
constexpr int getSdMiso () const { return config_data[9]; } // 目标sd卡的 MISO 引脚, sd_share_spi == 1 时无效
|
||||
constexpr int getSdMosi () const { return config_data[10]; }// 目标sd卡的 MOSI 引脚, sd_share_spi == 1 时无效
|
||||
constexpr int getSdSclk () const { return config_data[11]; }// 目标sd卡的 SCLK 引脚, sd_share_spi == 1 时无效
|
||||
constexpr int getSdCs () const { return config_data[12]; }// 目标sd卡的 CS 引脚.
|
||||
constexpr int getI2cSda () const { return config_data[13]; }// 目标i2c总线的SDA引脚, 当且仅当启用i2c总线时才生效
|
||||
constexpr int getI2cScl () const { return config_data[14]; }// 目标i2c总线的SCL引脚, 当且仅当启用i2c总线时才生效
|
||||
constexpr int getSdMiso () const { return READGUY_sd_miso; } // 目标sd卡的 MISO 引脚, sd_share_spi == 1 时无效
|
||||
constexpr int getSdMosi () const { return READGUY_sd_mosi; }// 目标sd卡的 MOSI 引脚, sd_share_spi == 1 时无效
|
||||
constexpr int getSdSclk () const { return READGUY_sd_sclk; }// 目标sd卡的 SCLK 引脚, sd_share_spi == 1 时无效
|
||||
constexpr int getSdCs () const { return READGUY_sd_cs; }// 目标sd卡的CS引脚. 对ESP32S3, 返回127代表使用SDMMC
|
||||
constexpr int getI2cSda () const { return READGUY_i2c_sda; }// 目标i2c总线的SDA引脚, 当且仅当启用i2c总线时才生效
|
||||
constexpr int getI2cScl () const { return READGUY_i2c_scl; }// 目标i2c总线的SCL引脚, 当且仅当启用i2c总线时才生效
|
||||
//按键驱动部分, 为负代表高触发, 否则低触发,
|
||||
//注意, 这里的io编号是加1的, 即 1或-1 代表 gpio0 的低触发/高触发
|
||||
constexpr int getBtn1Pin () const { return config_data[15]; }
|
||||
constexpr int getBtn2Pin () const { return config_data[16]; }
|
||||
constexpr int getBtn3Pin () const { return config_data[17]; }
|
||||
constexpr int getBlPin () const { return config_data[18]; } //前置光接口引脚IO
|
||||
constexpr int getRtcType () const { return config_data[19]; } //使用的RTC型号(待定, 还没用上)
|
||||
constexpr int getButtonsCount() const { return config_data[21]; } //按钮个数, 0-3都有可能
|
||||
constexpr int getBtn1Pin () const { return abs((int)READGUY_btn1)-1; }
|
||||
constexpr int getBtn2Pin () const { return abs((int)READGUY_btn2)-1; }
|
||||
constexpr int getBtn3Pin () const { return abs((int)READGUY_btn3)-1; }
|
||||
constexpr int getBtn1Info() const { return READGUY_btn1; }
|
||||
constexpr int getBtn2Info() const { return READGUY_btn2; }
|
||||
constexpr int getBtn3Info() const { return READGUY_btn3; }
|
||||
constexpr int getBlPin () const { return READGUY_bl_pin; } //前置光接口引脚IO
|
||||
constexpr int getRtcType () const { return READGUY_rtc_type; } //现已弃用 RTC 功能. 保留是为了兼容性 让代码更简单维护
|
||||
constexpr int getButtonsCount() const { return READGUY_buttons; } //按钮个数, 0-3都有可能
|
||||
constexpr int getReadguy_user1 () const { return READGUY_user1; } //用户变量
|
||||
constexpr int getReadguy_user2 () const { return READGUY_user2; } //用户变量
|
||||
constexpr int getReadguy_user3 () const { return READGUY_user3; } //用户变量
|
||||
constexpr int getReadguy_user4 () const { return READGUY_user4; } //用户变量
|
||||
constexpr int getReadguy_user5 () const { return READGUY_user5; } //用户变量
|
||||
constexpr int getReadguy_user6 () const { return READGUY_user6; } //用户变量
|
||||
constexpr int getReadguy_user7 () const { return READGUY_user7; } //用户变量
|
||||
constexpr int getReadguy_user8 () const { return READGUY_user8; } //用户变量
|
||||
constexpr int getReadguy_user9 () const { return READGUY_user9; } //用户变量
|
||||
constexpr int getReadguy_user10() const { return READGUY_user10;} //用户变量
|
||||
constexpr int getReadguyUseSdio() const { //返回程序调用SD卡时 是否使用了SDIO
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S3 //仅对ESP32S3可用
|
||||
return (READGUY_user1 != -1) && (READGUY_user2 != -1);
|
||||
#else
|
||||
return 0; //非ESP32S3平台不可用SDIO
|
||||
#endif
|
||||
} //用于esp32s3使用SDIO卡数据的DAT2
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S3 //仅对ESP32S3可用
|
||||
constexpr int getSdio_dat0 () const { return getReadguyUseSdio()?READGUY_sd_miso:-1; } //用于esp32s3使用SDIO卡数据的DAT0
|
||||
constexpr int getSdio_dat1 () const { return getReadguyUseSdio()?READGUY_user1 :-1; } //用于esp32s3使用SDIO卡数据的DAT1
|
||||
constexpr int getSdio_dat2 () const { return getReadguyUseSdio()?READGUY_user2 :-1; } //用于esp32s3使用SDIO卡数据的DAT2
|
||||
constexpr int getSdio_dat3 () const { return getReadguyUseSdio()?READGUY_sd_cs :-1; } //用于esp32s3使用SDIO卡数据的DAT3
|
||||
constexpr int getSdio_clk () const { return getReadguyUseSdio()?READGUY_sd_sclk:-1; } //用于esp32s3使用SDIO卡数据的CLK
|
||||
constexpr int getSdio_cmd () const { return getReadguyUseSdio()?READGUY_sd_mosi:-1; } //用于esp32s3使用SDIO卡数据的CMD
|
||||
#else
|
||||
constexpr int getSdio_dat0 () const { return -1; } //用于esp32s3使用SDIO卡数据的DAT0
|
||||
constexpr int getSdio_dat1 () const { return -1; } //用于esp32s3使用SDIO卡数据的DAT1
|
||||
constexpr int getSdio_dat2 () const { return -1; } //用于esp32s3使用SDIO卡数据的DAT2
|
||||
constexpr int getSdio_dat3 () const { return -1; } //用于esp32s3使用SDIO卡数据的DAT3
|
||||
constexpr int getSdio_clk () const { return -1; } //用于esp32s3使用SDIO卡数据的CLK
|
||||
constexpr int getSdio_cmd () const { return -1; } //用于esp32s3使用SDIO卡数据的CMD
|
||||
#endif
|
||||
//constexpr int memWidth () const { return guy_width ; } //返回显存宽度(不是画幅宽度),不会随着画布旋转改变
|
||||
//constexpr int memHeight () const { return guy_height ; } //返回显存高度(不是画幅高度),不会随着画布旋转改变
|
||||
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 width () const { return READGUY_cali==127?((getRotation()&1)?drvHeight():drvWidth()):0; }
|
||||
int height() const { return READGUY_cali==127?((getRotation()&1)?drvWidth():drvHeight()):0; }
|
||||
//int width () const { return (getRotation()&1)?drvHeight():drvWidth(); }
|
||||
//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:
|
||||
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);
|
||||
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. */
|
||||
Reference in New Issue
Block a user