mirror of
https://github.com/fsender/readguy.git
synced 2025-12-09 03:28:15 +08:00
update to 1.2.0 ver
This commit is contained in:
20
CHANGELOG.md
20
CHANGELOG.md
@@ -1,14 +1,24 @@
|
||||
## Release 1.1.1 - 2023/20/20
|
||||
## Release 1.2.0 - 2023/11/3
|
||||
|
||||
1. 引脚配置页更新,内置预设开发板的引脚定义。
|
||||
1. 添加了图片demo, 和 可选关闭的WiFi 的示例程序。其中图片相关功能相当节省内存, 还请大胆使用。
|
||||
|
||||
2. 可以配置wifi和线上固件升级。
|
||||
2. 新增了接口函数 getReadguy...(), guyMemoryWidth(), guyMemoryHeight(), guyDriverWidth(), guyDriverHeight() 等函数, 可以在程序内获取到一些硬件相关信息。
|
||||
|
||||
3. 增加了保姆级教程, 比现有教程更加简单易用。
|
||||
|
||||
4. 修复了一些bug。现在4.2寸HINK屏幕的16灰度刷新不会导致内存溢出了.
|
||||
|
||||
## Release 1.1.1 - 2023/10/20
|
||||
|
||||
1. 引脚配置页更新,内置预设开发板的引脚预定义。此选项的内置定义可以被用户更改成自己的板子预定义。
|
||||
|
||||
2. 可以配置wifi并对时。
|
||||
|
||||
3. 支持在库内设置i2c总线。实际i2c功能需要自己编写程序,本库只提供了i2c引脚的定义接口。此次更新之后,设备需要重新配网。
|
||||
|
||||
4. 支持16级灰度的抖动算法,并可在程序内切换渲染方式和算法。
|
||||
4. 支持16级灰度的抖动算法,并可在编译时切换显示算法。
|
||||
|
||||
5. 添加了更多例程,例程注释更简洁易用。比如 WiFi获取时间demo, 按键demo, 图片demo, 文本和字体demo, 使用静态引脚定义的demo.
|
||||
5. 添加了更多例程,例程注释更简洁易用。比如 WiFi获取时间demo, 按键demo, 文本和字体demo, 使用静态引脚定义的demo.
|
||||
|
||||
6. 修复了一些bug.
|
||||
|
||||
|
||||
@@ -32,6 +32,12 @@
|
||||
|
||||
#### 可以使用wifi配网来配置硬件信息。
|
||||
|
||||
有不少人吐槽我这个库的WiFi功能可不可以关掉 就是把WiFi独立出来 其实是可以的, 教程如下
|
||||
|
||||
其中的WiFi功能, 其实是可以禁掉的. 只要你提前配置成功, 那么就可以摆脱WiFi配网配引脚功能.
|
||||
|
||||
使用方法: 打开文件[guy_driver_config.h](src/guy_driver_config.h), 随后便根据注释来选择性的开启或关闭一些系统功能.
|
||||
|
||||
----
|
||||
|
||||
## 支持芯片:esp8266/esp32/esp32s3/esp32s2/esp32c3
|
||||
|
||||
@@ -180,11 +180,17 @@ void setup(){
|
||||
|
||||
guy.drawImage(sp,10,10); //使用抖动像素的方式显示图片(不是灰度, 只有黑点和白点的那种显示效果)
|
||||
|
||||
guy.display(); //自从1.2.0更新之后, drawImage不再刷屏, 此处需要额外调用display函数刷屏
|
||||
|
||||
Serial.printf("[%lu] drawn dithering bmp.\n",millis()); //显示信息
|
||||
|
||||
delay(2000);
|
||||
|
||||
|
||||
guy.setGreyQuality(1); //设置灰度刷新方式. 对于支持连续刷灰度的屏幕才有效.
|
||||
// 1(默认)为连续刷新, 0为循环调用 setDepth+display 来刷新 (可能会有白边)
|
||||
//如果连续刷新效果不好, 请将此处改为0再试一次.
|
||||
|
||||
guy.draw16grey(sp,10,10); //使用16级灰度的方式显示图片 需要的时间比较长
|
||||
|
||||
sp.deleteSprite(); //关闭图片文件, 释放图片占用的大量内存
|
||||
@@ -240,7 +246,9 @@ void setup(){
|
||||
|
||||
guy.fillScreen(1); //清屏
|
||||
|
||||
guy.display(false); //慢刷清屏
|
||||
guy.display(FILL_WHITE,false); //慢刷清屏. 左侧的FILL_WHITE表示 不写入屏幕缓存, 直接刷全白
|
||||
//可以改为FILL_BLACK来设置写入缓存全黑.
|
||||
//以上的方式均不会修改屏幕缓存中的内容. 右侧的false表示全屏慢刷.
|
||||
|
||||
guy.setTextColor(0); //设置显示的颜色. 0代表黑色, 一个参数代表黑白显示.
|
||||
//注意这个函数不是设定显示灰度的函数!
|
||||
|
||||
BIN
examples/ex06_Image/data/bmp.bmp
Normal file
BIN
examples/ex06_Image/data/bmp.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 450 KiB |
BIN
examples/ex06_Image/data/jpg.jpg
Normal file
BIN
examples/ex06_Image/data/jpg.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 280 KiB |
BIN
examples/ex06_Image/data/png.png
Normal file
BIN
examples/ex06_Image/data/png.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 980 KiB |
299
examples/ex06_Image/guy_image.cpp
Normal file
299
examples/ex06_Image/guy_image.cpp
Normal file
@@ -0,0 +1,299 @@
|
||||
/******************** 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_image.cpp
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief guy_image 基础功能 源代码文件.
|
||||
* @version 1.0
|
||||
* @date 2023-11-01
|
||||
|
||||
* @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_image.h"
|
||||
#include "readguy.h"
|
||||
#define GUY_STAGES ((h+_h-1)/_h)
|
||||
|
||||
/// @brief 此函数为自定义图片显示程序
|
||||
uint8_t readguyImage::drawImgHandler(int r, LGFX_Sprite *spr){
|
||||
int widthDiv8=spr->width()>>3; //宽度的1/8. 注意此处宽度一定是8的倍数.
|
||||
int stage = widthDiv8*_h;
|
||||
//uint32_t colors[8]={0x101010,0x303030,0x505050,0x707070,0x909090,0xb0b0b0,0xd0d0d0,0xf0f0f0};//for debug
|
||||
|
||||
if(r%stage==0){ //分为8个阶段绘制图像, 每个阶段开始时, 打开图片文件尝试绘制.
|
||||
guy->implEndTransfer();
|
||||
Serial.printf("filename: %s(%d) Stage %d: Pixels: w=%d, h=%d\n",filename,format,r/stage,spr->width(),_h);
|
||||
|
||||
spr->fillScreen(background?0xffff:0); //背景色填充白色
|
||||
|
||||
//spr->drawBmp(*baseFs,filename,x,y,std::min(w,spr->width()),std::min(h,_h),
|
||||
//offsetx,offsety,scalex,scaley,datum);
|
||||
int yr=y-r/stage*_h;
|
||||
if(yr<_h){
|
||||
int yd=0;
|
||||
if(yr<0){
|
||||
yd=-yr;
|
||||
yr=0;
|
||||
}
|
||||
switch(format&3){
|
||||
case 1:
|
||||
spr->drawBmpFile(*baseFs,filename,x,yr,0,0,offsetx,offsety+yd,scalex,scaley,datum);
|
||||
break;
|
||||
case 2:
|
||||
spr->drawPngFile(*baseFs,filename,x,yr,0,0,offsetx,offsety+yd,scalex,scaley,datum);
|
||||
break;
|
||||
case 3:
|
||||
spr->drawJpgFile(*baseFs,filename,x,yr,0,0,offsetx,offsety+yd,scalex,scaley,datum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//spr->setTextColor(0u,colors[r/stage]);//for debug
|
||||
//spr->drawString("Hello",0,0);//for debug
|
||||
/*此函数将会把图片文件绘制到这个灰度图里面.
|
||||
for(int j=0;j<spr->height();j++){
|
||||
for(int i=0;i<spr->width();i++){
|
||||
Serial.print((spr->readPixelRGB(i,j).R8())&0xff,HEX);
|
||||
Serial.write(' ');
|
||||
}
|
||||
Serial.print("\r\n\r\n");
|
||||
}*/
|
||||
delay(1);
|
||||
guy->implBeginTransfer();
|
||||
}
|
||||
// *
|
||||
if(r%widthDiv8==0){ //开始显示新的一行像素, 读取到buff内
|
||||
guy->implEndTransfer();
|
||||
int w=spr->width();
|
||||
//Serial.printf("line: %d %d, readStart: %d, readEnd: %d\n",r/w,r/widthDiv8,((r%stage)<<3), ((r%stage)<<3)+w);
|
||||
if(r==0){
|
||||
memset(floyd,0,w<<1);
|
||||
//Serial.printf("floyd buff = %d:\n",w);
|
||||
//for(int j=0;j<(w<<1);j++){
|
||||
// Serial.printf("%d ",floyd[j]);
|
||||
//}
|
||||
//Serial.println();
|
||||
}
|
||||
memcpy_P(readBuff,((uint8_t*)spr->getBuffer())+((r%stage)<<3),w);
|
||||
uint_fast8_t buff8bit=0;
|
||||
for(int32_t j=0;j<w;j++){
|
||||
int32_t flodelta = floyd[((r/widthDiv8)&1)*w+j]+(int32_t)((readBuff[j]<<8)|readBuff[j]);
|
||||
if(format>>2){ //是灰度模式
|
||||
uint_fast8_t cg=0;
|
||||
if(enableFloyd){
|
||||
while(flodelta>=0x800) {
|
||||
cg++;
|
||||
if(flodelta>=0) flodelta -= 0x1000;
|
||||
}
|
||||
if(flodelta<0) flodelta++;
|
||||
}
|
||||
else{ cg=readBuff[j]>>4; }
|
||||
if(format>>6){
|
||||
if(cg<15) //白色不考虑
|
||||
buff8bit |= (cg>=((~(format>>2))&0xf))<<((~j)&7);
|
||||
}
|
||||
else{
|
||||
buff8bit |= (cg<(format>>2))<<((~j)&7);
|
||||
}
|
||||
}
|
||||
else if(flodelta>=0x8000) {
|
||||
//spr.drawPixel(j,i,1);
|
||||
buff8bit |= 1<<((~j)&7);
|
||||
flodelta -= 0xffff;
|
||||
}
|
||||
if((j&7)==7 || j==(w-1)){
|
||||
writeBuff[j>>3]=buff8bit^((format>>2)?0xff:0);
|
||||
buff8bit=0;
|
||||
}
|
||||
//计算出读取到的颜色, 然后与128比较, 如果小于128, 显示黑色,否则显示白色
|
||||
//else { spr.drawPixel(j,i,0); }
|
||||
//if(j!=(int32_t)spr.width()-1) {
|
||||
// floyd[ i&1 ][j+1] += (flodelta*7)>>4;
|
||||
// floyd[!(i&1)][j+1] += (flodelta )>>4;
|
||||
//}
|
||||
//if(j) { floyd[!(i&1)][j-1] += (flodelta*3)>>4; }
|
||||
// { floyd[!(i&1)][j ] += (flodelta*5)>>4; }
|
||||
if(j!=w-1) { floyd[ ((r/widthDiv8)&1) *w+j+1] += (flodelta*7)>>4; }
|
||||
if(j) { floyd[(!((r/widthDiv8)&1))*w+j-1] += (flodelta*3)>>4; }
|
||||
{ floyd[(!((r/widthDiv8)&1))*w+j ] += (flodelta*5)>>4; }
|
||||
if(j!=w-1) { floyd[(!((r/widthDiv8)&1))*w+j+1] += (flodelta )>>4; }
|
||||
}
|
||||
for(int floi=0;floi<w;floi++) floyd[((r/widthDiv8)&1)*w+floi]=0;
|
||||
guy->implBeginTransfer();
|
||||
}
|
||||
return writeBuff[r%widthDiv8];
|
||||
/*
|
||||
//根据r的值返回对应位置上的的颜色. 一次读取8个像素
|
||||
uint_fast8_t colorBase = 0; //即将发送出去的像素数据
|
||||
//根据r的值返回对应位置上的的颜色. 一次读取8个像素
|
||||
for(uint_fast8_t j=0;j<8;j++){
|
||||
uint_fast8_t grey = *(((uint8_t *)spr->getBuffer())+((r%stage)<<3)+j); //获取对应位置的像素点的灰度值
|
||||
//计算灰度数值, 并使用floyd算法转化为位图.
|
||||
//if(readguyEpdBase::greysc(grey)>=128) colorBase|=(1<<(7-j));
|
||||
if(grey>=128) colorBase|=(1<<(7-j));
|
||||
}
|
||||
return colorBase;
|
||||
*/
|
||||
}
|
||||
|
||||
/// @brief 获取文件的扩展名, 最大长度为 exname_len
|
||||
uint8_t readguyImage::getExName(const char* fname, char* exname, size_t exname_len){
|
||||
const char * dataex[12] = {
|
||||
"txt","bmp","jpg","png","mp3","wav","aac","flac","json","bin","html","js"
|
||||
};
|
||||
char dbuff[6];
|
||||
uint8_t foundLastName = 0;
|
||||
int fnamelen = strlen(fname);
|
||||
//Serial.print("test file name hook: ");
|
||||
//Serial.println(fname);
|
||||
if(fname[fnamelen-1] == '/') {
|
||||
//fname[fnamelen-1] = '\0'; //删除文件夹标记辅助位
|
||||
exname[0] = '/';
|
||||
exname[1] = '\0';
|
||||
return 2; //文件夹类型
|
||||
}
|
||||
for(int i=0;i<5;i++){
|
||||
if(fnamelen-1-i>=0) dbuff[i] = fname[fnamelen-1-i];
|
||||
else dbuff[i] = 0;
|
||||
if(dbuff[i] == '.'){
|
||||
dbuff[i] = 0;
|
||||
foundLastName = strlen(dbuff); //标记找到了扩展名
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(foundLastName>exname_len) foundLastName = exname_len;
|
||||
for(int i=0;i<foundLastName;i++){
|
||||
exname[i] = dbuff[foundLastName-1-i];
|
||||
}
|
||||
exname[foundLastName] = 0;
|
||||
//Serial.print("test exname hook: ");
|
||||
//Serial.println(exname);
|
||||
if(exname[0] == 0) return 0; //无类型
|
||||
for(int i=0;i<12;i++){
|
||||
if(strcmp(exname,dataex[i]) == 0) return i+3;
|
||||
}
|
||||
return 1; //未知类型
|
||||
}
|
||||
|
||||
/// @brief 显示图像
|
||||
void readguyImage::drawImageFile(bool use16grey){
|
||||
if(filename == nullptr || filename[0] == 0 || !(baseFs->exists(filename))) return; //文件不存在
|
||||
char ex[8]; //保存文件的扩展名
|
||||
getExName(filename,ex,7); //获取文件的扩展名.最后一个参数用于防止数组越界
|
||||
format = 0; //16灰度模式
|
||||
//Serial.printf("filename: %s, exname: %s\n",filename,ex);
|
||||
|
||||
//图片将会分割成8个部分, 分块绘制, 节省内存.
|
||||
int _w=(guy->memWidth()+7)&0x7ffffff8; //guy->guyMemoryWidth() 返回不随旋转参数而改变的显示内存宽度
|
||||
if(!_w) return; //保证宽度>0
|
||||
if(exPoolSize>guy->bufferLength()){ //当外部缓存的像素超过屏幕缓存时,使用外部缓存作为主缓冲区
|
||||
_h=exPoolSize/_w;
|
||||
_pool=exPool;
|
||||
}
|
||||
if(_pool==nullptr) {
|
||||
_h=(guy->memHeight()+7)>>3; //设置缓存区的高度. 更多内存将可以更快显示
|
||||
_pool=(uint8_t *)guy->getBuffer();
|
||||
}
|
||||
//(guy->guyMemoryHeight()+7)>>3 返回高度,并补齐后右移三位 (等效于除以2³, 分成8份)
|
||||
//最后一个参数代表bpp,也就是有多少位, 在这里需要使用8位灰度.
|
||||
|
||||
LGFX_Sprite bmpspr;
|
||||
//首先, 需要获取到内部显存的地址, 用于建立图片分块绘制缓存.
|
||||
//获取屏幕缓存, 随后分配图片解码所需的内存.
|
||||
bmpspr.setBuffer(_pool,_w,_h,lgfx::v1::color_depth_t::grayscale_8bit);
|
||||
//bmpspr.createSprite(guy_width,(guy_height+7)&0x7ffffff8);
|
||||
|
||||
//必须在此处转化为8bit灰度 (256等阶)
|
||||
//bmpspr.setColorDepth(lgfx::v1::grayscale_8bit); //因为LGFX的限制, 图片经过解码之后不能直接转换为单色/16色
|
||||
|
||||
//随后打开图片进行解码. 可选显示的位置和宽度高度参数, 屏幕上的其他部分则会变成白色.
|
||||
if(strcmp(ex,"bmp") == 0 || strcmp(ex,"BMP") == 0) //BMP格式, 绘制BMP图片
|
||||
format|=1; //BMP格式
|
||||
else if(strcmp(ex,"png") == 0 || strcmp(ex,"PNG") == 0) //PNG格式, 绘制PNG图片
|
||||
format|=2; //PNG格式
|
||||
else if(strcmp(ex,"jpg") == 0 || strcmp(ex,"JPG") == 0 || strcmp(ex,"jpeg") == 0 || strcmp(ex,"JPEG") == 0)
|
||||
format|=3; //JPG格式
|
||||
else return; //未知格式
|
||||
//bmpspr.drawBmp(*baseFs,filename,x,y,w,h,offsetx,offsety,scalex,scaley,datum);
|
||||
floyd = new int16_t[_w<<1];
|
||||
readBuff = new uint8_t[_w];
|
||||
writeBuff = new uint8_t[_w>>3];
|
||||
//guy->display([](int)->uint8_t{ return 0xff; },true);
|
||||
|
||||
if(use16grey){
|
||||
for(int i=1;i<16;i++){
|
||||
format |= (i<<2);
|
||||
if(guy->supportGreyscaling()==16) format|=64;
|
||||
guy->draw16greyStep(std::bind(&readguyImage::drawImgHandler,this,std::placeholders::_1,&bmpspr),i);
|
||||
format &= 0x03;
|
||||
}
|
||||
}
|
||||
else{
|
||||
// ************* 提示: 编写此示例时的最新版本LovyanGFX库不提供此函数. 请看ex06_Image.ino文件开头的解决方法!
|
||||
guy->display(std::bind(&readguyImage::drawImgHandler,this,std::placeholders::_1,&bmpspr));
|
||||
// 此函数过不了编译 需要改库.
|
||||
}
|
||||
|
||||
delete []floyd;
|
||||
delete []readBuff;
|
||||
delete []writeBuff;
|
||||
guy->fillScreen(0xff); //清空乱码
|
||||
}
|
||||
|
||||
uint8_t readguyImage::drawImageToBuffer(){
|
||||
if(filename == nullptr || filename[0] == 0 || !(baseFs->exists(filename))) return 1; //文件不存在
|
||||
if( w==0 || h==0 || w>=0x8000 || h>=0x8000 || exPool==nullptr || exPoolSize<1024) return 3; //内存不足
|
||||
char ex[8]; //保存文件的扩展名
|
||||
format = 0; //16灰度模式
|
||||
getExName(filename,ex,7); //获取文件的扩展名.最后一个参数用于防止数组越界
|
||||
Serial.printf("filename: %s, exname: %s\n",filename,ex);
|
||||
|
||||
if(strcmp(ex,"bmp") == 0 || strcmp(ex,"BMP") == 0) //BMP格式, 绘制BMP图片
|
||||
format|=1; //BMP格式
|
||||
else if(strcmp(ex,"png") == 0 || strcmp(ex,"PNG") == 0) //PNG格式, 绘制PNG图片
|
||||
format|=2; //PNG格式
|
||||
else if(strcmp(ex,"jpg") == 0 || strcmp(ex,"JPG") == 0 || strcmp(ex,"jpeg") == 0 || strcmp(ex,"JPEG") == 0)
|
||||
format|=3; //JPG格式
|
||||
else return 2; //未知格式
|
||||
|
||||
_h=exPoolSize/w;
|
||||
if(_h>h) _h=h; //分配的内存更多了, 直接使用
|
||||
_pool=exPool;
|
||||
if(_h==0 || GUY_STAGES>8) return 3; //内存不足以在显示8次之内就... 总之就是内存不够
|
||||
|
||||
LGFX_Sprite spr;
|
||||
spr.setBuffer(_pool,w,_h,lgfx::v1::color_depth_t::grayscale_8bit);
|
||||
for(int i=0;i<GUY_STAGES;i++){
|
||||
spr.fillScreen(background?0xffff:0);
|
||||
switch(format&3){
|
||||
case 1:
|
||||
spr.drawBmpFile(*baseFs,filename,0,0,0,0,offsetx,offsety+_h*i,scalex,scaley);
|
||||
break;
|
||||
case 2:
|
||||
spr.drawPngFile(*baseFs,filename,0,0,0,0,offsetx,offsety+_h*i,scalex,scaley);
|
||||
break;
|
||||
case 3:
|
||||
spr.drawJpgFile(*baseFs,filename,0,0,0,0,offsetx,offsety+_h*i,scalex,scaley);
|
||||
break;
|
||||
}
|
||||
guy->drawImageStage(spr,x,y+_h*i,i,GUY_STAGES);
|
||||
}
|
||||
return 0;
|
||||
} /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
101
examples/ex06_Image/guy_image.h
Normal file
101
examples/ex06_Image/guy_image.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/******************** 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_image.h
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @brief guy_image 基础功能 头文件.
|
||||
* @version 1.0
|
||||
* @date 2023-11-01
|
||||
|
||||
* @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 _GUY_IMAGE_H_FILE
|
||||
#define _GUY_IMAGE_H_FILE
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include <FS.h>
|
||||
|
||||
#define LGFX_USE_V1
|
||||
#include <LovyanGFX.hpp>
|
||||
#include "readguy.h"
|
||||
|
||||
|
||||
class readguyImage{
|
||||
public:
|
||||
readguyImage(ReadguyDriver &_guy):guy(&_guy){}
|
||||
|
||||
/** @brief 显示图像. use16grey: 为true则使用16灰度,false则不用
|
||||
* @note 需要提前设置绘制参数, 直接在类的外部 设置此类的成员函数即可.
|
||||
* 对于不会C++的朋友们, 可以看示例.
|
||||
* @param baseFs, filename 文件系统和文件名. 必须指定.
|
||||
* @param x, y 显示在屏幕的什么地方
|
||||
*
|
||||
* @param use16grey 0: 使用单色抖动 1:使用16灰度 2:使用16灰度但不抖动
|
||||
* */
|
||||
void drawImageFile(bool use16grey = 0);
|
||||
|
||||
/** @brief 将图像绘制到系统缓存内. 必须预分配内存, 并且需要知道分配的大小.
|
||||
* @note 需要提前设置绘制参数, 直接在类的外部 设置此类的成员函数即可.
|
||||
* 对于不会C++的朋友们, 可以看示例.
|
||||
* @param baseFs, filename 文件系统和文件名. 必须指定.
|
||||
* @param x, y 显示在屏幕缓存的什么地方
|
||||
* @param w, h 开辟的缓存宽度和高度. 最好是和图片的大小相匹配.
|
||||
* @param exPool 外部内存位置, 必须指定. 此处的pool为1字节=1像素(8bit灰度)
|
||||
* @param exPoolSize 外部内存大小, 必须指定. 太小会无法显示.
|
||||
* @return 0:正常显示, 1:文件打不开 2:文件格式不支持 3:内存不足 4:其他问题 */
|
||||
uint8_t drawImageToBuffer();
|
||||
|
||||
/// @brief 获取文件的扩展名.
|
||||
static uint8_t getExName(const char* fname, char* exname, size_t exname_len);
|
||||
|
||||
fs::FS *baseFs = nullptr;/// // / //要绘制的图片所属的文件系统
|
||||
const char *filename = nullptr; // / //要绘制的图片的文件名和文件路径
|
||||
int32_t x = 0; //// // / //绘制位置坐标X
|
||||
int32_t y = 0; //// // / //绘制位置坐标Y
|
||||
int32_t w = 0x7fffffff; // / //绘制图片的最大宽度, 无需更改
|
||||
int32_t h = 0x7fffffff; // / //绘制图片的最大高度, 无需更改
|
||||
int32_t offsetx = 0; // / //从图片的哪个坐标点开始绘制图片,一般无需更改
|
||||
int32_t offsety = 0; // / //从图片的哪个坐标点开始绘制图片, 一般无需更改
|
||||
float scalex = 1.0f; // / //横坐标缩放水平. >1为放大, <1为缩小
|
||||
float scaley = 0.0f; // / //纵坐标缩放水平. 0代表与scalex相同.
|
||||
lgfx::v1::textdatum::textdatum_t datum=lgfx::v1::textdatum::top_left;
|
||||
uint8_t background = 1; // //背景颜色. 0黑 1白, 默认白色.
|
||||
uint8_t enableFloyd = 1; //是否开启floyd抖动算法. (抗锯齿) 默认开启
|
||||
uint8_t *exPool = nullptr;//额外的内存池, 外部缓存
|
||||
uint32_t exPoolSize = 0; //额外的内存池 外部缓存的字节数
|
||||
private: // //私有部分. 以下函数和成员只能是类内成员能调用
|
||||
ReadguyDriver *guy;// //readguy类型指针. 用于沟通硬件.
|
||||
|
||||
/// @brief 设置绘制函数. 此函数不建议单独调用.
|
||||
uint8_t drawImgHandler(int r, LGFX_Sprite *spr);
|
||||
|
||||
uint8_t format = 0; //图片格式
|
||||
int32_t _h = 0; //内存池的像素高度 可能是内部内存池也可能是外部的
|
||||
//分多次完成显示, 次数为 h/_h.
|
||||
uint8_t *_pool = nullptr; //内存池, 可能是内部内存池也可能是外部的
|
||||
int16_t *floyd = nullptr; //用于显示图片
|
||||
uint8_t *readBuff = nullptr;
|
||||
uint8_t *writeBuff = nullptr;
|
||||
};
|
||||
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
340
examples/ex06_Image/main.cpp
Normal file
340
examples/ex06_Image/main.cpp
Normal file
@@ -0,0 +1,340 @@
|
||||
/******************** F r i e n d s h i p E n d e r ********************
|
||||
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
||||
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
||||
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
||||
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
||||
*
|
||||
* @file ex06_Image.ino
|
||||
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
||||
* @version 1.0
|
||||
* @date 2023-11-01
|
||||
* @brief ReadGuy 图片显示功能演示.
|
||||
* 1. 在运行过ex01或者ex02的开发板上 编译烧录本程序.
|
||||
* 2. 将该项目data文件夹内的所有文件放置于SD卡的根目录上.
|
||||
*
|
||||
* @note 重要消息: 这是一个实验性功能. 可能你所使用的LGFX库版本较旧而无法通过编译.
|
||||
* 如果你的项目中无法成功编译源码中的setBuffer, 请更改LovyanGFX库的函数!
|
||||
* 位于文件 LovyanGFX/src/lgfx/v1/LGFX_Sprite.hpp
|
||||
* 第155行 void setBuffer 函数:
|
||||
* 修改为如下内容并保存
|
||||
*
|
||||
``` C++
|
||||
void setBuffer(void* buffer, int32_t w, int32_t h, color_depth_t bpp = rgb565_2Byte)
|
||||
{
|
||||
deleteSprite();
|
||||
if (bpp != 0) {
|
||||
_write_conv.setColorDepth(bpp);
|
||||
_read_conv = _write_conv;
|
||||
_panel_sprite.setColorDepth(bpp);
|
||||
}
|
||||
|
||||
_panel_sprite.setBuffer(buffer, w, h, &_write_conv);
|
||||
_img = _panel_sprite.getBuffer();
|
||||
|
||||
_sw = w;
|
||||
_clip_r = w - 1;
|
||||
_xpivot = w >> 1;
|
||||
|
||||
_sh = h;
|
||||
_clip_b = h - 1;
|
||||
_ypivot = h >> 1;
|
||||
}
|
||||
```
|
||||
* 完成后请再次尝试编译
|
||||
* [已经向lovyan03/LovyanGFX发布issue, 等待解决]
|
||||
*
|
||||
* @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 "guy_image.h" //包含 readguy_image 图片功能库. 此库文件放在项目文件夹内.
|
||||
|
||||
constexpr const char * BMP_FILE = "/bmp.bmp"; //在此更改你的图片文件路径名
|
||||
constexpr const char * JPG_FILE = "/jpg.jpg"; //在此更改你的图片文件路径名
|
||||
constexpr const char * PNG_FILE = "/png.png"; //在此更改你的图片文件路径名
|
||||
|
||||
ReadguyDriver guy;//新建一个readguy对象, 用于显示驱动.
|
||||
|
||||
void setup(){
|
||||
|
||||
// 1 - 初始化和启动ReadGuy --------------------- 1 - 初始化和启动ReadGuy -------<
|
||||
Serial.begin(115200); //初始化串口
|
||||
|
||||
guy.init(); //初始化readguy_driver 基础驱动库.
|
||||
|
||||
// 2 - 显示图片 方式1 --------------------- 2 - 显示图片 方式1:使用readguy提供的drawImage方法. ------<<
|
||||
|
||||
//此功能可以在Sprite绘制图片, 再使用内置的drawImage方法来显示出这个sprite.
|
||||
//此方法消耗的内存颇多, 需要整个sprite才能成功绘制.
|
||||
guy.fillScreen(1); //清屏
|
||||
guy.display(); //显示白屏,用于将来显示图片.
|
||||
LGFX_Sprite sp(&guy); //创建一个Sprite (可以存储一些像素, 快速读写)
|
||||
sp.setColorDepth(lgfx::v1::color_depth_t::grayscale_8bit); //设置sprite的色彩深度
|
||||
sp.createSprite(80,80); //从文件创建BMP图像信息.
|
||||
sp.drawBmpFile(guy.guyFS(),BMP_FILE,0,0); //显示JPG文件
|
||||
Serial.printf("[%lu] sp.w: %d, h: %d, res: %im.\n",millis(),sp.width(),sp.height(),ESP.getFreeHeap());
|
||||
guy.drawImage(sp,9,9); //使用抖动像素的方式显示图片(不是灰度, 只有黑点和白点的那种显示效果)
|
||||
Serial.printf("[%lu] drawn dithering bmp.\n",millis()); //显示信息
|
||||
guy.display(); //1.2.0版本之后, drawImage不再刷屏, 需要额外调用display函数刷屏.
|
||||
delay(2000);
|
||||
|
||||
//0-关闭连续刷屏 开启16阶灰度抖动
|
||||
guy.setGreyQuality(0); //部分屏幕允许使用不同的灰度显示模式.
|
||||
guy.draw16grey(sp,9,9); //使用16级灰度的方式显示图片 需要的时间比较长
|
||||
delay(2000);
|
||||
|
||||
//1-开启连续刷屏 开启16阶灰度抖动 (默认值)
|
||||
guy.setGreyQuality(1); //部分屏幕允许使用不同的灰度显示模式.
|
||||
guy.draw16grey(sp,9,9); //使用16级灰度的方式显示图片 需要的时间比较长
|
||||
delay(2000);
|
||||
|
||||
//2-关闭连续刷屏 关闭16阶灰度抖动
|
||||
guy.setGreyQuality(2); //部分屏幕允许使用不同的灰度显示模式.
|
||||
guy.draw16grey(sp,9,9); //使用16级灰度的方式显示图片 需要的时间比较长
|
||||
delay(2000);
|
||||
|
||||
//3-开启连续刷屏 关闭16阶灰度抖动
|
||||
guy.setGreyQuality(3); //部分屏幕允许使用不同的灰度显示模式.
|
||||
guy.draw16grey(sp,9,9); //使用16级灰度的方式显示图片 需要的时间比较长
|
||||
delay(2000);
|
||||
|
||||
sp.deleteSprite(); //关闭图片文件, 释放图片占用的大量内存
|
||||
Serial.printf("[%lu] drawn 16-layer greyscale bmp.\n",millis()); //显示信息
|
||||
delay(2000);
|
||||
|
||||
|
||||
// 3 - 显示图片 方式2 --------------------- 3 - 显示图片 方式2:使用readguyImage类. -----<<<
|
||||
|
||||
//readguy驱动程序的内部有一个屏幕缓存, 可以用于存储显示引擎显示的内容, 在刷屏时 直接发送此缓存的内容.
|
||||
//显示引擎会通过显示函数, 来改写屏幕缓存的内容. (显示就是这样显示的. 类似于print, drawPixel, fillRect...)
|
||||
|
||||
//此绘制方式可以做到几乎不消耗额外的内存, 仅需要屏幕缓存即可显示图片.
|
||||
//适合用在esp8266或者消耗的内存较多的项目上.
|
||||
//显示原理比较复杂, 因为显示函数的限制, 图片不能直接显示到屏幕缓存中.
|
||||
//大体上说就是用屏幕缓存作为显示图片的中间内存, 再分阶段解码图片, 最后通过自定义刷屏函数, 完成刷新图片
|
||||
//使用此方法, 因为屏幕缓存被复用作图片解码中间内存, 屏幕缓存上原本的内容会因为图片解码而发生改变.
|
||||
|
||||
//不需要指定额外的外部内存.
|
||||
|
||||
//显示BMP格式
|
||||
readguyImage im(guy); //定义一个绘制器, 此类中的函数用于绘制图片.
|
||||
//所有的绘制图片的参数均需要放入此结构内
|
||||
//直接更改im内的数据即可设置绘制参数. (就像结构体一样用它)
|
||||
im.baseFs=&guy.guyFS(); //在此处就是设置文件系统.
|
||||
|
||||
im.filename=BMP_FILE; //在此直接设置文件路径和文件名.
|
||||
|
||||
guy.display(FILL_WHITE,false); //将屏幕全刷成白屏. 为了即将的图片刷新.
|
||||
//建议在使用drawImageFile函数之前, 使用慢刷刷白屏, 可以保证显示效果清晰可见.
|
||||
|
||||
im.drawImageFile(); //显示BMP格式.图片. im会自动识别文件扩展名并绘制.
|
||||
//此处不再需要调用 guy.display() 函数即可显示.
|
||||
//此时显示缓存已经清空(因为显示缓存内原本是用来解码图片用的)
|
||||
//此时直接使用guy.display()将刷白屏.
|
||||
|
||||
delay(2000);
|
||||
|
||||
|
||||
//显示JPG格式
|
||||
im.filename=JPG_FILE; //在此直接设置文件路径和文件名.
|
||||
|
||||
im.scalex=0.3333333f; //设置横坐标图片缩放
|
||||
im.scaley=0.3333333f; //设置纵坐标图片缩放.
|
||||
im.offsetx=70; //设置显示偏移. 此处的70说明 JPG图像应该从图片文件的(70,40)坐标处开始解码
|
||||
im.offsety=40; //设置显示偏移Y轴方向.
|
||||
|
||||
im.background=0; //设置背景颜色, 0黑1白, 此处设为背景色为黑色.
|
||||
|
||||
guy.display(FILL_WHITE,false); //将屏幕全刷成白屏. 为了即将的图片刷新.
|
||||
|
||||
im.drawImageFile(); //显示JPG格式.图片. im会自动识别文件扩展名并绘制.
|
||||
delay(2000);
|
||||
|
||||
|
||||
#ifndef ESP8266 //显示PNG格式. ESP8266不支持PNG格式
|
||||
im.filename=PNG_FILE; //PNG图片. ESP8266的内存不够, 所以不能显示PNG格式~(T_T)~
|
||||
|
||||
im.x=10; //设置在哪里绘制图片. 在此编辑图片绘制起始点的 X, Y 坐标
|
||||
im.y=5 ; //
|
||||
im.scalex=400.0f/1280.0f;
|
||||
im.scaley=300.0f/576.0f;
|
||||
|
||||
guy.display(FILL_WHITE, false); //显示. 此处的功能就是将显示缓存输出到屏幕上
|
||||
|
||||
im.drawImageFile(); //显示JPG格式.图片. ESP8266可能不会绘制.
|
||||
delay(2000);
|
||||
|
||||
#endif
|
||||
|
||||
//开启灰度显示, 然后显示BMP格式
|
||||
im.filename=BMP_FILE; //在此直接设置文件路径和文件名.
|
||||
|
||||
im.scalex=0.75f; //设置横坐标图片缩放
|
||||
im.scaley=0.5625f; //设置纵坐标图片缩放.
|
||||
im.offsetx=0; //设置显示偏移. 此处的70说明 JPG图像应该从图片文件的(70,40)坐标处开始解码
|
||||
im.offsety=0; //设置显示偏移Y轴方向.
|
||||
|
||||
im.background=1; //设置背景颜色, 0黑1白, 此处设为背景色为黑色.
|
||||
|
||||
#ifdef ESP8266
|
||||
#define MEM_POOL 10000
|
||||
#else
|
||||
#define MEM_POOL 60000
|
||||
#endif
|
||||
|
||||
uint8_t *buffer = new uint8_t [ MEM_POOL ]; //分配缓存
|
||||
im.exPool=buffer; //设置外部缓存内存地址
|
||||
im.exPoolSize=MEM_POOL; //设置外部缓存内存大小
|
||||
|
||||
guy.setGreyQuality(1); //设置灰度模式为默认灰度显示模式
|
||||
guy.display(FILL_WHITE,false); //将屏幕全刷成白屏. 为了即将显示灰度图.
|
||||
|
||||
im.enableFloyd=0; //禁用掉抖动算法.
|
||||
|
||||
im.drawImageFile(1); //显示JPG格式.图片.
|
||||
|
||||
delay(2000);
|
||||
|
||||
guy.display(FILL_WHITE,false); //将屏幕全刷成白屏. 为了即将显示灰度图.
|
||||
|
||||
im.enableFloyd=1; // 重新启用抖动算法.
|
||||
|
||||
im.drawImageFile(1); //显示JPG格式.图片.
|
||||
|
||||
delay(5000);
|
||||
|
||||
delete []buffer;
|
||||
im.exPool=nullptr; //用完之后将这个内存地址置为null, 避免重复使用导致内存不可访问.
|
||||
im.exPoolSize=0;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
// 灰度测试代码 -------------------------------------------------------------------------- 灰度测试代码
|
||||
|
||||
im.filename=BMP_FILE; //在此直接设置文件路径和文件名.
|
||||
|
||||
guy.setGreyQuality(0);
|
||||
|
||||
guy.display(FILL_WHITE, false);
|
||||
|
||||
#ifdef ESP8266
|
||||
#define MEM_POOL 10000
|
||||
#else
|
||||
#define MEM_POOL 60000
|
||||
#endif
|
||||
uint8_t *buffer = new uint8_t [ MEM_POOL ]; //分配缓存
|
||||
im.exPool=buffer; //设置外部缓存内存地址
|
||||
im.exPoolSize=MEM_POOL; //设置外部缓存内存大小
|
||||
|
||||
im.enableFloyd = 0;
|
||||
im.drawImageFile(true); //显示BMP格式.图片. im会自动识别文件扩展名并绘制.
|
||||
//此处不再需要调用 guy.display() 函数即可显示.
|
||||
//此时显示缓存已经清空(因为显示缓存内原本是用来解码图片用的)
|
||||
//此时直接使用guy.display()将刷白屏.
|
||||
|
||||
delay(3000);
|
||||
|
||||
guy.display(FILL_WHITE,false);
|
||||
|
||||
im.enableFloyd = 1;
|
||||
guy.setGreyQuality(1);
|
||||
im.drawImageFile(true); //显示BMP格式.图片. im会自动识别文件扩展名并绘制.
|
||||
|
||||
delay(3000);
|
||||
|
||||
//显示JPG格式
|
||||
im.filename=JPG_FILE; //在此直接设置文件路径和文件名.
|
||||
|
||||
im.scalex=1.3333333f;
|
||||
im.scaley=1.3333333f;
|
||||
|
||||
//im.scalex=0.3333333f; //设置横坐标图片缩放
|
||||
//im.scaley=0.3333333f; //设置纵坐标图片缩放.
|
||||
//im.offsetx=70; //设置显示偏移. 此处的70说明 JPG图像应该从图片文件的(70,40)坐标处开始解码
|
||||
//im.offsety=40; //设置显示偏移Y轴方向.
|
||||
|
||||
im.background=0; //设置背景颜色, 0黑1白, 此处设为背景色为黑色.
|
||||
|
||||
guy.display(FILL_WHITE, false);
|
||||
|
||||
im.drawImageFile(); //显示JPG格式.图片. im会自动识别文件扩展名并绘制.
|
||||
delete []buffer;
|
||||
|
||||
// 灰度测试代码 -------------------------------------------------------------------------- 灰度测试代码
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// --------------------- 4 - 显示图片 使用readguyImage类的externalBuffer绘制到主屏幕缓存. -----<<<
|
||||
|
||||
//实现原理: 通过一个额外的缓存, 显示引擎可以分多次将图片显示在这个额外的内存中, 再将这块内存写入到缓存内.
|
||||
//由于用了外部内存, 所以可以分多次显示一张大图片, 相比于分配整张大图片的内存, 要更节省内存.代价是速度更慢
|
||||
|
||||
//readguy驱动程序的内部有一个屏幕缓存, 如果使用这个缓存来显示图片, 屏幕上原本的东西也会变得混乱.(上个示例)
|
||||
//因此, readguyImage类提供了使用外部内存的显示功能.
|
||||
//分为多次, 每次将图片的一小部分显示到外部内存中, 再写入到屏幕缓存内.
|
||||
|
||||
//需要提供额外分配好的内存, 但此函数不会更改显示区域之外的显示缓存.
|
||||
|
||||
guy.fillScreen(1); //将屏幕全刷成白屏. 为了即将的图片刷新.
|
||||
|
||||
for(int i=1;i<10;i++){ //在屏幕上绘画线段. 本质是更改显示缓存.
|
||||
guy.drawLine(i*guy.width()/10,0,0,i*guy.height()/10,0);
|
||||
guy.drawLine(i*guy.width()/10,guy.height()-1,guy.width()-1,i*guy.height()/10,0);
|
||||
}
|
||||
guy.drawLine(guy.width(),0,0,guy.height(),0);
|
||||
|
||||
guy.display(false); //刷新屏幕, 显示绘画的线段
|
||||
|
||||
//im.baseFs=&guy.guyFS(); //直接更改im内的数据即可设置绘制参数. 在此处就是设置文件系统.
|
||||
im.filename=BMP_FILE; //在此直接设置文件路径和文件名.
|
||||
im.background=0; //设置背景颜色, 0黑1白, 此处设为背景色为黑色.
|
||||
|
||||
im.x=15; //设置将要显示的横坐标
|
||||
im.y=15; //设置将要显示的纵坐标
|
||||
im.w=180; //设置将要显示区域的宽度
|
||||
im.h=270; //设置将要显示区域的高度
|
||||
im.offsetx=0; //如果不从左上角开始解码图片, 从哪个坐标开始显示/解码图片?
|
||||
im.offsety=0;
|
||||
im.scalex=0.5625f; //设置横坐标缩放.
|
||||
im.scaley=0.5625f; //设置纵坐标缩放. 为0代表与横坐标缩放相同.
|
||||
|
||||
buffer = new uint8_t [ 60*270 ]; //分配缓存
|
||||
im.exPool=buffer; //设置外部缓存内存地址
|
||||
im.exPoolSize=60*270; //设置外部缓存内存大小
|
||||
|
||||
im.drawImageToBuffer(); //将图片写入到屏幕缓存. im会自动识别文件扩展名并绘制.
|
||||
|
||||
guy.display(); //显示缓存.此时应当能看到图片.
|
||||
|
||||
delete []buffer;
|
||||
|
||||
}
|
||||
|
||||
void loop(){
|
||||
delay(1);
|
||||
}/* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
|
||||
|
||||
@@ -75,26 +75,6 @@ void drvBase::SetLut(const unsigned char* lut) {
|
||||
}
|
||||
}
|
||||
|
||||
void drvBase::SetFrameWriter(std::function<uint8_t(int)> f,uint8_t _extra) {
|
||||
guy_epdCmd(0x44);
|
||||
guy_epdParam((0 >> 3) & 0xFF);
|
||||
guy_epdParam(((epdWidth-1) >> 3) & 0xFF);
|
||||
guy_epdCmd(0x45);
|
||||
guy_epdParam(0 & 0xFF);
|
||||
guy_epdParam((0 >> 8) & 0xFF);
|
||||
guy_epdParam((epdHeight-1) & 0xFF);
|
||||
guy_epdParam(((epdHeight-1) >> 8) & 0xFF);
|
||||
|
||||
guy_epdCmd(0x4e);
|
||||
guy_epdParam((0 >> 3) & 0xFF);
|
||||
guy_epdCmd(0x4f);
|
||||
guy_epdParam(0 & 0xFF);
|
||||
guy_epdParam((0 >> 8) & 0xFF);
|
||||
guy_epdCmd(_extra);
|
||||
for (int i = 0; i < epdHeight*epdWidth / 8; i++)
|
||||
guy_epdParam(f(i));
|
||||
}
|
||||
|
||||
const PROGMEM unsigned char lut_slow[] =
|
||||
{
|
||||
/* 0x02, 0x02, 0x01, 0x11, 0x12, 0x12, 0x22, 0x22,
|
||||
@@ -134,7 +114,7 @@ void drvBase::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新等
|
||||
guy_epdBusy(100);
|
||||
guy_epdCmd(0x24); /* will send the color data */
|
||||
for (int i = 0; i < epdHeight*epdWidth / 8; i++)
|
||||
guy_epdParam(f(i));
|
||||
SpiTransfer(f(i));
|
||||
guy_epdCmd(0x22);
|
||||
guy_epdParam(0xC4);
|
||||
guy_epdCmd(0x20);
|
||||
@@ -146,7 +126,7 @@ void drvBase::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新等
|
||||
guy_epdBusy(90);
|
||||
guy_epdCmd(0x26); /* will send the color data */
|
||||
for (int i = 0; i < epdHeight*epdWidth / 8; i++)
|
||||
guy_epdParam(f(i));
|
||||
SpiTransfer(f(i));
|
||||
EndTransfer();
|
||||
}
|
||||
void drvBase::drv_sleep() { //开始屏幕睡眠
|
||||
|
||||
@@ -55,7 +55,6 @@ protected:
|
||||
int idleFastRf;
|
||||
private:
|
||||
int Init(const unsigned char* lut);
|
||||
void SetFrameWriter(std::function<uint8_t(int)> f,uint8_t _extra);
|
||||
const unsigned char* lut;
|
||||
uint8_t iLut = 15;
|
||||
uint8_t sleeping=1;
|
||||
|
||||
@@ -121,31 +121,6 @@ void drvSSD168x::epd_init() {
|
||||
SetLut();
|
||||
}
|
||||
|
||||
void drvSSD168x::SetFrameWriter(std::function<uint8_t(int)> f) {
|
||||
if(_part && epd_PowerOn){
|
||||
//Reset();
|
||||
SetLut();
|
||||
guy_epdCmd(0x37);
|
||||
for(int i=0;i<10;i++) guy_epdParam(i==5?0x40:0x00);
|
||||
guy_epdCmd(0x3C); //BorderWavefrom
|
||||
guy_epdParam(0x80);
|
||||
|
||||
guy_epdCmd(0x22);
|
||||
guy_epdParam(0xC0);
|
||||
guy_epdCmd(0x20);
|
||||
guy_epdBusy(140);
|
||||
}
|
||||
else epd_init();
|
||||
SetMemory();
|
||||
guy_epdCmd(0x24);
|
||||
for (int i = 0; i < epdHeight*epdWidth / 8; i++)
|
||||
guy_epdParam(f(i));
|
||||
if(!_part){
|
||||
guy_epdCmd(0x26);
|
||||
for (int i = 0; i < epdHeight*epdWidth / 8; i++)
|
||||
guy_epdParam(f(i));
|
||||
}
|
||||
}
|
||||
void drvSSD168x::DisplayFrame(void) {
|
||||
guy_epdCmd(0x22);
|
||||
guy_epdParam(_part?0x0f:0xc7);
|
||||
@@ -198,7 +173,29 @@ void drvSSD168x::drv_fullpart(bool part){ //切换慢刷/快刷功能
|
||||
}
|
||||
void drvSSD168x::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
|
||||
BeginTransfer();
|
||||
SetFrameWriter(f);
|
||||
if(_part && epd_PowerOn){
|
||||
//Reset();
|
||||
SetLut();
|
||||
guy_epdCmd(0x37);
|
||||
for(int i=0;i<10;i++) guy_epdParam(i==5?0x40:0x00);
|
||||
guy_epdCmd(0x3C); //BorderWavefrom
|
||||
guy_epdParam(0x80);
|
||||
|
||||
guy_epdCmd(0x22);
|
||||
guy_epdParam(0xC0);
|
||||
guy_epdCmd(0x20);
|
||||
guy_epdBusy(140);
|
||||
}
|
||||
else epd_init();
|
||||
SetMemory();
|
||||
guy_epdCmd(0x24);
|
||||
for (int i = 0; i < epdHeight*epdWidth / 8; i++)
|
||||
SpiTransfer(f(i));
|
||||
if(!_part){
|
||||
guy_epdCmd(0x26);
|
||||
for (int i = 0; i < epdHeight*epdWidth / 8; i++)
|
||||
SpiTransfer(f(i));
|
||||
}
|
||||
DisplayFrame();
|
||||
EndTransfer();
|
||||
guy_epdBusy(_part?600:2300);
|
||||
@@ -220,7 +217,7 @@ void drvSSD168x::drv_setDepth(uint8_t i){ //设置显示颜色深度, 不支持
|
||||
else iLut=15;
|
||||
}
|
||||
void drvSSD168x::drv_draw16grey_step(std::function<uint8_t(int)> f, int step){
|
||||
if(_quality) return readguyEpdBase::drv_draw16grey_step(f,step);
|
||||
if(_quality&1) return readguyEpdBase::drv_draw16grey_step(f,step);
|
||||
if(step==1){
|
||||
drv_fullpart(1);
|
||||
greyScaling=1;
|
||||
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
void drv_sleep() ; //开始屏幕睡眠
|
||||
int drv_width() const { return epdWidth; }; //返回显示区域宽度
|
||||
int drv_height() const{ return epdHeight; }; //返回显示区域高度
|
||||
int drv_supportGreyscaling() const { return _quality?16:-16; }
|
||||
int drv_supportGreyscaling() const { return (_quality&1)?16:-16; }
|
||||
void drv_setDepth(uint8_t i); //设置显示颜色深度, 不支持的话什么都不做
|
||||
void drv_draw16grey_step(std::function<uint8_t(int)> f, int step);
|
||||
protected:
|
||||
@@ -61,10 +61,8 @@ private:
|
||||
static const unsigned char VSH_table[32];
|
||||
|
||||
void epd_init();
|
||||
void SetFrameWriter(std::function<uint8_t(int)> f);
|
||||
void DisplayFrame(void);
|
||||
void SetLut();
|
||||
//void SetLut_by_host(const unsigned char *lut);
|
||||
};
|
||||
|
||||
#ifdef READGUY_DEV_154B
|
||||
|
||||
@@ -128,14 +128,14 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
|
||||
// for (int k = 0; k < GUY_D_WIDTH/8; k++)
|
||||
// guy_epdParam(f(j*(GUY_D_WIDTH/8)+k)); //按照给定的RAM写入数据
|
||||
for (int i = 0; i < GUY_D_WIDTH/8*GUY_D_HEIGHT; i++)
|
||||
guy_epdParam(f(i));
|
||||
SpiTransfer(f(i));
|
||||
}
|
||||
guy_epdCmd(0x24);
|
||||
//for (int j = GUY_D_HEIGHT-1; j >= 0; j--)
|
||||
// for (int k = 0; k < GUY_D_WIDTH/8; k++)
|
||||
// guy_epdParam(f(j*(GUY_D_WIDTH/8)+k)); //按照给定的RAM写入数据
|
||||
for (int i = 0; i < GUY_D_WIDTH/8*GUY_D_HEIGHT; i++)
|
||||
guy_epdParam(f(i));
|
||||
SpiTransfer(f(i));
|
||||
epd_Init();
|
||||
guy_epdCmd(0x22);
|
||||
guy_epdParam(epdFull?0xc4:0x04);
|
||||
|
||||
@@ -163,7 +163,7 @@ void drv_base::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
|
||||
//for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/8;i++)
|
||||
// guy_epdParam(c);
|
||||
for (int i = 0; i < epdHeight*epdWidth/8; i++)
|
||||
guy_epdParam(f(i)); //按照给定的RAM写入数据
|
||||
SpiTransfer(f(i)); //按照给定的RAM写入数据
|
||||
|
||||
guy_epdCmd(0x92);
|
||||
if(part_mode){
|
||||
@@ -201,7 +201,7 @@ void drv_base::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
|
||||
//send image data -_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
|
||||
//Total 5624 data written.
|
||||
for (int i = 0; i < epdHeight*epdWidth/8; i++)
|
||||
guy_epdParam(f(i)); //按照给定的RAM写入数据
|
||||
SpiTransfer(f(i)); //按照给定的RAM写入数据
|
||||
guy_epdCmd(0x92);
|
||||
EndTransfer();
|
||||
//[EPDrg_BW<>] powerOff fx
|
||||
@@ -224,7 +224,7 @@ void drv_base::drv_sleep() { //开始屏幕睡眠
|
||||
}
|
||||
|
||||
void drv_base::drv_draw16grey_step(std::function<uint8_t(int)> f, int step){
|
||||
if(_quality) return readguyEpdBase::drv_draw16grey_step(f,step);
|
||||
if(_quality&1) return readguyEpdBase::drv_draw16grey_step(f,step);
|
||||
if(step==1){
|
||||
greyHQ=3;
|
||||
drv_setDepth(3);
|
||||
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
int drv_width() const { return epdWidth; }; //返回显示区域宽度
|
||||
int drv_height() const{ return epdHeight; }; //返回显示区域高度
|
||||
void drv_setDepth(uint8_t i); //设置显示颜色深度
|
||||
int drv_supportGreyscaling() const { return _quality?16:-16; }
|
||||
int drv_supportGreyscaling() const { return (_quality&1)?16:-16; }
|
||||
void drv_draw16grey_step(std::function<uint8_t(int)> f, int step);
|
||||
protected:
|
||||
int epdWidth;
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include "guy_370a.h"
|
||||
#ifdef READGUY_DEV_370A
|
||||
namespace guydev_370A{
|
||||
static const PROGMEM unsigned char lut_1Gray_GC[] ={
|
||||
static const PROGMEM unsigned char lut_1Grey_GC[] ={
|
||||
0x2A,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//1
|
||||
0x05,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//2
|
||||
0x2A,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//3
|
||||
@@ -39,7 +39,7 @@ static const PROGMEM unsigned char lut_1Gray_GC[] ={
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//5
|
||||
0x00,0x02,0x03,0x0A,0x00,0x02,0x06,0x0A,0x05,0x00
|
||||
};
|
||||
static const PROGMEM unsigned char lut_1Gray_A2[] ={
|
||||
static const PROGMEM unsigned char lut_1Grey_A2[] ={
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //1
|
||||
0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //2
|
||||
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //3
|
||||
@@ -88,12 +88,12 @@ void drv::Load_LUT(unsigned char mode) {
|
||||
guy_epdCmd(0x32);
|
||||
for (i = 0; i < 60; i++) {
|
||||
if(mode == 1)
|
||||
guy_epdParam(pgm_read_byte(lut_1Gray_GC+i));
|
||||
guy_epdParam(pgm_read_byte(lut_1Grey_GC+i));
|
||||
else if(mode == 0){
|
||||
if(20==i && greyScaling<8) guy_epdParam(0x03);
|
||||
else if(53==i && greyScaling<3) guy_epdParam(greyScaling);
|
||||
else if(53==i && greyScaling==15) guy_epdParam(5);
|
||||
else guy_epdParam(pgm_read_byte(lut_1Gray_A2+i));
|
||||
else guy_epdParam(pgm_read_byte(lut_1Grey_A2+i));
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 45; i++) {
|
||||
@@ -124,11 +124,11 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
|
||||
|
||||
guy_epdCmd(0x24);
|
||||
for (int i = 0; i < GUY_D_HEIGHT*GUY_D_WIDTH/8; i++)
|
||||
guy_epdParam(f(i)); //按照给定的RAM写入数据
|
||||
SpiTransfer(f(i)); //按照给定的RAM写入数据
|
||||
if(!part_mode) {
|
||||
guy_epdCmd(0x26);
|
||||
for (int i = 0; i < GUY_D_HEIGHT*GUY_D_WIDTH/8; i++)
|
||||
guy_epdParam(f(i)); //按照给定的RAM写入数据
|
||||
SpiTransfer(f(i)); //按照给定的RAM写入数据
|
||||
}
|
||||
|
||||
Load_LUT(!part_mode);
|
||||
|
||||
@@ -100,6 +100,7 @@ const PROGMEM unsigned char drv::lut_213_B72_16grey[]={
|
||||
|
||||
void drv::epd_Init(void){
|
||||
const uint16_t GreyDrvFrameFreq[]={
|
||||
0x1108, /* 75Hz */
|
||||
0x1108, /* 75Hz */
|
||||
0x180c, /* 35Hz */
|
||||
0x2c0a, /* 50Hz */
|
||||
@@ -115,7 +116,6 @@ void drv::epd_Init(void){
|
||||
0x1804, /* 140Hz */
|
||||
0x0d04, /* 145Hz */
|
||||
0x0304, /* 150Hz */
|
||||
//0x0304, /* 150Hz */
|
||||
};
|
||||
//_InitDisplay fx
|
||||
if(epdFull==2) {
|
||||
@@ -203,11 +203,11 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
|
||||
if(epdFull){ //慢刷
|
||||
guy_epdCmd(0x26);
|
||||
for (int i = 0; i < GUY_D_HEIGHT*GUY_D_WIDTH/8; i++)
|
||||
guy_epdParam(f(i)); //按照给定的RAM写入数据
|
||||
SpiTransfer(f(i)); //按照给定的RAM写入数据
|
||||
}
|
||||
guy_epdCmd(0x24);
|
||||
for (int i = 0; i < GUY_D_HEIGHT*GUY_D_WIDTH/8; i++)
|
||||
guy_epdParam(f(i)); //按照给定的RAM写入数据
|
||||
SpiTransfer(f(i)); //按照给定的RAM写入数据
|
||||
if(epdFull){ //慢刷
|
||||
epd_Init();
|
||||
SetMemory();
|
||||
@@ -232,12 +232,12 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
|
||||
SetMemory();
|
||||
guy_epdCmd(0x26);
|
||||
for (int i = 0; i < GUY_D_HEIGHT*GUY_D_WIDTH/8; i++)
|
||||
guy_epdParam(f(i)); //按照给定的RAM写入数据
|
||||
SpiTransfer(f(i)); //按照给定的RAM写入数据
|
||||
EndTransfer();
|
||||
if(epdFull) power_down();
|
||||
}
|
||||
void drv::drv_draw16grey_step(std::function<uint8_t(int)> f, int step){
|
||||
if(_quality) return readguyEpdBase::drv_draw16grey_step(f,step);
|
||||
if(_quality&1) return readguyEpdBase::drv_draw16grey_step(f,step);
|
||||
if(step==1) drv_fullpart(1);//初始阶段,完成准备工作 //设置为快刷模式
|
||||
GreyScalingHighQuality=step; //开启高品质灰度模式
|
||||
drv_dispWriter(f);
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
int drv_height() const{ return GUY_D_HEIGHT; }; //返回显示区域高度
|
||||
void drv_setDepth(uint8_t i) { epdFull=0; GreyScaling = i>15?15:i; if(!i) GreyScaling=15;}
|
||||
void drv_draw16grey_step(std::function<uint8_t(int)> f, int step);
|
||||
int drv_supportGreyscaling() const { return _quality?16:-16; }
|
||||
int drv_supportGreyscaling() const { return (_quality&1)?16:-16; }
|
||||
private:
|
||||
//void Lut(unsigned char* lut);
|
||||
void epd_Init(void);
|
||||
|
||||
@@ -138,15 +138,15 @@ const PROGMEM unsigned char drv::lutFast_w_w[] ={ 0x02,2,0,48,0,1 };
|
||||
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::epd_display(){
|
||||
void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
|
||||
BeginTransfer();
|
||||
Init(part_mode);
|
||||
if(part_mode){
|
||||
sendArea();
|
||||
guy_epdCmd(0x13);
|
||||
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/8;i++){
|
||||
send(i); //guy_epdParam(d[i]);
|
||||
}
|
||||
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/8;i++)
|
||||
SpiTransfer(f(i));
|
||||
//data
|
||||
guy_epdCmd(0x92);
|
||||
sendAreaRaw();
|
||||
@@ -155,14 +155,12 @@ void drv::epd_display(){
|
||||
else{
|
||||
guy_epdCmd(0x10);
|
||||
//刷新数据
|
||||
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/8;i++){
|
||||
send(i); //guy_epdParam(d[i]);
|
||||
}
|
||||
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/8;i++)
|
||||
SpiTransfer(f(i));
|
||||
guy_epdCmd(0x13);
|
||||
//刷新数据
|
||||
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/8;i++){
|
||||
send(i); //guy_epdParam(d[i]);
|
||||
}
|
||||
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/8;i++)
|
||||
SpiTransfer(f(i));
|
||||
guy_epdCmd(0x92);
|
||||
//[EPDrg_BW<>] refresh fx
|
||||
guy_epdCmd(0x00);
|
||||
@@ -179,9 +177,8 @@ void drv::epd_display(){
|
||||
if(part_mode){
|
||||
sendArea();
|
||||
guy_epdCmd(0x13);
|
||||
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/8;i++){
|
||||
send(i); //guy_epdParam(d[i]);
|
||||
}
|
||||
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/8;i++)
|
||||
SpiTransfer(f(i));
|
||||
guy_epdCmd(0x92);
|
||||
EndTransfer();
|
||||
}
|
||||
@@ -189,9 +186,8 @@ void drv::epd_display(){
|
||||
Init(2);
|
||||
sendArea();
|
||||
guy_epdCmd(0x13);
|
||||
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/8;i++){
|
||||
send(i); //guy_epdParam(d[i]);
|
||||
}
|
||||
for(int i=0;i<GUY_D_WIDTH*GUY_D_HEIGHT/8;i++)
|
||||
SpiTransfer(f(i));
|
||||
guy_epdCmd(0x92);
|
||||
guy_epdCmd(0x02);
|
||||
EndTransfer();
|
||||
@@ -212,10 +208,6 @@ void drv::drv_fullpart(bool part){ //切换慢刷/快刷功能
|
||||
part_mode = part;
|
||||
//Init(part);
|
||||
}
|
||||
void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
|
||||
send = [&](int i){ guy_epdParam(f(i)); };
|
||||
epd_display();
|
||||
}
|
||||
void drv::drv_sleep() { //开始屏幕睡眠
|
||||
if(RST_PIN>=0){ //未定义RST_PIN时无法唤醒
|
||||
BeginTransfer();
|
||||
|
||||
@@ -79,9 +79,6 @@ private:
|
||||
|
||||
void SendLuts(uint8_t lutOption); //0:慢刷, 1:快刷, 2:四阶灰度
|
||||
uint8_t customLut, customGreyscale; //customLut 是灰度刷新时的自定义lut
|
||||
void epd_display();
|
||||
//void (*send)(int);
|
||||
std::function<void(int)> send; //此处不能用 void (*send)(int); 是因为lambda函数是std的
|
||||
static const PROGMEM uint8_t greyTable[16];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,27 +29,19 @@
|
||||
|
||||
#include "guy_epdbase.h"
|
||||
#include <spi.h>
|
||||
|
||||
#pragma GCC optimize ("O3")
|
||||
readguyEpdBase::readguyEpdBase() {
|
||||
};
|
||||
|
||||
readguyEpdBase::~readguyEpdBase() {
|
||||
};
|
||||
|
||||
void readguyEpdBase::DigitalWrite(int pin, int value) {
|
||||
if(pin>=0) digitalWrite(pin, value);
|
||||
}
|
||||
|
||||
int readguyEpdBase::DigitalRead(int pin) {
|
||||
return (pin>=0)?digitalRead(pin):1;
|
||||
}
|
||||
|
||||
void readguyEpdBase::DelayMs(unsigned int delaytime) {
|
||||
delay(delaytime);
|
||||
}
|
||||
void readguyEpdBase::BeginTransfer(){
|
||||
if(!in_trans && CS_PIN>=0) {
|
||||
digitalWrite(CS_PIN, LOW);
|
||||
DigitalWrite(CS_PIN, LOW);
|
||||
if(spi_tr_press!=nullptr) spi_tr_press();
|
||||
}
|
||||
in_trans++;
|
||||
@@ -57,11 +49,11 @@ void readguyEpdBase::BeginTransfer(){
|
||||
void readguyEpdBase::EndTransfer(){
|
||||
if(in_trans) in_trans--;
|
||||
if(!in_trans && CS_PIN>=0) {
|
||||
digitalWrite(CS_PIN, HIGH);
|
||||
DigitalWrite(CS_PIN, HIGH);
|
||||
if(spi_tr_release!=nullptr) spi_tr_release();
|
||||
}
|
||||
}
|
||||
void readguyEpdBase::SpiTransfer(unsigned char data) {
|
||||
/*IRAM_ATTR void readguyEpdBase::SpiTransfer(unsigned char data) {
|
||||
if(in_trans) {
|
||||
_spi->transfer(data);
|
||||
return;
|
||||
@@ -69,7 +61,7 @@ void readguyEpdBase::SpiTransfer(unsigned char data) {
|
||||
if(CS_PIN>=0) digitalWrite(CS_PIN, LOW);
|
||||
_spi->transfer(data);
|
||||
if(CS_PIN>=0) digitalWrite(CS_PIN, HIGH);
|
||||
}
|
||||
}*/
|
||||
int readguyEpdBase::IfInit(SPIClass &c,int8_t cs,int8_t dc,int8_t rst,int8_t busy) {
|
||||
//static uint8_t IfHadInit=0;
|
||||
//if(IfHadInit) return;
|
||||
@@ -165,7 +157,7 @@ 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){
|
||||
void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_t x,uint16_t y,int o){
|
||||
#ifndef FLOYD_STEINBERG_DITHERING
|
||||
static const uint8_t bayer_tab [64]={
|
||||
0, 32, 8, 40, 2, 34, 10, 42,
|
||||
@@ -180,20 +172,21 @@ void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_
|
||||
#endif
|
||||
const uint32_t w = (spr.width()+7)>>3;
|
||||
if((!w) || (!spr.height())) return;
|
||||
uint16_t *readBuff = new uint16_t[spr.width()];
|
||||
uint8_t *writeBuff = new uint8_t[w];
|
||||
if(o==0 || o==1){
|
||||
readBuff = new uint16_t[spr.width()];
|
||||
#ifdef FLOYD_STEINBERG_DITHERING
|
||||
int16_t *floyd_tab[2];
|
||||
floyd_tab[0] = new int16_t [spr.width()];
|
||||
floyd_tab[1] = new int16_t [spr.width()];
|
||||
for(int j=0;j<spr.width();j++){ floyd_tab[0][j] = 0; floyd_tab[1][j] = 0; }
|
||||
#endif
|
||||
floyd_tab[0] = new int16_t [spr.width()];
|
||||
floyd_tab[1] = new int16_t [spr.width()];
|
||||
for(int j=0;j<spr.width();j++){ floyd_tab[0][j] = 0; floyd_tab[1][j] = 0; }
|
||||
#endif
|
||||
writeBuff = new uint8_t[w];
|
||||
}
|
||||
sprbase.fillRect(x,y,spr.width(),spr.height(),1);
|
||||
for(int32_t i=0;i<(int32_t)spr.height();i++){
|
||||
spr.readRect(0,i,spr.width(),1,readBuff);
|
||||
for(int32_t i=y;i<(int32_t)spr.height()+y;i++){
|
||||
spr.readRect(0,i-y,spr.width(),1,readBuff);
|
||||
#ifdef FLOYD_STEINBERG_DITHERING
|
||||
uint_fast8_t buff8bit=0;
|
||||
for(int32_t j=0;j<(int32_t)spr.width();j++){
|
||||
for(int32_t j=0;j<spr.width();j++){
|
||||
int32_t flodelta = floyd_tab[i&1][j]+(int32_t)((greysc(readBuff[j])<<8)|greysc(readBuff[j]));
|
||||
if(flodelta>=0x8000) {
|
||||
//spr.drawPixel(j,i,1);
|
||||
@@ -212,11 +205,11 @@ void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_
|
||||
}
|
||||
if(j) { floyd_tab[!(i&1)][j-1] += (flodelta*3)>>4; }
|
||||
{ floyd_tab[!(i&1)][j ] += (flodelta*5)>>4; }*/
|
||||
if(j!=(int32_t)spr.width()-1)
|
||||
if(j!=spr.width()-1)
|
||||
{ floyd_tab[i&1] [j+1] += (flodelta*7)>>4; }
|
||||
if(j) { floyd_tab[!(i&1)][j-1] += (flodelta*3)>>4; }
|
||||
{ floyd_tab[!(i&1)][j ] += (flodelta*5)>>4; }
|
||||
if(j!=(int32_t)spr.width()-1)
|
||||
if(j!=spr.width()-1)
|
||||
{ floyd_tab[!(i&1)][j+1] += (flodelta )>>4; }
|
||||
}
|
||||
for(int floi=0;floi<spr.width();floi++) floyd_tab[i&1][floi]=0;
|
||||
@@ -228,81 +221,94 @@ void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_
|
||||
writeBuff[j]=buff8bit;
|
||||
}
|
||||
#endif
|
||||
sprbase.drawBitmap(x,y+i,writeBuff,spr.width(),1,1,0);
|
||||
sprbase.drawBitmap(x,i,writeBuff,spr.width(),1,1,0);
|
||||
}
|
||||
_display((const uint8_t*)sprbase.getBuffer());
|
||||
delete []readBuff;
|
||||
delete []writeBuff;
|
||||
//_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] ;
|
||||
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){
|
||||
//Serial.println("drv_draw16grey fx");
|
||||
const uint32_t w = (spr.width()+7)>>3;
|
||||
if((!w) || (!spr.height())) return;
|
||||
uint16_t *readBuff = new uint16_t[spr.width()];
|
||||
uint8_t *writeBuff = new uint8_t[w];
|
||||
readBuff = new uint16_t[spr.width()];
|
||||
if(_quality&2){
|
||||
#ifdef FLOYD_DITHERING_16GREY
|
||||
int16_t *floyd_tab[2];
|
||||
floyd_tab[0] = new int16_t [spr.width()];
|
||||
floyd_tab[1] = new int16_t [spr.width()];
|
||||
floyd_tab[0] = new int16_t [spr.width()];
|
||||
floyd_tab[1] = new int16_t [spr.width()];
|
||||
#endif
|
||||
}
|
||||
writeBuff = new uint8_t[w];
|
||||
sprbase.fillRect(x,y,spr.width(),spr.height(),1);
|
||||
bool negativeOrder=(drv_supportGreyscaling()==-16);
|
||||
drv_fullpart(0);
|
||||
_display((const uint8_t*)sprbase.getBuffer()); //先对区域慢刷白屏确保颜色正确
|
||||
//_display((const uint8_t*)sprbase.getBuffer()); //先对区域慢刷白屏确保颜色正确
|
||||
drv_dispWriter(FILL_WHITE);
|
||||
drv_fullpart(1);
|
||||
for(uint_fast8_t k=1;k<16;k++){ //亮度为15的不用绘制,因为本来就是白色
|
||||
#ifdef FLOYD_DITHERING_16GREY
|
||||
for(int j=0;j<spr.width();j++){ floyd_tab[0][j] = 0; floyd_tab[1][j] = 0; }
|
||||
if(_quality&2) for(int j=0;j<spr.width();j++){ floyd_tab[0][j] = 0; floyd_tab[1][j] = 0; }
|
||||
#endif
|
||||
for(int i=0;i<spr.height();i++){
|
||||
spr.readRect(0,i,spr.width(),1,readBuff);
|
||||
for(uint32_t j=0;j<w;j++){
|
||||
uint_fast8_t buff8bit=0;
|
||||
for(uint_fast8_t b=0;b<8;b++){
|
||||
for(int i=y;i<spr.height()+y;i++){
|
||||
uint_fast8_t buff8bit=0;
|
||||
spr.readRect(0,i-y,spr.width(),1,readBuff);
|
||||
for(int32_t j=0;j<spr.width();j++){
|
||||
//for(uint_fast8_t b=0;b<8;b++){
|
||||
#ifdef FLOYD_DITHERING_16GREY
|
||||
uint_fast8_t cg=0;
|
||||
int32_t fd = floyd_tab[i&1][(j<<3)+b]+(int32_t)((greysc(readBuff[(j<<3)+b])<<8)|greysc(readBuff[(j<<3)+b]));
|
||||
uint_fast8_t cg=0;
|
||||
if(_quality&2){
|
||||
int gv=greysc(readBuff[j]);
|
||||
int32_t fd = floyd_tab[i&1][j]+((gv<<8)|gv);
|
||||
while(fd>=0x800) {
|
||||
cg++;
|
||||
if(fd>=0) fd -= 0x1000;
|
||||
}
|
||||
if(fd<0) fd++;
|
||||
if((j<<3)+b!=(uint32_t)spr.width()-1)
|
||||
{ floyd_tab[i&1] [(j<<3)+b+1] += (fd*7)>>4; }
|
||||
if((j<<3)+b) { floyd_tab[!(i&1)][(j<<3)+b-1] += (fd*3)>>4; }
|
||||
{ floyd_tab[!(i&1)][(j<<3)+b ] += (fd*5)>>4; }
|
||||
if((j<<3)+b!=(uint32_t)spr.width()-1)
|
||||
{ floyd_tab[!(i&1)][(j<<3)+b+1] += (fd )>>4; }
|
||||
if(j!=spr.width()-1)
|
||||
{ floyd_tab[i&1] [j+1] += (fd*7)>>4; }
|
||||
if(j) { floyd_tab[!(i&1)][j-1] += (fd*3)>>4; }
|
||||
{ floyd_tab[!(i&1)][j ] += (fd*5)>>4; }
|
||||
if(j!=spr.width()-1)
|
||||
{ floyd_tab[!(i&1)][j+1] += (fd )>>4; }
|
||||
}
|
||||
else{ cg=greysc(readBuff[j])>>4; }
|
||||
#else
|
||||
uint_fast8_t cg=greysc(readBuff[(j<<3)+b])>>4;
|
||||
uint_fast8_t cg=greysc(readBuff[j])>>4;
|
||||
#endif
|
||||
if(negativeOrder)
|
||||
buff8bit |= (cg<k)<<((~b)&7);
|
||||
buff8bit |= (cg<k)<<((~j)&7);
|
||||
else{
|
||||
if(cg==15) continue; //白色不考虑
|
||||
buff8bit |= (cg>=((~k)&15))<<((~b)&7);
|
||||
if(cg<15) //白色不考虑
|
||||
buff8bit |= (cg>=((~k)&15))<<((~j)&7);
|
||||
}
|
||||
}
|
||||
//sprbase.drawPixel(x+j,y+i,(greysc(readBuff[j])/16)==(15-k));
|
||||
writeBuff[j]=buff8bit^0xff;
|
||||
if((j&7)==7 || j==((int32_t)spr.width()-1)){
|
||||
writeBuff[j>>3]=buff8bit^0xff;
|
||||
buff8bit=0;
|
||||
}
|
||||
//}
|
||||
//sprbase.drawPixel(x+j,i,(greysc(readBuff[j])/16)==(15-k));
|
||||
}
|
||||
#ifdef FLOYD_DITHERING_16GREY
|
||||
for(int floi=0;floi<spr.width();floi++) floyd_tab[i&1][floi]=0;
|
||||
if(_quality&2) for(int floi=0;floi<spr.width();floi++) floyd_tab[i&1][floi]=0;
|
||||
#endif
|
||||
sprbase.drawBitmap(x,y+i,writeBuff,spr.width(),1,1,0);
|
||||
sprbase.drawBitmap(x,i,writeBuff,spr.width(),1,1,0);
|
||||
}
|
||||
drv_draw16grey_step((const uint8_t*)sprbase.getBuffer(),k); //使用灰度显示函数
|
||||
}
|
||||
delete []readBuff;
|
||||
delete []writeBuff;
|
||||
if(_quality&2){
|
||||
#ifdef FLOYD_DITHERING_16GREY
|
||||
delete [] floyd_tab[0] ;
|
||||
delete [] floyd_tab[1] ;
|
||||
delete [] floyd_tab[0] ;
|
||||
delete [] floyd_tab[1] ;
|
||||
#endif
|
||||
}
|
||||
} /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
@@ -38,6 +38,8 @@
|
||||
#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;})
|
||||
class readguyEpdBase {
|
||||
protected:
|
||||
SPIClass *_spi;
|
||||
@@ -47,24 +49,32 @@ protected:
|
||||
int8_t CS_PIN ;
|
||||
int8_t BUSY_PIN;
|
||||
uint8_t in_trans=0;
|
||||
uint8_t _quality=0; //灰度显示品质 0(默认)-高品质 1-低品质 部分屏幕支持高品质的连续刷灰度.
|
||||
uint8_t _quality=2; //灰度显示品质 0(默认)-高品质 1-低品质 部分屏幕支持高品质的连续刷灰度.
|
||||
#ifdef MEPD_DEBUG_WAVE
|
||||
uint16_t 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
|
||||
|
||||
public:
|
||||
readguyEpdBase(void);
|
||||
virtual ~readguyEpdBase(void);
|
||||
int IfInit(SPIClass &c,int8_t cs,int8_t dc,int8_t rst,int8_t busy);
|
||||
void DigitalWrite(int pin, int value);
|
||||
int DigitalRead(int pin);
|
||||
IRAM_ATTR void DigitalWrite(int pin, int value) { if(pin>=0) digitalWrite(pin, value); }
|
||||
IRAM_ATTR int DigitalRead(int pin) { return (pin>=0)?digitalRead(pin):1; }
|
||||
void DelayMs(unsigned int delaytime);
|
||||
void BeginTransfer();
|
||||
void EndTransfer();
|
||||
void SpiTransfer(unsigned char data);
|
||||
void SpiTransfer(unsigned char data){
|
||||
if(in_trans)
|
||||
_spi->transfer(data);
|
||||
}
|
||||
//basic I/O operation
|
||||
void guy_epdCmd(unsigned char command);
|
||||
void guy_epdParam(unsigned char data);
|
||||
void guy_epdParam(unsigned char data); //发送数据, 注意此方式速度会比较慢 大量数据发送请直接用SpiTransfer()
|
||||
void guy_epdBusy(int32_t maxt);
|
||||
void Reset(uint32_t minTime = 20);
|
||||
void SetMemory(); //集成了0x44 0x45 0x4e 0x4f指令的函数. 此函数用于设置墨水屏内存写入方式
|
||||
@@ -86,8 +96,8 @@ public:
|
||||
* @param gamma_on 是否对灰度值进行gamma校正(速度慢)
|
||||
* @return uint32_t 颜色的灰度值
|
||||
*/
|
||||
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); //分步完成灰度刷新
|
||||
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); //分步完成灰度刷新
|
||||
void drv_draw16grey(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_t x,uint16_t y);//省内存方式
|
||||
void drv_draw16grey_step(const uint8_t *buf, int step){ //分步完成灰度刷新
|
||||
drv_draw16grey_step([&](int n)->uint8_t{return buf[n];},step);
|
||||
@@ -96,9 +106,10 @@ public:
|
||||
drv_setDepth(step);
|
||||
drv_dispWriter(f);
|
||||
}
|
||||
void setGreyQuality(bool q) { _quality=!q; } //设置灰度的渲染画质. 高画质模式在某些屏幕某些情况下可能表现不好.
|
||||
void setGreyQuality(uint8_t q){_quality=q^3;} //设置灰度的渲染画质. 高画质模式在某些屏幕某些情况下可能表现不好.
|
||||
void (*spi_tr_release)(void);
|
||||
void (*spi_tr_press)(void);
|
||||
friend class ReadguyDriver;
|
||||
#ifdef MEPD_DEBUG_DISPLAY
|
||||
friend class LGFX;
|
||||
#endif
|
||||
|
||||
@@ -73,9 +73,11 @@
|
||||
//#define _DEFINA_SD_CS_PIN 0
|
||||
|
||||
// * for NodeMcu ctg stack LCF board
|
||||
#define WHITE_GAP 8
|
||||
|
||||
#ifdef ESP8266
|
||||
#define DISPLAY_TYPE_ST7789_240320 //2.0寸的ST7789 IPS TFT模块
|
||||
#define _DEFINA_IPS_CS_PIN 15
|
||||
#define _DEFINA_IPS_CS_PIN 15 //lcdDebug是不支持自定义引脚的
|
||||
#define _DEFINA_IPS_DC_PIN 5
|
||||
#define _DEFINA_IPS_RST_PIN -1
|
||||
|
||||
|
||||
@@ -54,12 +54,15 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
|
||||
}
|
||||
for(int j=0;j<drv_height();j++){
|
||||
for(int i=0;i<xbits;i++){
|
||||
if(f(j*xbits+i) == 0xff && i!=xbits-1)
|
||||
uint_fast8_t readf=f(j*xbits+i);
|
||||
if(readf == 0xff && i!=xbits-1)
|
||||
ips.drawFastHLine(WHITE_GAP+i*8,WHITE_GAP+j,8,0xffff);
|
||||
else {
|
||||
int lineOK=0;
|
||||
ips.readRect(WHITE_GAP+i*8,WHITE_GAP+j,8,1,dat); //注意这里 readrect函数已经自动化实现边界处理了
|
||||
if(f(j*xbits+i) == 0x00 && i!=xbits-1){
|
||||
if(partMode)//注意这里 readrect函数已经自动化实现边界处理了
|
||||
ips.readRect(WHITE_GAP+i*8,WHITE_GAP+j,8,1,dat);
|
||||
else memset(dat,0xff,sizeof(dat));
|
||||
if(readf == 0x00 && i!=xbits-1){
|
||||
for(int k=0;k<8;k++)
|
||||
if((dat[k]&0x1f)==0x1f) lineOK++;
|
||||
if(lineOK==8) {
|
||||
@@ -69,7 +72,7 @@ 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;
|
||||
if((f(j*xbits+i)&(0x80>>k)))
|
||||
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));
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#ifdef MEPD_DEBUG_DISPLAY
|
||||
#include "ctg_stack_c_defines.h"
|
||||
|
||||
#define WHITE_GAP 4
|
||||
namespace EpdLcdDebug{
|
||||
|
||||
class drv : public readguyEpdBase {
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "readguy.h"
|
||||
|
||||
#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";
|
||||
@@ -111,7 +112,6 @@ const char *ReadguyDriver::epd_drivers_list[EPD_DRIVERS_NUM_MAX]={
|
||||
NAME_guyDev420WF,
|
||||
NAME_epdLcd
|
||||
};
|
||||
#ifdef READGUY_ESP_ENABLE_WIFI
|
||||
//static const char *index_cn_html;
|
||||
//static const uint8_t faviconData[1150];
|
||||
|
||||
|
||||
@@ -172,18 +172,23 @@ uint8_t ReadguyDriver::checkEpdDriver(){
|
||||
Serial.println(F("IfInit OK"));
|
||||
return READGUY_epd_type;
|
||||
}
|
||||
void ReadguyDriver::setEpdDriver(){
|
||||
void ReadguyDriver::setEpdDriver(int g_width,int g_height){
|
||||
guy_dev->spi_tr_release = in_release;
|
||||
guy_dev->spi_tr_press = in_press;
|
||||
guy_dev->drv_init(); //初始化epd驱动层
|
||||
if(g_width) guy_width = g_width;
|
||||
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("EPD init OK"));
|
||||
//以下依赖于你的图形驱动
|
||||
setColorDepth(1); //单色模式
|
||||
createPalette(); //初始化颜色系统
|
||||
Serial.printf_P(PSTR("mono set: w: %d, h: %d\n"),guy_dev->drv_width(),guy_dev->drv_height());
|
||||
Serial.printf_P(PSTR("mono set: w: %d, h: %d\n"),guy_width,guy_height);
|
||||
//创建画布. 根据LovyanGFX的特性, 如果以前有画布会自动重新生成新画布
|
||||
//此外, 即使画布宽度不是8的倍数(如2.13寸单色),也支持自动补全8的倍数 ( 250x122 => 250x128 )
|
||||
createSprite(guy_dev->drv_width(),guy_dev->drv_height());
|
||||
//为了保证图片显示功能的正常使用, 高度也必须是8的倍数.
|
||||
createSprite(guy_width,(guy_height+7)&0x7ffffff8);
|
||||
//setRotation(1); //旋转之后操作更方便
|
||||
setRotation(0);
|
||||
setFont(&fonts::Font0);
|
||||
@@ -209,7 +214,6 @@ bool ReadguyDriver::setSDcardDriver(){
|
||||
READGUY_sd_ok = SDFS.begin();
|
||||
#else
|
||||
if(sd_spi == nullptr) {
|
||||
//sd_spi = new SPIClass(HSPI);
|
||||
#if (defined(CONFIG_IDF_TARGET_ESP32))
|
||||
sd_spi = new SPIClass(VSPI);
|
||||
#else
|
||||
@@ -386,6 +390,10 @@ void ReadguyDriver::display(std::function<uint8_t(int)> f, bool part){
|
||||
void ReadguyDriver::drawImage(LGFX_Sprite &spr,uint16_t x,uint16_t y) {
|
||||
if(READGUY_cali==127) guy_dev->drv_drawImage(*this, spr, x, y);
|
||||
}
|
||||
void ReadguyDriver::drawImageStage(LGFX_Sprite &spr,uint16_t x,uint16_t y,uint8_t stage,uint8_t totalstage) {
|
||||
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)));
|
||||
}
|
||||
void ReadguyDriver::setDepth(uint8_t d){
|
||||
if(READGUY_cali==127 && guy_dev->drv_supportGreyscaling()) guy_dev->drv_setDepth(d);
|
||||
}
|
||||
@@ -396,16 +404,20 @@ void ReadguyDriver::draw16grey(LGFX_Sprite &spr,uint16_t x,uint16_t y){
|
||||
guy_dev->drv_drawImage(*this, spr, x, y);
|
||||
}
|
||||
void ReadguyDriver::draw16greyStep(int step){
|
||||
if(READGUY_cali==127 && guy_dev->drv_supportGreyscaling())
|
||||
return guy_dev->drv_draw16grey_step((const uint8_t *)this->getBuffer(),step);
|
||||
if(READGUY_cali==127 && guy_dev->drv_supportGreyscaling() && step>0 && step<16 ){
|
||||
if(step==1) guy_dev->drv_fullpart(1);
|
||||
guy_dev->drv_draw16grey_step((const uint8_t *)this->getBuffer(),step);
|
||||
}
|
||||
}
|
||||
void ReadguyDriver::draw16greyStep(std::function<uint8_t(int)> f, int step){
|
||||
if(READGUY_cali==127 && guy_dev->drv_supportGreyscaling())
|
||||
return guy_dev->drv_draw16grey_step(f,step);
|
||||
if(READGUY_cali==127 && guy_dev->drv_supportGreyscaling() && step>0 && step<16 ){
|
||||
if(step==1) guy_dev->drv_fullpart(1);
|
||||
guy_dev->drv_draw16grey_step(f,step);
|
||||
}
|
||||
}
|
||||
void ReadguyDriver::invertDisplay(){
|
||||
if(READGUY_cali==127){
|
||||
const int pixels=((guy_dev->drv_width()+7)>>3)*guy_dev->drv_height();
|
||||
const int pixels=((guy_width+7)>>3)*guy_height;
|
||||
for(int i=0;i<pixels;i++)
|
||||
((uint8_t*)(getBuffer()))[i]=uint8_t(~(((uint8_t*)(getBuffer()))[i]));
|
||||
}
|
||||
|
||||
@@ -178,12 +178,15 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
|
||||
/** @brief 返回目标屏幕是否支持16级灰度 返回非0代表支持.
|
||||
* @note 返回负整数则代表调用draw16greyStep需要从深色到浅色刷新, 而不是从浅色到深色刷新 */
|
||||
int supportGreyscaling() const{return READGUY_cali==127?guy_dev->drv_supportGreyscaling():0;}
|
||||
/// @brief 设置灰度的渲染画质. 高画质模式在某些屏幕某些情况下可能表现不好.
|
||||
void setGreyQuality(bool q) { if(READGUY_cali==127) guy_dev->setGreyQuality(q); }
|
||||
|
||||
/** @brief 设置灰度的渲染画质. 高画质模式在某些屏幕某些情况下可能表现不好.
|
||||
* @param q 0-关闭连续刷屏 开启16阶灰度抖动 1-开启连续刷屏 开启16阶灰度抖动
|
||||
* 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);
|
||||
/** @brief 按照自定义分步显示灰度图片,如果支持,否则就不显示灰度图片了. 可以用省内存的方法显示
|
||||
* @param step 步骤代号. 从1开始到15,依次调用此函数来自定义的灰度显示显存内容. 没有16.
|
||||
* @param step 步骤代号. 从1开始到15,依次调用此函数来自定义的灰度显示显存内容. 没有0和16.
|
||||
* @note 必须按照 "慢刷全屏->绘图->设置参数1->绘图->设置参数2... 调用15次 来完成一次自定义灰度刷屏
|
||||
* 连续调用多次此函数之间, 可以修改显存内的像素颜色, 但只能从白色改为黑色.
|
||||
* @attention 需要先调用 supportGreyscaling() 来确定是否支持灰度分步刷新.为负数时需要从深到浅刷新
|
||||
@@ -219,8 +222,10 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
|
||||
#endif
|
||||
/// @brief 检查初始化屏幕硬件, 若检查失败返回0,否则返回硬件代号
|
||||
uint8_t checkEpdDriver();
|
||||
/// @brief 初始化屏幕, 设置驱动代号, 引脚排列顺序. 过程会检验引脚可用性.
|
||||
void setEpdDriver();
|
||||
/** @brief 初始化屏幕, 设置驱动代号, 引脚排列顺序. 过程会检验引脚可用性.
|
||||
* @param g_width, g_height 显示区域的宽度和高度. 为0表示直接使用屏幕的宽度和高度
|
||||
* @note 这两个参数转专为指定分辨率的程序画面设计, 其他分辨率的画面会自动拉伸. [1.2新增] */
|
||||
void setEpdDriver(int g_width = 0,int g_height = 0);
|
||||
/** @brief 初始化SD卡, 设置驱动代号, 引脚排列顺序. 过程会检验引脚可用性.
|
||||
* @return SD卡初始化成功与否 */
|
||||
bool setSDcardDriver();
|
||||
@@ -256,6 +261,7 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
|
||||
#endif
|
||||
int epd_OK=0; //墨水屏可用
|
||||
int currentBright = -3; //初始亮度
|
||||
int16_t guy_width=0,guy_height=0;
|
||||
|
||||
//LGFX_Sprite gfx; // 图形引擎类指针, 可以用这个指针去操作屏幕缓冲区
|
||||
readguyEpdBase *guy_dev = nullptr;
|
||||
@@ -331,30 +337,39 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
|
||||
#endif
|
||||
}
|
||||
public: //增加了一些返回系统状态变量的函数, 它们是静态的, 而且不会对程序造成任何影响.
|
||||
constexpr int getReadguyShareSpi() const { return config_data[1]; }
|
||||
constexpr int getReadguyEpdType () const { return config_data[2]; } // 对应的epd驱动程序代号, -1为未指定
|
||||
constexpr int getShareSpi() const { return config_data[1]; }
|
||||
constexpr int getEpdType () const { return config_data[2]; } // 对应的epd驱动程序代号, -1为未指定
|
||||
//显示驱动部分, 显示默认使用vspi (vspi也是默认SPI库的通道)
|
||||
constexpr int getReadguyEpdMosi () const { return config_data[3]; } // 目标显示器的 MOSI 引脚
|
||||
constexpr int getReadguyEpdSclk () const { return config_data[4]; } // 目标显示器的 SCLK 引脚
|
||||
constexpr int getReadguyEpdCs () const { return config_data[5]; } // 目标显示器的 CS 引脚
|
||||
constexpr int getReadguyEpdDc () const { return config_data[6]; } // 目标显示器的 DC 引脚
|
||||
constexpr int getReadguyEpdRst () const { return config_data[7]; } // 目标显示器的 RST 引脚
|
||||
constexpr int getReadguyEpdBusy () const { return config_data[8]; } // 目标显示器的 BUSY 引脚
|
||||
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 引脚
|
||||
//sd卡驱动部分, 默认使用hspi (sd卡建议用hspi)
|
||||
constexpr int getReadguySdMiso () const { return config_data[9]; } // 目标sd卡的 MISO 引脚, sd_share_spi == 1 时无效
|
||||
constexpr int getReadguySdMosi () const { return config_data[10]; }// 目标sd卡的 MOSI 引脚, sd_share_spi == 1 时无效
|
||||
constexpr int getReadguySdSclk () const { return config_data[11]; }// 目标sd卡的 SCLK 引脚, sd_share_spi == 1 时无效
|
||||
constexpr int getReadguySdCs () const { return config_data[12]; }// 目标sd卡的 CS 引脚.
|
||||
constexpr int getReadguyI2cSda () const { return config_data[13]; }// 目标i2c总线的SDA引脚, 当且仅当启用i2c总线时才生效
|
||||
constexpr int getReadguyI2cScl () const { return config_data[14]; }// 目标i2c总线的SCL引脚, 当且仅当启用i2c总线时才生效
|
||||
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总线时才生效
|
||||
//按键驱动部分, 为负代表高触发, 否则低触发,
|
||||
//注意, 这里的io编号是加1的, 即 1或-1 代表 gpio0 的低触发/高触发
|
||||
constexpr int getReadguyBtn1Pin () const { return config_data[15]; }
|
||||
constexpr int getReadguyBtn2Pin () const { return config_data[16]; }
|
||||
constexpr int getReadguyBtn3Pin () const { return config_data[17]; }
|
||||
constexpr int getReadguyBlPin () const { return config_data[18]; }//前置光接口引脚IO
|
||||
constexpr int getReadguyRtcType () const { return config_data[19]; }//使用的RTC型号(待定, 还没用上)
|
||||
constexpr int getButtonsCount () const { return config_data[21]; } //按钮个数, 0-3都有可能
|
||||
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 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; } //返回显示屏硬件高度(不是画幅高度)
|
||||
// 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);
|
||||
};
|
||||
#endif /* END OF FILE. ReadGuy project.
|
||||
Copyright (C) 2023 FriendshipEnder. */
|
||||
Reference in New Issue
Block a user