#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal.h>
#include <Servo.h>
// LCD: RS, E, D4, D5, D6, D7
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
// RTC module
RTC_DS1307 rtc;
// Servo motor
Servo feederServo;
// Push buttons
const int BUTTON_HOUR = 2;
const int BUTTON_MINUTE = 3;
const int BUTTON_OK = 4;
const int BUTTON_FEED = 5;
// Servo signal pin
const int SERVO_PIN = 6;
// Feeding schedule: default 08:00
int feedHour = 8;
int feedMinute = 0;
bool scheduleConfirmed = false;
int lastFedDate = -1;
// Servo positions
const int CLOSED_ANGLE = 0;
const int OPEN_ANGLE = 90;
// Button debounce variables
const int buttonPins[] = {2, 3, 4, 5};
bool lastReading[4] = {HIGH, HIGH, HIGH, HIGH};
bool stableState[4] = {HIGH, HIGH, HIGH, HIGH};
unsigned long lastChange[4] = {0, 0, 0, 0};
bool buttonPressed(int index) {
bool reading = digitalRead(buttonPins[index]);
if (reading != lastReading[index]) {
lastChange[index] = millis();
lastReading[index] = reading;
}
if (millis() - lastChange[index] > 40) {
if (reading != stableState[index]) {
stableState[index] = reading;
if (stableState[index] == LOW) {
return true;
}
}
}
return false;
}
// Dispense food
void feedPet() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Feeding Pet...");
feederServo.write(OPEN_ANGLE);
delay(1000);
feederServo.write(CLOSED_ANGLE);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Food Dispensed!");
delay(1000);
}
// Display current time and schedule
void displayStatus(DateTime now) {
lcd.setCursor(0, 0);
lcd.print("Time ");
if (now.hour() < 10) lcd.print("0");
lcd.print(now.hour());
lcd.print(":");
if (now.minute() < 10) lcd.print("0");
lcd.print(now.minute());
lcd.print(" ");
lcd.setCursor(0, 1);
if (!scheduleConfirmed) {
lcd.print("Set ");
if (feedHour < 10) lcd.print("0");
lcd.print(feedHour);
lcd.print(":");
if (feedMinute < 10) lcd.print("0");
lcd.print(feedMinute);
lcd.print(" Press OK");
} else {
lcd.print("Feed ");
if (feedHour < 10) lcd.print("0");
lcd.print(feedHour);
lcd.print(":");
if (feedMinute < 10) lcd.print("0");
lcd.print(feedMinute);
lcd.print(" ");
}
}
void setup() {
Serial.begin(9600);
Wire.begin();
// Initialize standard 16-pin LCD
lcd.begin(16, 2);
lcd.clear();
lcd.print("Pet Feeder");
lcd.setCursor(0, 1);
lcd.print("Starting...");
// Initialize servo
feederServo.attach(SERVO_PIN);
feederServo.write(CLOSED_ANGLE);
// Configure buttons
for (int i = 0; i < 4; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
}
delay(1500);
// Initialize RTC
if (!rtc.begin()) {
lcd.clear();
lcd.print("RTC Not Found!");
while (true) {
delay(100);
}
}
// Set RTC if it is not running
if (!rtc.isrunning()) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
lcd.clear();
}
void loop() {
DateTime now = rtc.now();
// Button 1: Increase feeding hour
if (buttonPressed(0)) {
feedHour = (feedHour + 1) % 24;
scheduleConfirmed = false;
}
// Button 2: Increase feeding minute
if (buttonPressed(1)) {
feedMinute = (feedMinute + 1) % 60;
scheduleConfirmed = false;
}
// Button 3: Confirm schedule
if (buttonPressed(2)) {
scheduleConfirmed = true;
lcd.clear();
lcd.print("Schedule Saved");
delay(700);
}
// Button 4: Manual feeding
if (buttonPressed(3)) {
feedPet();
}
// Feed once per day at the selected time
int today = now.year() * 10000
+ now.month() * 100
+ now.day();
if (scheduleConfirmed &&
now.hour() == feedHour &&
now.minute() == feedMinute &&
lastFedDate != today) {
feedPet();
lastFedDate = today;
}
displayStatus(now);
delay(50);
}