// *** คู่มือการใช้งานระบบนับเวลาถอยหลัง ***
// 1.ส่วนประกอบของระบบ
// *LCD: หน้าจอแสดงผลเพื่อแสดงเวลาและสถานะของระบบ
// *Keypad: แป้นพิมพ์สำหรับป้อนข้อมูลการตั้งเวลาถอยหลัง
// *LED: ไฟ LED เพื่อแสดงสถานะเมื่อเวลาถอยหลังหมด
// *Buzzer: บัซเซอร์เพื่อแจ้งเตือนเมื่อเวลาถอยหลังหมด
// *WiFi: การเชื่อมต่อ WiFi สำหรับการซิงค์เวลากับเซิร์ฟเวอร์ NTP
// *** วิธีการใช้งาน ***
// 1.การตั้งค่าเวลา:
// *เมื่อระบบเริ่มต้น จะพยายามเชื่อมต่อกับ WiFi และซิงค์เวลากับเซิร์ฟเวอร์ NTP
// *จากนั้นระบบจะแสดงหน้าจอการตั้งค่าเวลาถอยหลัง
// *กดปุ่ม C เพื่อเริ่มการตั้งเวลาใหม่
// *ป้อนจำนวนชั่วโมงที่ต้องการโดยใช้ปุ่มตัวเลขบน Keypad และกดปุ่ม A เพื่อยืนยัน
// *ป้อนจำนวนนาทีและวินาทีในลักษณะเดียวกัน
// 2.การนับเวลาถอยหลัง:
// *หลังจากตั้งค่าเวลาเสร็จ ระบบจะเริ่มนับเวลาถอยหลัง
// *หน้าจอจะแสดงเวลาที่เหลืออยู่
// *หากต้องการยกเลิกการนับเวลาถอยหลัง ให้กดปุ่ม C จะมีข้อความ "Cancelled" แสดงขึ้นมาเป็นเวลา 3 วินาที จากนั้นระบบจะกลับไปที่หน้าจอการตั้งเวลา
// 3.การแจ้งเตือนเมื่อหมดเวลา:
// *เมื่อเวลาถอยหลังหมด ไฟ LED จะกระพริบและบัซเซอร์จะส่งเสียง
// *หน้าจอจะแสดงข้อความ "Timer Done"
// *หากต้องการหยุดการแจ้งเตือน ให้กดปุ่ม B จะมีข้อความ "Closed" แสดงขึ้นมาเป็นเวลา 3 วินาที จากนั้นระบบจะกลับไปที่หน้าจอการตั้งเวลา
// [][][][] [][][][] [] [] [][] [][][][]
// [] [] [] [] [] [] [] [] []
// [] [][] [] [] [] [] [] [] [] []
// [] [] [] [][][][] [][][][] [][][][] []
// [] [][] [] [] [] [] [] [] []
// [] [] [] [] [] [] [] []
// [][][][] [] [] [] [] [] []
#include <WiFi.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
// กำหนดการเชื่อมต่อกับหน้าจอ LCD
LiquidCrystal_I2C LCD(0x27, 16, 2);
// กำหนดค่าการเชื่อมต่อกับเซิร์ฟเวอร์ NTP และเขตเวลา
#define NTP_SERVER "th.pool.ntp.org"
#define UTC_OFFSET 7*3600
#define UTC_OFFSET_DST 0
// กำหนดพอร์ตสำหรับ LED และ Buzzer
const int LED = 13;
const int BUZZER = 12;
// กำหนดแป้นพิมพ์ Keypad
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {18, 5, 17, 16};
byte colPins[COLS] = {4, 0, 2, 15};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
unsigned long timerEndTime;
int countdownHours, countdownMinutes, countdownSeconds;
bool timerRunning = false;
bool timerDone = false;
// ฟังก์ชันแสดงเวลาท้องถิ่นบนหน้าจอ LCD
void printLocalTime() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
LCD.setCursor(0, 1);
LCD.print("Connection Err");
return;
}
LCD.setCursor(0, 1);
LCD.print("Real - ");
LCD.print(String(timeinfo.tm_hour) + ":" + String(timeinfo.tm_min) + ":" + String(timeinfo.tm_sec) + " ");
}
// ฟังก์ชันรับค่าจาก Keypad
int getNumberFromKeypad(const char* prompt) {
String numStr = "";
char key;
LCD.clear();
LCD.setCursor(0, 0);
LCD.print(prompt);
LCD.setCursor(0, 1);
LCD.print(":");
int cursorPos = 1;
while (true) {
key = keypad.getKey();
if (key != NO_KEY) {
if (key >= '0' && key <= '9') {
numStr += key;
LCD.setCursor(cursorPos, 1);
LCD.print(key);
cursorPos++;
} else if (key == 'D' && numStr.length() > 0) {
numStr.remove(numStr.length() - 1);
cursorPos--;
LCD.setCursor(cursorPos, 1);
LCD.print(" ");
LCD.setCursor(cursorPos, 1);
} else if (key == 'A') {
if (numStr.length() == 0) return 0;
return numStr.toInt();
}
}
}
}
// ฟังก์ชันเริ่มต้นระบบ
void setup() {
Serial.begin(115200);
LCD.init();
LCD.backlight();
LCD.setCursor(0, 0);
LCD.print("Connecting to ");
LCD.setCursor(0, 1);
LCD.print("WiFi ");
WiFi.begin("Wokwi-GUEST", "", 6);
while (WiFi.status() != WL_CONNECTED) {
delay(250);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
LCD.clear();
LCD.setCursor(0, 0);
LCD.print("Online");
LCD.setCursor(0, 1);
LCD.print("Updating time...");
configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER);
pinMode(LED, OUTPUT);
pinMode(BUZZER, OUTPUT);
getTimerInput();
}
// ฟังก์ชันหลักของระบบ
void loop() {
char key = keypad.getKey();
if (timerRunning) {
unsigned long currentTime = millis();
if (currentTime < timerEndTime) {
unsigned long remainingTime = (timerEndTime - currentTime) / 1000;
int remainingHours = remainingTime / 3600;
remainingTime %= 3600;
int remainingMinutes = remainingTime / 60;
int remainingSeconds = remainingTime % 60;
LCD.setCursor(0, 0);
LCD.print("CD - ");
LCD.print(String(remainingHours) + ":" + String(remainingMinutes) + ":" + String(remainingSeconds) + " ");
} else {
timerRunning = false;
timerDone = true;
}
if (key == 'C') {
LCD.clear();
LCD.setCursor(0, 0);
LCD.print("Cancelled");
delay(3000);
cancelTimer();
getTimerInput();
}
} else if (timerDone) {
LCD.setCursor(0, 0);
LCD.print("Timer Done ");
while (true) {
digitalWrite(LED, HIGH);
tone(BUZZER, 1000);
delay(500);
digitalWrite(LED, LOW);
noTone(BUZZER);
delay(500);
char key = keypad.getKey();
if (key == 'B') {
LCD.clear();
LCD.setCursor(0, 0);
LCD.print("Closed");
delay(3000);
cancelTimer();
getTimerInput();
break;
}
}
} else {
LCD.setCursor(0, 0);
LCD.print("Press C to set ");
LCD.setCursor(0, 1);
LCD.print("new timer ");
if (key == 'C') {
LCD.clear();
cancelTimer();
getTimerInput();
}
}
printLocalTime();
delay(250);
}
// ฟังก์ชันรับค่าการตั้งเวลาจากผู้ใช้
void getTimerInput() {
countdownHours = getNumberFromKeypad("Set hour");
countdownMinutes = getNumberFromKeypad("Set minute");
countdownSeconds = getNumberFromKeypad("Set second");
LCD.clear();
LCD.setCursor(0, 0);
LCD.print("Timer set to:");
LCD.setCursor(0, 1);
LCD.print(String(countdownHours) + ":" + String(countdownMinutes) + ":" + String(countdownSeconds));
delay(2000);
LCD.clear();
unsigned long currentTime = millis();
timerEndTime = currentTime + (countdownHours * 3600L + countdownMinutes * 60L + countdownSeconds) * 1000L;
timerRunning = true;
}
// ฟังก์ชันยกเลิกการนับเวลา
void cancelTimer() {
timerRunning = false;
timerDone = false;
digitalWrite(LED, LOW);
noTone(BUZZER);
LCD.clear();
}