Conectând un cablu USB de la laptop la placa Arduino Uno, aceasta devine centrul de control al întregului sistem. Pe display este afișat numele proiectului pe prima linie, iar ora și data curentă pe a doua și a treia linie. La apăsarea butonului dedicat, se declanșează o întrerupere care va afișa un meniu pe ecran. Utilizatorul are trei opțiuni principale: apăsând tasta 'A' poate introduce manual ora la care se va elibera hrana, sau apăsând tasta 'B' (meniu dietă) sau 'C' (meniu normal), poate seta hrănirea automată a pisicii de trei ori pe zi la ore prestabilite.
Dacă un meniu a fost deja ales și utilizatorul dorește să selecteze un alt meniu, poate apăsa tasta 'D' pentru a reseta meniul, iar pe ecran va apărea mesajul 'Meniul a fost șters!'. Dacă se încearcă introducerea unei alte taste după ce un meniu a fost selectat, pe ecran va apărea mesajul 'Ai introdus deja un meniu!'. În cazul în care nu a fost ales niciun meniu și se introduce o altă tastă decât cele specificate, se va afișa mesajul 'Tastă invalidă'. De asemenea, dacă utilizatorul a introdus greșit ora după selectarea tastei 'A', poate apăsa tasta 'D' pentru a anula ora.
Motorul servo, controlat de Arduino, este esențial în acest sistem. După ce utilizatorul a ales opțiunea dorită, dispozitivul așteaptă până când modulul RTC indică că ora presetată a fost atinsă. În acel moment, Arduino activează motorul servo, care acționează ușița pentru a elibera hrana pentru pisică. Această integrare eficientă a modulelor RTC și servo motor asigură o hrănire precisă și la timp pentru animalul de companie.
Tastatura are 8 pini care se conectează la pinurile digitale ale Arduino pentru a detecta apăsările de taste.
Modulul RTC are 4 pini: VCC, GND, SDA, SCL, și utilizează comunicarea I2C pentru sincronizarea timpului.
Display-ul LCD simplifică conexiunile datorită modulului I2C integrat, reducând necesitatea de pini suplimentari.
Butonul tactil detectează apăsările pentru a activa meniul de setări.
Servo motorul are 3 pini: VCC, GND și Semnal, și controlează mecanismul de eliberare a hranei.
Mediul de dezvoltare utilizat pentru realizarea proiectului a fost: https://www.arduino.cc/en/software/ - versiunea 2.3.2
Elementul de noutate al proiectului constă în integrarea completă a mai multor componente hardware și software pentru a crea un sistem autonom de hrănire a pisicilor. Utilizarea unui meniu interactiv pentru setarea orelor de hrănire și posibilitatea de a selecta diferite programe de hrănire sunt caracteristici inovative care oferă flexibilitate și ușurință în utilizare.
Descrierea codului:
Servo servo1; int servoPin = 10; 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] = { 2, 3, 4, 5 }; byte colPins[COLS] = { 6, 7, 8, 9 }; Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS); LiquidCrystal_I2C lcd(0x27, 20, 4); RTC_DS3231 rtc; const int buttonPin = A3; // Pinul la care este conectat butonul int buttonState = 0; // Variabila pentru a stoca starea butonului (apasat sau nu) bool showMenu = false; // Dacă este true se afișează meniul boolean feed = false; // Dacă a fost ales meniul A true, altfel false int feedingHour = -1; int feedingMinute = -1; int menuSelected = 0; // 0 = Niciun meniu, 1 = Meniu B dieta, 2 = Meniu C normal, 3 = Meniu A int presetFeedingTimes[3][3]; // Ora, minut, secundă pentru hrănirile prestabilite bool butB = false; // Dacă a fost ales meniul B true, altfel false bool butC = false; // Dacă a fost ales meniul C true, altfel false
void setup() { Wire.begin(); lcd.begin(20, 4); lcd.backlight(); servo1.attach(servoPin); presetFeedingTimes[0][0] = 20; // Prima ora de hrănire prestabilită presetFeedingTimes[0][1] = 44; // Minutul presetFeedingTimes[0][2] = 0; // Secunda presetFeedingTimes[1][0] = 20; // A doua ora de hrănire prestabilită presetFeedingTimes[1][1] = 44; presetFeedingTimes[1][2] = 20; presetFeedingTimes[2][0] = 20; // A treia ora de hrănire prestabilită presetFeedingTimes[2][1] = 44; presetFeedingTimes[2][2] = 35; if (!rtc.begin()) { lcd.print("Couldn't find RTC"); while (1); } if (rtc.lostPower()) { rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); } pinMode(buttonPin, INPUT); // Seteaza pinul butonului ca pin de intrare }
void loop() { // Citeste starea butonului int buttonPress = digitalRead(buttonPin); // Dacă butonul este apăsat if (buttonPress == 1) { showMenu = true; lcd.clear(); // Curăță ecranul pentru a afișa meniul lcd.setCursor(0, 0); lcd.print("Selecteaza tasta: "); lcd.setCursor(0, 1); lcd.print("A - Alege ora mesei"); lcd.setCursor(0, 2); lcd.print("B - Meniu 1 dieta"); lcd.setCursor(0, 3); lcd.print("C - Meniu 2 normal"); delay(500); // Debounce delay } else if (showMenu) { // Citeste tasta apasata de la keypad char key = keypad.getKey(); if (key) { lcd.clear(); switch (key) { case 'A': if (menuSelected == 0) { lcd.setCursor(0, 0); lcd.print("Ai ales tasta 'A'"); setFeedingTimeA(); menuSelected = 3; } else { lcd.setCursor(0, 0); lcd.print("Ai introdus deja un meniu!"); } break; case 'B': if (menuSelected == 0) { lcd.setCursor(0, 0); lcd.print("Ai ales tasta 'B'"); menuSelected = 1; butB = true; } else { lcd.setCursor(0, 0); lcd.print("Ai introdus deja un meniu!"); } break; case 'C': if (menuSelected == 0) { lcd.setCursor(0, 0); lcd.print("Ai ales tasta 'C'"); menuSelected = 2; butC = true; } else { lcd.setCursor(0, 0); lcd.print("Ai introdus deja un meniu!"); } break; case 'D': if (menuSelected == 0) { lcd.setCursor(0, 0); lcd.print("Tasta invalida"); } else { lcd.setCursor(0, 0); lcd.print("Meniul a fost sters!"); menuSelected = 0; butB = false; butC = false; feed = false; } break; default: lcd.setCursor(0, 0); lcd.print("Tasta invalida"); break; } delay(2000); // Afișează mesajul timp de 2 secunde showMenu = false; // Revine la afișarea datei și orei după selectarea opțiunii } } else { // Afiseaza data si ora curenta pe ecran lcd.clear(); DateTime now = rtc.now(); lcd.setCursor(0, 0); lcd.print("CAT FEEDER! <3"); lcd.setCursor(0, 1); 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(':'); if (now.second() < 10) lcd.print('0'); lcd.print(now.second()); lcd.setCursor(0, 2); lcd.print("Date: "); if (now.day() < 10) lcd.print('0'); lcd.print(now.day()); lcd.print('/'); if (now.month() < 10) lcd.print('0'); lcd.print(now.month()); lcd.print('/'); lcd.print(now.year()); // Verifică dacă este ora de hrănire setată pentru meniul A if (now.hour() == feedingHour && now.minute() == feedingMinute && feed) { servo1.write(-90); delay(1000); servo1.write(90); delay(1000); menuSelected = 0; feed = false; // Dezactivează hrănirea după efectuare } // Dacă a fost ales meniul B if (butB == true) { int i; for (i = 0; i < 3; i ++) { if (now.hour() == presetFeedingTimes[i][0] && now.minute() == presetFeedingTimes[i][1] && now.second() == presetFeedingTimes[i][2]) { servo1.write(-90); delay(1000); servo1.write(90); delay(2000); if (i == 2) { butB = false; menuSelected = 0; } break; } } } // Dacă a fost ales meniul C if (butC == true) { int i; for (i = 0; i < 3; i ++) { if (now.hour() == presetFeedingTimes[i][0] && now.minute() == presetFeedingTimes[i][1] && now.second() == presetFeedingTimes[i][2]) { servo1.write(-90); delay(1000); servo1.write(90); delay(2000); servo1.write(-90); delay(1000); servo1.write(90); delay(2000); if (i == 2) { butC = false; menuSelected = 0; } break; } } } } delay(100); // Mică întârziere pentru debounce }
void setFeedingTimeA() { feed = true; int i = 0; int j = 0; char key; char r[4]; lcd.clear(); lcd.setCursor(0, 0); lcd.print("Set feeding Time"); lcd.setCursor(0, 1); lcd.print("HH:MM"); lcd.setCursor(0, 2); while(1){ key = keypad.getKey(); if(key >= '0' && key <= '9'){ // Acceptă doar cifre lcd.setCursor(j, 2); lcd.print(key); r[i] = key - '0'; // Convertește tasta apăsată la valoare numerică i++; j++; if (j == 2) { lcd.print(":"); j++; } if (i == 4) { // Toate cifrele au fost introduse feedingHour = r[0] * 10 + r[1]; feedingMinute = r[2] * 10 + r[3]; break; } } if (key == 'D') { // Anulează setarea feed = false; break; } } }
Funcționalități din laborator
Proiectul integrează mai multe noțiuni fundamentale învățate în laboratoare, cum ar fi utilizarea ADC, I2C, Keypad, RTC și Servo.
Cu toate că Oscar, motanul meu, nu pare să fie impresionat de proiect, știu că are o latură entuziasmată pe care o păstrează pentru el.
Rezumat video:Inițial, am selectat tasta 'C' pentru a seta meniul normal, cu orele prestabilite la 16:04:00, 16:04:20 și 16:04:35. În timp ce așteptam să se facă orele respective, am vrut să testez și alte funcționalități ale sistemului. Pentru a verifica dacă ecranul afișează mesajele corecte, am selectat un alt meniu la întâmplare. Am vrut să mă asigur că mesajul “Ai introdus deja un meniu!” apare pe ecran atunci când se încearcă setarea unui meniu nou după ce unul este deja activ. Exact așa s-a întâmplat: ecranul a afișat corect mesajul, indicând că nu pot seta un alt meniu până nu îl șterg pe cel actual. Apoi, am ales o tasta la întâmplare, alta decât cele specifice meniului, pentru a testa cum se comportă sistemul. După apăsarea tastei necorespunzătoare, ecranul a afișat mesajul “Tasta invalida!”, confirmând că programul recunoaște și gestionează corect inputurile incorecte. La ora 16:04:00, sistemul a început să execute meniul 'C'. Conform specificațiilor, meniul 'C' face două ture pentru fiecare oră prestabilită, rotind servomecanismul cu -90 de grade și apoi înapoi la 90 de grade. Această secvență s-a repetat și la 16:04:20 și 16:04:35, confirmând că funcția a fost implementată corect. După ce aceste ore au trecut și meniul 'C' și-a încheiat ciclul, am introdus meniul 'A'. Pentru acesta, a trebuit să aleg ora de hrănire manual, introducând-o prin keypad. Am setat ora la 16:05, iar sistemul a acceptat și afișat noua oră corect. Ulterior, am ales meniul 'B' și am vrut să testez funcția de ștergere a meniului. Am apăsat tasta 'D', iar ecranul a afișat mesajul “Meniul a fost sters!”, indicând că toate meniurile active au fost resetate și sistemul este pregătit pentru o nouă selecție.