From ca21b5d9c37f439be7b2505285372ccdf823a17e Mon Sep 17 00:00:00 2001 From: YYD <39893972+yanyuandi@users.noreply.github.com> Date: Thu, 18 Apr 2024 16:01:01 +0800 Subject: [PATCH] Add files via upload --- 7.5inch-fast_bw.ino | 236 +++++++++++++ GxEPD2_3C.h | 688 +++++++++++++++++++++++++++++++++++++ GxEPD2_750c_Z08.cpp | 802 ++++++++++++++++++++++++++++++++++++++++++++ GxEPD2_750c_Z08.h | 110 ++++++ 4 files changed, 1836 insertions(+) create mode 100644 7.5inch-fast_bw.ino create mode 100644 GxEPD2_3C.h create mode 100644 GxEPD2_750c_Z08.cpp create mode 100644 GxEPD2_750c_Z08.h diff --git a/7.5inch-fast_bw.ino b/7.5inch-fast_bw.ino new file mode 100644 index 0000000..0df8a84 --- /dev/null +++ b/7.5inch-fast_bw.ino @@ -0,0 +1,236 @@ +#include +#include +#include +//#include "shuma.c" +#include +#include +#include + +//#include "jpg.h" + +#define NORMAL_FONT u8g2_font_wqy16_t_gb2312a //设置NORMAL_FONT默认字体 + +const char* ssid = "yanyuandi"; +const char* password = "beipiaoguizu"; + +// NTP服务器相关信息 +#define TZ 8 // 时区偏移值,以 UTC+8 为例 +#define DST_MN 0 // 夏令时持续时间(分钟) + +#define TZ_SEC ((TZ)*3600) // 时区偏移值(秒) +#define DST_SEC ((DST_MN)*60) // 夏令时持续时间(秒) + +U8G2_FOR_ADAFRUIT_GFX u8g2Fonts; + +GxEPD2_3C display(GxEPD2_750c_Z08(/*CS=D8*/ 4, /*DC=D3*/ 27, /*RST=D4*/ 26, /*BUSY=D2*/ 25)); //即可。GxEPD2_420c_1680就是驱动程序文件名。 +//GxEPD2_BW display(GxEPD2_750_YT7(/*CS=D8*/ 4, /*DC=D3*/ 27, /*RST=D4*/ 26, /*BUSY=D2*/ 25)); // GDEY075T7 800x480, UC8179 (GD7965) +//GxEPD2_BW display(GxEPD2_583_T8(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); +//GxEPD2_BW display(GxEPD2_750(/*CS=D8*/ 4, /*DC=D3*/ 27, /*RST=D4*/ 26, /*BUSY=D2*/ 25)); // GDEW075T8 640x384, UC8159c (IL0371) +//GxEPD2_BW display(GxEPD2_750_T7(/*CS=D8*/ 4, /*DC=D3*/ 27, /*RST=D4*/ 26, /*BUSY=D2*/ 25)); // GDEW075T7 800x480, EK79655 (GD7965) + + +void setup() { + Serial.begin(115200); + Serial.println(); + Serial.println("UI 初始化"); + SPI.end(); + SPI.begin(13, 14, 14, 4); + + // 连接WiFi + WiFi.begin(ssid, password); + Serial.print("Connecting to WiFi"); + while (WiFi.status() != WL_CONNECTED) { + delay(1000); + Serial.print("."); + } + Serial.println("\nConnected to WiFi"); + + if (time(nullptr) < 1000000000) { + // 如果没有获取过时间,重新获取时间 + uint8_t i = 0; + configTime(TZ_SEC, DST_SEC, "ntp1.aliyun.com", "ntp2.aliyun.com"); + while ((time(nullptr) < 1000000000) & (i < 20)) { + i++; + Serial.print("."); + delay(500); + } + Serial.println("时间同步成功"); + } + + + + + display.init(115200, true, 2, false); + display.setRotation(0); // 对这块 4.2 寸屏幕而言,2 是横向(排线在上方) + + u8g2Fonts.begin(display); + u8g2Fonts.setFontDirection(0); + u8g2Fonts.setForegroundColor(GxEPD_BLACK); // 设置前景色 + u8g2Fonts.setBackgroundColor(GxEPD_WHITE); // 设置背景色 + u8g2Fonts.setFont(NORMAL_FONT); + + display.setFullWindow(); + display.firstPage(); + do { + display.fillRect(0, 30, 800, 100, GxEPD_RED); //屏幕顶部画一个红色的矩形 + u8g2Fonts.setFont(u8g2_font_fub42_tf); + u8g2Fonts.setForegroundColor(GxEPD_BLACK); + u8g2Fonts.setBackgroundColor(GxEPD_WHITE); + u8g2Fonts.setCursor(101, 285); + u8g2Fonts.print("8"); + + u8g2Fonts.setFont(u8g2_font_wqy16_t_gb2312); + u8g2Fonts.setBackgroundColor(GxEPD_RED); + u8g2Fonts.setForegroundColor(GxEPD_WHITE); + u8g2Fonts.setCursor(268, 84); + u8g2Fonts.print("此区域为7.5寸三色屏幕的红色刷新"); + + u8g2Fonts.setFont(u8g2_font_wqy16_t_gb2312); + u8g2Fonts.setBackgroundColor(GxEPD_WHITE); + u8g2Fonts.setForegroundColor(GxEPD_BLACK); + u8g2Fonts.setCursor(61, 189); + u8g2Fonts.print("三色的黑色刷新"); + + u8g2Fonts.setFont(u8g2_font_wqy16_t_gb2312); + u8g2Fonts.setBackgroundColor(GxEPD_WHITE); + u8g2Fonts.setForegroundColor(GxEPD_BLACK); + u8g2Fonts.setCursor(242, 189); + u8g2Fonts.print("局部白底黑字快刷"); + + u8g2Fonts.setFont(u8g2_font_wqy16_t_gb2312); + u8g2Fonts.setBackgroundColor(GxEPD_WHITE); + u8g2Fonts.setForegroundColor(GxEPD_BLACK); + u8g2Fonts.setCursor(434, 189); + u8g2Fonts.print("局部黑底白字快刷"); + + u8g2Fonts.setFont(u8g2_font_wqy16_t_gb2312); + u8g2Fonts.setBackgroundColor(GxEPD_WHITE); + u8g2Fonts.setForegroundColor(GxEPD_BLACK); + u8g2Fonts.setCursor(610, 189); + u8g2Fonts.print("三色屏幕本身局部刷新"); + + u8g2Fonts.setFont(u8g2_font_wqy16_t_gb2312); + u8g2Fonts.setBackgroundColor(GxEPD_WHITE); + u8g2Fonts.setForegroundColor(GxEPD_BLACK); + u8g2Fonts.setCursor(258, 24); + u8g2Fonts.print("7.5寸三色屏幕局部黑白快刷测试DEMO"); + + u8g2Fonts.setFont(u8g2_font_wqy16_t_gb2312); + u8g2Fonts.setBackgroundColor(GxEPD_WHITE); + u8g2Fonts.setForegroundColor(GxEPD_RED); + u8g2Fonts.setCursor(374, 468); + u8g2Fonts.print("BY YYD"); + + + + } while (display.nextPage()); + + + for (int i = 0; i < 3; i++) { + //display.fillScreen(GxEPD_BLACK); + display.setPartialWindow(248, 204, 120, 120); + //display.fillScreen(GxEPD_WHITE); + display.firstPage(); + u8g2Fonts.setFont(u8g2_font_fub42_tf); + + + do { + u8g2Fonts.setForegroundColor(GxEPD_BLACK); + u8g2Fonts.setBackgroundColor(GxEPD_WHITE); + u8g2Fonts.setCursor(286, 285); + u8g2Fonts.print(i); + Serial.println(i); + } while (display.nextPageBW()); + } + + for (int i = 0; i < 3; i++) { + + display.setPartialWindow(434, 204, 120, 120); + display.firstPage(); + display.fillScreen(GxEPD_BLACK); + u8g2Fonts.setFont(u8g2_font_fub42_tf); + + + do { + u8g2Fonts.setForegroundColor(GxEPD_WHITE); + u8g2Fonts.setBackgroundColor(GxEPD_BLACK); + u8g2Fonts.setCursor(474, 285); + u8g2Fonts.print(i); + Serial.println(i); + } while (display.nextPageBW()); + } + + for (int i = 0; i < 1; i++) { + + display.setPartialWindow(620, 204, 120, 120); + display.firstPage(); + //display.fillScreen(GxEPD_WHITE); + u8g2Fonts.setFont(u8g2_font_fub42_tf); + + + do { + u8g2Fonts.setForegroundColor(GxEPD_BLACK); + u8g2Fonts.setBackgroundColor(GxEPD_WHITE); + u8g2Fonts.setCursor(660, 285); + u8g2Fonts.print(i); + Serial.println(i); + } while (display.nextPage()); + } + // 显示“时间获取中...” + display.setPartialWindow(175, 329, 450, 120); + display.firstPage(); + do { + u8g2Fonts.setFont(u8g2_font_wqy16_t_gb2312); + u8g2Fonts.setForegroundColor(GxEPD_BLACK); + u8g2Fonts.setBackgroundColor(GxEPD_WHITE); + u8g2Fonts.setCursor(347, 376); + u8g2Fonts.print("时间获取中..."); + } while (display.nextPageBW()); + + delay(3000); // 延迟3秒 + + + display.powerOff(); +} + +void loop() { + static int prevHour = -1; // 用于存储上一次获取的小时 + static int prevMin = -1; // 用于存储上一次获取的分钟 + + time_t now = time(nullptr); // 获取当前时间 + struct tm* ltm = localtime(&now); // 将时间转换为本地时间结构体 + + // 如果获取时间失败,打印错误信息并返回 + if (now == (time_t)-1) { + Serial.println("Failed to obtain time"); + return; + } + + // 仅当小时或分钟发生变化时才刷新显示 + if (ltm->tm_hour != prevHour || ltm->tm_min != prevMin) { + // 更新上一次获取的小时和分钟 + prevHour = ltm->tm_hour; + prevMin = ltm->tm_min; + + // 显示时间 + display.setPartialWindow(175, 329, 450, 120); + display.firstPage(); + do { + char timeString[20]; + sprintf(timeString, "%02d:%02d", ltm->tm_hour, ltm->tm_min); // 将时间格式化为字符串 + u8g2Fonts.setFont(u8g2_font_logisoso50_tn); + u8g2Fonts.setForegroundColor(GxEPD_BLACK); + u8g2Fonts.setBackgroundColor(GxEPD_WHITE); + u8g2Fonts.setCursor(355, 415); + u8g2Fonts.print(timeString); // 显示时间字符串 + u8g2Fonts.setForegroundColor(GxEPD_BLACK); + u8g2Fonts.setBackgroundColor(GxEPD_WHITE); + u8g2Fonts.setFont(u8g2_font_wqy16_t_gb2312); + u8g2Fonts.setCursor(261, 415); + u8g2Fonts.print("当前时间:"); // 显示时间字符串 + } while (display.nextPageBW()); + } + + // 等待一段时间再继续循环 + delay(1000); +} diff --git a/GxEPD2_3C.h b/GxEPD2_3C.h new file mode 100644 index 0000000..296a3fc --- /dev/null +++ b/GxEPD2_3C.h @@ -0,0 +1,688 @@ +// Display Library for SPI e-paper panels from Dalian Good Display and boards from Waveshare. +// Requires HW SPI and Adafruit_GFX. Caution: these e-papers require 3.3V supply AND data lines! +// +// based on Demo Example from Good Display: http://www.e-paper-display.com/download_list/downloadcategoryid=34&isMode=false.html +// +// Author: Jean-Marc Zingg +// +// Version: see library.properties +// +// Library: https://github.com/ZinggJM/GxEPD2 + +#ifndef _GxEPD2_3C_H_ +#define _GxEPD2_3C_H_ +// uncomment next line to use class GFX of library GFX_Root instead of Adafruit_GFX +//#include + +#ifndef ENABLE_GxEPD2_GFX +// default is off +#define ENABLE_GxEPD2_GFX 0 +#endif + +#if ENABLE_GxEPD2_GFX +#include "GxEPD2_GFX.h" +#define GxEPD2_GFX_BASE_CLASS GxEPD2_GFX +#elif defined(_GFX_H_) +#define GxEPD2_GFX_BASE_CLASS GFX +#else +#include +#define GxEPD2_GFX_BASE_CLASS Adafruit_GFX +#endif + +#include "GxEPD2_EPD.h" + +// for __has_include see https://en.cppreference.com/w/cpp/preprocessor/include +// see also https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html +// #if !defined(__has_include) || __has_include("epd/GxEPD2_102.h") is not portable! + +#if defined __has_include +# if __has_include("GxEPD2.h") +# // __has_include can be used +# else +# // __has_include doesn't work for us, include anyway +# undef __has_include +# define __has_include(x) true +# endif +#else +# // no __has_include, include anyway +# define __has_include(x) true +#endif + +#if __has_include("epd3c/GxEPD2_154c.h") +#include "epd3c/GxEPD2_154c.h" +#endif +#if __has_include("epd3c/GxEPD2_154_Z90c.h") +#include "epd3c/GxEPD2_154_Z90c.h" +#endif +#if __has_include("epd3c/GxEPD2_213c.h") +#include "epd3c/GxEPD2_213c.h" +#endif +#if __has_include("epd3c/GxEPD2_213_Z19c.h") +#include "epd3c/GxEPD2_213_Z19c.h" +#endif +#if __has_include("epd3c/GxEPD2_213_Z98c.h") +#include "epd3c/GxEPD2_213_Z98c.h" +#endif +#if __has_include("epd3c/GxEPD2_290c.h") +#include "epd3c/GxEPD2_290c.h" +#endif +#if __has_include("epd3c/GxEPD2_290_Z13c.h") +#include "epd3c/GxEPD2_290_Z13c.h" +#endif +#if __has_include("epd3c/GxEPD2_290_C90c.h") +#include "epd3c/GxEPD2_290_C90c.h" +#endif +#if __has_include("epd3c/GxEPD2_266c.h") +#include "epd3c/GxEPD2_266c.h" +#endif +#if __has_include("epd3c/GxEPD2_150_BN.h") +#include "epd3c/GxEPD2_270c.h" +#endif +#if __has_include("epd3c/GxEPD2_420c.h") +#include "epd3c/GxEPD2_420c.h" +#endif +#if __has_include("epd3c/GxEPD2_420c_Z21.h") +#include "epd3c/GxEPD2_420c_Z21.h" +#endif +#if __has_include("epd3c/GxEPD2_583c.h") +#include "epd3c/GxEPD2_583c.h" +#endif +#if __has_include("epd3c/GxEPD2_583c_Z83.h") +#include "epd3c/GxEPD2_583c_Z83.h" +#endif +#if __has_include("epd7c/GxEPD2_565c.h") +#include "epd7c/GxEPD2_565c.h" +#endif +#if __has_include("epd3c/GxEPD2_750c.h") +#include "epd3c/GxEPD2_750c.h" +#endif +#if __has_include("epd3c/GxEPD2_750c_Z08.h") +#include "epd3c/GxEPD2_750c_Z08.h" +#endif +#if __has_include("epd3c/GxEPD2_750c_Z90.h") +#include "epd3c/GxEPD2_750c_Z90.h" +#endif +#if __has_include("epd3c/GxEPD2_1248c.h") +#include "epd3c/GxEPD2_1248c.h" +#endif + +template +class GxEPD2_3C : public GxEPD2_GFX_BASE_CLASS +{ + public: + GxEPD2_Type epd2; +#if ENABLE_GxEPD2_GFX + GxEPD2_3C(GxEPD2_Type epd2_instance) : GxEPD2_GFX_BASE_CLASS(epd2, GxEPD2_Type::WIDTH_VISIBLE, GxEPD2_Type::HEIGHT), epd2(epd2_instance) +#else + GxEPD2_3C(GxEPD2_Type epd2_instance) : GxEPD2_GFX_BASE_CLASS(GxEPD2_Type::WIDTH_VISIBLE, GxEPD2_Type::HEIGHT), epd2(epd2_instance) +#endif + { + _page_height = page_height; + _pages = (HEIGHT / _page_height) + ((HEIGHT % _page_height) > 0); + _mirror = false; + _using_partial_mode = false; + _current_page = 0; + setFullWindow(); + } + + uint16_t pages() + { + return _pages; + } + + uint16_t pageHeight() + { + return _page_height; + } + + bool mirror(bool m) + { + _swap_ (_mirror, m); + return m; + } + + void drawPixel(int16_t x, int16_t y, uint16_t color) + { + if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) return; + if (_mirror) x = width() - x - 1; + // check rotation, move pixel around if necessary + switch (getRotation()) + { + case 1: + _swap_(x, y); + x = WIDTH - x - 1; + break; + case 2: + x = WIDTH - x - 1; + y = HEIGHT - y - 1; + break; + case 3: + _swap_(x, y); + y = HEIGHT - y - 1; + break; + } + // transpose partial window to 0,0 + x -= _pw_x; + y -= _pw_y; + // clip to (partial) window + if ((x < 0) || (x >= int16_t(_pw_w)) || (y < 0) || (y >= int16_t(_pw_h))) return; + // adjust for current page + y -= _current_page * _page_height; + // check if in current page + if ((y < 0) || (y >= int16_t(_page_height))) return; + uint16_t i = x / 8 + y * (_pw_w / 8); + _black_buffer[i] = (_black_buffer[i] | (1 << (7 - x % 8))); // white + _color_buffer[i] = (_color_buffer[i] | (1 << (7 - x % 8))); + if (color == GxEPD_WHITE) return; + else if (color == GxEPD_BLACK) _black_buffer[i] = (_black_buffer[i] & (0xFF ^ (1 << (7 - x % 8)))); + else if ((color == GxEPD_RED) || (color == GxEPD_YELLOW)) _color_buffer[i] = (_color_buffer[i] & (0xFF ^ (1 << (7 - x % 8)))); + } + + void init(uint32_t serial_diag_bitrate = 0) // = 0 : disabled + { + epd2.init(serial_diag_bitrate); + _using_partial_mode = false; + _current_page = 0; + setFullWindow(); + } + + // init method with additional parameters: + // initial false for re-init after processor deep sleep wake up, if display power supply was kept + // only relevant for b/w displays with fast partial update + // reset_duration = 20 is default; a value of 2 may help with "clever" reset circuit of newer boards from Waveshare + // pulldown_rst_mode true for alternate RST handling to avoid feeding 5V through RST pin + void init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration = 20, bool pulldown_rst_mode = false) + { + epd2.init(serial_diag_bitrate, initial, reset_duration, pulldown_rst_mode); + _using_partial_mode = false; + _current_page = 0; + setFullWindow(); + } + + // init method with additional parameters: + // SPIClass& spi: either SPI or alternate HW SPI channel + // SPISettings spi_settings: e.g. for higher SPI speed selection + void init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration, bool pulldown_rst_mode, SPIClass& spi, SPISettings spi_settings) + { + epd2.selectSPI(spi, spi_settings); + epd2.init(serial_diag_bitrate, initial, reset_duration, pulldown_rst_mode); + _using_partial_mode = false; + _current_page = 0; + setFullWindow(); + } + + // release SPI and control pins + void end() + { + epd2.end(); + } + + void fillScreen(uint16_t color) // 0x0 black, >0x0 white, to buffer + { + uint8_t black = 0xFF; + uint8_t red = 0xFF; + if (color == GxEPD_WHITE); + else if (color == GxEPD_BLACK) black = 0x00; + else if ((color == GxEPD_RED) || (color == GxEPD_YELLOW)) red = 0x00; + for (uint16_t x = 0; x < sizeof(_black_buffer); x++) + { + _black_buffer[x] = black; + _color_buffer[x] = red; + } + } + + // display buffer content to screen, useful for full screen buffer + void display(bool partial_update_mode = false) + { + epd2.writeImage(_black_buffer, _color_buffer, 0, 0, GxEPD2_Type::WIDTH, _page_height); + epd2.refresh(partial_update_mode); + if (!partial_update_mode) epd2.powerOff(); + } + + // display part of buffer content to screen, useful for full screen buffer + // displayWindow, use parameters according to actual rotation. + // x and w should be multiple of 8, for rotation 0 or 2, + // y and h should be multiple of 8, for rotation 1 or 3, + // else window is increased as needed, + // this is an addressing limitation of the e-paper controllers + void displayWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) + { + x = gx_uint16_min(x, width()); + y = gx_uint16_min(y, height()); + w = gx_uint16_min(w, width() - x); + h = gx_uint16_min(h, height() - y); + _rotate(x, y, w, h); + epd2.writeImagePart(_black_buffer, _color_buffer, x, y, GxEPD2_Type::WIDTH, _page_height, x, y, w, h); + epd2.refresh(x, y, w, h); + } + + void displayWindowBW(uint16_t x, uint16_t y, uint16_t w, uint16_t h) + { + x = gx_uint16_min(x, width()); + y = gx_uint16_min(y, height()); + w = gx_uint16_min(w, width() - x); + h = gx_uint16_min(h, height() - y); + _rotate(x, y, w, h); + epd2.writeImagePartNew(_black_buffer, x, y, GxEPD2_Type::WIDTH, _page_height, x, y, w, h); + epd2.refresh_bw(x, y, w, h); + epd2.writeImagePartPrevious(_black_buffer, x, y, GxEPD2_Type::WIDTH, _page_height, x, y, w, h); + } + + void setFullWindow() + { + _using_partial_mode = false; + _pw_x = 0; + _pw_y = 0; + _pw_w = GxEPD2_Type::WIDTH; + _pw_h = HEIGHT; + } + + // setPartialWindow, use parameters according to actual rotation. + // x and w should be multiple of 8, for rotation 0 or 2, + // y and h should be multiple of 8, for rotation 1 or 3, + // else window is increased as needed, + // this is an addressing limitation of the e-paper controllers + void setPartialWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) + { + if (!epd2.hasPartialUpdate) return; + _pw_x = gx_uint16_min(x, width()); + _pw_y = gx_uint16_min(y, height()); + _pw_w = gx_uint16_min(w, width() - _pw_x); + _pw_h = gx_uint16_min(h, height() - _pw_y); + _rotate(_pw_x, _pw_y, _pw_w, _pw_h); + _using_partial_mode = true; + // make _pw_x, _pw_w multiple of 8 + _pw_w += _pw_x % 8; + if (_pw_w % 8 > 0) _pw_w += 8 - _pw_w % 8; + _pw_x -= _pw_x % 8; + } + + void firstPage() + { + fillScreen(GxEPD_WHITE); + _current_page = 0; + _second_phase = false; + epd2.setPaged(); // for GxEPD2_154c paged workaround + } + + bool nextPage() + { + uint16_t page_ys = _current_page * _page_height; + if (_using_partial_mode) + { + Serial.print(" 111nextPage("); Serial.print(_pw_x); Serial.print(", "); Serial.print(_pw_y); Serial.print(", "); + Serial.print(_pw_w); Serial.print(", "); Serial.print(_pw_h); Serial.print(") P"); Serial.println(_current_page); + uint16_t page_ye = _current_page < int16_t(_pages - 1) ? page_ys + _page_height : HEIGHT; + uint16_t dest_ys = _pw_y + page_ys; // transposed + uint16_t dest_ye = gx_uint16_min(_pw_y + _pw_h, _pw_y + page_ye); + if (dest_ye > dest_ys) + { + Serial.print("1111writeImage("); Serial.print(_pw_x); Serial.print(", "); Serial.print(dest_ys); Serial.print(", "); + Serial.print(_pw_w); Serial.print(", "); Serial.print(dest_ye - dest_ys); Serial.println(")"); + epd2.writeImage(_black_buffer, _color_buffer, _pw_x, dest_ys, _pw_w, dest_ye - dest_ys); + } + else + { + Serial.print("2222writeImage("); Serial.print(_pw_x); Serial.print(", "); Serial.print(dest_ys); Serial.print(", "); + Serial.print(_pw_w); Serial.print(", "); Serial.print(dest_ye - dest_ys); Serial.print(") skipped "); + Serial.print(dest_ys); Serial.print(".."); Serial.println(dest_ye); + } + _current_page++; + if (_current_page == int16_t(_pages)) + { + _current_page = 0; + if (!_second_phase) + { + + epd2.refresh(_pw_x, _pw_y, _pw_w, _pw_h); + if (epd2.hasFastPartialUpdate) + { + _second_phase = true; + return true; + } + } + return false; + } + fillScreen(GxEPD_WHITE); + return true; + } + else // full update + { + epd2.writeImage(_black_buffer, _color_buffer, 0, page_ys, GxEPD2_Type::WIDTH, gx_uint16_min(_page_height, HEIGHT - page_ys)); + _current_page++; + if (_current_page == int16_t(_pages)) + { + _current_page = 0; + if ((epd2.panel == GxEPD2::GDEW0154Z04) && (_pages > 1)) + { + if (!_second_phase) + { + epd2.refresh(false); // full update after first phase + _second_phase = true; + fillScreen(GxEPD_WHITE); + return true; + } + else epd2.refresh(true); // partial update after second phase + } else epd2.refresh(false); // full update after only phase + epd2.powerOff(); + return false; + } + fillScreen(GxEPD_WHITE); + return true; + } + } + bool nextPageBW() + { + if (_using_partial_mode) + { + epd2.writeImagePartFresh(0x13,_black_buffer, _pw_x, _pw_y, _pw_w, _pw_h); + epd2.refresh_bw(_pw_x, _pw_y, _pw_w, _pw_h); + epd2.writeImageRedFix(0x13,_black_buffer, _pw_x, _pw_y, _pw_w, _pw_h); + } + else // full update + { + //epd2.writeImage(_black_buffer, 0, 0, GxEPD2_Type::WIDTH, HEIGHT); + //epd2.refresh(false); + //epd2.writeImagePrevious(_black_buffer, 0, 0, GxEPD2_Type::WIDTH, HEIGHT); + //epd2.powerOff(); + } + + // 添加返回语句 + return false; // 或者根据实际逻辑返回 true 或 false + } + + + + //bool nextPageBW() + //{ + // if (1 == _pages) + // { + // if (_using_partial_mode) + // { + // epd2.writeImageNew(_black_buffer, _pw_x, _pw_y, _pw_w, _pw_h); + // epd2.refresh_bw(_pw_x, _pw_y, _pw_w, _pw_h); + // epd2.writeImagePrevious(_black_buffer, _pw_x, _pw_y, _pw_w, _pw_h); + // } + // else // full update + // { + // epd2.writeImage(_black_buffer, 0, 0, GxEPD2_Type::WIDTH, HEIGHT); + // epd2.refresh(false); + // epd2.writeImagePrevious(_black_buffer, 0, 0, GxEPD2_Type::WIDTH, HEIGHT); + // epd2.powerOff(); + // } + // return false; + // } + // uint16_t page_ys = _current_page * _page_height; + // if (_using_partial_mode) + // { + // //Serial.print(" nextPage("); Serial.print(_pw_x); Serial.print(", "); Serial.print(_pw_y); Serial.print(", "); + // //Serial.print(_pw_w); Serial.print(", "); Serial.print(_pw_h); Serial.print(") P"); Serial.println(_current_page); + // uint16_t page_ye = _current_page < (_pages - 1) ? page_ys + _page_height : HEIGHT; + // uint16_t dest_ys = _pw_y + page_ys; // transposed + // uint16_t dest_ye = gx_uint16_min(_pw_y + _pw_h, _pw_y + page_ye); + // if (dest_ye > dest_ys) + // { + // //Serial.print("writeImage("); Serial.print(_pw_x); Serial.print(", "); Serial.print(dest_ys); Serial.print(", "); + // //Serial.print(_pw_w); Serial.print(", "); Serial.print(dest_ye - dest_ys); Serial.println(")"); + // if (!_second_phase) epd2.writeImageNew(_black_buffer, _pw_x, dest_ys, _pw_w, dest_ye - dest_ys); + // else epd2.writeImagePrevious(_black_buffer, _pw_x, dest_ys, _pw_w, dest_ye - dest_ys); + // } + // else + // { + // //Serial.print("writeImage("); Serial.print(_pw_x); Serial.print(", "); Serial.print(dest_ys); Serial.print(", "); + // //Serial.print(_pw_w); Serial.print(", "); Serial.print(dest_ye - dest_ys); Serial.print(") skipped "); + // //Serial.print(dest_ys); Serial.print(".."); Serial.println(dest_ye); + // } + // _current_page++; + // if (_current_page == _pages) + // { + // _current_page = 0; + // if (!_second_phase) + // { + // epd2.refresh_bw(_pw_x, _pw_y, _pw_w, _pw_h); + // _second_phase = true; + // fillScreen(GxEPD_WHITE); + // return true; + // } + // return false; + // } + // fillScreen(GxEPD_WHITE); + // return true; + // } + // else // full update + // { + // if (!_second_phase) epd2.writeImage(_black_buffer, 0, page_ys, GxEPD2_Type::WIDTH, gx_uint16_min(_page_height, HEIGHT - page_ys)); + // else epd2.writeImagePrevious(_black_buffer, 0, page_ys, GxEPD2_Type::WIDTH, gx_uint16_min(_page_height, HEIGHT - page_ys)); + // _current_page++; + // if (_current_page == _pages) + // { + // _current_page = 0; + // if (!_second_phase) + // { + // epd2.refresh(false); // full update after first phase + // _second_phase = true; + // fillScreen(GxEPD_WHITE); + // return true; + // } + // epd2.powerOff(); + // return false; + // } + // fillScreen(GxEPD_WHITE); + // return true; + // } + //} + + // GxEPD style paged drawing; drawCallback() is called as many times as needed + void drawPaged(void (*drawCallback)(const void*), const void* pv) + { + if (_using_partial_mode) + { + for (_current_page = 0; _current_page < _pages; _current_page++) + { + uint16_t page_ys = _current_page * _page_height; + uint16_t page_ye = _current_page < (_pages - 1) ? page_ys + _page_height : HEIGHT; + uint16_t dest_ys = _pw_y + page_ys; // transposed + uint16_t dest_ye = gx_uint16_min(_pw_y + _pw_h, _pw_y + page_ye); + if (dest_ye > dest_ys) + { + fillScreen(GxEPD_WHITE); + drawCallback(pv); + epd2.writeImage(_black_buffer, _color_buffer, _pw_x, dest_ys, _pw_w, dest_ye - dest_ys); + } + } + epd2.refresh(_pw_x, _pw_y, _pw_w, _pw_h); + } + else // full update + { + epd2.setPaged(); // for GxEPD2_154c paged workaround + for (_current_page = 0; _current_page < _pages; _current_page++) + { + uint16_t page_ys = _current_page * _page_height; + fillScreen(GxEPD_WHITE); + drawCallback(pv); + epd2.writeImage(_black_buffer, _color_buffer, 0, page_ys, GxEPD2_Type::WIDTH, gx_uint16_min(_page_height, HEIGHT - page_ys)); + } + if (epd2.panel == GxEPD2::GDEW0154Z04) + { // GxEPD2_154c paged workaround: write color part + for (_current_page = 0; _current_page < _pages; _current_page++) + { + uint16_t page_ys = _current_page * _page_height; + fillScreen(GxEPD_WHITE); + drawCallback(pv); + epd2.writeImage(_black_buffer, _color_buffer, 0, page_ys, GxEPD2_Type::WIDTH, gx_uint16_min(_page_height, HEIGHT - page_ys)); + } + } + epd2.refresh(false); // full update + epd2.powerOff(); + } + _current_page = 0; + } + + void drawInvertedBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color) + { + // taken from Adafruit_GFX.cpp, modified + int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + for (int16_t j = 0; j < h; j++) + { + for (int16_t i = 0; i < w; i++ ) + { + if (i & 7) byte <<= 1; + else + { +#if defined(__AVR) || defined(ESP8266) || defined(ESP32) + byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); +#else + byte = bitmap[j * byteWidth + i / 8]; +#endif + } + if (!(byte & 0x80)) + { + drawPixel(x + i, y + j, color); + } + } + } + } + + // Support for Bitmaps (Sprites) to Controller Buffer and to Screen + void clearScreen(uint8_t value = 0xFF) // init controller memory and screen (default white) + { + epd2.clearScreen(value); + } + void writeScreenBuffer(uint8_t value = 0xFF) // init controller memory (default white) + { + epd2.writeScreenBuffer(value); + } + // write to controller memory, without screen refresh; x and w should be multiple of 8 + void writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) + { + epd2.writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm); + } + void writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) + { + epd2.writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); + } + void writeImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) + { + epd2.writeImage(black, color, x, y, w, h, invert, mirror_y, pgm); + } + void writeImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h) + { + epd2.writeImage(black, color, x, y, w, h, false, false, false); + } + void writeImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) + { + epd2.writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); + } + void writeImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h) + { + epd2.writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, false, false, false); + } + // write sprite of native data to controller memory, without screen refresh; x and w should be multiple of 8 + void writeNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) + { + epd2.writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm); + } + // write to controller memory, with screen refresh; x and w should be multiple of 8 + void drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) + { + epd2.drawImage(bitmap, x, y, w, h, invert, mirror_y, pgm); + } + void drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) + { + epd2.drawImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); + } + void drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) + { + epd2.drawImage(black, color, x, y, w, h, invert, mirror_y, pgm); + } + void drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h) + { + epd2.drawImage(black, color, x, y, w, h, false, false, false); + } + void drawImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) + { + epd2.drawImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); + } + void drawImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h) + { + epd2.drawImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, false, false, false); + } + // write sprite of native data to controller memory, with screen refresh; x and w should be multiple of 8 + void drawNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) + { + epd2.drawNative(data1, data2, x, y, w, h, invert, mirror_y, pgm); + } + void refresh(bool partial_update_mode = false) // screen refresh from controller memory to full screen + { + epd2.refresh(partial_update_mode); + if (!partial_update_mode) epd2.powerOff(); + } + void refresh(int16_t x, int16_t y, int16_t w, int16_t h) // screen refresh from controller memory, partial screen + { + epd2.refresh(x, y, w, h); + } + // turns off generation of panel driving voltages, avoids screen fading over time + void powerOff() + { + epd2.powerOff(); + } + // turns powerOff() and sets controller to deep sleep for minimum power use, ONLY if wakeable by RST (rst >= 0) + void hibernate() + { + epd2.hibernate(); + } + + private: + template static inline void + _swap_(T & a, T & b) + { + T t = a; + a = b; + b = t; + }; + static inline uint16_t gx_uint16_min(uint16_t a, uint16_t b) + { + return (a < b ? a : b); + }; + static inline uint16_t gx_uint16_max(uint16_t a, uint16_t b) + { + return (a > b ? a : b); + }; + void _rotate(uint16_t& x, uint16_t& y, uint16_t& w, uint16_t& h) + { + switch (getRotation()) + { + case 1: + _swap_(x, y); + _swap_(w, h); + x = WIDTH - x - w; + break; + case 2: + x = WIDTH - x - w; + y = HEIGHT - y - h; + break; + case 3: + _swap_(x, y); + _swap_(w, h); + y = HEIGHT - y - h; + break; + } + } + private: + uint8_t _black_buffer[(GxEPD2_Type::WIDTH / 8) * page_height]; + uint8_t _color_buffer[(GxEPD2_Type::WIDTH / 8) * page_height]; + bool _using_partial_mode, _second_phase, _mirror; + uint16_t _width_bytes, _pixel_bytes; + int16_t _current_page; + uint16_t _pages, _page_height; + uint16_t _pw_x, _pw_y, _pw_w, _pw_h; +}; + +#endif diff --git a/GxEPD2_750c_Z08.cpp b/GxEPD2_750c_Z08.cpp new file mode 100644 index 0000000..979e8a0 --- /dev/null +++ b/GxEPD2_750c_Z08.cpp @@ -0,0 +1,802 @@ +//原作者: Jean-Marc Zingg Library: https://github.com/ZinggJM/GxEPD2 +//本驱动经过魔改现支持黑白双色的局部快刷,可以很轻松的在三色墨水屏上显示时间等 +//覆盖请注意备份原有驱动 +//作者:YYD 同时感谢@su @游牧 @BlackCat +//QQ交流群:1051455459 +//欢迎进群交流!! +//GitHub地址:https://github.com/yanyuandi/FastFreshBWOnColor +//───────────────────────────────────────────────────────────────────────────────────────────── +//─██████████████───████████──████████────████████──████████─████████──████████─████████████─── +//─██░░░░░░░░░░██───██░░░░██──██░░░░██────██░░░░██──██░░░░██─██░░░░██──██░░░░██─██░░░░░░░░████─ +//─██░░██████░░██───████░░██──██░░████────████░░██──██░░████─████░░██──██░░████─██░░████░░░░██─ +//─██░░██──██░░██─────██░░░░██░░░░██────────██░░░░██░░░░██─────██░░░░██░░░░██───██░░██──██░░██─ +//─██░░██████░░████───████░░░░░░████────────████░░░░░░████─────████░░░░░░████───██░░██──██░░██─ +//─██░░░░░░░░░░░░██─────████░░████────────────████░░████─────────████░░████─────██░░██──██░░██─ +//─██░░████████░░██───────██░░██────────────────██░░██─────────────██░░██───────██░░██──██░░██─ +//─██░░██────██░░██───────██░░██────────────────██░░██─────────────██░░██───────██░░██──██░░██─ +//─██░░████████░░██───────██░░██────────────────██░░██─────────────██░░██───────██░░████░░░░██─ +//─██░░░░░░░░░░░░██───────██░░██────────────────██░░██─────────────██░░██───────██░░░░░░░░████─ +//─████████████████───────██████────────────────██████─────────────██████───────████████████─── +//───────────────────────────────────────────────────────────────────────────────────────────── + +#include "GxEPD2_750c_Z08.h" + +GxEPD2_750c_Z08::GxEPD2_750c_Z08(int16_t cs, int16_t dc, int16_t rst, int16_t busy) : + GxEPD2_EPD(cs, dc, rst, busy, LOW, 20000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate) +{ +} + +void GxEPD2_750c_Z08::clearScreen(uint8_t value) +{ + clearScreen(value, 0xFF); +} + +void GxEPD2_750c_Z08::clearScreen(uint8_t black_value, uint8_t color_value) +{ + _initial_write = false; // initial full screen buffer clean done + _Init_Part(); + _writeCommand(0x91); // partial in + _setPartialRamArea(0, 0, WIDTH, HEIGHT); + _writeCommand(0x10); + _startTransfer(); + for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++) + { + _transfer(black_value); + } + _endTransfer(); + _writeCommand(0x13); + _startTransfer(); + for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++) + { + _transfer(~color_value); + } + _endTransfer(); + _Update_Part(); + + _writeCommand(0x92); // partial out + //Serial.println("清除屏幕"); +} + +void GxEPD2_750c_Z08::writeScreenBuffer(uint8_t value) +{ + writeScreenBuffer(value, 0xFF); +} + +void GxEPD2_750c_Z08::writeScreenBuffer(uint8_t black_value, uint8_t color_value) +{ + _initial_write = false; // initial full screen buffer clean done + _Init_Part(); + _writeCommand(0x91); // partial in + _setPartialRamArea(0, 0, WIDTH, HEIGHT); + _writeCommand(0x10); + _startTransfer(); + for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++) + { + _transfer(black_value); + } + _endTransfer(); + _writeCommand(0x13); + _startTransfer(); + for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++) + { + _transfer(~color_value); + } + _endTransfer(); + _writeCommand(0x92); // partial out + //Serial.println("写入屏幕缓存区"); +} + +void GxEPD2_750c_Z08::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + writeImage(bitmap, NULL, x, y, w, h, invert, mirror_y, pgm); +} + +void GxEPD2_750c_Z08::writeImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + //if (_using_partial_mode) _Init_Part2(); + //if (_using_partial_mode) writeScreenBuffer(); // initial full screen buffer clean + if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean + delay(1); // yield() to avoid WDT on ESP8266 and ESP32 + uint16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded + x -= x % 8; // byte boundary + w = wb * 8; // byte boundary + int16_t x1 = x < 0 ? 0 : x; // limit + int16_t y1 = y < 0 ? 0 : y; // limit + int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit + int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit + int16_t dx = x1 - x; + int16_t dy = y1 - y; + w1 -= dx; + h1 -= dy; + if ((w1 <= 0) || (h1 <= 0)) return; + _Init_Part(); + _writeCommand(0x91); // partial in + _setPartialRamArea(x1, y1, w1, h1); + _writeCommand(0x10); + _startTransfer(); + for (int16_t i = 0; i < h1; i++) + { + for (int16_t j = 0; j < w1 / 8; j++) + { + uint8_t data = 0xFF; + if (black) + { + // use wb, h of bitmap for index! + uint16_t idx = mirror_y ? j + dx / 8 + uint16_t((h - 1 - (i + dy))) * wb : j + dx / 8 + uint16_t(i + dy) * wb; + if (pgm) + { +#if defined(__AVR) || defined(ESP8266) || defined(ESP32) + data = pgm_read_byte(&black[idx]); +#else + data = black[idx]; +#endif + } + else + { + data = black[idx]; + } + if (invert) data = ~data; + } + _transfer(data); + } + } + _endTransfer(); + _writeCommand(0x13); + _startTransfer(); + for (int16_t i = 0; i < h1; i++) + { + for (int16_t j = 0; j < w1 / 8; j++) + { + uint8_t data = 0xFF; + if (color) + { + // use wb, h of bitmap for index! + uint16_t idx = mirror_y ? j + dx / 8 + uint16_t((h - 1 - (i + dy))) * wb : j + dx / 8 + uint16_t(i + dy) * wb; + if (pgm) + { +#if defined(__AVR) || defined(ESP8266) || defined(ESP32) + data = pgm_read_byte(&color[idx]); +#else + data = color[idx]; +#endif + } + else + { + data = color[idx]; + } + if (invert) data = ~data; + } + _transfer(~data); + } + } + _endTransfer(); + _writeCommand(0x92); // partial out + delay(1); // yield() to avoid WDT on ESP8266 and ESP32 + //Serial.println("写入图像数据-writeimage"); +} + +void GxEPD2_750c_Z08::_writeImage(uint8_t command, const uint8_t* bitmap, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + //if (_using_partial_mode) _Init_Part2(); + + if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean + delay(1); // yield() to avoid WDT on ESP8266 and ESP32 + int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded + x -= x % 8; // byte boundary + w = wb * 8; // byte boundary + int16_t x1 = x < 0 ? 0 : x; // limit + int16_t y1 = y < 0 ? 0 : y; // limit + int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit + int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit + int16_t dx = x1 - x; + int16_t dy = y1 - y; + w1 -= dx; + h1 -= dy; + if ((w1 <= 0) || (h1 <= 0)) return; + if (!_using_partial_mode) _Init_Part(); + _writeCommand(0x91); // partial in + _setPartialRamArea(x1, y1, w1, h1); + _writeCommand(command); + _startTransfer(); + + bool isBlack = (command == 0x10); // 判断是否是黑色数据,command 为 0x10 表示黑色数据,为 0x13 表示彩色数据 + + for (int16_t i = 0; i < h1; i++) + { + for (int16_t j = 0; j < w1 / 8; j++) + { + uint8_t data = 0xFF; + if (bitmap) + { + int16_t idx = mirror_y ? j + dx / 8 + ((h - 1 - (i + dy))) * wb : j + dx / 8 + (i + dy) * wb; + if (pgm) + { +#if defined(__AVR) || defined(ESP8266) || defined(ESP32) + data = pgm_read_byte(&bitmap[idx]); +#else + data = bitmap[idx]; +#endif + } + else + { + data = bitmap[idx]; + } + if (isBlack) { + // 处理黑色数据 + if (invert) data = ~data; + } else { + // 处理彩色数据 + if (!invert) data = ~data; + } + } + _transfer(data); + } + } + _endTransfer(); + _writeCommand(0x92); // partial out + delay(1); // yield() to avoid WDT on ESP8266 and ESP32 + + //_initial_write = true; + //Serial.println("写入图像数据"); +} + +void GxEPD2_750c_Z08::writeImagePartFresh(uint8_t command,const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + _writeImagePartFresh(command, bitmap, x, y, w, h, invert, mirror_y, pgm); +} +void GxEPD2_750c_Z08::writeImageRedFix(uint8_t command,const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + _writeImageRedFix(command, bitmap, x, y, w, h, invert, mirror_y, pgm); +} + +void GxEPD2_750c_Z08::_writeImagePartFresh(uint8_t command, const uint8_t* bitmap, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + //if (_using_partial_mode) _Init_Part2(); + + if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean + delay(1); // yield() to avoid WDT on ESP8266 and ESP32 + uint16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded + x -= x % 8; // byte boundary + w = wb * 8; // byte boundary + int16_t x1 = x < 0 ? 0 : x; // limit + int16_t y1 = y < 0 ? 0 : y; // limit + int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit + int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit + int16_t dx = x1 - x; + int16_t dy = y1 - y; + w1 -= dx; + h1 -= dy; + if ((w1 <= 0) || (h1 <= 0)) return; + if (!_using_partial_mode) _Init_Part(); + _writeCommand(0x91); // partial in + _setPartialRamArea(x1, y1, w1, h1); + _writeCommand(command); + _startTransfer(); + for (int16_t i = 0; i < h1; i++) + { + for (int16_t j = 0; j < w1 / 8; j++) + { + uint8_t data; + // use wb, h of bitmap for index! + uint16_t idx = mirror_y ? j + dx / 8 + uint16_t((h - 1 - (i + dy))) * wb : j + dx / 8 + uint16_t(i + dy) * wb; + if (pgm) + { +#if defined(__AVR) || defined(ESP8266) || defined(ESP32) + data = pgm_read_byte(&bitmap[idx]); +#else + data = bitmap[idx]; +#endif + } + else + { + data = bitmap[idx]; + } + if (invert) data = ~data; + _transfer(data); + } + } + _endTransfer(); + _writeCommand(0x92); // partial out + delay(1); // yield() to avoid WDT on ESP8266 and ESP32 + //Serial.println("写入图像数据-writeImagePartFresh"); +} + +void GxEPD2_750c_Z08::_writeImageRedFix(uint8_t command, const uint8_t* bitmap, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + //if (_using_partial_mode) _Init_Part2(); + + if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean + delay(1); // yield() to avoid WDT on ESP8266 and ESP32 + uint16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded + x -= x % 8; // byte boundary + w = wb * 8; // byte boundary + int16_t x1 = x < 0 ? 0 : x; // limit + int16_t y1 = y < 0 ? 0 : y; // limit + int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit + int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit + int16_t dx = x1 - x; + int16_t dy = y1 - y; + w1 -= dx; + h1 -= dy; + if ((w1 <= 0) || (h1 <= 0)) return; + _Init_Part(); + _writeCommand(0x91); // partial in + _setPartialRamArea(x1, y1, w1, h1); + _writeCommand(command); + _startTransfer(); + + // 将bitmap数组中的所有元素赋值为0x00 + memset((void*)bitmap, 0x00, wb * h); + + for (int16_t i = 0; i < h1; i++) + { + for (int16_t j = 0; j < w1 / 8; j++) + { + uint8_t data; + // use wb, h of bitmap for index! + uint16_t idx = mirror_y ? j + dx / 8 + uint16_t((h - 1 - (i + dy))) * wb : j + dx / 8 + uint16_t(i + dy) * wb; + if (pgm) + { + #if defined(__AVR) || defined(ESP8266) || defined(ESP32) + data = pgm_read_byte(&bitmap[idx]); + #else + data = bitmap[idx]; + #endif + } + else + { + data = bitmap[idx]; + } + if (invert) data = ~data; + _transfer(data); + } + } + _endTransfer(); + _writeCommand(0x92); // partial out + delay(1); // yield() to avoid WDT on ESP8266 and ESP32 + //Serial.println("写入图像数据-writeImageRedFix"); +} + + +void GxEPD2_750c_Z08::writeImagePrevious(const uint8_t* black, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + _writeImage(0x10, black, x, y, w, h, invert, mirror_y, pgm); + //Serial.println("写入之前图像数据"); +} + +void GxEPD2_750c_Z08::writeImageNew(const uint8_t* black, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + _writeImage(0x13, black, x, y, w, h, invert, mirror_y, pgm); + //Serial.println("写入新的图像数据"); +} + +void GxEPD2_750c_Z08::writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + writeImagePart(bitmap, NULL, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); +} + +void GxEPD2_750c_Z08::writeImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + _writeImagePart(0x10, black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); + _writeImagePart(0x13, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); +} + +void GxEPD2_750c_Z08::_writeImagePart(uint8_t command, const uint8_t* bitmap, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean + delay(1); // yield() to avoid WDT on ESP8266 and ESP32 + uint16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded + x -= x % 8; // byte boundary + w = wb * 8; // byte boundary + int16_t x1 = x < 0 ? 0 : x; // limit + int16_t y1 = y < 0 ? 0 : y; // limit + int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit + int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit + int16_t dx = x1 - x; + int16_t dy = y1 - y; + w1 -= dx; + h1 -= dy; + if ((w1 <= 0) || (h1 <= 0)) return; + if (!_using_partial_mode) _Init_Part(); + _writeCommand(0x91); // partial in + _setPartialRamArea(x1, y1, w1, h1); + _writeCommand(command); + _startTransfer(); + for (int16_t i = 0; i < h1; i++) + { + for (int16_t j = 0; j < w1 / 8; j++) + { + uint8_t data; + // use wb, h of bitmap for index! + uint16_t idx = mirror_y ? j + dx / 8 + uint16_t((h - 1 - (i + dy))) * wb : j + dx / 8 + uint16_t(i + dy) * wb; + if (pgm) + { +#if defined(__AVR) || defined(ESP8266) || defined(ESP32) + data = pgm_read_byte(&bitmap[idx]); +#else + data = bitmap[idx]; +#endif + } + else + { + data = bitmap[idx]; + } + if (invert) data = ~data; + _transfer(data); + } + } + _endTransfer(); + _writeCommand(0x92); // partial out + delay(1); // yield() to avoid WDT on ESP8266 and ESP32 + //Serial.println("写入部分图像数据"); +} +void GxEPD2_750c_Z08::writeImagePartPrevious(const uint8_t* black, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + //Serial.println("写入之前部分图像数据"); + _writeImagePart(0x10, black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); +} + +void GxEPD2_750c_Z08::writeImagePartNew(const uint8_t* black, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + //Serial.println("写入新的部分图像数据"); + _writeImagePart(0x13, black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); +} + +void GxEPD2_750c_Z08::writeNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + if (data1) + { + writeImage(data1, x, y, w, h, invert, mirror_y, pgm); + } +} + +void GxEPD2_750c_Z08::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm); + refresh(x, y, w, h); +} + +void GxEPD2_750c_Z08::drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); + refresh(x, y, w, h); +} + +void GxEPD2_750c_Z08::drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + writeImage(black, color, x, y, w, h, invert, mirror_y, pgm); + refresh(x, y, w, h); +} + +void GxEPD2_750c_Z08::drawImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); + refresh(x, y, w, h); +} + +void GxEPD2_750c_Z08::drawNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) +{ + writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm); + refresh(x, y, w, h); +} + +void GxEPD2_750c_Z08::refresh(bool partial_update_mode) +{ + if (partial_update_mode) refresh(0, 0, WIDTH, HEIGHT); + else _Update_Full(); + //Serial.println("refresh选择"); +} + +void GxEPD2_750c_Z08::refresh(int16_t x, int16_t y, int16_t w, int16_t h) +{ + // intersection with screen + int16_t w1 = x < 0 ? w + x : w; // reduce + int16_t h1 = y < 0 ? h + y : h; // reduce + int16_t x1 = x < 0 ? 0 : x; // limit + int16_t y1 = y < 0 ? 0 : y; // limit + w1 = x1 + w1 < int16_t(WIDTH) ? w1 : int16_t(WIDTH) - x1; // limit + h1 = y1 + h1 < int16_t(HEIGHT) ? h1 : int16_t(HEIGHT) - y1; // limit + if ((w1 <= 0) || (h1 <= 0)) return; + // make x1, w1 multiple of 8 + w1 += x1 % 8; + if (w1 % 8 > 0) w1 += 8 - w1 % 8; + x1 -= x1 % 8; + _Init_Part(); + //if (usePartialUpdateWindow) _writeCommand(0x91); // partial in + _setPartialRamArea(x1, y1, w1, h1); + _Update_Part(); + //if (usePartialUpdateWindow) _writeCommand(0x92); // partial out + //Serial.println("refresh刷新"); + +} + +void GxEPD2_750c_Z08::powerOff() +{ + _PowerOff(); +} + +void GxEPD2_750c_Z08::hibernate() +{ + _PowerOff(); + if (_rst >= 0) + { + _writeCommand(0x07); // deep sleep + _writeData(0xA5); // check code + _hibernating = true; + } +} + +void GxEPD2_750c_Z08::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h) +{ + uint16_t xe = (x + w - 1) | 0x0007; // byte boundary inclusive (last byte) + uint16_t ye = y + h - 1; + x &= 0xFFF8; // byte boundary + xe |= 0x0007; // byte boundary + _writeCommand(0x90); // partial window + _writeData(x / 256); + _writeData(x % 256); + _writeData(xe / 256); + _writeData(xe % 256); + _writeData(y / 256); + _writeData(y % 256); + _writeData(ye / 256); + _writeData(ye % 256); + _writeData(0x01); + //Serial.println("设置部分更新区域"); +} + +void GxEPD2_750c_Z08::_PowerOn() +{ + if (!_power_is_on) + { + _writeCommand(0x04); + //_waitWhileBusy("_PowerOn", power_on_time); + _waitWhileBusy("电源开启时间", power_on_time); + } + _power_is_on = true; +} + +void GxEPD2_750c_Z08::_PowerOff() +{ + _writeCommand(0x02); // power off + //_waitWhileBusy("_PowerOff", power_off_time); + _waitWhileBusy("电源关闭时间", power_off_time); + _power_is_on = false; +} + +void GxEPD2_750c_Z08::_InitDisplay() +{ + if (_hibernating) _reset(); + _writeCommand(0x01); // POWER SETTING + _writeData (0x07); + _writeData (0x07); // VGH=20V,VGL=-20V + _writeData (0x3f); // VDH=15V + _writeData (0x3f); // VDL=-15V + _writeCommand(0x00); //PANEL SETTING + _writeData(0x0f); //KW: 3f, KWR: 2F, BWROTP: 0f, BWOTP: 1f + _writeCommand(0x61); //tres + _writeData (WIDTH / 256); //source 800 + _writeData (WIDTH % 256); + _writeData (HEIGHT / 256); //gate 480 + _writeData (HEIGHT % 256); + _writeCommand(0x15); + _writeData(0x00); + _writeCommand(0x50); //VCOM AND DATA INTERVAL SETTING + _writeData(0x11); + _writeData(0x07); + _writeCommand(0x60); //TCON SETTING + _writeData(0x22); + //Serial.println("屏幕初始化"); +} + +void GxEPD2_750c_Z08::_Init_Full() +{ + //Serial.println("全刷初始化"); + _InitDisplay(); + _PowerOn(); +} +#define T1 30 // charge balance pre-phase +#define T2 5 // optional extension +#define T3 30 // color change phase (b/w) +#define T4 5 // optional extension for one color +const unsigned char GxEPD2_750c_Z08::lut_20_LUTC_partial[42] PROGMEM = +{ + 0x00, T1, T2, T3, T4, 1, + //0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +const unsigned char GxEPD2_750c_Z08::lut_21_LUTWW_partial[42] PROGMEM = +{ // 10 w + 0x00, T1, T2, T3, T4, 1, + //0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +const unsigned char GxEPD2_750c_Z08::lut_22_LUTKW_partial[42] PROGMEM = +{ // 10 w + 0x5A, T1, T2, T3, T4, 1, + //0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +const unsigned char GxEPD2_750c_Z08::lut_23_LUTWK_partial[42] PROGMEM = +{ // 01 b + 0x84, T1, T2, T3, T4, 1, + //0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +const unsigned char GxEPD2_750c_Z08::lut_24_LUTKK_partial[42] PROGMEM = +{ // 01 b + 0x00, T1, T2, T3, T4, 1, + //0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +const unsigned char GxEPD2_750c_Z08::lut_25_LUTBD_partial[42] PROGMEM = +{ + 0x00, T1, T2, T3, T4, 1, + //0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +void GxEPD2_750c_Z08::_Init_Part() +{ + //Serial.println("局刷初始化"); + _InitDisplay(); + _PowerOn(); +} + +void GxEPD2_750c_Z08::_Update_Full() +{ + + _writeCommand(0x12); //display refresh + //_waitWhileBusy("_Update_Full", full_refresh_time); + _waitWhileBusy("全部刷新时间", full_refresh_time); +} + +void GxEPD2_750c_Z08::_Update_Part() +{ + _writeCommand(0x12); //display refresh + //_waitWhileBusy("_Update_Part", partial_refresh_time); + _waitWhileBusy("局部刷新时间", partial_refresh_time); +} + + +void GxEPD2_750c_Z08::refresh_bw(int16_t x, int16_t y, int16_t w, int16_t h) +{ + //Serial.println("refresh_bw局刷黑白"); + int16_t w1 = x < 0 ? w + x : w; // reduce + int16_t h1 = y < 0 ? h + y : h; // reduce + int16_t x1 = x < 0 ? 0 : x; // limit + int16_t y1 = y < 0 ? 0 : y; // limit + w1 = x1 + w1 < int16_t(WIDTH) ? w1 : int16_t(WIDTH) - x1; // limit + h1 = y1 + h1 < int16_t(HEIGHT) ? h1 : int16_t(HEIGHT) - y1; // limit + if ((w1 <= 0) || (h1 <= 0)) return; + // make x1, w1 multiple of 8 + w1 += x1 % 8; + if (w1 % 8 > 0) w1 += 8 - w1 % 8; + x1 -= x1 % 8; + + _Init_Part(); + + _writeCommand(0x20); + _writeDataPGM(lut_20_LUTC_partial, sizeof(lut_20_LUTC_partial), 42); + _writeCommand(0x21); + _writeDataPGM(lut_21_LUTWW_partial, sizeof(lut_21_LUTWW_partial), 42); + _writeCommand(0x22); + _writeDataPGM(lut_22_LUTKW_partial, sizeof(lut_22_LUTKW_partial), 42); + _writeCommand(0x23); + _writeDataPGM(lut_23_LUTWK_partial, sizeof(lut_23_LUTWK_partial), 42); + _writeCommand(0x24); + _writeDataPGM(lut_24_LUTKK_partial, sizeof(lut_24_LUTKK_partial), 42); + _writeCommand(0x25); + _writeDataPGM(lut_25_LUTBD_partial, sizeof(lut_25_LUTBD_partial), 42); + + _writeCommand(0x00); //panel setting + _writeData(0x3F); // partial update LUT from registers + + _writeCommand(0x01); + _writeData(0x07); + _writeData(0x07); + _writeData(0x3f); + _writeData(0x3f); + + _writeCommand(0x61); + _writeData(0x03); + _writeData(0x20); + _writeData(0x01); + _writeData(0xE0); + + _writeCommand(0x15); + _writeData(0x00); + + _writeCommand(0x60); + _writeData(0x22); + + _writeCommand(0x82); + _writeData(0x31); + + _writeCommand(0X50); //VCOM AND DATA INTERVAL SETTING + _writeData(0x39); + _writeData(0x07); + + _PowerOn(); + _using_partial_mode = true; + _writeCommand(0x91); // partial in + _setPartialRamArea(x1, y1, w1, h1); + _Update_Part(); + _writeCommand(0x92); // partial out + +} + + +//void GxEPD2_750c_Z08::_Init_Part2() +//{ +// +// +// +// _writeCommand(0x00); //panel setting +// _writeData(0x3F); // partial update LUT from registers +// +// _writeCommand(0x01); +// _writeData(0x07); +// _writeData(0x07); +// _writeData(0x3f); +// _writeData(0x3f); +// +// _writeCommand(0x04); +// delay(100); +// +// //Enhanced display drive(Add 0x06 command) +// // _writeCommand(0x06); //Booster Soft Start +// // _writeData(0x17); +// // _writeData(0x17); +// // _writeData(0x28); +// // _writeData(0x17); +// // +// // _writeCommand(0xE0); +// // _writeData(0x02); +//// +// // _writeCommand(0xE5); +// // _writeData(0xFF); +// +// +// +// _writeCommand(0x61); +// _writeData(0x03); +// _writeData(0x20); +// _writeData(0x01); +// _writeData(0xE0); +// +// _writeCommand(0x15); +// _writeData(0x00); +// +// _writeCommand(0x60); +// _writeData(0x22); +// +// _writeCommand(0x82); +// _writeData(0x31); +// +// _writeCommand(0X50); //VCOM AND DATA INTERVAL SETTING +// _writeData(0x39); +// _writeData(0x07); +// +// _writeCommand(0x20); +// _writeDataPGM(lut_20_LUTC_partial, sizeof(lut_20_LUTC_partial), 42); +// _writeCommand(0x21); +// _writeDataPGM(lut_21_LUTWW_partial, sizeof(lut_21_LUTWW_partial), 42); +// _writeCommand(0x22); +// _writeDataPGM(lut_22_LUTKW_partial, sizeof(lut_22_LUTKW_partial), 42); +// _writeCommand(0x23); +// _writeDataPGM(lut_23_LUTWK_partial, sizeof(lut_23_LUTWK_partial), 42); +// _writeCommand(0x24); +// _writeDataPGM(lut_24_LUTKK_partial, sizeof(lut_24_LUTKK_partial), 42); +// _writeCommand(0x25); +// _writeDataPGM(lut_25_LUTBD_partial, sizeof(lut_25_LUTBD_partial), 42); +// +// _PowerOn(); +// _using_partial_mode = true; +// +//} \ No newline at end of file diff --git a/GxEPD2_750c_Z08.h b/GxEPD2_750c_Z08.h new file mode 100644 index 0000000..78269ec --- /dev/null +++ b/GxEPD2_750c_Z08.h @@ -0,0 +1,110 @@ +//原作者: Jean-Marc Zingg Library: https://github.com/ZinggJM/GxEPD2 +//本驱动经过魔改现支持黑白双色的局部快刷,可以很轻松的在三色墨水屏上显示时间等 +//覆盖请注意备份原有驱动 +//作者:YYD 同时感谢@su @游牧 @BlackCat +//QQ交流群:1051455459 +//欢迎进群交流!! +//GitHub地址:https://github.com/yanyuandi/FastFreshBWOnColor +//───────────────────────────────────────────────────────────────────────────────────────────── +//─██████████████───████████──████████────████████──████████─████████──████████─████████████─── +//─██░░░░░░░░░░██───██░░░░██──██░░░░██────██░░░░██──██░░░░██─██░░░░██──██░░░░██─██░░░░░░░░████─ +//─██░░██████░░██───████░░██──██░░████────████░░██──██░░████─████░░██──██░░████─██░░████░░░░██─ +//─██░░██──██░░██─────██░░░░██░░░░██────────██░░░░██░░░░██─────██░░░░██░░░░██───██░░██──██░░██─ +//─██░░██████░░████───████░░░░░░████────────████░░░░░░████─────████░░░░░░████───██░░██──██░░██─ +//─██░░░░░░░░░░░░██─────████░░████────────────████░░████─────────████░░████─────██░░██──██░░██─ +//─██░░████████░░██───────██░░██────────────────██░░██─────────────██░░██───────██░░██──██░░██─ +//─██░░██────██░░██───────██░░██────────────────██░░██─────────────██░░██───────██░░██──██░░██─ +//─██░░████████░░██───────██░░██────────────────██░░██─────────────██░░██───────██░░████░░░░██─ +//─██░░░░░░░░░░░░██───────██░░██────────────────██░░██─────────────██░░██───────██░░░░░░░░████─ +//─████████████████───────██████────────────────██████─────────────██████───────████████████─── +//───────────────────────────────────────────────────────────────────────────────────────────── + +#ifndef _GxEPD2_750c_Z08_H_ +#define _GxEPD2_750c_Z08_H_ + +#include "../GxEPD2_EPD.h" + +class GxEPD2_750c_Z08 : public GxEPD2_EPD +{ + public: + // attributes + static const uint16_t WIDTH = 800; + static const uint16_t WIDTH_VISIBLE = WIDTH; + static const uint16_t HEIGHT = 480; + static const GxEPD2::Panel panel = GxEPD2::GDEW075Z08; + static const bool hasColor = true; + static const bool hasPartialUpdate = true; + static const bool usePartialUpdateWindow = true; // needs be false, controller issue + static const bool hasFastPartialUpdate = false; + static const uint16_t power_on_time = 150; // ms, e.g. 79414us + static const uint16_t power_off_time = 30; // ms, e.g. 39140us + static const uint16_t full_refresh_time = 18000; // ms, e.g. 16788187us + static const uint16_t partial_refresh_time = 1600; // ms, e.g. 16788187us + // constructor + GxEPD2_750c_Z08(int16_t cs, int16_t dc, int16_t rst, int16_t busy); + // methods (virtual) + // Support for Bitmaps (Sprites) to Controller Buffer and to Screen + void clearScreen(uint8_t value = 0xFF); // init controller memory and screen (default white) + void clearScreen(uint8_t black_value, uint8_t color_value); // init controller memory and screen + void writeScreenBuffer(uint8_t value = 0xFF); // init controller memory (default white) + void writeScreenBuffer(uint8_t black_value, uint8_t color_value); // init controller memory + // write to controller memory, without screen refresh; x and w should be multiple of 8 + void writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false); + void writeImagePartFresh(uint8_t command,const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false); + void writeImageRedFix(uint8_t command,const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false); + void writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false); + void writeImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false); + //void writeImagejushua(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false); + void writeImagePrevious(const uint8_t* black, int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false); + void writeImageNew(const uint8_t* black, int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false); + void writeImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false); + void writeImagePartPrevious(const uint8_t* black, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false); + void writeImagePartNew(const uint8_t* black, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false); + // write sprite of native data to controller memory, without screen refresh; x and w should be multiple of 8 + void writeNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false); + // write to controller memory, with screen refresh; x and w should be multiple of 8 + void drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false); + void drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false); + void drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false); + void drawImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false); + // write sprite of native data to controller memory, with screen refresh; x and w should be multiple of 8 + void drawNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false); + void refresh(bool partial_update_mode = false); // screen refresh from controller memory to full screen + void refresh(int16_t x, int16_t y, int16_t w, int16_t h); // screen refresh from controller memory, partial screen + void refresh_bw(int16_t x, int16_t y, int16_t w, int16_t h); // screen refresh from controller memory, partial screen, bw differential + void powerOff(); + + void hibernate(); // turns powerOff() and sets controller to deep sleep for minimum power use, ONLY if wakeable by RST (rst >= 0) + private: + void _writeScreenBuffer(uint8_t value); + void _writeImage(uint8_t command, const uint8_t* bitmap, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm); + void _writeImagePartFresh(uint8_t command, const uint8_t* bitmap, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm); + void _writeImageRedFix(uint8_t command, const uint8_t* bitmap, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm); + void _writeImagePart(uint8_t command, const uint8_t* bitmap, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm); + void _setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h); + void _PowerOn(); + void _PowerOff(); + void _InitDisplay(); + void _Init_Full(); + void _Init_Part(); + //void _Init_Part2(); + void _Update_Full(); + void _Update_Part(); + + private: + static const unsigned char lut_20_LUTC_partial[]; + static const unsigned char lut_21_LUTWW_partial[]; + static const unsigned char lut_22_LUTKW_partial[]; + static const unsigned char lut_23_LUTWK_partial[]; + static const unsigned char lut_24_LUTKK_partial[]; + static const unsigned char lut_25_LUTBD_partial[]; +}; + +#endif