ตั้งแต่ยุคโบราณไดโนเสาร์พึ่งถือกำเนิดเกิดมา การจะเรียนรู้อุปกรณ์อะไรสักอย่าง ต้องรู้จริง ตั้งใจจริง เรียนรู้วงจร และเขียนโปรแกรมอย่างละเอียด เช่นสมัยก่อน จะเรียนรู้แค่สั่งงานจอ LCD แบบสองบรรทัด ต้องอ่านหนังสือเป็นเล่ม ฮาร์ดแวร์ต้องแม่น เขียนโปรแกรมต้องเฉียบคม ยากจริง!! ทำให้การเรียนรู้ถูกจำกัดเฉพาะนักอิเล็กทรอนิกส์เท่านั้น!!
แต่ยุคปัจจุบัน เทคโนโลยีเปลี่ยนเร็ว ทุกอย่างมีให้พร้อม เราสามารถเห็นความสำเร็จก่อนเริ่มต้นด้วยซ้ำ อยากสั่งงานพัดลมแบบ ioT วงจรก็มา หาซื้อง่าย ราคาถูก อยากเขียนโปรแกรมกับอุปกรณ์ ก็ไปหาไลบารี่มาใช้ให้ถูก ชีวิตช่างสุขสบาย เป็นโลกกว้างของนัก diy ไม่ต้องจบอิเล็กทรอนิกส์ เป็นงูเป็นปลา ขอแค่ขยันหน่อย มีทริกเล็กน้อย ก็สามารถเรียนรู้ได้ ทำโปรเจคที่สะเทือนวงการได้ไม่ยาก
epaper ซื้อมา ยังไม่รู้ว่าคืออะไรเลย หาข้อมูลทาง google ดูคลิปทาง youtube ก็อปตัดแปะจากลิงค์ คอมพาย ทำงานได้ซะงั้น
epaper คืออะไร เป็นเทคโนโลยีที่ถูกพัฒนาเรียนแบบการลงหมึกบนกระดาษจริงๆ และมีความสามารถเปลี่ยนเนื้อหาการแสดงผลด้วยระบบอิเล็กทรอนิกส์ ไม่ต้องใช้แสง Backlight ใช้พลังงานต่ำ สั่งแสดงผลเสร็จดึงไฟออก อักษรหรือภาพที่แสดงจะติดค้าง(โดยไม่ต้องใช้พลังงานไฟฟ้าเลย) หน้าจอแบบ epaper ซื้อมาทดสอบ แบบ 2 สี(ขาว ,ดำ) ขนาด 2.9 นิ้ว และแบบ 3 สี(ขาว ,ดำ ,แดง) ขนาด 4.2 นิ้ว ควบคุมสั่งงานใช้ ESP8266 ครับผม ส่วนโปรแกรมก็ไปก็อปของชาวบ้านมาเลย ง่ายสุดๆ
ขา cs = 15 ,reset = 2 ,dc = 4 ,busy = 5 ,sdi = 13 ,scl = 14

// base class GxEPD2_GFX can be used to pass references or pointers to the display instance as parameter, uses ~1.2k more code
// enable or disable GxEPD2_GFX base class
#define ENABLE_GxEPD2_GFX 0
#include <GxEPD2_BW.h>
#include <GxEPD2_3C.h>
#include <Fonts/FreeMonoBold9pt7b.h>
#include <Fonts/FreeMonoBold18pt7b.h>
#include <TimeLib.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
// ESP8266 CS(SS)=15,SCL(SCK)=14,SDA(MOSI)=13,BUSY=16,RES(RST)=5,DC=4
// 2.13” EPD Module
GxEPD2_BW<GxEPD2_290, GxEPD2_290::HEIGHT> display(GxEPD2_290(/*CS=D8*/ 15, /*DC=D3*/ 4, /*RST=D4*/ 2, /*BUSY=D2*/ 5)); // GDEH029A1 128×296, SSD1608 (IL3820)
//GxEPD2_3C<GxEPD2_213_Z98c, GxEPD2_213_Z98c::HEIGHT> display(GxEPD2_213_Z98c(/*CS=5*/ 15, /*DC=*/ 4, /*RES=*/ 2, /*BUSY=*/ 16)); // GDEY0213Z98 122×250, SSD1680
const char ssid[] = “****”; // your network SSID (name)
const char pass[] = “****”; // your network password
String formatted_date = “2000-01-01”;
String formatted_time = “00:00:00”;
// NTP Servers:
static const char ntpServerName[] = “us.pool.ntp.org“;
const int timeZone = 7; // Central European Time
WiFiUDP Udp;
unsigned int localPort = 8888; // local port to listen for UDP packets
time_t getNtpTime();
void sendNTPpacket(IPAddress &address);
void setup()
{
Serial.begin(115200);
while (!Serial) ; // Needed for Leonardo only
delay(250);
Serial.println(“TimeNTP Example”);
Serial.print(“Connecting to “);
Serial.println(ssid);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(“.”);
}
Serial.print(“IP number assigned by DHCP is “);
Serial.println(WiFi.localIP());
Serial.println(“Starting UDP”);
Udp.begin(localPort);
Serial.print(“Local port: “);
Serial.println(Udp.localPort());
Serial.println(“waiting for sync”);
setSyncProvider(getNtpTime);
setSyncInterval(300);
display.init(115200, false, 50, false);
header_text();
delay(1000);
refreshing_white();
delay(1000);
}
time_t prevDisplay = 0; // when the digital clock was displayed
void header_text()
{
formatted_date = String(year()) + “-” + String(month()) + “-” + String(day());
int16_t tbx, tby;
uint16_t tbw, tbh;
display.getTextBounds(formatted_date, 0, 0, &tbx, &tby, &tbw, &tbh);
uint16_t x = ((display.width() – tbw) / 2) – tbx;
display.setRotation(1);
display.setFont(&FreeMonoBold9pt7b);
display.setTextColor(GxEPD_BLACK);
display.setFullWindow();
display.firstPage();
do
{
display.fillScreen(GxEPD_WHITE);
display.setCursor(0, 15);
display.print(“Date:”);
display.setCursor(0, 75);
display.print(“Time:”);
display.setFont(&FreeMonoBold18pt7b);
display.setCursor(x, 50);
display.print(formatted_date);
}
while (display.nextPage());
}
void refreshing_white()
{
// Box for time and date
uint16_t box_w = 200;
uint16_t box_h = 30;
// calculate the center position
uint16_t box_x = (display.width() – box_w) / 2;
uint16_t box_y = ((display.height() – box_h) / 2) + 40;
for (uint16_t r = 1; r < 15; r++)
{
display.setRotation(1);
display.setPartialWindow(box_x, box_y, box_w, box_h);
display.firstPage();
do
{
display.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE);
}
while (display.nextPage());
delay(200);
}
}
void showPartialUpdate()
{
//delay(100);
// Box for time and date
uint16_t box_w = 200;
uint16_t box_h = 30;
// calculate the center position
uint16_t box_x = (display.width() – box_w) / 2;
uint16_t box_y = ((display.height() – box_h) / 2) + 40;
uint16_t incr = display.epd2.hasFastPartialUpdate ? 1 : 3;
display.setFont(&FreeMonoBold18pt7b);
if (display.epd2.WIDTH < 104) display.setFont(0);
display.setTextColor(GxEPD_BLACK);
display.setRotation(1);
display.setPartialWindow(box_x, box_y, box_w, box_h);
display.firstPage();
do
{
display.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE);
int16_t tbx, tby;
uint16_t tbw, tbh;
display.getTextBounds(formatted_time, 0, 0, &tbx, &tby, &tbw, &tbh);
// Hitung posisi tengah kotak
int16_t x = box_x + (box_w – tbw) / 2;
int16_t y = box_y + (box_h – tbh) / 2 + tbh;
display.setCursor(x, y);
display.print(formatted_time);
}
while (display.nextPage());
}
void loop() {
formatted_time = String(hour() < 10 ? “0” : “”) + String(hour()) + “:” +
String(minute() < 10 ? “0” : “”) + String(minute()) + “:” +
String(second() < 10 ? “0” : “”) + String(second());
showPartialUpdate();
//delay(10000);
if (formatted_date != String(year()) + “-” + String(month()) + “-” + String(day())) {
header_text();
delay(1000);
refreshing_white();
delay(1000);
}
}
/*——– NTP code ———-*/
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets
time_t getNtpTime()
{
IPAddress ntpServerIP; // NTP server’s ip address
while (Udp.parsePacket() > 0) ; // discard any previously received packets
Serial.println(“Transmit NTP Request”);
// get a random server from the pool
WiFi.hostByName(ntpServerName, ntpServerIP);
Serial.print(ntpServerName);
Serial.print(“: “);
Serial.println(ntpServerIP);
sendNTPpacket(ntpServerIP);
uint32_t beginWait = millis();
while (millis() – beginWait < 1500) {
int size = Udp.parsePacket();
if (size >= NTP_PACKET_SIZE) {
Serial.println(“Receive NTP Response”);
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
unsigned long secsSince1900;
// convert four bytes starting at location 40 to a long integer
secsSince1900 = (unsigned long)packetBuffer[40] << 24;
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
secsSince1900 |= (unsigned long)packetBuffer[43];
return secsSince1900 – 2208988800UL + timeZone * SECS_PER_HOUR;
}
}
Serial.println(“No NTP Response “);
return 0; // return 0 if unable to get the time
}
// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress &address)
{
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}
//**********************************

