Components and supplies
Arduino Nano R3
RGB Backlight LCD - 16x2
Rod Magnets 3mm dismeter, 5mm lenght
Real Time Clock
Hall sensor UNIPOLAR
Apem Push button momentary IP67
LED (generic)
Hammond Multi ABS housing with flange
Small push buttons momentary
lcd i2c backpack
Continuous Rotation Servo
Cereal dispenser
Apps and platforms
LCD character generator
Project description
Code
Pet Feed-O-Matic v 1.1 - 20-02-2018
arduino
v 1.1: pressing the Cancel1 or 2 buttons will show a explanation
1// c++ stuff... 2//#include <Arduino.h> 3//#line 1 4//#line 1 "/Users/Erik/Documents/PlatformIO/Projects/180202-151127-uno/src/Pet_Feeder_1_1_ENG.cpp" 5/* 6 _ _ 7 /\ | | (_) 8 / \ _ __ __| |_ _ _ _ __ ___ 9 / /\\| '__/ _` | | | | | '_ \/ _ \\ 10 / ____ \\| | | (_| | |_| | | | | | (_) | 11 /_/ \\_\\_| \\__,_|\\__,_|_|_| |_|\\___/ 12 _____ _ ______ _ 13 | __ \ | | | ____| | | 14 | |__) |__| |_ | |__ ___ ___ __| | ___ _ __ 15 | ___/ _ \__| | __/ _ \\/ _ \\/ _` |/ _ \'__| 16 | | | __/ |_ | | | __/ __/ (_| | __/ | 17 |_| \\___|\\__| |_| \\___|\\___|\\__,_|\\___|_| 18 19 20 21 Erik de Ruiter 22 ----------------------------------------------------------------------------- 23 24 To do: 25 - remote feeding? 26 - feeder stop delay as menu editable item 27 28 last change: 29 dinsdag 20 februari 2018 - 17:20:28 30 31 FEATURES: 32 - *Accurate portions* each time! (by using a Hall sensor) 33 - Two feeding times, once a day 34 - *Extremely* accurate Real Time Clock (Only with genuine DS3231 chip) 35 - Cancel upcoming feeding individually for both timers with 36 display and Led indicator. Automatically reset after time has passed. 37 - Manual feed function (one portion per button press) 38 - Adjustable portions for each of the two feeding times (1-9 portions) 39 - Overview of all set parameters in the main screen 40 - Easy to navigate menu system 41 - LED indication if feeding was successful 42 - LCD backlight timer (off after 30 sec, on with any button press) 43 - Backup in the event of a failing Hall sensor 44 - Hass sensor LED will blink until midnight if the Hall sensor has failed 45 - Time and other settings are safely stored in EEPROM 46 47 WEBSITES: 48 LCD HD44780 character generator website to make your own lcd symbols 49 https://omerk.github.io/lcdchargen/ 50 51 Arduino sketch Large letter comment generator 52 http://patorjk.com/software/taag/#p=display&c=c%2B%2B&f=Big&t=Comment 53 54 55 Revisions: 56 zondag 28 januari 2018 - 20:17:10 57 58 59*/ 60 61//////////////////////////////////////////////////////////////////////////////// 62// USER CHANGEABLE VARIABLES 63//////////////////////////////////////////////////////////////////////////////// 64 65// used for the Hall sensor fail backup function. 66// the interval time should be somewhat larger than one 60 degree 67// turn of the feeder (one portion) 68#define HALL_SENSOR_BACKUP_VALUE 300 69 70// delay before stopping the feeder servo after feeding. This way you can 71// let the rotating peddle wheel stop at the right position 72#define FEEDER_STOP_DELAY 100 73 74// lcd backlight on time after pressing a button 75#define LCD_BACKLIGHT_ON_TIME 30000 76 77// exit menu without save after amanout of time set here in ms 78#define MENU_TIMEOUT_VALUE 7000 79 80//////////////////////////////////////////////////////////////////////////////// 81 82// https:// github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library 83#include <LiquidCrystal_I2C.h> 84// https:// github.com/JChristensen/Button 85#include <Button.h> 86// http:// github.com/JChristensen/DS3232RTC 87#include <DS3232RTC.h> 88// http:// www.arduino.cc/playground/Code/Time 89#include <Time.h> 90// http:// arduino.cc/en/Reference/Wire (included with Arduino IDE) 91#include <Wire.h> 92#include <EEPROM.h> 93 94// CONNECTIONS: 95// 96// LCD (I2C module): 97// SCL - A5 98// SDA - A4 99// VCC 100// GND 101 102// interrupt hal sensor pin 103#define HALL_SENSOR_PIN 3 104 105#define BUTTON_BACK_PIN 4 106#define BUTTON_UP_PIN 5 107#define BUTTON_DOWN_PIN 6 108#define BUTTON_SELECT_PIN 7 109#define BUTTON_CANCEL1_PIN 8 110#define BUTTON_CANCEL2_PIN 9 111#define BUTTON_MANUAL_PIN 10 112 113#define LED_CANCEL1_PIN A0 114#define LED_CANCEL2_PIN A1 115#define LED_SUCCESS1_PIN A2 116#define LED_SUCCESS2_PIN A3 117 118// feeder Servo output Pin 119#define SERVO_OUTPUT_PIN 12 120 121// Hall sensor input Pin 122#define LED_HALL_SENSOR_PIN 13 123 124// address LCD(16x2) 0x27 or 0x3F 125LiquidCrystal_I2C lcd(0x3F, 16, 2); 126 127// define button library settings 128// A debounce time of 20 milliseconds usually works well 129// for tactile button switches. 130#define DEBOUNCE_MS 20 131// ms required before repeating on long press 132#define REPEAT_FIRST 1000 133// repeat interval for long press 134#define REPEAT_INCR 200 135// To keep things simple, we use the Arduino's internal pullup resistor. 136#define PULLUP true 137#define INVERT true 138 139// Declare the buttons 140Button buttonSelect (BUTTON_SELECT_PIN, PULLUP, INVERT, DEBOUNCE_MS); 141Button buttonUp (BUTTON_UP_PIN, PULLUP, INVERT, DEBOUNCE_MS); 142Button buttonDown (BUTTON_DOWN_PIN, PULLUP, INVERT, DEBOUNCE_MS); 143Button buttonBack (BUTTON_BACK_PIN, PULLUP, INVERT, DEBOUNCE_MS); 144Button buttonCancel1 (BUTTON_CANCEL1_PIN, PULLUP, INVERT, DEBOUNCE_MS); 145Button buttonCancel2 (BUTTON_CANCEL2_PIN, PULLUP, INVERT, DEBOUNCE_MS); 146Button buttonManual (BUTTON_MANUAL_PIN, PULLUP, INVERT, DEBOUNCE_MS); 147 148// The number that is adjusted 149int count; 150// Previous value of count (initialized to ensure it's different when 151// the sketch starts) 152int lastCount = -1; 153// A variable time that is used to drive the repeats for long presses 154unsigned long rpt = REPEAT_FIRST; 155 156// used for the menu time-out 157unsigned long timeoutValue = 0; 158 159// manual cancel feeding times variables 160boolean manualCancelFeed1 = false; 161boolean manualCancelFeed2 = false; 162 163// Manaual feed option 164boolean manualFeed = false; 165 166// Feed amount (in portions) 167int feedAmount1 = 1; 168int feedAmount2 = 1; 169bool feederSuccess = false; 170 171// feeder portions 172int portions = 0; 173int turns = 0; 174 175// input actions 176enum {btnSELECT, btnUP, btnDOWN, btnBACK, btnCANCEL1, btnCANCEL2, btnMANUAL, trigTIMEOUT}; 177 178// States of the Finite State Machine (FSM) 179enum STATES 180{ 181 MAIN, 182 MENU_EDIT_FEEDTIME1, 183 MENU_EDIT_FEEDTIME2, 184 MENU_EDIT_FEEDAMOUNT, 185 MENU_EDIT_TIME, 186 MENU_EDIT_DATE, 187 MENU_EDIT_SETTINGS, 188 189 EDIT_FEED_TIME1_HOUR, 190 EDIT_FEED_TIME1_MINUTE, 191 EDIT_FEED_TIME1_ON_OFF, 192 193 EDIT_FEED_TIME2_HOUR, 194 EDIT_FEED_TIME2_MINUTE, 195 EDIT_FEED_TIME2_ON_OFF, 196 197 EDIT_FEED_AMOUNT1, 198 EDIT_FEED_AMOUNT2, 199 200 EDIT_HOUR, 201 EDIT_MINUTE, 202 203 EDIT_DAY, 204 EDIT_MONTH, 205 EDIT_YEAR, 206 207 EDIT_SERVO_STOP_DELAY, 208 EDIT_SERVO_BACKUP_DELAY, 209}; 210// Holds the current state of the system 211STATES state; 212 213int8_t userInput; 214int8_t trigger; 215 216int Second; 217int Minute; 218int Hour; 219int Day; 220int Month; 221int Year; 222 223int8_t DoW; 224String day_of_week; 225unsigned char address, data; 226 227int testt = 0; 228 229int feed_time1_hour; 230int feed_time1_minute; 231bool feed_time1_active = false; 232bool alarm1Activated = false; 233 234int feed_time2_hour; 235int feed_time2_minute; 236bool feed_time2_active = false; 237bool alarm2Activated = false; 238 239 240// used for the blink funtion when editing values 241uint32_t blink_interval = 500; 242uint32_t blink_previousMillis = 0; 243uint32_t blink_currentMillis = 0; 244boolean blink_state = false; 245 246// used for the blink funtion when editing values 247uint32_t spinningWheel_interval = 170; 248uint32_t spinningWheel_previousMillis = 0; 249uint32_t spinningWheel_currentMillis = 0; 250int spinningWheelSymbol = 0; 251 252// used for the Hall sensor fail backup function 253// the interval time should be somewhat larger than one 60 degree 254// turn of the feeder (one portion). 255uint32_t hallSensorBackup_interval = HALL_SENSOR_BACKUP_VALUE; 256uint32_t hallSensorBackup_currentMillis = 0; 257boolean hallSensorFail = false; 258 259// used for the lcd backlight timer 260uint32_t lcdBacklight_interval = LCD_BACKLIGHT_ON_TIME; 261uint32_t lcdBacklight_currentMillis = 0; 262 263boolean RTC_error = true; 264boolean long_press_button = false; 265 266// Define custom symbols for the LCD display 267byte bell_symbol_Char[8] = { 268 B00100, 269 B01110, 270 B01110, 271 B01110, 272 B11111, 273 B00100, 274 B00000, 275 B00000 276}; 277 278byte inverted_one_Char[8] = { 279 0b11111, 280 0b11011, 281 0b10011, 282 0b11011, 283 0b11011, 284 0b11011, 285 0b10001, 286 0b11111 287}; 288 289byte inverted_two_Char[8] = { 290 0b11111, 291 0b11011, 292 0b10101, 293 0b11101, 294 0b11011, 295 0b10111, 296 0b10001, 297 0b11111 298}; 299 300byte arrow_up_Char[8] = { 301 0b00100, 302 0b01110, 303 0b11111, 304 0b01110, 305 0b01110, 306 0b01110, 307 0b01110, 308 0b00000 309}; 310 311byte arrow_down_Char[8] = { 312 0b00000, 313 0b01110, 314 0b01110, 315 0b01110, 316 0b01110, 317 0b11111, 318 0b01110, 319 0b00100 320}; 321 322byte inverted_p_Char[8] = { 323 0b11111, 324 0b10001, 325 0b10101, 326 0b10001, 327 0b10111, 328 0b10111, 329 0b11111, 330 0b00000 331}; 332 333byte backslash_Char[8] = { 334 0b00000, 335 0b10000, 336 0b01000, 337 0b00100, 338 0b00010, 339 0b00001, 340 0b00000, 341 0b00000 342}; 343 344byte thickDash_Char[8] = { 345 0b00000, 346 0b00000, 347 0b11111, 348 0b11111, 349 0b11111, 350 0b00000, 351 0b00000, 352 0b00000 353}; 354 355volatile boolean hallSensorActivated = false; 356 357// Interrupt 1 358void HallSensorIsr() 359{ 360 hallSensorActivated = true; 361 // turn on Hall sensor LED 362 digitalWrite(LED_HALL_SENSOR_PIN, HIGH); 363} 364// These lines are needed to make this sketch a C++ file. 365// I use it because I edit the code with the Atom 366// text editor and the PlatformIO add-on 367void HallSensorIsr(); 368void setup(); 369void loop(); 370void change_states(); 371void check_inputs(); 372void transition(int trigger); 373void check_alarm(); 374void check_manual_feed(); 375void display_menu_option_set_feedtime1(); 376void display_menu_option_set_feedtime2(); 377void display_menu_option_set_feed_amount(); 378void display_menu_option_set_time(); 379void display_menu_option_set_date(); 380void midnight_reset(); 381void display_time(); 382void displayFeedingAmouts(); 383void displayFeedingTimes(); 384void set_feedAmount(); 385void set_time(); 386void set_date(); 387void set_feeding1_time(); 388void set_feeding2_time(); 389void get_time(); 390void get_date(); 391void write_time(); 392void write_date(); 393void write_feeding_time1(); 394void write_feeding_time2(); 395void write_feedamount(); 396void get_feedamount(); 397void get_feed_time1(); 398void get_feed_time2(); 399void check_RTC(); 400byte decToBcd(byte val); 401byte bcdToDec(byte val); 402void leading_zero(int digits); 403void blinkFunction(); 404void displaySpinningWheel(); 405void startFeederServo(); 406void stopFeederServo(); 407void activateFeeder(int portions); 408void check_LcdBacklight(); 409void lcd_backlight_ON(); 410void ledsAndLcdDisplayStartup(); 411void hallSensorCheck(); 412#line 355 413// ****************************************************************************** 414// SETUP 415 416void setup() 417{ 418 // activate the lcd screen 419 lcd.begin(); 420 // turn lcd backlight on and start backlight off-timer 421 lcd_backlight_ON(); 422 423 // start I2C 424 Wire.begin(); 425 426 // hall sensor input to detect rotation of the feeder/feed amount output check 427 pinMode(HALL_SENSOR_PIN, INPUT_PULLUP); 428 pinMode(LED_HALL_SENSOR_PIN, OUTPUT); 429 pinMode(SERVO_OUTPUT_PIN, OUTPUT); 430 pinMode(LED_CANCEL1_PIN, OUTPUT); 431 pinMode(LED_CANCEL2_PIN, OUTPUT); 432 pinMode(LED_SUCCESS1_PIN, OUTPUT); 433 pinMode(LED_SUCCESS2_PIN, OUTPUT); 434 435 // set default state of LED's to OFF 436 digitalWrite(LED_CANCEL1_PIN, LOW); 437 digitalWrite(LED_CANCEL2_PIN, LOW); 438 digitalWrite(LED_SUCCESS1_PIN, LOW); 439 digitalWrite(LED_SUCCESS2_PIN, LOW); 440 digitalWrite(LED_HALL_SENSOR_PIN, LOW); 441 442 lcd.createChar(0, thickDash_Char); 443 lcd.createChar(1, bell_symbol_Char); 444 lcd.createChar(2, backslash_Char); 445 lcd.createChar(3, inverted_p_Char); 446 lcd.createChar(4, inverted_one_Char); 447 lcd.createChar(5, inverted_two_Char); 448 lcd.createChar(6, arrow_up_Char); 449 lcd.createChar(7, arrow_down_Char); 450 451 // set feeder Servo to default state OFF 452 stopFeederServo(); 453 454 Wire.begin(); 455 456 // set RTC as the Syncprovider 457 setSyncProvider(RTC.get); 458 // time in sec of resync with RTC 459 setSyncInterval(60); 460 461 // Disable the default square wave of the SQW pin. 462 RTC.squareWave(SQWAVE_NONE); 463 464 // Attach an interrupt on the Hall sensor (when unput turns LOW) 465 // ever 60 degree turn of the feeder shaft, the hall sensor 466 // should generate an interrupt 467 attachInterrupt(INT1, HallSensorIsr, FALLING); 468 469 // display test 470 ledsAndLcdDisplayStartup(); 471 472 // Initial state of the FSM 473 state = MAIN; 474 475 // read the stored alarm value from the Arduino memory 476 get_feed_time1(); 477 get_feed_time2(); 478 479}// End SETUP 480 481 482 483// ****************************************************************************** 484// LOOP 485 486void loop() 487{ 488 // change states of FSM 489 change_states(); 490 491 // check inputs (buttons) 492 check_inputs(); 493 494 // check if alarm was called 495 check_alarm(); 496 497 // check if manual feed was requsted 498 check_manual_feed(); 499 500 // at midnight, reset some variables 501 midnight_reset(); 502 503 // check connection RTC 504 check_RTC(); 505 506 // Check the Hall sensor function 507 hallSensorCheck(); 508 509 // check if lcd backlight must be turned off 510 check_LcdBacklight(); 511 512}// End of LOOP 513 514 515// ****************************************************************************** 516// ****************************************************************************** 517// ****************************************************************************** 518// ****************************************************************************** 519 520 521 522//****************************************************************************** 523// Finite State Machine 524void change_states() 525{ 526 // states 527 switch (state) 528 { 529 //--------------------------------------- 530 case MAIN: 531 display_time(); 532 displayFeedingAmouts(); 533 displayFeedingTimes(); 534 break; 535 //--------------------------------------- 536 case MENU_EDIT_FEEDTIME1: 537 display_menu_option_set_feedtime1(); 538 break; 539 //--------------------------------------- 540 case MENU_EDIT_FEEDTIME2: 541 display_menu_option_set_feedtime2(); 542 break; 543 //--------------------------------------- 544 case MENU_EDIT_FEEDAMOUNT: 545 display_menu_option_set_feed_amount(); 546 break; 547 //--------------------------------------- 548 case MENU_EDIT_TIME: 549 display_menu_option_set_time(); 550 break; 551 //--------------------------------------- 552 case MENU_EDIT_DATE: 553 display_menu_option_set_date(); 554 break; 555 556 //--------------------------------------- 557 case EDIT_FEED_TIME1_HOUR: 558 set_feeding1_time(); 559 break; 560 //--------------------------------------- 561 case EDIT_FEED_TIME1_MINUTE: 562 set_feeding1_time(); 563 break; 564 //--------------------------------------- 565 case EDIT_FEED_TIME1_ON_OFF: 566 set_feeding1_time(); 567 break; 568 569 //--------------------------------------- 570 case EDIT_FEED_TIME2_HOUR: 571 set_feeding2_time(); 572 break; 573 //--------------------------------------- 574 case EDIT_FEED_TIME2_MINUTE: 575 set_feeding2_time(); 576 break; 577 //--------------------------------------- 578 case EDIT_FEED_TIME2_ON_OFF: 579 set_feeding2_time(); 580 break; 581 582 //--------------------------------------- 583 case EDIT_FEED_AMOUNT1: 584 set_feedAmount(); 585 break; 586 //--------------------------------------- 587 case EDIT_FEED_AMOUNT2: 588 set_feedAmount(); 589 break; 590 591 //--------------------------------------- 592 case EDIT_HOUR: 593 set_time(); 594 break; 595 //--------------------------------------- 596 case EDIT_MINUTE: 597 set_time(); 598 break; 599 //--------------------------------------- 600 case EDIT_DAY: 601 set_date(); 602 break; 603 //--------------------------------------- 604 case EDIT_MONTH: 605 set_date(); 606 break; 607 //--------------------------------------- 608 case EDIT_YEAR: 609 set_date(); 610 break; 611 //--------------------------------------- 612 } 613} 614 615 616//****************************************************************************** 617// Check INPUTS 618 619void check_inputs() 620{ 621 // first check if timeout has occurred 622 if ( millis() - timeoutValue > MENU_TIMEOUT_VALUE ) 623 { 624 userInput = trigTIMEOUT; 625 transition(userInput); 626 } 627 628 // check state of buttons 629 buttonSelect.read(); 630 buttonUp.read(); 631 buttonDown.read(); 632 buttonBack.read(); 633 buttonManual.read(); 634 buttonCancel1.read(); 635 buttonCancel2.read(); 636 637 // check manual cancel Feed1 button 638 switch (buttonCancel1.wasPressed()) 639 { 640 case 1: 641 // invert variable value (true to false and vise versa) 642 manualCancelFeed1 = !manualCancelFeed1; 643 //turn on lcd backlight manually 644 lcd_backlight_ON(); 645 646 // message when Cancel1 button is pressed 647 if (manualCancelFeed1 == 1) 648 { 649 lcd.clear(); 650 lcd.setCursor(0, 0); 651 // 0123456789012345 - LCD screen character counter 652 lcd.print("Upcoming Feed #1"); 653 lcd.setCursor(0, 1); 654 lcd.print("cancelled once "); 655 delay(2000); 656 lcd.clear(); 657 } 658 else if (manualCancelFeed1 == 0) 659 { 660 lcd.clear(); 661 lcd.setCursor(0, 0); 662 // 0123456789012345 - LCD screen character counter 663 lcd.print("Upcoming Feed #1"); 664 lcd.setCursor(0, 1); 665 lcd.print("canceling undone"); 666 delay(2000); 667 lcd.clear(); 668 } 669 break; 670 } 671 672 // check manual cancel Feed2 button 673 switch (buttonCancel2.wasPressed()) 674 { 675 case 1: 676 // invert variable value (true to false and vise versa) 677 manualCancelFeed2 = !manualCancelFeed2; 678 //turn on lcd backlight manually 679 lcd_backlight_ON(); 680 // message when Cancel1 button is pressed 681 if (manualCancelFeed2 == 1) 682 { 683 lcd.clear(); 684 lcd.setCursor(0, 0); 685 // 0123456789012345 - LCD screen character counter 686 lcd.print("Upcoming Feed #2"); 687 lcd.setCursor(0, 1); 688 lcd.print("cancelled once "); 689 delay(2000); 690 lcd.clear(); 691 } 692 else if (manualCancelFeed2 == 0) 693 { 694 lcd.clear(); 695 lcd.setCursor(0, 0); 696 // 0123456789012345 - LCD screen character counter 697 lcd.print("Upcoming Feed #2"); 698 lcd.setCursor(0, 1); 699 lcd.print("canceling undone"); 700 delay(2000); 701 lcd.clear(); 702 } 703 break; 704 } 705 706 // check manual Feed button 707 switch (buttonManual.wasPressed()) 708 { 709 case 1: 710 manualFeed = true; 711 //turn on lcd backlight manually 712 lcd_backlight_ON(); 713 break; 714 } 715 716 // check MENU/SELECT button 717 switch (buttonSelect.wasPressed()) 718 { 719 case 1: 720 userInput = btnSELECT; 721 //turn on lcd backlight manually 722 lcd_backlight_ON(); 723 transition(userInput); 724 break; 725 } 726 // check UP button 727 switch (buttonUp.wasPressed()) 728 { 729 case 1: 730 userInput = btnUP; 731 transition(userInput); 732 //turn on lcd backlight manually 733 lcd_backlight_ON(); 734 break; 735 } 736 // check long press UP button 737 switch (buttonUp.wasReleased()) 738 { 739 case 1: 740 long_press_button = false; 741 rpt = REPEAT_FIRST; 742 break; 743 } 744 switch (buttonUp.pressedFor(rpt)) 745 { 746 case 1: 747 // increment the long press interval 748 rpt += REPEAT_INCR; 749 long_press_button = true; 750 userInput = btnUP; 751 transition(userInput); 752 break; 753 } 754 // check DOWN button 755 switch (buttonDown.wasPressed()) 756 { 757 case 1: 758 userInput = btnDOWN; 759 transition(userInput); 760 //turn on lcd backlight manually 761 lcd_backlight_ON(); 762 break; 763 } 764 // check long press DOWN button 765 switch (buttonDown.wasReleased()) 766 { 767 case 1: 768 long_press_button = false; 769 rpt = REPEAT_FIRST; 770 break; 771 } 772 switch (buttonDown.pressedFor(rpt)) 773 { 774 case 1: 775 // increment the long press interval 776 rpt += REPEAT_INCR; 777 long_press_button = true; 778 userInput = btnDOWN; 779 transition(userInput); 780 break; 781 } 782 // check btnBACK button 783 switch (buttonBack.wasPressed()) 784 { 785 case 1: 786 userInput = btnBACK; 787 transition(userInput); 788 //turn on lcd backlight manually 789 lcd_backlight_ON(); 790 break; 791 } 792 793} 794 795 796//****************************************************************************** 797// Check for state transition trigger 798 799void transition(int trigger) 800{ 801 switch (state) 802 { 803 //--------------------------------------- 804 case MAIN: 805 806 // set time-out timr 807 timeoutValue = millis(); 808 809 if (trigger == btnSELECT) 810 { 811 lcd.clear(); 812 state = MENU_EDIT_FEEDTIME1; 813 } 814 else if (trigger == btnBACK) 815 { 816 //lcd.clear(); 817 //state = ALARM1_AND_2_TIME; 818 } 819 break; 820 //--------------------------------------- 821 case MENU_EDIT_FEEDTIME1: 822 823 // set time-out timer 824 timeoutValue = millis(); 825 // check for time-out 'button' trigger 826 if (trigger == trigTIMEOUT) 827 { 828 lcd.clear(); 829 state = MAIN; 830 } 831 832 // Now check for button triggers 833 if (trigger == btnUP) 834 { 835 //no action, this is the first menu 836 } 837 else if (trigger == btnDOWN) 838 { 839 lcd.clear(); 840 state = MENU_EDIT_FEEDTIME2; 841 } 842 if (trigger == btnSELECT) 843 { 844 lcd.clear(); 845 state = EDIT_FEED_TIME1_HOUR; 846 } 847 if (trigger == btnBACK) 848 { 849 lcd.clear(); 850 state = MAIN; 851 } 852 break; 853 //--------------------------------------- 854 case MENU_EDIT_FEEDTIME2: 855 856 // set time-out timer 857 timeoutValue = millis(); 858 // check for time-out 'button' trigger 859 if (trigger == trigTIMEOUT) 860 { 861 lcd.clear(); 862 state = MAIN; 863 } 864 865 // Now check for button triggers 866 if (trigger == btnUP) 867 { 868 lcd.clear(); 869 state = MENU_EDIT_FEEDTIME1; 870 } 871 else if (trigger == btnDOWN) 872 { 873 lcd.clear(); 874 state = MENU_EDIT_FEEDAMOUNT; 875 } 876 if (trigger == btnSELECT) 877 { 878 lcd.clear(); 879 state = EDIT_FEED_TIME2_HOUR; 880 } 881 if (trigger == btnBACK) 882 { 883 lcd.clear(); 884 state = MAIN; 885 } 886 break; 887 //--------------------------------------- 888 case MENU_EDIT_FEEDAMOUNT: 889 890 // set time-out timer 891 timeoutValue = millis(); 892 // check for time-out 'button' trigger 893 if (trigger == trigTIMEOUT) 894 { 895 lcd.clear(); 896 state = MAIN; 897 } 898 899 // Now check for button triggers 900 if (trigger == btnUP) 901 { 902 lcd.clear(); 903 state = MENU_EDIT_FEEDTIME2; 904 } 905 else if (trigger == btnDOWN) 906 { 907 lcd.clear(); 908 state = MENU_EDIT_TIME; 909 } 910 if (trigger == btnSELECT) 911 { 912 lcd.clear(); 913 state = EDIT_FEED_AMOUNT1; 914 } 915 if (trigger == btnBACK) 916 { 917 lcd.clear(); 918 state = MAIN; 919 } 920 break; 921 //--------------------------------------- 922 case MENU_EDIT_TIME: 923 924 // set time-out timer 925 timeoutValue = millis(); 926 // check for time-out 'button' trigger 927 if (trigger == trigTIMEOUT) 928 { 929 lcd.clear(); 930 state = MAIN; 931 } 932 933 // Now check for button triggers 934 if (trigger == btnUP) 935 { 936 lcd.clear(); 937 state = MENU_EDIT_FEEDTIME2; 938 } 939 if (trigger == btnDOWN) 940 { 941 lcd.clear(); 942 state = MENU_EDIT_DATE; 943 } 944 if (trigger == btnSELECT) 945 { 946 lcd.clear(); 947 state = EDIT_HOUR; 948 } 949 if (trigger == btnBACK) 950 { 951 lcd.clear(); 952 state = MAIN; 953 } 954 break; 955 //--------------------------------------- 956 case MENU_EDIT_DATE: 957 958 // set time-out timer 959 timeoutValue = millis(); 960 // check for time-out 'button' trigger 961 if (trigger == trigTIMEOUT) 962 { 963 lcd.clear(); 964 state = MAIN; 965 } 966 967 // Now check for button triggers 968 if (trigger == btnUP) 969 { 970 lcd.clear(); 971 state = MENU_EDIT_TIME; 972 } 973 else if (trigger == btnDOWN) 974 { 975 //no action, end of menu items! 976 } 977 if (trigger == btnSELECT) 978 { 979 lcd.clear(); 980 state = EDIT_DAY; 981 } 982 if (trigger == btnBACK) 983 { 984 lcd.clear(); 985 state = MAIN; 986 } 987 break; 988 989 //--------------------------------------- 990 case EDIT_FEED_TIME1_HOUR: 991 // set time-out timer 992 timeoutValue = millis(); 993 // check for time-out 'button' trigger 994 if (trigger == trigTIMEOUT) 995 { 996 lcd.clear(); 997 state = MAIN; 998 } 999 1000 // Now check for button triggers 1001 if (trigger == btnUP) 1002 { 1003 feed_time1_hour++; 1004 if (feed_time1_hour > 23) feed_time1_hour = 0; 1005 } 1006 else if (trigger == btnDOWN) 1007 { 1008 feed_time1_hour--; 1009 if (feed_time1_hour < 0) feed_time1_hour = 23; 1010 } 1011 if (trigger == btnSELECT) 1012 { 1013 state = EDIT_FEED_TIME1_MINUTE; 1014 } 1015 break; 1016 //--------------------------------------- 1017 case EDIT_FEED_TIME1_MINUTE: 1018 // set time-out timer 1019 timeoutValue = millis(); 1020 // check for time-out 'button' trigger 1021 if (trigger == trigTIMEOUT) 1022 { 1023 lcd.clear(); 1024 state = MAIN; 1025 } 1026 1027 // Now check for button triggers 1028 if (trigger == btnUP) 1029 { 1030 feed_time1_minute++; 1031 if (feed_time1_minute > 59) feed_time1_minute = 0; 1032 } 1033 else if (trigger == btnDOWN) 1034 { 1035 feed_time1_minute--; 1036 if (feed_time1_minute < 0) feed_time1_minute = 59; 1037 } 1038 if (trigger == btnSELECT) 1039 { 1040 state = EDIT_FEED_TIME1_ON_OFF; 1041 } 1042 if (trigger == btnBACK) 1043 { 1044 state = EDIT_FEED_TIME1_HOUR; 1045 } 1046 break; 1047 //--------------------------------------- 1048 case EDIT_FEED_TIME1_ON_OFF: 1049 // set time-out timer 1050 timeoutValue = millis(); 1051 // check for time-out 'button' trigger 1052 if (trigger == trigTIMEOUT) 1053 { 1054 lcd.clear(); 1055 state = MAIN; 1056 } 1057 1058 // Now check for button triggers 1059 if (trigger == btnUP) 1060 { 1061 feed_time1_active = true; 1062 } 1063 else if (trigger == btnDOWN) 1064 { 1065 feed_time1_active = false; 1066 } 1067 if (trigger == btnBACK) 1068 { 1069 state = EDIT_FEED_TIME1_MINUTE; 1070 } 1071 if (trigger == btnSELECT) 1072 { 1073 // write alarm settings to the RTC chip 1074 write_feeding_time1(); 1075 // reset feed override variable when timer is set to OFF 1076 if (feed_time1_active == false) 1077 { 1078 manualCancelFeed1 = false; 1079 } 1080 lcd.clear(); 1081 lcd.setCursor(0, 0); 1082 // 0123456789012345 - LCD screen character counter - LCD screen character counter 1083 lcd.print("*Settings saved*"); 1084 delay(1000); 1085 lcd.clear(); 1086 state = MAIN; 1087 } 1088 1089 break; 1090 //--------------------------------------- 1091 case EDIT_FEED_TIME2_HOUR: 1092 // set time-out timer 1093 timeoutValue = millis(); 1094 // check for time-out 'button' trigger 1095 if (trigger == trigTIMEOUT) 1096 { 1097 lcd.clear(); 1098 state = MAIN; 1099 } 1100 1101 // Now check for button triggers 1102 if (trigger == btnUP) 1103 { 1104 feed_time2_hour++; 1105 if (feed_time2_hour > 23) feed_time2_hour = 0; 1106 } 1107 else if (trigger == btnDOWN) 1108 { 1109 feed_time2_hour--; 1110 if (feed_time2_hour < 0) feed_time2_hour = 23; 1111 } 1112 if (trigger == btnSELECT) 1113 { 1114 state = EDIT_FEED_TIME2_MINUTE; 1115 } 1116 break; 1117 //--------------------------------------- 1118 case EDIT_FEED_TIME2_MINUTE: 1119 // set time-out timer 1120 timeoutValue = millis(); 1121 // check for time-out 'button' trigger 1122 if (trigger == trigTIMEOUT) 1123 { 1124 lcd.clear(); 1125 state = MAIN; 1126 } 1127 1128 // Now check for button triggers 1129 if (trigger == btnUP) 1130 { 1131 feed_time2_minute++; 1132 if (feed_time2_minute > 59) feed_time2_minute = 0; 1133 } 1134 else if (trigger == btnDOWN) 1135 { 1136 feed_time2_minute--; 1137 if (feed_time2_minute < 0) feed_time2_minute = 59; 1138 } 1139 if (trigger == btnSELECT) 1140 { 1141 state = EDIT_FEED_TIME2_ON_OFF; 1142 } 1143 if (trigger == btnBACK) 1144 { 1145 state = EDIT_FEED_TIME2_HOUR; 1146 } 1147 break; 1148 //--------------------------------------- 1149 case EDIT_FEED_TIME2_ON_OFF: 1150 // set time-out timer 1151 timeoutValue = millis(); 1152 // check for time-out 'button' trigger 1153 if (trigger == trigTIMEOUT) 1154 { 1155 lcd.clear(); 1156 state = MAIN; 1157 } 1158 1159 // Now check for button triggers 1160 if (trigger == btnUP) 1161 { 1162 feed_time2_active = true; 1163 } 1164 else if (trigger == btnDOWN) 1165 { 1166 feed_time2_active = false; 1167 } 1168 if (trigger == btnBACK) 1169 { 1170 state = EDIT_FEED_TIME2_MINUTE; 1171 } 1172 if (trigger == btnSELECT) 1173 { 1174 // write alarm settings to the RTC chip 1175 write_feeding_time2(); 1176 // reset feed override variable when timer is set to OFF 1177 if (feed_time2_active == false) 1178 { 1179 manualCancelFeed2 = false; 1180 } 1181 lcd.clear(); 1182 lcd.setCursor(0, 0); 1183 // 0123456789012345 - LCD screen character counter - LCD screen character counter 1184 lcd.print("*Settings saved*"); 1185 delay(1000); 1186 lcd.clear(); 1187 state = MAIN; 1188 } 1189 break; 1190 //--------------------------------------- 1191 case EDIT_FEED_AMOUNT1: 1192 1193 // set time-out timer 1194 timeoutValue = millis(); 1195 // check for time-out 'button' trigger 1196 if (trigger == trigTIMEOUT) 1197 { 1198 lcd.clear(); 1199 state = MAIN; 1200 } 1201 1202 // Now check for button triggers 1203 if (trigger == btnUP) 1204 { 1205 feedAmount1++; 1206 if (feedAmount1 > 9) feedAmount1 = 1; 1207 } 1208 else if (trigger == btnDOWN) 1209 { 1210 feedAmount1--; 1211 if (feedAmount1 < 1) feedAmount1 = 9; 1212 } 1213 if (trigger == btnSELECT) 1214 { 1215 state = EDIT_FEED_AMOUNT2; 1216 } 1217 break; 1218 //--------------------------------------- 1219 case EDIT_FEED_AMOUNT2: 1220 1221 // set time-out timer 1222 timeoutValue = millis(); 1223 // check for time-out 'button' trigger 1224 if (trigger == trigTIMEOUT) 1225 { 1226 lcd.clear(); 1227 state = MAIN; 1228 } 1229 1230 // Now check for button triggers 1231 if (trigger == btnUP) 1232 { 1233 feedAmount2++; 1234 if (feedAmount2 > 9) feedAmount2 = 1; 1235 } 1236 else if (trigger == btnDOWN) 1237 { 1238 feedAmount2--; 1239 if (feedAmount2 < 1) feedAmount2 = 9; 1240 } 1241 if (trigger == btnSELECT) 1242 { 1243 write_feedamount(); 1244 lcd.clear(); 1245 lcd.setCursor(0, 0); 1246 // 0123456789012345 - LCD screen character counter - LCD screen character counter 1247 lcd.print("*Settings saved*"); 1248 delay(1000); 1249 1250 lcd.clear(); 1251 state = MAIN; 1252 } 1253 break; 1254 //--------------------------------------- 1255 case EDIT_HOUR: 1256 1257 // set time-out timer 1258 timeoutValue = millis(); 1259 // check for time-out 'button' trigger 1260 if (trigger == trigTIMEOUT) 1261 { 1262 lcd.clear(); 1263 state = MAIN; 1264 } 1265 1266 // Now check for button triggers 1267 if (trigger == btnUP) 1268 { 1269 Hour++; 1270 if (Hour > 23) Hour = 0; 1271 } 1272 else if (trigger == btnDOWN) 1273 { 1274 Hour--; 1275 if (Hour < 0) Hour = 23; 1276 } 1277 if (trigger == btnSELECT) 1278 { 1279 state = EDIT_MINUTE; 1280 } 1281 break; 1282 1283 //--------------------------------------- 1284 case EDIT_MINUTE: 1285 1286 // set time-out timer 1287 timeoutValue = millis(); 1288 // check for time-out 'button' trigger 1289 if (trigger == trigTIMEOUT) 1290 { 1291 lcd.clear(); 1292 state = MAIN; 1293 } 1294 1295 // Now check for button triggers 1296 if (trigger == btnUP) 1297 { 1298 Minute++; 1299 if (Minute > 59) Minute = 0; 1300 } 1301 else if (trigger == btnDOWN) 1302 { 1303 Minute--; 1304 if (Minute < 0) Minute = 59; 1305 } 1306 1307 if (trigger == btnBACK) 1308 { 1309 state = EDIT_HOUR; 1310 } 1311 if (trigger == btnSELECT) 1312 { 1313 write_time(); 1314 lcd.clear(); 1315 lcd.setCursor(0, 0); 1316 // 0123456789012345 - LCD screen character counter - LCD screen character counter 1317 lcd.print("*Settings saved*"); 1318 delay(1000); 1319 1320 lcd.clear(); 1321 state = MAIN; 1322 } 1323 break; 1324 1325 //--------------------------------------- 1326 case EDIT_DAY: 1327 // set time-out timer 1328 timeoutValue = millis(); 1329 // check for time-out 'button' trigger 1330 if (trigger == trigTIMEOUT) 1331 { 1332 lcd.clear(); 1333 state = MAIN; 1334 } 1335 1336 // Now check for button triggers 1337 if (trigger == btnUP) 1338 { 1339 Day++; 1340 if (Day > 31) Day = 1; 1341 } 1342 else if (trigger == btnDOWN) 1343 { 1344 Day--; 1345 if (Day < 1) Day = 31; 1346 } 1347 if (trigger == btnSELECT) 1348 { 1349 state = EDIT_MONTH; 1350 } 1351 break; 1352 //--------------------------------------- 1353 case EDIT_MONTH: 1354 // set time-out timer 1355 timeoutValue = millis(); 1356 // check for time-out 'button' trigger 1357 if (trigger == trigTIMEOUT) 1358 { 1359 lcd.clear(); 1360 state = MAIN; 1361 } 1362 1363 // Now check for button triggers 1364 if (trigger == btnUP) 1365 { 1366 Month++; 1367 if (Month > 12) Month = 1; 1368 } 1369 else if (trigger == btnDOWN) 1370 { 1371 Month--; 1372 if (Month < 1) Month = 12; 1373 } 1374 if (trigger == btnSELECT) 1375 { 1376 // to do: insert check here: day is not > 28 1377 // when month = 2 and we have no leap year ?? 1378 state = EDIT_YEAR; 1379 } 1380 if (trigger == btnBACK) 1381 { 1382 state = EDIT_DAY; 1383 } 1384 break; 1385 //--------------------------------------- 1386 case EDIT_YEAR: 1387 // set time-out timer 1388 timeoutValue = millis(); 1389 // check for time-out 'button' trigger 1390 if (trigger == trigTIMEOUT) 1391 { 1392 lcd.clear(); 1393 state = MAIN; 1394 } 1395 1396 // Now check for button triggers 1397 if (trigger == btnUP) 1398 { 1399 Year++; 1400 if (Year > 50) Year = 18; 1401 } 1402 else if (trigger == btnDOWN) 1403 { 1404 Year--; 1405 if (Year < 18) Year = 50; 1406 } 1407 if (trigger == btnBACK) 1408 { 1409 state = EDIT_MONTH; 1410 } 1411 if (trigger == btnSELECT) 1412 { 1413 write_date(); 1414 lcd.clear(); 1415 lcd.setCursor(0, 0); 1416 // 0123456789012345 - LCD screen character counter - LCD screen character counter 1417 lcd.print("*Settings saved*"); 1418 delay(1000); 1419 lcd.clear(); 1420 state = MAIN; 1421 } 1422 break; 1423 } 1424} 1425 1426 1427//****************************************************************************** 1428//****************************************************************************** 1429//****************************************************************************** 1430// FUNCTIONS 1431 1432//****************************************************************************** 1433void check_alarm() 1434{ 1435 // check only every minute 1436 if (Second == 0) 1437 { 1438 1439 //////////////////////////////////////////////////////////////////////////// 1440 // condition = true 1441 if ( (Hour == feed_time1_hour) && (Minute == feed_time1_minute) ) 1442 { 1443 // set variable so we can reset the manualCancelFeed1 variable later. 1444 alarm1Activated = true; 1445 1446 // two 'if' statements before feeding proceeds: 1) feed timer 1 must be ON 1447 // and 2) feeding time 1 is not cancelled by the user 1448 if ( (feed_time1_active == true) && (manualCancelFeed1 == false) ) 1449 { 1450 lcd.clear(); 1451 lcd.setCursor(0, 0); 1452 // 0123456789012345 - LCD screen character counter - LCD screen character counter 1453 lcd.print("*** Feed #1 ****"); 1454 // portions counter display, handled by the activateFeeder function 1455 lcd.setCursor(1, 1); 1456 lcd.print("/"); 1457 lcd.print(feedAmount1); 1458 lcd.print(" portions"); 1459 1460 // start the feeder Servo, with the number of turns (portions) 1461 // dependant of the feedamount1 value 1462 activateFeeder(feedAmount1); 1463 1464 // Set the feed success LED on or off depending on the succesfull 1465 // activation of the Hall sensor. 1466 if (hallSensorFail == false) 1467 { 1468 // no hall sensor faillure so turn Success led 1 on 1469 digitalWrite(LED_SUCCESS1_PIN, HIGH); 1470 } 1471 else 1472 { 1473 // hall sensor faillure so turn Success led 1 off 1474 digitalWrite(LED_SUCCESS1_PIN, LOW); 1475 } 1476 }//if (manualCancelFeed1 == false) 1477 }//if ( (Hour == feed_time1_hour) && (Minute == feed_time1_minute) ) 1478 1479 1480 //////////////////////////////////////////////////////////////////////////// 1481 // alarm2 condition = true 1482 if ( (Hour == feed_time2_hour) && (Minute == feed_time2_minute) ) 1483 { 1484 // set variable so we can reset the manualCancelFeed1 variable later 1485 alarm2Activated = true; 1486 1487 // two 'if' statements before feeding proceeds: 1) feed timer 2 must be ON 1488 // and 2) feeding time 2 is not cancelled by the user 1489 if ( (feed_time2_active == true) && (manualCancelFeed2 == false) ) 1490 { 1491 lcd.clear(); 1492 lcd.setCursor(0, 0); 1493 // 0123456789012345 - LCD screen character counter - LCD screen character counter 1494 lcd.print("*** Feed #2 ****"); 1495 // portions counter display, handled by the activateFeeder function 1496 lcd.setCursor(1, 1); 1497 lcd.print("/"); 1498 lcd.print(feedAmount2); 1499 lcd.print(" portions"); 1500 1501 // start the feeder Servo, with the number of turns (portions) 1502 // dependant of the feedamount2 value 1503 activateFeeder(feedAmount2); 1504 1505 // Set the feed success LED on or off depending on the succesfull 1506 // activation of the Hall sensor. 1507 if (hallSensorFail == false) 1508 { 1509 // no hall sensor faillure so turn Success led 1 on 1510 digitalWrite(LED_SUCCESS2_PIN, HIGH); 1511 } 1512 else 1513 { 1514 // hall sensor faillure so turn Success led 1 off 1515 digitalWrite(LED_SUCCESS2_PIN, LOW); 1516 } 1517 1518 }//if (manualCancelFeed2 == false) 1519 }//if ( (Hour == feed_time2_hour) && (Minute == feed_time2_minute) ) 1520 1521 }//if (Second == 0) 1522 1523 // else, so second value > 0 1524 else 1525 { 1526 // only if alarm1 has been triggered, reset the user cancellation 1527 // of the feed timer 1, ready for feeding the next day 1528 if (alarm1Activated == true) 1529 { 1530 // of course, we need also to reset the alarm1Activated flag 1531 alarm1Activated = false; 1532 manualCancelFeed1 = false; 1533 } 1534 // only if alarm2 has been triggered, reset the user cancellation 1535 // of the feed timer 2, ready for feeding the next day 1536 if (alarm2Activated == true) 1537 { 1538 // of course, we need also to reset the alarm2Activated flag 1539 alarm2Activated = false; 1540 manualCancelFeed2 = false; 1541 } 1542 }//else 1543}//void check_alarm() 1544 1545 1546//****************************************************************************** 1547void check_manual_feed() 1548{ 1549 if (manualFeed == true) 1550 { 1551 // display 1552 lcd.clear(); 1553 lcd.setCursor(0, 0); 1554 // 0123456789012345 - LCD screen character counter - LCD screen character counter 1555 lcd.print(" Manual feeding "); 1556 lcd.setCursor(2, 1); 1557 lcd.print("portion"); 1558 1559 // activate the feeder Servo, one portion only 1560 activateFeeder(1); 1561 1562 // reset manual feed variable 1563 // must happen AFTER calling the activateFeeder function 1564 manualFeed = false; 1565 } 1566} 1567 1568//****************************************************************************** 1569void display_menu_option_set_feedtime1() 1570{ 1571 // temporarely turn off the cancel1 and cancel2 button LED indicators 1572 // when entering the menu's. After exiting the LED's will resume their 1573 // previous status 1574 digitalWrite(LED_CANCEL1_PIN, LOW); 1575 digitalWrite(LED_CANCEL2_PIN, LOW); 1576 1577 // display menu top line 1578 lcd.setCursor(0, 0); 1579 // thick dash character 1580 lcd.write(0); 1581 lcd.print("MENU"); 1582 // display 9 thick dash characters 1583 for (int dash = 1; dash <= 9; dash++) 1584 { 1585 lcd.write(0); 1586 } 1587 1588 // display arrow symbols 1589 lcd.setCursor(15, 1); 1590 // down arrow 1591 lcd.write(7); 1592 1593 // display menu bottom line 1594 lcd.setCursor(0, 1); 1595 // 0123456789012345 - LCD screen character counter 1596 lcd.print("Feedingtime #1 "); 1597} 1598 1599//****************************************************************************** 1600void display_menu_option_set_feedtime2() 1601{ 1602 // display menu top line 1603 lcd.setCursor(0, 0); 1604 // thick dash character 1605 lcd.write(0); 1606 lcd.print("MENU"); 1607 // display 9 thick dash characters 1608 for (int dash = 1; dash <= 9; dash++) 1609 { 1610 lcd.write(0); 1611 } 1612 1613 // display arrow symbols 1614 lcd.setCursor(15, 0); 1615 // up arrow 1616 lcd.write(6); 1617 lcd.setCursor(15, 1); 1618 // down arrow 1619 lcd.write(7); 1620 1621 // display menu bottom line 1622 lcd.setCursor(0, 1); 1623 lcd.print("Feedingtime #2 "); 1624 1625} 1626 1627//****************************************************************************** 1628void display_menu_option_set_feed_amount() 1629{ 1630 // display menu top line 1631 lcd.setCursor(0, 0); 1632 // thick dash character 1633 lcd.write(0); 1634 lcd.print("MENU"); 1635 // display 9 thick dash characters 1636 for (int dash = 1; dash <= 9; dash++) 1637 { 1638 lcd.write(0); 1639 } 1640 1641 // display arrow symbols 1642 lcd.setCursor(15, 0); 1643 // up arrow 1644 lcd.write(6); 1645 lcd.setCursor(15, 1); 1646 // down arrow 1647 lcd.write(7); 1648 1649 // display menu bottom line 1650 lcd.setCursor(0, 1); 1651 // 0123456789012345 - LCD screen character counter 1652 lcd.print("Feed portions "); 1653 1654} 1655 1656//****************************************************************************** 1657void display_menu_option_set_time() 1658{ 1659 // display menu top line 1660 lcd.setCursor(0, 0); 1661 // thick dash character 1662 lcd.write(0); 1663 lcd.print("MENU"); 1664 // display 9 thick dash characters 1665 for (int dash = 1; dash <= 9; dash++) 1666 { 1667 lcd.write(0); 1668 } 1669 1670 // display arrow symbols 1671 lcd.setCursor(15, 0); 1672 // up arrow 1673 lcd.write(6); 1674 lcd.setCursor(15, 1); 1675 // down arrow 1676 lcd.write(7); 1677 1678 // display menu bottom line 1679 lcd.setCursor(0, 1); 1680 // 0123456789012345 - LCD screen character counter 1681 lcd.print("Set the time "); 1682} 1683 1684//****************************************************************************** 1685void display_menu_option_set_date() 1686{ 1687 // display menu top line 1688 lcd.setCursor(0, 0); 1689 // thick dash character 1690 lcd.write(0); 1691 lcd.print("MENU"); 1692 // display 9 thick dash characters 1693 for (int dash = 1; dash <= 9; dash++) 1694 { 1695 lcd.write(0); 1696 } 1697 1698 // display arrow symbols 1699 lcd.setCursor(15, 0); 1700 // up arrow 1701 lcd.write(6); 1702 lcd.setCursor(15, 1); 1703 // down arrow 1704 // lcd.write(7); 1705 1706 lcd.setCursor(0, 1); 1707 // 0123456789012345 - LCD screen character counter 1708 lcd.print("Set the date "); 1709} 1710 1711 1712//****************************************************************************** 1713void midnight_reset() 1714{ 1715 // check for midnight 1716 if ( (Hour == 0) && (Minute == 0) ) 1717 { 1718 // reset the Hall sensor fail indicator 1719 hallSensorFail = false; 1720 1721 // turn off the feeding success LED's 1722 digitalWrite(LED_SUCCESS1_PIN, LOW); 1723 digitalWrite(LED_SUCCESS2_PIN, LOW); 1724 1725 // reset overriding Feeding time(s) 1726 //manualCancelFeed1 = false; 1727 //manualCancelFeed2 = false; 1728 } 1729} 1730 1731//****************************************************************************** 1732void display_time() 1733{ 1734 // read the time and date from the RTC3231 chip 1735 get_time(); 1736 get_date(); 1737 // display the values on the LCD 1738 lcd.setCursor(11, 0); 1739 leading_zero(Hour); 1740 lcd.print(":"); 1741 leading_zero(Minute); 1742 lcd.setCursor(14, 1); 1743 leading_zero(Second); 1744} 1745 1746//****************************************************************************** 1747void displayFeedingAmouts() 1748{ 1749 // read the values from the Arduino EEPROM 1750 get_feedamount(); 1751 // display the stored feeding amounts 1752 lcd.setCursor(8, 0); 1753 lcd.write(3); 1754 lcd.print(feedAmount1); 1755 lcd.setCursor(8, 1); 1756 lcd.write(3); 1757 lcd.print(feedAmount2); 1758} 1759 1760//****************************************************************************** 1761void displayFeedingTimes() 1762{ 1763 //---------------------------------- 1764 //-- first feeding time -- 1765 //---------------------------------- 1766 // display '1' symbol 1767 lcd.setCursor(0, 0); 1768 lcd.write(4); 1769 1770 // display 'bell' symbol (or not) 1771 lcd.setCursor(6, 0); 1772 if (feed_time1_active == true) 1773 { 1774 if (manualCancelFeed1 == true) 1775 { 1776 // blink the bell symbol and led 1777 if (blink_state == 0) 1778 { 1779 // display the Bell symbol 1780 lcd.write(1); 1781 // turn on the cancel1 button LED indicator 1782 digitalWrite(LED_CANCEL1_PIN, HIGH); 1783 } 1784 else 1785 { 1786 // remove the Bell symbol 1787 lcd.print(" "); 1788 // turn off the cancel1 button LED indicator 1789 digitalWrite(LED_CANCEL1_PIN, LOW); 1790 } 1791 } 1792 else 1793 { 1794 // Just display the Bell symbol 1795 lcd.write(1); 1796 // turn off the cancel1 button LED indicator 1797 digitalWrite(LED_CANCEL1_PIN, LOW); 1798 } 1799 } 1800 1801 else 1802 { 1803 // alarm active not true so no Bell symbol 1804 lcd.print(" "); 1805 // turn off the cancel1 button LED indicator 1806 digitalWrite(LED_CANCEL1_PIN, LOW); 1807 } 1808 1809 // display alarm time 1 1810 lcd.setCursor(1, 0); 1811 leading_zero(feed_time1_hour); 1812 lcd.print(":"); 1813 leading_zero(feed_time1_minute); 1814 1815 //---------------------------------- 1816 //-- second feeding time -- 1817 //---------------------------------- 1818 // display '2' symbol 1819 lcd.setCursor(0, 1); 1820 lcd.write(5); 1821 1822 // display 'bell' symbol (or not) 1823 lcd.setCursor(6, 1); 1824 if (feed_time2_active == true) 1825 { 1826 if (manualCancelFeed2 == true) 1827 { 1828 // blink the bell symbol and led 1829 if (blink_state == 0) 1830 { 1831 // display the Bell symbol 1832 lcd.write(1); 1833 // turn on the cancel1 button LED indicator 1834 digitalWrite(LED_CANCEL2_PIN, HIGH); 1835 } 1836 else 1837 { 1838 // remove the Bell symbol 1839 lcd.print(" "); 1840 // turn off the cancel1 button LED indicator 1841 digitalWrite(LED_CANCEL2_PIN, LOW); 1842 } 1843 } 1844 else 1845 { 1846 // Just display the Bell symbol 1847 lcd.write(1); 1848 // turn off the cancel1 button LED indicator 1849 digitalWrite(LED_CANCEL2_PIN, LOW); 1850 } 1851 } 1852 1853 else 1854 { 1855 // alarm active not true so no Bell symbol 1856 lcd.print(" "); 1857 // turn off the cancel1 button LED indicator 1858 digitalWrite(LED_CANCEL2_PIN, LOW); 1859 } 1860 1861 // display alarm time 2 1862 lcd.setCursor(1, 1); 1863 leading_zero(feed_time2_hour); 1864 lcd.print(":"); 1865 leading_zero(feed_time2_minute); 1866 1867 // call blinkfunction 1868 blinkFunction(); 1869} 1870 1871//****************************************************************************** 1872void set_feedAmount() 1873{ 1874 lcd.setCursor(0, 0); 1875 // thick dash character 1876 lcd.write(0); 1877 // 0123456789012345 - LCD screen character counter 1878 lcd.print("SET PORTIONS "); 1879 // display 8 thick dash characters 1880 for (int dash = 1; dash <= 3; dash++) 1881 { 1882 lcd.write(0); 1883 } 1884 1885 switch (state) 1886 { 1887 //--------------------------------------- 1888 case EDIT_FEED_AMOUNT1: 1889 1890 lcd.setCursor(0, 1); 1891 lcd.print("Feed1:"); 1892 if (long_press_button == false) 1893 { 1894 if (blink_state == 0) 1895 { 1896 lcd.setCursor(6, 1); 1897 lcd.print(feedAmount1); 1898 } 1899 else 1900 { 1901 lcd.setCursor(6, 1); 1902 lcd.print(" "); 1903 } 1904 } 1905 else 1906 { 1907 lcd.setCursor(6, 1); 1908 lcd.print(feedAmount1); 1909 } 1910 1911 lcd.setCursor(9, 1); 1912 lcd.print("Feed2:"); 1913 lcd.print(feedAmount2); 1914 break; 1915 //--------------------------------------- 1916 case EDIT_FEED_AMOUNT2: 1917 1918 lcd.setCursor(0, 1); 1919 lcd.print("Feed1:"); 1920 lcd.print(feedAmount1); 1921 1922 if (long_press_button == false) 1923 { 1924 if (blink_state == 0) 1925 { 1926 lcd.setCursor(15, 1); 1927 lcd.print(feedAmount2); 1928 } 1929 else 1930 { 1931 lcd.setCursor(15, 1); 1932 lcd.print(" "); 1933 } 1934 } 1935 else 1936 { 1937 lcd.setCursor(15, 1); 1938 lcd.print(feedAmount2); 1939 } 1940 break; 1941 } 1942 1943 // call blink funtion 1944 blinkFunction(); 1945} 1946//****************************************************************************** 1947void set_time() 1948{ 1949 lcd.setCursor(0, 0); 1950 // thick dash character 1951 lcd.write(0); 1952 // 0123456789012345 - LCD screen character counter 1953 lcd.print("SET THE TIME "); 1954 for (int dash = 1; dash <= 3; dash++) 1955 { 1956 lcd.write(0); 1957 } 1958 1959 switch (state) 1960 { 1961 //--------------------------------------- 1962 case EDIT_HOUR: 1963 if (long_press_button == false) 1964 { 1965 if (blink_state == 0) 1966 { 1967 lcd.setCursor(4, 1); 1968 leading_zero(Hour); 1969 } 1970 else 1971 { 1972 lcd.setCursor(4, 1); 1973 lcd.print(" "); 1974 } 1975 } 1976 else 1977 { 1978 lcd.setCursor(4, 1); 1979 leading_zero(Hour); 1980 } 1981 lcd.print(":"); 1982 leading_zero(Minute); 1983 break; 1984 //--------------------------------------- 1985 case EDIT_MINUTE: 1986 lcd.setCursor(4, 1); 1987 leading_zero(Hour); 1988 lcd.print(":"); 1989 if (long_press_button == false) 1990 { 1991 if (blink_state == 0) { 1992 lcd.setCursor(7, 1); 1993 leading_zero(Minute); 1994 } 1995 else 1996 { 1997 lcd.setCursor(7, 1); 1998 lcd.print(" "); 1999 } 2000 } 2001 else 2002 { 2003 lcd.setCursor(7, 1); 2004 leading_zero(Minute); 2005 } 2006 break; 2007 } 2008 2009 // call blink funtion 2010 blinkFunction(); 2011} 2012 2013//****************************************************************************** 2014void set_date() 2015{ 2016 lcd.setCursor(0, 0); 2017 // thick dash character 2018 lcd.write(0); 2019 // 0123456789012345 - LCD screen character counter 2020 lcd.print("SET THE TIME "); 2021 for (int dash = 1; dash <= 3; dash++) 2022 { 2023 lcd.write(0); 2024 } 2025 2026 switch (state) 2027 { 2028 case EDIT_DAY: 2029 if (long_press_button == false) 2030 { 2031 if (blink_state == 0) 2032 { 2033 lcd.setCursor(4, 1); 2034 leading_zero(Day); 2035 } 2036 else 2037 { 2038 lcd.setCursor(4, 1); 2039 lcd.print(" "); 2040 } 2041 } 2042 else 2043 { 2044 lcd.setCursor(4, 1); 2045 leading_zero(Day); 2046 } 2047 lcd.print("/"); 2048 leading_zero(Month); 2049 lcd.print("/"); 2050 leading_zero(Year); 2051 break; 2052 //--------------------------------------- 2053 case EDIT_MONTH: 2054 lcd.setCursor(4, 1); 2055 leading_zero(Day); 2056 lcd.print("/"); 2057 if (long_press_button == false) 2058 { 2059 if (blink_state == 0) 2060 { 2061 lcd.setCursor(7, 1); 2062 leading_zero(Month); 2063 } 2064 else 2065 { 2066 lcd.setCursor(7, 1); 2067 lcd.print(" "); 2068 } 2069 } 2070 else 2071 { 2072 lcd.setCursor(7, 1); 2073 leading_zero(Month); 2074 } 2075 2076 lcd.print("/"); 2077 leading_zero(Year); 2078 break; 2079 //--------------------------------------- 2080 case EDIT_YEAR: 2081 2082 lcd.setCursor(4, 1); 2083 leading_zero(Day); 2084 lcd.print("/"); 2085 leading_zero(Month); 2086 lcd.print("/"); 2087 if (long_press_button == false) 2088 { 2089 if (blink_state == 0) 2090 { 2091 lcd.setCursor(10, 1); 2092 leading_zero(Year); 2093 } 2094 else 2095 { 2096 lcd.setCursor(10, 1); 2097 lcd.print(" "); 2098 } 2099 } 2100 else 2101 { 2102 lcd.setCursor(10, 1); 2103 leading_zero(Year); 2104 } 2105 break; 2106 } 2107 2108 // call blink funtion 2109 blinkFunction(); 2110} 2111 2112//****************************************************************************** 2113void set_feeding1_time() 2114{ 2115 lcd.setCursor(0, 0); 2116 // thick dash character 2117 lcd.write(0); 2118 // 0123456789012345 - LCD screen character counter 2119 lcd.print("FEEDING TIME 1"); 2120 // thick dash character 2121 lcd.write(0); 2122 ///////////////////////////////////// 2123 if (feed_time1_active == true) 2124 { 2125 lcd.setCursor(8, 1); 2126 lcd.print("ENABLED "); 2127 } else 2128 { 2129 lcd.setCursor(8, 1); 2130 lcd.print("DISABLED"); 2131 } 2132 2133 switch (state) 2134 { 2135 //--------------------------------------- 2136 case EDIT_FEED_TIME1_HOUR: 2137 if (long_press_button == false) 2138 { 2139 if (blink_state == 0) 2140 { 2141 lcd.setCursor(1, 1); 2142 leading_zero(feed_time1_hour); 2143 } 2144 else 2145 { 2146 lcd.setCursor(1, 1); 2147 lcd.print(" "); 2148 } 2149 } 2150 else 2151 { 2152 lcd.setCursor(1, 1); 2153 leading_zero(feed_time1_hour); 2154 } 2155 lcd.print(":"); 2156 leading_zero(feed_time1_minute); 2157 break; 2158 //--------------------------------------- 2159 case EDIT_FEED_TIME1_MINUTE: 2160 lcd.setCursor(1, 1); 2161 leading_zero(feed_time1_hour); 2162 lcd.print(":"); 2163 if (long_press_button == false) 2164 { 2165 if (blink_state == 0) 2166 { 2167 lcd.setCursor(4, 1); 2168 leading_zero(feed_time1_minute); 2169 } 2170 else 2171 { 2172 lcd.setCursor(4, 1); 2173 lcd.print(" "); 2174 } 2175 } 2176 else 2177 { 2178 lcd.setCursor(4, 1); 2179 leading_zero(feed_time1_minute); 2180 } 2181 break; 2182 //--------------------------------------- 2183 case EDIT_FEED_TIME1_ON_OFF: 2184 lcd.setCursor(4, 1); 2185 leading_zero(feed_time1_minute); 2186 2187 if (feed_time1_active == true) 2188 { 2189 if (blink_state == 0) 2190 { 2191 lcd.setCursor(8, 1); 2192 lcd.print("ENABLED "); 2193 } 2194 else 2195 { 2196 lcd.setCursor(8, 1); 2197 lcd.print(" "); 2198 } 2199 } 2200 else 2201 { 2202 if (blink_state == 0) 2203 { 2204 lcd.setCursor(8, 1); 2205 lcd.print("DISABLED"); 2206 } 2207 else 2208 { 2209 lcd.setCursor(8, 1); 2210 lcd.print(" "); 2211 } 2212 } 2213 break; 2214 } 2215 2216 // call blink funtion 2217 blinkFunction(); 2218} 2219 2220//****************************************************************************** 2221void set_feeding2_time() 2222{ 2223 lcd.setCursor(0, 0); 2224 // thick dash character 2225 lcd.write(0); 2226 // 0123456789012345 - LCD screen character counter 2227 lcd.print("FEEDING TIME 2"); 2228 // thick dash character 2229 lcd.write(0); 2230 2231 ///////////////////////////////////// 2232 if (feed_time2_active == true) 2233 { 2234 lcd.setCursor(8, 1); 2235 lcd.print("ENABLED "); 2236 } else 2237 { 2238 lcd.setCursor(8, 1); 2239 lcd.print("DISABLED"); 2240 } 2241 2242 switch (state) 2243 { 2244 //--------------------------------------- 2245 case EDIT_FEED_TIME2_HOUR: 2246 if (long_press_button == false) 2247 { 2248 if (blink_state == 0) 2249 { 2250 lcd.setCursor(1, 1); 2251 leading_zero(feed_time2_hour); 2252 } 2253 else 2254 { 2255 lcd.setCursor(1, 1); 2256 lcd.print(" "); 2257 } 2258 } 2259 else 2260 { 2261 lcd.setCursor(1, 1); 2262 leading_zero(feed_time2_hour); 2263 } 2264 lcd.print(":"); 2265 leading_zero(feed_time2_minute); 2266 break; 2267 //--------------------------------------- 2268 case EDIT_FEED_TIME2_MINUTE: 2269 lcd.setCursor(1, 1); 2270 leading_zero(feed_time2_hour); 2271 lcd.print(":"); 2272 if (long_press_button == false) 2273 { 2274 if (blink_state == 0) 2275 { 2276 lcd.setCursor(4, 1); 2277 leading_zero(feed_time2_minute); 2278 } 2279 else 2280 { 2281 lcd.setCursor(4, 1); 2282 lcd.print(" "); 2283 } 2284 } 2285 else 2286 { 2287 lcd.setCursor(4, 1); 2288 leading_zero(feed_time2_minute); 2289 } 2290 break; 2291 //--------------------------------------- 2292 case EDIT_FEED_TIME2_ON_OFF: 2293 lcd.setCursor(4, 1); 2294 leading_zero(feed_time2_minute); 2295 2296 if (feed_time2_active == true) 2297 { 2298 if (blink_state == 0) 2299 { 2300 lcd.setCursor(8, 1); 2301 lcd.print("ENABLED "); 2302 } 2303 else 2304 { 2305 lcd.setCursor(8, 1); 2306 lcd.print(" "); 2307 } 2308 } 2309 else 2310 { 2311 if (blink_state == 0) 2312 { 2313 lcd.setCursor(8, 1); 2314 lcd.print("DISABLED"); 2315 } 2316 else 2317 { 2318 lcd.setCursor(8, 1); 2319 lcd.print(" "); 2320 } 2321 } 2322 break; 2323 } 2324 2325 // call blink funtion 2326 blinkFunction(); 2327} 2328 2329//****************************************************************************** 2330void get_time() 2331{ 2332 Wire.beginTransmission(0x68); 2333 // set register to zero 2334 Wire.write(0); 2335 Wire.endTransmission(); 2336 // 3 bytes (sec, min, hour) 2337 Wire.requestFrom(0x68, 3); 2338 Second = bcdToDec(Wire.read() & 0x7f); 2339 Minute = bcdToDec(Wire.read() ); 2340 Hour = bcdToDec(Wire.read() & 0x3f); 2341} 2342 2343//****************************************************************************** 2344void get_date() 2345{ 2346 Wire.beginTransmission(0x68); 2347 // set register to 3 (day) 2348 Wire.write(4); 2349 Wire.endTransmission(); 2350 // 3 bytes (day, month, year) 2351 // DOW, we get from Time.h library 2352 Wire.requestFrom(0x68, 3); 2353 Day = bcdToDec(Wire.read()); 2354 Month = bcdToDec(Wire.read()); 2355 Year = bcdToDec(Wire.read()); 2356} 2357 2358//****************************************************************************** 2359void write_time() 2360{ 2361 Wire.beginTransmission(0x68); 2362 Wire.write(0x00); 2363 Second = 0; 2364 Wire.write(decToBcd(Second)); 2365 Wire.write(decToBcd(Minute)); 2366 Wire.write(decToBcd(Hour)); 2367 Wire.write(0x00); 2368 Wire.endTransmission(); 2369} 2370 2371//****************************************************************************** 2372void write_date() 2373{ 2374 Wire.beginTransmission(0x68); 2375 Wire.write(4); 2376 // Wire.write(decToBcd(DoW)); 2377 Wire.write(decToBcd(Day)); 2378 Wire.write(decToBcd(Month)); 2379 Wire.write(decToBcd(Year)); 2380 Wire.endTransmission(); 2381} 2382 2383//****************************************************************************** 2384void write_feeding_time1() 2385{ 2386 // save alarm time to EEPROM of the Arduino 2387 EEPROM.write(0, feed_time1_hour); 2388 EEPROM.write(1, feed_time1_minute); 2389 EEPROM.write(2, feed_time1_active); 2390} 2391 2392//****************************************************************************** 2393void write_feeding_time2() 2394{ 2395 // save alarm time to EEPROM of the Arduino 2396 EEPROM.write(3, feed_time2_hour); 2397 EEPROM.write(4, feed_time2_minute); 2398 EEPROM.write(5, feed_time2_active); 2399} 2400 2401//****************************************************************************** 2402void write_feedamount() 2403{ 2404 // save feed amount values to EEPROM of the Arduino 2405 EEPROM.write(6, feedAmount1); 2406 EEPROM.write(7, feedAmount2); 2407} 2408 2409//****************************************************************************** 2410void get_feedamount() 2411{ 2412 // save feed amount values to EEPROM of the Arduino 2413 feedAmount1 = EEPROM.read(6); 2414 if (feedAmount1 > 9) feedAmount1 = 0; 2415 feedAmount2 = EEPROM.read(7); 2416 if (feedAmount2 > 9) feedAmount2 = 0; 2417} 2418 2419//****************************************************************************** 2420void get_feed_time1() 2421{ 2422 // read feed time 1 from Arduino EEPROM 2423 feed_time1_hour = EEPROM.read(0); 2424 if (feed_time1_hour > 23) feed_time1_hour = 0; 2425 feed_time1_minute = EEPROM.read(1); 2426 if (feed_time1_minute > 59) feed_time1_minute = 0; 2427 feed_time1_active = EEPROM.read(2); 2428} 2429 2430//****************************************************************************** 2431void get_feed_time2() 2432{ 2433 // read feed time 2 from Arduino EEPROM 2434 feed_time2_hour = EEPROM.read(3); 2435 if (feed_time2_hour > 23) feed_time2_hour = 0; 2436 feed_time2_minute = EEPROM.read(4); 2437 if (feed_time2_minute > 59) feed_time2_minute = 0; 2438 feed_time2_active = EEPROM.read(5); 2439} 2440 2441//****************************************************************************** 2442// check communication with RTC 2443void check_RTC() 2444{ 2445 if (timeStatus() != timeSet) 2446 // RTC could not be read 2447 RTC_error = true; 2448 else 2449 // RTC could be read 2450 RTC_error = false; 2451} 2452 2453//****************************************************************************** 2454// convert dec to BCD value 2455byte decToBcd(byte val) 2456{ 2457 return ( (val / 10 * 16) + (val % 10) ); 2458} 2459 2460//****************************************************************************** 2461// convert BCD to dec value 2462byte bcdToDec(byte val) 2463{ 2464 return ( (val / 16 * 10) + (val % 16) ); 2465} 2466 2467//****************************************************************************** 2468void leading_zero(int digits) 2469{ 2470 // dispay leading zero when only one digit 2471 if (digits < 10) 2472 { 2473 lcd.print("0"); 2474 } 2475 // display value 2476 lcd.print(digits); 2477 2478} 2479 2480//****************************************************************************** 2481void blinkFunction() 2482{ 2483 // Blink function 2484 blink_currentMillis = millis(); 2485 if (blink_currentMillis - blink_previousMillis > blink_interval) 2486 { 2487 //reset blink timer 2488 blink_previousMillis = blink_currentMillis; 2489 // invert value of blink_state 2490 blink_state = !blink_state; 2491 } 2492} 2493//****************************************************************************** 2494void displaySpinningWheel() 2495{ 2496 2497 // display on bottom line, position 15 a 'spinning wheel' symbol 2498 lcd.setCursor(15, 1); 2499 switch (spinningWheelSymbol) 2500 { 2501 case 1: 2502 lcd.print("|"); 2503 break; 2504 case 2: 2505 lcd.print("/"); 2506 break; 2507 case 3: 2508 lcd.print("-"); 2509 break; 2510 case 4: 2511 // call backslash character 2512 // (not available in the LCD display characterset) 2513 lcd.write(2); 2514 break; 2515 case 5: 2516 // start 'spinning wheel' again with symbol "|" 2517 spinningWheelSymbol = 1; 2518 break; 2519 } 2520 2521 // check if it is time to change spinning wheel symbol 2522 spinningWheel_currentMillis = millis(); 2523 if (spinningWheel_currentMillis - spinningWheel_previousMillis 2524 > spinningWheel_interval) 2525 { 2526 //reset busy timer 2527 spinningWheel_previousMillis = spinningWheel_currentMillis; 2528 // increase value to select next symbol 2529 spinningWheelSymbol += 1; 2530 } 2531} 2532//****************************************************************************** 2533void startFeederServo() 2534{ 2535 digitalWrite(SERVO_OUTPUT_PIN, HIGH); 2536 // 950µSec = turn full speed CCW (for the HSR-2645CRH Servo) 2537 // use 2050µSec to turn the Servo full speed CW 2538 delayMicroseconds(950); 2539 digitalWrite(SERVO_OUTPUT_PIN, LOW); 2540 delay(20); 2541} 2542 2543//****************************************************************************** 2544void stopFeederServo() 2545{ 2546 digitalWrite(SERVO_OUTPUT_PIN, HIGH); 2547 // ~1490µSec = stop servo (for the HSR-2645CRH Servo) 2548 delayMicroseconds(1490); 2549 digitalWrite(SERVO_OUTPUT_PIN, LOW); 2550 delay(20); 2551} 2552 2553//****************************************************************************** 2554void activateFeeder(int portions) 2555{ 2556 // reset the feeder Servo turn counter 2557 // every turn of 60 degrees = 1 portion 2558 turns = 1; 2559 int rotationTime = 0; 2560 2561 // reset spinning wheel indicator 2562 spinningWheelSymbol = 1; 2563 2564 // set the time-out variable as backup for a possibly failing hall sensor 2565 hallSensorBackup_currentMillis = millis(); 2566 2567 // activate the feeder Servo until the number of turns exceeds the 2568 // desired number of feed 'portions' requested, by using the 2569 // 'portions' variable which is given when calling this function 2570 while (turns <= portions) 2571 { 2572 // display the current portion being delivered, in the 2573 // lower left corner of the LCD display 2574 lcd.setCursor(0, 1); 2575 lcd.print(turns); 2576 2577 // display 'spinning wheel' 2578 displaySpinningWheel(); 2579 2580 // activate feeder Servo 2581 startFeederServo(); 2582 2583 // check if the Hall sensor has been activated by 2584 // the magnets on the feeder 2585 if ( hallSensorActivated == true 2586 || 2587 millis() - hallSensorBackup_currentMillis > hallSensorBackup_interval ) 2588 { 2589 // store the time for one rotation of the feeder 2590 rotationTime = millis() - hallSensorBackup_currentMillis; 2591 2592 // Hall sensor FAIL check: 2593 // if we got here by the timing instead of the Hall sensor being 2594 // activated (and variable set via the interrupt routine), 2595 // set the hallSensorFail variable to blink the the Hall sensor FAIL LED. 2596 if (hallSensorActivated == false) 2597 { 2598 hallSensorFail = true; 2599 } 2600 2601 // reset variable and wait for next hall sensor interrupt 2602 hallSensorActivated = false; 2603 hallSensorBackup_currentMillis = millis(); 2604 2605 // check if user wants to cancel the feeding 2606 buttonBack.read(); 2607 if (buttonBack.wasPressed()) 2608 { 2609 // reset variables 2610 hallSensorActivated = false; 2611 // break While loop 2612 break; 2613 } 2614 2615 // one turn completed, increment the counter 2616 turns += 1; 2617 2618 // turn off Hall sensor LED, ready for the next activation 2619 // by the Hall sensor interrupt function 2620 digitalWrite(LED_HALL_SENSOR_PIN, LOW); 2621 2622 }//if (hallSensorActivated == true) 2623 }//while(1) 2624 2625 // number of requested turns (portions) done or user has cancelled the 2626 // feeding process. 2627 // Remove the 'spinning wheel' symbol 2628 lcd.setCursor(15, 1); 2629 lcd.print(" "); 2630 // delay to stop the feeder at the right position 2631 delay(FEEDER_STOP_DELAY); 2632 // stop the feeder servo 2633 stopFeederServo(); 2634 2635 // clear screen and display message 2636 lcd.clear(); 2637 lcd.setCursor(0, 0); 2638 // "0123456789012345 - LCD screen character counter" 2639 lcd.print("* Feeding done *"); 2640 // when manual feed button was pressed, display after one turn 2641 // the timing between one turn, just for fun but also to determine 2642 // the value of the hallSensorBackup_interval! Set this value 100ms 2643 // larger than value of one turn of the feeder. 2644 if (manualFeed == true) 2645 { 2646 lcd.setCursor(0, 1); 2647 lcd.print("1 rotation="); 2648 lcd.print(rotationTime); 2649 lcd.print("ms"); 2650 } 2651 delay(2000); 2652 lcd.clear(); 2653} 2654 2655//****************************************************************************** 2656void check_LcdBacklight() 2657{ 2658 if ( millis() - lcdBacklight_currentMillis > LCD_BACKLIGHT_ON_TIME) 2659 { 2660 lcd.noBacklight(); 2661 } 2662} 2663 2664//****************************************************************************** 2665void lcd_backlight_ON() 2666{ 2667 // reset lcd backlight timer 2668 lcdBacklight_currentMillis = millis(); 2669 // turn lcd backlight ON 2670 lcd.backlight(); 2671} 2672//****************************************************************************** 2673void ledsAndLcdDisplayStartup() 2674{ 2675 //LED test 2676 digitalWrite(LED_CANCEL1_PIN, HIGH); 2677 digitalWrite(LED_CANCEL2_PIN, HIGH); 2678 digitalWrite(LED_SUCCESS1_PIN, HIGH); 2679 digitalWrite(LED_SUCCESS2_PIN, HIGH); 2680 digitalWrite(LED_HALL_SENSOR_PIN, HIGH); 2681 2682 //LCD test, just for the fun of it ;) 2683 lcd.clear(); 2684 for (int p = 0; p <= 15; p++) 2685 { 2686 // block character fill from left to right on line 0 2687 lcd.setCursor(p, 0); 2688 lcd.write(255); 2689 // block character fill from right to left on line 1 2690 lcd.setCursor(15 - p, 1); 2691 lcd.write(255); 2692 delay(50); 2693 } 2694 lcd.clear(); 2695 // now do it in reverse :) 2696 for (int p = 0; p <= 15; p++) 2697 { 2698 // block character fill from right to left on line 0 2699 lcd.setCursor(15 - p, 0); 2700 lcd.write(255); 2701 // block character fill from left to right on line 1 2702 lcd.setCursor(p, 1); 2703 lcd.write(255); 2704 delay(50); 2705 } 2706 2707 // display startup screen 2708 lcd.clear(); 2709 lcd.setCursor(0, 0); 2710 // LCD pos:0123456789012345 - LCD screen character counter 2711 lcd.print("Pet Feed-O-Matic"); 2712 lcd.setCursor(0, 1); 2713 lcd.print("v1.1_UK 20-02-18"); 2714 delay(5000); 2715 lcd.clear(); 2716 2717 // clear lcd display and turn led's off 2718 lcd.clear(); 2719 digitalWrite(LED_CANCEL1_PIN, LOW); 2720 digitalWrite(LED_CANCEL2_PIN, LOW); 2721 digitalWrite(LED_SUCCESS1_PIN, LOW); 2722 digitalWrite(LED_SUCCESS2_PIN, LOW); 2723 digitalWrite(LED_HALL_SENSOR_PIN, LOW); 2724 2725} 2726//****************************************************************************** 2727void hallSensorCheck() 2728{ 2729 if (hallSensorFail == true) 2730 { 2731 // blink the Hall sensor LED 2732 if (blink_state == 0) 2733 { 2734 // turn on the Hall sensor LED 2735 digitalWrite(LED_HALL_SENSOR_PIN, HIGH); 2736 } 2737 else 2738 { 2739 // turn on the Hall sensor LED 2740 digitalWrite(LED_HALL_SENSOR_PIN, LOW); 2741 } 2742 // call the blink function 2743 blinkFunction(); 2744 } 2745} 2746
Downloadable files
Arduino Pet Feed-O-Matic
Arduino based Pet Feeder
Arduino Pet Feed-O-Matic
ZIP files with all the files you need: .ino; .hex and all the libraries used
I used Arduino IDE 1.8.2. BE CAREFUL NOT TO HAVE TWO VERSIONS OF THE SAME LIBRARIES IN YOUR LIBRARIES FOLDER!!
ZIP files with all the files you need: .ino; .hex and all the libraries used
Arduino Pet Feed-O-Matic
Arduino based Pet Feeder
Arduino Pet Feed-O-Matic
ZIP files with all the files you need: .ino; .hex and all the libraries used
I used Arduino IDE 1.8.2. BE CAREFUL NOT TO HAVE TWO VERSIONS OF THE SAME LIBRARIES IN YOUR LIBRARIES FOLDER!!
ZIP files with all the files you need: .ino; .hex and all the libraries used
Comments
Only logged in users can leave comments
edr1924
0 Followers
•0 Projects
Table of contents
Intro
40
0