数码之家

 找回密码
 立即注册
搜索
查看: 3483|回复: 2

[Arduino] 10元的Esp8266 墨水屏 留言板(hink E0213A04)

[复制链接]
发表于 2022-9-8 21:20:08 | 显示全部楼层 |阅读模式
数码之家镇楼

都是咸鱼二手屏和二手esp8266,价格差不多10元吧, 立创再打个板子,免费!哈哈哈
话不多说,继续分享,先上用法:
1. reset 系统或上电,连接热点 wifiepd  ,打开浏览器,输入网址192.168.4.1,做这步之前把黑白图片先保存好,分辨率120*249 比分辨率小一点(2.13寸),竖版图片,24位 bmp图片  :




打开浏览器后如下图 ,点击选择你的图片,点击确定。



屏幕会自动刷新,然后图片就上去了。


再说缺点,这个对图片有要求,只能黑白,彩色的会显示不好(也不是不能用哈,)。也没有判断横竖屏,而且图片加工下, 没有抖动算法,对线条图支持的好一点。灰度基本不能看了。

ps,屏幕是hink E0213A04,E029A1也可以了, 威锋的屏好像只能全局刷新,不好用,没改适配代码,原理应该一样的。

上代码吧,代码也是借鉴别人的,自己不是专业编程,对某些部分看的也不是太懂。希望有高手继续改良分享。注意红色部分,如果换屏需要修改,还有个隐藏功能,看大家能从代码看出来么,哈哈哈
  1. //接线定义
  2. // mapping from Waveshare 2.9inch e-Paper to Wemos D1 mini
  3. // BUSY -> D2(4), RST -> D4(2), DC -> D3(0), CS -> D8(15), CLK -> D5(14), DIN -> D7(13), GND -> GND, 3.3V -> 3.3V

  4. // mapping example for AVR, UNO, NANO etc.
  5. // BUSY -> 7, RST -> 9, DC -> 8, C S-> 10, CLK -> 13, DIN -> 11

  6. // include library, include base class, make path known


  7. //epd resolotion 122*250(2.13) ,296x128(2.9)
  8. #define  EPDX 122
  9. #define  EPDY 250

  10. #include <ESP8266WebServer.h>
  11. #include <ESP8266WiFi.h>
  12. #include <WiFiClient.h>
  13. #include <ESP8266HTTPClient.h>
  14. #include <FS.h>
  15. #include <GxEPD.h>

  16. // select the display class to use, only one
  17. //#include <GxGDEH029A1/GxGDEH029A1.h>      // 2.9" b/w
  18. #include <GxGDE0213B1/GxGDE0213B1.h>      // 2.13" b/w

  19. #include <GxIO/GxIO_SPI/GxIO_SPI.h>
  20. #include <GxIO/GxIO.h>

  21. // FreeFonts from Adafruit_GFX
  22. #include <Fonts/FreeMonoBold9pt7b.h>
  23. #include <Fonts/FreeMonoBold18pt7b.h>

  24. const char mainPageString[] PROGMEM = "<!DOCTYPE html>\r\n\
  25. <html>\r\n\
  26. <head>\r\n\
  27.   <meta http-equiv='Content-type' content='text/html; charset=utf-8'>\r\n\
  28.   <title>ESP Monitor</title>\r\n\
  29. </head>\r\n\
  30. <body>\r\n\
  31.   <img src='/logo.bmp' width='128' height='296' />\r\n\
  32.   <form method='POST' action='/' enctype='multipart/form-data'>\r\n\
  33.   <input type='file' name='update' id='update'><input type='submit' value='提交'></form>\r\n\
  34.   文件格式必须为bmp,24位,竖版,屏幕为2.9寸E029A1,分辨率296*128\r\n\ 屏幕为2.13寸E0213,分辨率250*122\r\n\
  35. </body>\r\n\
  36. </html>";


  37. GxIO_Class io(SPI, /*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2); // arbitrary selection of D3(=0), D4(=2), selected for default of GxEPD_Class
  38. GxEPD_Class display(io /*RST=D4*/ /*BUSY=D2*/); // default selection of D4(=2), D2(=4)

  39. #if defined(_GxGDE0213B1_H_) || defined(_GxGDEH029A1_H_) || defined(_GxGDEW042T2_H_)
  40. const uint32_t partial_update_period_s = 2;
  41. const uint32_t full_update_period_s = 1 * 60 * 60;
  42. #endif

  43. unsigned char pic[4736]={0};

  44. // 设置mode 按钮
  45. const int MODE_PIN = 5; //  可以是0,但是屏幕刷新前要改回output状态

  46. ESP8266WebServer server(80);
  47. File fsUploadFile;

  48. #define BUFFPIXEL 20

  49. bool b_setup=false;  // 判断是否为设置模式
  50. bool b_wifistatus=false;

  51. //========================================


  52. // These read 16- and 32-bit types from the SD card file.
  53. // BMP data is stored little-endian, Arduino is little-endian too.
  54. // May need to reverse subscript order if porting elsewhere.

  55. uint16_t read16(File f) {
  56.   uint16_t result;
  57.   ((uint8_t *)&result)[0] = f.read(); // LSB
  58.   ((uint8_t *)&result)[1] = f.read(); // MSB
  59.   return result;
  60. }

  61. uint32_t read32(File f) {
  62.   uint32_t result;
  63.   ((uint8_t *)&result)[0] = f.read(); // LSB
  64.   ((uint8_t *)&result)[1] = f.read();
  65.   ((uint8_t *)&result)[2] = f.read();
  66.   ((uint8_t *)&result)[3] = f.read(); // MSB
  67.   return result;
  68. }

  69. void bmpDraw(char *filename, uint8_t x, uint8_t y) {

  70.   File     bmpFile;
  71.   int      bmpWidth, bmpHeight;   // W+H in pixels
  72.   uint8_t  bmpDepth;              // Bit depth (currently must be 24)
  73.   uint32_t bmpImageoffset;        // Start of image data in file
  74.   uint32_t rowSize;               // Not always = bmpWidth; may have padding
  75.   uint8_t  sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel)
  76.   uint8_t  buffidx = sizeof(sdbuffer); // Current position in sdbuffer
  77.   boolean  goodBmp = false;       // Set to true on valid header parse
  78.   boolean  flip    = true;        // BMP is stored bottom-to-top
  79.   int      w, h, row, col;
  80.   uint8_t  r, g, b;
  81.   uint32_t pos = 0, startTime = millis();
  82.   int j=0;
  83.    // epd resolotion
  84.   if((x >= EPDX) || (y >= EPDY)) return;

  85.   Serial.println();
  86.   Serial.print("Loading image '");
  87.   Serial.print(filename);
  88.   Serial.println('\'');
  89.   bmpFile = SPIFFS.open(filename,"r");
  90.   // Open requested file on SD card
  91.   if (!bmpFile) {
  92.     Serial.print("File not found");
  93.     return;
  94.   }

  95.   // Parse BMP header
  96.   if(read16(bmpFile) == 0x4D42) { // BMP signature
  97.     Serial.print("File size: "); Serial.println(read32(bmpFile));
  98.     (void)read32(bmpFile); // Read & ignore creator bytes
  99.     bmpImageoffset = read32(bmpFile); // Start of image data
  100.     Serial.print("Image Offset: "); Serial.println(bmpImageoffset, DEC);
  101.     // Read DIB header
  102.     Serial.print("Header size: "); Serial.println(read32(bmpFile));
  103.     bmpWidth  = read32(bmpFile);
  104.     bmpHeight = read32(bmpFile);
  105.     if(read16(bmpFile) == 1) { // # planes -- must be '1'
  106.       bmpDepth = read16(bmpFile); // bits per pixel
  107.       Serial.print("Bit Depth: "); Serial.println(bmpDepth);
  108.       if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed

  109.         goodBmp = true; // Supported BMP format -- proceed!
  110.         Serial.print("Image size: ");
  111.         Serial.print(bmpWidth);
  112.         Serial.print('x');
  113.         Serial.println(bmpHeight);

  114.         // BMP rows are padded (if needed) to 4-byte boundary
  115.         rowSize = (bmpWidth * 3 + 3) & ~3;

  116.         // If bmpHeight is negative, image is in top-down order.
  117.         // This is not canon but has been observed in the wild.
  118.         if(bmpHeight < 0) {
  119.           bmpHeight = -bmpHeight;
  120.           flip      = false;
  121.         }

  122.         // Crop area to be loaded
  123.         w = bmpWidth;
  124.         h = bmpHeight;
  125.         //Serial.print("bmpHeight:")  ; Serial.print(h);
  126.         //if((x+w-1) >= 296)  w = 296  - x;
  127.         //if((y+h-1) >= 128) h = 128 - y;
  128.         //Serial.print("bmpHeight:")  ; Serial.print(h);

  129.         for (row=0; row<h; row++) { // For each scanline...
  130.            String strs="";
  131.           // Seek to start of scan line.  It might seem labor-
  132.           // intensive to be doing this on every line, but this
  133.           // method covers a lot of gritty details like cropping
  134.           // and scanline padding.  Also, the seek only takes
  135.           // place if the file position actually needs to change
  136.           // (avoids a lot of cluster math in SD library).
  137.           if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
  138.             pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
  139.           else     // Bitmap is stored top-to-bottom
  140.             pos = bmpImageoffset + row * rowSize;
  141.           if(bmpFile.position() != pos) { // Need seek?
  142.             bmpFile.seek(pos,SeekSet);
  143.             buffidx = sizeof(sdbuffer); // Force buffer reload
  144.           }

  145.           for (col=0; col<w; col++) { // For each pixel...
  146.             // Time to read more pixel data?
  147.             if (buffidx >= sizeof(sdbuffer)) { // Indeed
  148.               bmpFile.read(sdbuffer, sizeof(sdbuffer));
  149.               buffidx = 0; // Set index to beginning
  150.             }

  151.             // Convert pixel from BMP to TFT format, push to display
  152.             b = sdbuffer[buffidx++];
  153.             g = sdbuffer[buffidx++];
  154.             r = sdbuffer[buffidx++];

  155.               if (b==g and b==r and r==g and b>=200)
  156.               {
  157.                 strs+="0";
  158.               }  
  159.               else
  160.                 strs+="1";

  161.           } // end pixel
  162.            //Serial.println(strs);
  163.             //const char *strt = strs.c_str();
  164.             unsigned char rt = 0;
  165.             for (int i=0; i< strs.length(); i++)  // for every character in the string  strlen(s) returns the length of a char array
  166.             {
  167.               rt = rt << 1;
  168.               rt = rt | (strs & 1);

  169.               if( i % 8 ==7)
  170.               {
  171.                   pic[j]=rt;
  172.                   rt=0;
  173.                   j++;
  174.               }         
  175.             }


  176.         } // end scanline

  177.         full_clear();
  178.         Serial.println("ready update!")  ; //Serial.print(w)  ; Serial.print(" x ")  ; Serial.println(h)  ;
  179.         display.drawBitmap(0, 0, (const uint8_t *)pic, w, h, GxEPD_BLACK);
  180.         //display.updateWindow(row, col,w,h, true);
  181.         display.update();
  182.         Serial.print("Loaded in ");
  183.         Serial.print(millis() - startTime);
  184.         Serial.println(" ms");
  185.       } // end goodBmp
  186.     }
  187.   }

  188.   bmpFile.close();
  189.   if(!goodBmp) Serial.println("BMP format not recognized.");
  190. }

  191. //======================

  192. //======================

  193. //format bytes
  194. String formatBytes(size_t bytes){
  195.   if (bytes < 1024){
  196.     return String(bytes)+"B";
  197.   } else if(bytes < (1024 * 1024)){
  198.     return String(bytes/1024.0)+"KB";
  199.   } else if(bytes < (1024 * 1024 * 1024)){
  200.     return String(bytes/1024.0/1024.0)+"MB";
  201.   } else {
  202.     return String(bytes/1024.0/1024.0/1024.0)+"GB";
  203.   }
  204. }

  205. //文件格式转换
  206. String getContentType(String filename){
  207.   if(server.hasArg("download")) return "application/octet-stream";
  208.   else if(filename.endsWith(".htm")) return "text/html";
  209.   else if(filename.endsWith(".html")) return "text/html";
  210.   else if(filename.endsWith(".css")) return "text/css";
  211.   else if(filename.endsWith(".js")) return "application/javascript";
  212.   else if(filename.endsWith(".png")) return "image/png";
  213.   else if(filename.endsWith(".gif")) return "image/gif";
  214.   else if(filename.endsWith(".jpg")) return "image/jpeg";
  215.   else if(filename.endsWith(".ico")) return "image/x-icon";
  216.   else if(filename.endsWith(".xml")) return "text/xml";
  217.   else if(filename.endsWith(".pdf")) return "application/x-pdf";
  218.   else if(filename.endsWith(".zip")) return "application/x-zip";
  219.   else if(filename.endsWith(".gz")) return "application/x-gzip";
  220.   return "text/plain";
  221. }

  222. //读取spiffs中的文件
  223. bool handleFileRead(String path){
  224.   Serial.println("handleFileRead: " + path);
  225.   if(path.endsWith("/")) path += "index.htm";
  226.   String contentType = getContentType(path);
  227.   String pathWithGz = path + ".gz";
  228.   if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)){
  229.     if(SPIFFS.exists(pathWithGz))
  230.       path += ".gz";
  231.     File file = SPIFFS.open(path, "r");
  232.     size_t sent = server.streamFile(file, contentType);
  233.     file.close();
  234.     return true;
  235.   }
  236.   return false;
  237. }

  238. //上传文件到spiffs中
  239. void handleFileUpload(){
  240.   if(server.uri() != "/") return;
  241.   HTTPUpload& upload = server.upload();
  242.   if(upload.status == UPLOAD_FILE_START){
  243.     String filename = upload.filename;
  244.     if(!filename.startsWith("/")) filename = "/"+filename;
  245.     Serial.print("handleFileUpload Name: "); Serial.println(filename);
  246.     SPIFFS.rename("/logo.bmp","/last.bmp");
  247.     fsUploadFile = SPIFFS.open("/logo.bmp", "w");
  248.     filename = String();
  249.   } else if(upload.status == UPLOAD_FILE_WRITE){
  250.     //Serial.print("handleFileUpload Data: "); Serial.println(upload.currentSize);
  251.     if(fsUploadFile)
  252.       fsUploadFile.write(upload.buf, upload.currentSize);
  253.   } else if(upload.status == UPLOAD_FILE_END){
  254.     if(fsUploadFile)
  255.       fsUploadFile.close();
  256.     Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize);
  257.     //上传完立即显示图片
  258.     //full_clear();
  259.     bmpDraw("/logo.bmp", 0, 0);
  260.     //休眠最长时间直到按下reset
  261.     Serial.print("deepsleep until reset");
  262.     ESP.deepSleep(0);
  263.   }
  264. }

  265. void handleRoot()
  266. {
  267.   server.send(200, "text/html", mainPageString);
  268.   server.client().stop();
  269. }

  270. void uplaodFinish() {
  271.   server.send(200, "text/html", mainPageString);
  272. }


  273. void setup(void){
  274.   Serial.begin(115200);
  275.   Serial.print("\n");
  276. // Serial.setDebugOutput(true);

  277.   display.init(); // disable diagnostic output on Serial
  278.   display.setTextColor(GxEPD_BLACK);
  279.   //display.setRotation(1);

  280.   SPIFFS.begin();
  281.   {
  282.     Dir dir = SPIFFS.openDir("/");
  283.     while (dir.next()) {   
  284.       String fileName = dir.fileName();
  285.       size_t fileSize = dir.fileSize();
  286.       Serial.printf("FS File: %s, size: %s\n", fileName.c_str(), formatBytes(fileSize).c_str());
  287.     }
  288.     Serial.printf("\n");
  289.   }

  290.   full_clear();

  291.   //WIFI INIT

  292.   WiFi.disconnect();
  293.   //WiFi.mode(WIFI_STA);
  294.   String ssid="wifiepd";
  295.   WiFi.softAP(ssid.c_str());

  296.   Serial.print("Open http://192.168.4.1");
  297.   Serial.println(" to see the file browser");

  298.   showbrand();
  299.   //SERVER INIT
  300.   server.on("/", HTTP_GET, handleRoot);
  301.   //把上传的数据保存到spiffs
  302.   server.on("/", HTTP_POST,[](){uplaodFinish();}, handleFileUpload);

  303.   //访问的url没有在找spiffs中找到回复404
  304.     //访问的url没有在找spiffs中找到回复404
  305.   server.onNotFound([](){
  306.     if(!handleFileRead(server.uri()))
  307.       server.send(404, "text/plain", "FileNotFound");
  308.   });
  309.   server.begin();
  310.   Serial.println("HTTP server started");
  311.   pinMode(MODE_PIN,INPUT_PULLUP);
  312.   bool mod_val = digitalRead(MODE_PIN);
  313.   delay(3000);
  314.   if (mod_val == LOW )
  315.   {
  316.     bmpDraw("/last.bmp", 0, 0);
  317.     //休眠最长时间直到按下reset
  318.     Serial.print("deepsleep until reset");
  319.     ESP.deepSleep(0);
  320.   }

  321. }

  322. void loop(void){
  323.   server.handleClient();
  324. }


  325. void showbrand()
  326. {
  327.   //display.drawBitmap(60, 0, ewm, 254, 122, GxEPD_BLACK);

  328.   display.setTextColor(GxEPD_BLACK);
  329.   display.setFont(&FreeMonoBold18pt7b);
  330.   display.setCursor(10, 0);
  331.   display.println();
  332.   //display.println("0123456789:;<=>?");
  333.   display.println(" WIFI");
  334.   display.println(" PIC");
  335.   display.println();
  336.   display.setFont(&FreeMonoBold9pt7b);
  337.   display.println("WIFI:");
  338.   display.println("wifiepd");
  339.   display.println();
  340.   display.println("open 192.168.4.1 update pic!");
  341.   //display.updateWindow(0, 0, 250, 122, true);
  342.   display.update();

  343. }


  344. void stopWiFiAndSleep() {
  345.   //WiFi.disconnect();
  346.   //WiFi.mode(WIFI_OFF);
  347.   //Serial.println("WIFI sleep");
  348.   wifi_set_sleep_type(LIGHT_SLEEP_T);
  349.   //WiFi.forcelseepBegin();
  350.   delay(1);
  351. }

  352. void full_clear()
  353. {
  354.      display.fillScreen(GxEPD_WHITE);
  355.      display.update();
  356.     delay(200);
  357. }
复制代码


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

打赏

参与人数 3家元 +130 收起 理由
springvirus + 20 謝謝分享
hongo + 10 原創內容
家睦 + 100

查看全部打赏

发表于 2022-9-18 16:32:14 | 显示全部楼层
来学习学习,不会玩
回复 支持 1 反对 0

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-5-6 07:57 , Processed in 0.156000 second(s), 15 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

快速回复 返回顶部 返回列表