#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <ESP32Servo.h>
// กำหนดพินสำหรับสวิตช์
const int immediateFeedPin = 15; // สวิตช์สำหรับให้อาหารทันที
const int setHourPin = 13; // สวิตช์สำหรับตั้งค่าชั่วโมงการนับถอยหลัง
const int resetTimePin = 12; // สวิตช์สำหรับรีเซ็ตเวลาการนับถอยหลัง
// กำหนดพินสำหรับ HC-SR04
const int trigPin = 4; // พิน TRIG สำหรับส่งสัญญาณ
const int echoPin = 18; // พิน ECHO สำหรับรับสัญญาณสะท้อนกลับ
// กำหนดพินสำหรับเซนเซอร์วัดระดับน้ำ Solu SL067
const int waterSensorVccPin = 25; // พิน VCC สำหรับจ่ายไฟให้เซนเซอร์น้ำ
const int waterSensorGroundPin = 26; // พิน GND สำหรับต่อกราวด์ให้เซนเซอร์น้ำ
const int waterSensorDataPin = 34; // พินสำหรับรับข้อมูลจากเซนเซอร์น้ำ (Analog)
// กำหนดพินสำหรับเซอร์โว
const int servoPin = 19;
Servo servo; // สร้างออบเจ็กต์ Servo
int countdownHours = 0; // ตัวแปรเก็บชั่วโมงที่นับถอยหลัง
int countdownMinutes = 0; // ตัวแปรเก็บนาทีที่นับถอยหลัง
unsigned long countdownTime = 0; // ตัวแปรเก็บเวลาที่นับถอยหลังทั้งหมด (ในหน่วยวินาที)
bool countdownActive = false; // สถานะการทำงานของการนับถอยหลัง
bool countdownSet = false; // สถานะการตั้งค่าการนับถอยหลัง
unsigned long lastButtonPressMillis = 0; // เวลาที่บันทึกเมื่อกดปุ่มครั้งล่าสุด
const unsigned long autoStartDelay = 5000; // หน่วงเวลา 5 วินาทีเพื่อเริ่มการนับถอยหลังอัตโนมัติ
// กำหนดพินและขนาดของ LCD (20x4)
LiquidCrystal_I2C lcd(0x27, 20, 4); // ที่อยู่ I2C ของ LCD 0x27, 20 คอลัมน์ และ 4 แถว
unsigned long lastDisplayUpdateMillis = 0; // ตัวแปรบันทึกเวลาที่อัปเดตหน้าจอ LCD ครั้งล่าสุด
void setup() {
Serial.begin(9600); // เริ่มการสื่อสารผ่าน Serial ที่ความเร็ว 9600 bps
pinMode(immediateFeedPin, INPUT_PULLUP); // กำหนดพินสวิตช์ให้อาหารทันทีเป็น INPUT พร้อมเปิด PULLUP
pinMode(setHourPin, INPUT_PULLUP); // กำหนดพินสวิตช์ตั้งค่าชั่วโมงเป็น INPUT พร้อมเปิด PULLUP
pinMode(resetTimePin, INPUT_PULLUP); // กำหนดพินสวิตช์รีเซ็ตเวลาเป็น INPUT พร้อมเปิด PULLUP
pinMode(trigPin, OUTPUT); // กำหนดพิน TRIG เป็น OUTPUT
pinMode(echoPin, INPUT); // กำหนดพิน ECHO เป็น INPUT
// กำหนดพินสำหรับเซนเซอร์น้ำ
pinMode(waterSensorVccPin, OUTPUT); // พินจ่ายไฟให้เซนเซอร์น้ำ
pinMode(waterSensorGroundPin, OUTPUT); // พิน Ground ต่อเข้า GND
pinMode(waterSensorDataPin, INPUT); // รับข้อมูลจากเซนเซอร์น้ำ (Analog)
// เปิดการทำงานของเซนเซอร์น้ำ
digitalWrite(waterSensorVccPin, HIGH); // จ่ายไฟให้เซนเซอร์น้ำ
digitalWrite(waterSensorGroundPin, LOW); // กราวด์เซนเซอร์น้ำ
servo.attach(servoPin, 500, 2400); // กำหนดพินเซอร์โวและช่วงองศาการหมุน
// เริ่มต้นการทำงานของ LCD
lcd.init();
lcd.backlight(); // เปิดแสงสว่างของหน้าจอ
lcd.clear(); // ล้างหน้าจอ
lcd.print("System Ready"); // แสดงข้อความเริ่มต้น
}
void loop() {
Serial.print("15 = ");
Serial.println(digitalRead(15)); // แสดงสถานะของพิน 15 บน Serial Monitor
if(digitalRead(15)==1){
digitalWrite(4, 0); // ถ้าอ่านค่าพิน 15 ได้ 1 ให้ปิดการทำงานของ TRIG Pin
delay(500);
}
// การให้อาหารทันที
if (digitalRead(immediateFeedPin) == LOW) {
feed(); // เรียกฟังก์ชันให้อาหาร
resetCountdown(); // รีเซ็ตการนับถอยหลัง
delay(500); // หน่วงเวลาเพื่อป้องกันการกดซ้ำ (Debounce)
}
// การตั้งค่าชั่วโมงสำหรับการนับถอยหลัง
if (digitalRead(setHourPin) == LOW) {
countdownHours = (countdownHours + 1) % 24; // เพิ่มชั่วโมงการนับถอยหลังทีละ 1 ชั่วโมง โดยวนลูปที่ 24 ชั่วโมง
countdownSet = true; // กำหนดสถานะการตั้งค่าเป็นจริง
lastButtonPressMillis = millis(); // บันทึกเวลาที่กดปุ่มครั้งล่าสุด
// แสดงเวลาที่ตั้งค่าใหม่บนหน้าจอ
lcd.clear();
lcd.print("Set hours: ");
lcd.print(countdownHours);
lcd.setCursor(0, 1);
lcd.print("Countdown: ");
lcd.print(countdownHours);
lcd.print("h 0m");
delay(500); // หน่วงเวลาเพื่อป้องกันการกดซ้ำ (Debounce)
}
// การรีเซ็ตเวลานับถอยหลัง
if (digitalRead(resetTimePin) == LOW) {
resetCountdown(); // เรียกฟังก์ชันรีเซ็ตเวลานับถอยหลัง
countdownSet = false; // อนุญาตให้ตั้งค่าเวลาใหม่อีกครั้ง
lcd.clear();
lcd.print("Time Reset!"); // แสดงข้อความรีเซ็ตเวลา
delay(1000); // แสดงข้อความรีเซ็ตบนหน้าจอเป็นเวลา 1 วินาที
lcd.clear();
delay(500); // หน่วงเวลาเพื่อป้องกันการกดซ้ำ (Debounce)
}
// เริ่มการนับถอยหลังอัตโนมัติหลังจาก 5 วินาที หากไม่มีการกดปุ่ม
if (countdownSet && !countdownActive && (millis() - lastButtonPressMillis >= autoStartDelay)) {
startCountdown(); // เรียกฟังก์ชันเริ่มการนับถอยหลัง
}
// ลอจิกการนับถอยหลัง
if (countdownActive) {
static unsigned long previousMillis = 0;
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= 1000) {
previousMillis = currentMillis;
if (countdownTime > 0) {
countdownTime--; // ลดเวลานับถอยหลังลง 1 วินาที
int hours = countdownTime / 3600;
int minutes = (countdownTime % 3600) / 60;
int seconds = countdownTime % 60;
// แสดงเวลาที่เหลืออยู่บนหน้าจอ
lcd.setCursor(0, 0);
lcd.print(hours);
lcd.print("h ");
lcd.print(minutes);
lcd.print("m ");
lcd.print(seconds);
lcd.print("s ");
lcd.setCursor(0, 1);
lcd.print("Countdown");
} else {
feed(); // เมื่อเวลาหมด เรียกฟังก์ชันให้อาหาร
resetCountdown(); // รีเซ็ตการนับถอยหลัง
}
}
}
// อัปเดตหน้าจอ LCD เพื่อแสดงระยะทางและเปอร์เซ็นต์น้ำ
long distance = readDistance();
lcd.setCursor(0, 2); // ตั้งเคอร์เซอร์ที่แถวที่ 2
lcd.print("Distance: ");
lcd.print(distance);
lcd.print(" cm");
int waterLevel = analogRead(waterSensorDataPin); // อ่านค่าจากเซนเซอร์น้ำผ่านขา 34
int waterPercent = map(waterLevel, 0, 4095, 0, 100); // แปลงค่าที่อ่านได้เป็นเปอร์เซ็นต์
lcd.setCursor(0, 3); // ตั้งเคอร์เซอร์ที่แถวที่ 3
lcd.print("Water %: ");
lcd.print(waterPercent);
lcd.print("%");
}
// ฟังก์ชันอ่านระยะทางจาก HC-SR04
long readDistance() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH);
long distance = duration * 0.034 / 2;
return distance;
}
// ฟังก์ชันเริ่มการนับถอยหลัง
void startCountdown() {
countdownTime = countdownHours * 3600 + countdownMinutes * 60; // แปลงเวลาที่ตั้งค่าเป็นวินาที
countdownActive = true; // กำหนดสถานะการนับถอยหลังเป็น true
}
// ฟังก์ชันรีเซ็ตเวลานับถอยหลัง
void resetCountdown() {
countdownActive = false; // หยุดการนับถอยหลัง
countdownHours = 0; // รีเซ็ตชั่วโมงเป็น 0
countdownMinutes = 0; // รีเซ็ตนาทีเป็น 0
countdownTime = 0; // รีเซ็ตเวลาที่นับถอยหลังเป็น 0 วินาที
}
// ฟังก์ชันให้อาหาร
void feed() {
servo.write(180); // หมุนเซอร์โวไปที่ตำแหน่ง 180 องศา
delay(3000); // หน่วงเวลา 1 วินาที
servo.write(90); // หมุนเซอร์โวกลับไปที่ตำแหน่งเริ่มต้น
delay(1000); // หน่วงเวลา 1 วินาที
}