Erik de Ruiter
Published © CC BY-NC

Easy-to-Build Pet Feeder

This is an easy to build pet feeder with two timers. Delivers accurate portions each time.

BeginnerFull instructions provided41,377
Easy-to-Build Pet Feeder

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
Best to use a Arduino Nano if you want to use a compact housing
×1
Adafruit Real Time Clock
×1
Continuous Rotation Servo
×1
Cereal dispenser
×1
Hall sensor UNIPOLAR
×1
Rod Magnets 3mm dismeter, 5mm lenght
×6
RGB Backlight LCD - 16x2
Adafruit RGB Backlight LCD - 16x2
×1
lcd i2c backpack
×1
Apem Push button momentary IP67
×1
Small push buttons momentary
×1
LED (generic)
LED (generic)
×6
Hammond Multi ABS housing with flange
×1

Software apps and online services

LCD character generator

Story

Read more

Schematics

Arduino Pet Feed-O-Matic

Arduino based Pet Feeder

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!!

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
// c++ stuff...
//#include <Arduino.h>
//#line 1
//#line 1 "/Users/Erik/Documents/PlatformIO/Projects/180202-151127-uno/src/Pet_Feeder_1_1_ENG.cpp"
/*
                         _       _
           /\           | |     (_)
          /  \   _ __ __| |_   _ _ _ __   ___
         / /\ \ | '__/ _` | | | | | '_ \ / _ \
        / ____ \| | | (_| | |_| | | | | | (_) |
       /_/    \_\_|  \__,_|\__,_|_|_| |_|\___/
        _____     _     ______            _
       |  __ \   | |   |  ____|          | |
       | |__) |__| |_  | |__ ___  ___  __| | ___ _ __
       |  ___/ _ \ __| |  __/ _ \/ _ \/ _` |/ _ \ '__|
       | |  |  __/ |_  | | |  __/  __/ (_| |  __/ |
       |_|   \___|\__| |_|  \___|\___|\__,_|\___|_|



   Erik de Ruiter
   -----------------------------------------------------------------------------

   To do:
   - remote feeding?
   - feeder stop delay as menu editable item

  last change:
  dinsdag 20 februari 2018 - 17:20:28

   FEATURES:
   - *Accurate portions* each time! (by using a Hall sensor)
   - Two feeding times, once a day
   - *Extremely* accurate Real Time Clock (Only with genuine DS3231 chip)
   - Cancel upcoming feeding individually for both timers with
     display and Led indicator. Automatically reset after time has passed.
   - Manual feed function (one portion per button press)
   - Adjustable portions for each of the two feeding times (1-9 portions)
   - Overview of all set parameters in the main screen
   - Easy to navigate menu system
   - LED indication if feeding was successful
   - LCD backlight timer (off after 30 sec, on with any button press)
   - Backup in the event of a failing Hall sensor
   - Hass sensor LED will blink until midnight if the Hall sensor has failed
   - Time and other settings are safely stored in EEPROM

   WEBSITES:
   LCD HD44780 character generator website to make your own lcd symbols
   https://omerk.github.io/lcdchargen/

   Arduino sketch Large letter comment generator
   http://patorjk.com/software/taag/#p=display&c=c%2B%2B&f=Big&t=Comment


   Revisions:
   zondag 28 januari 2018 - 20:17:10

   
*/

////////////////////////////////////////////////////////////////////////////////
// USER CHANGEABLE VARIABLES
////////////////////////////////////////////////////////////////////////////////

// used for the Hall sensor fail backup function.
// the interval time should be somewhat larger than one 60 degree
// turn of the feeder (one portion)
#define HALL_SENSOR_BACKUP_VALUE 300

// delay before stopping the feeder servo after feeding. This way you can
// let the rotating peddle wheel stop at the right position
#define FEEDER_STOP_DELAY 100

// lcd backlight on time after pressing a button
#define LCD_BACKLIGHT_ON_TIME 30000

// exit menu without save after amanout of time set here in ms
#define MENU_TIMEOUT_VALUE 7000

////////////////////////////////////////////////////////////////////////////////

// https:// github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library
#include <LiquidCrystal_I2C.h>
// https:// github.com/JChristensen/Button
#include <Button.h>
// http:// github.com/JChristensen/DS3232RTC
#include <DS3232RTC.h>
// http:// www.arduino.cc/playground/Code/Time
#include <Time.h>
// http:// arduino.cc/en/Reference/Wire (included with Arduino IDE)
#include <Wire.h>
#include <EEPROM.h>

// CONNECTIONS:
//
// LCD (I2C module):
// SCL - A5
// SDA - A4
// VCC
// GND

// interrupt hal sensor pin
#define HALL_SENSOR_PIN 3

#define BUTTON_BACK_PIN     4
#define BUTTON_UP_PIN       5
#define BUTTON_DOWN_PIN     6
#define BUTTON_SELECT_PIN   7
#define BUTTON_CANCEL1_PIN  8
#define BUTTON_CANCEL2_PIN  9
#define BUTTON_MANUAL_PIN   10

#define LED_CANCEL1_PIN     A0
#define LED_CANCEL2_PIN     A1
#define LED_SUCCESS1_PIN    A2
#define LED_SUCCESS2_PIN    A3

// feeder Servo output Pin
#define SERVO_OUTPUT_PIN    12

// Hall sensor input Pin
#define LED_HALL_SENSOR_PIN 13

// address LCD(16x2) 0x27 or 0x3F
LiquidCrystal_I2C lcd(0x3F, 16, 2);

// define button library settings
// A debounce time of 20 milliseconds usually works well
// for tactile button switches.
#define DEBOUNCE_MS 20
// ms required before repeating on long press
#define REPEAT_FIRST 1000
// repeat interval for long press
#define REPEAT_INCR 200
// To keep things simple, we use the Arduino's internal pullup resistor.
#define PULLUP true
#define INVERT true

// Declare the buttons
Button buttonSelect  (BUTTON_SELECT_PIN,  PULLUP, INVERT, DEBOUNCE_MS);
Button buttonUp      (BUTTON_UP_PIN,      PULLUP, INVERT, DEBOUNCE_MS);
Button buttonDown    (BUTTON_DOWN_PIN,    PULLUP, INVERT, DEBOUNCE_MS);
Button buttonBack    (BUTTON_BACK_PIN,    PULLUP, INVERT, DEBOUNCE_MS);
Button buttonCancel1 (BUTTON_CANCEL1_PIN, PULLUP, INVERT, DEBOUNCE_MS);
Button buttonCancel2 (BUTTON_CANCEL2_PIN, PULLUP, INVERT, DEBOUNCE_MS);
Button buttonManual  (BUTTON_MANUAL_PIN,  PULLUP, INVERT, DEBOUNCE_MS);

// The number that is adjusted
int count;
// Previous value of count (initialized to ensure it's different when
// the sketch starts)
int lastCount = -1;
// A variable time that is used to drive the repeats for long presses
unsigned long rpt = REPEAT_FIRST;

// used for the menu time-out
unsigned long timeoutValue = 0;

// manual cancel feeding times variables
boolean manualCancelFeed1 = false;
boolean manualCancelFeed2 = false;

// Manaual feed option
boolean manualFeed = false;

// Feed amount (in portions)
int feedAmount1 = 1;
int feedAmount2 = 1;
bool feederSuccess = false;

// feeder portions
int portions = 0;
int turns = 0;

// input actions
enum {btnSELECT, btnUP, btnDOWN, btnBACK, btnCANCEL1, btnCANCEL2, btnMANUAL, trigTIMEOUT};

// States of the Finite State Machine (FSM)
enum STATES
{
  MAIN,
  MENU_EDIT_FEEDTIME1,
  MENU_EDIT_FEEDTIME2,
  MENU_EDIT_FEEDAMOUNT,
  MENU_EDIT_TIME,
  MENU_EDIT_DATE,
  MENU_EDIT_SETTINGS,

  EDIT_FEED_TIME1_HOUR,
  EDIT_FEED_TIME1_MINUTE,
  EDIT_FEED_TIME1_ON_OFF,

  EDIT_FEED_TIME2_HOUR,
  EDIT_FEED_TIME2_MINUTE,
  EDIT_FEED_TIME2_ON_OFF,

  EDIT_FEED_AMOUNT1,
  EDIT_FEED_AMOUNT2,

  EDIT_HOUR,
  EDIT_MINUTE,

  EDIT_DAY,
  EDIT_MONTH,
  EDIT_YEAR,

  EDIT_SERVO_STOP_DELAY,
  EDIT_SERVO_BACKUP_DELAY,
};
// Holds the current state of the system
STATES state;

int8_t userInput;
int8_t trigger;

int Second;
int Minute;
int Hour;
int Day;
int Month;
int Year;

int8_t DoW;
String day_of_week;
unsigned char address, data;

int testt = 0;

int feed_time1_hour;
int feed_time1_minute;
bool feed_time1_active = false;
bool alarm1Activated = false;

int feed_time2_hour;
int feed_time2_minute;
bool feed_time2_active = false;
bool alarm2Activated = false;


// used for the blink funtion when editing values
uint32_t blink_interval = 500;
uint32_t blink_previousMillis = 0;
uint32_t blink_currentMillis = 0;
boolean blink_state  = false;

// used for the blink funtion when editing values
uint32_t spinningWheel_interval = 170;
uint32_t spinningWheel_previousMillis = 0;
uint32_t spinningWheel_currentMillis = 0;
int spinningWheelSymbol = 0;

// used for the Hall sensor fail backup function
// the interval time should be somewhat larger than one 60 degree
// turn of the feeder (one portion).
uint32_t hallSensorBackup_interval = HALL_SENSOR_BACKUP_VALUE;
uint32_t hallSensorBackup_currentMillis = 0;
boolean hallSensorFail = false;

// used for the lcd backlight timer
uint32_t lcdBacklight_interval = LCD_BACKLIGHT_ON_TIME;
uint32_t lcdBacklight_currentMillis = 0;

boolean RTC_error = true;
boolean long_press_button = false;

// Define custom symbols for the LCD display
byte bell_symbol_Char[8] = {
  B00100,
  B01110,
  B01110,
  B01110,
  B11111,
  B00100,
  B00000,
  B00000
};

byte inverted_one_Char[8] = {
  0b11111,
  0b11011,
  0b10011,
  0b11011,
  0b11011,
  0b11011,
  0b10001,
  0b11111
};

byte inverted_two_Char[8] = {
  0b11111,
  0b11011,
  0b10101,
  0b11101,
  0b11011,
  0b10111,
  0b10001,
  0b11111
};

byte arrow_up_Char[8] = {
  0b00100,
  0b01110,
  0b11111,
  0b01110,
  0b01110,
  0b01110,
  0b01110,
  0b00000
};

byte arrow_down_Char[8] = {
  0b00000,
  0b01110,
  0b01110,
  0b01110,
  0b01110,
  0b11111,
  0b01110,
  0b00100
};

byte inverted_p_Char[8] = {
  0b11111,
  0b10001,
  0b10101,
  0b10001,
  0b10111,
  0b10111,
  0b11111,
  0b00000
};

byte backslash_Char[8] = {
  0b00000,
  0b10000,
  0b01000,
  0b00100,
  0b00010,
  0b00001,
  0b00000,
  0b00000
};

byte thickDash_Char[8] = {
  0b00000,
  0b00000,
  0b11111,
  0b11111,
  0b11111,
  0b00000,
  0b00000,
  0b00000
};

volatile boolean hallSensorActivated = false;

// Interrupt 1
void HallSensorIsr()
{
  hallSensorActivated = true;
  // turn on Hall sensor LED
  digitalWrite(LED_HALL_SENSOR_PIN, HIGH);
}
// These lines are needed to make this sketch a C++ file.
// I use it because I edit the code with the Atom
// text editor and the PlatformIO add-on
void HallSensorIsr();
void setup();
void loop();
void change_states();
void check_inputs();
void transition(int trigger);
void check_alarm();
void check_manual_feed();
void display_menu_option_set_feedtime1();
void display_menu_option_set_feedtime2();
void display_menu_option_set_feed_amount();
void display_menu_option_set_time();
void display_menu_option_set_date();
void midnight_reset();
void display_time();
void displayFeedingAmouts();
void displayFeedingTimes();
void set_feedAmount();
void set_time();
void set_date();
void set_feeding1_time();
void set_feeding2_time();
void get_time();
void get_date();
void write_time();
void write_date();
void write_feeding_time1();
void write_feeding_time2();
void write_feedamount();
void get_feedamount();
void get_feed_time1();
void get_feed_time2();
void check_RTC();
byte decToBcd(byte val);
byte bcdToDec(byte val);
void leading_zero(int digits);
void blinkFunction();
void displaySpinningWheel();
void startFeederServo();
void stopFeederServo();
void activateFeeder(int portions);
void check_LcdBacklight();
void lcd_backlight_ON();
void ledsAndLcdDisplayStartup();
void hallSensorCheck();
#line 355
// ******************************************************************************
// SETUP

void setup()
{
  // activate the lcd screen
  lcd.begin();
  // turn lcd backlight on and start backlight off-timer
  lcd_backlight_ON();

  // start I2C
  Wire.begin();

  // hall sensor input to detect rotation of the feeder/feed amount output check
  pinMode(HALL_SENSOR_PIN, INPUT_PULLUP);
  pinMode(LED_HALL_SENSOR_PIN, OUTPUT);
  pinMode(SERVO_OUTPUT_PIN, OUTPUT);
  pinMode(LED_CANCEL1_PIN, OUTPUT);
  pinMode(LED_CANCEL2_PIN, OUTPUT);
  pinMode(LED_SUCCESS1_PIN, OUTPUT);
  pinMode(LED_SUCCESS2_PIN, OUTPUT);

  // set default state of LED's to OFF
  digitalWrite(LED_CANCEL1_PIN, LOW);
  digitalWrite(LED_CANCEL2_PIN, LOW);
  digitalWrite(LED_SUCCESS1_PIN, LOW);
  digitalWrite(LED_SUCCESS2_PIN, LOW);
  digitalWrite(LED_HALL_SENSOR_PIN, LOW);

  lcd.createChar(0, thickDash_Char);
  lcd.createChar(1, bell_symbol_Char);
  lcd.createChar(2, backslash_Char);
  lcd.createChar(3, inverted_p_Char);
  lcd.createChar(4, inverted_one_Char);
  lcd.createChar(5, inverted_two_Char);
  lcd.createChar(6, arrow_up_Char);
  lcd.createChar(7, arrow_down_Char);

  // set feeder Servo to default state OFF
  stopFeederServo();

  Wire.begin();

  // set RTC as the Syncprovider
  setSyncProvider(RTC.get);
  // time in sec of resync with RTC
  setSyncInterval(60);

  // Disable the default square wave of the SQW pin.
  RTC.squareWave(SQWAVE_NONE);

  // Attach an interrupt on the Hall sensor (when unput turns LOW)
  // ever 60 degree turn of the feeder shaft, the hall sensor
  // should generate an interrupt
  attachInterrupt(INT1, HallSensorIsr, FALLING);

  // display test
  ledsAndLcdDisplayStartup();

  // Initial state of the FSM
  state = MAIN;

  // read the stored alarm value from the Arduino memory
  get_feed_time1();
  get_feed_time2();

}// End SETUP



// ******************************************************************************
// LOOP

void loop()
{
  // change states of FSM
  change_states();

  // check inputs (buttons)
  check_inputs();

  // check if alarm was called
  check_alarm();

  // check if manual feed was requsted
  check_manual_feed();

  // at midnight, reset some variables
  midnight_reset();

  // check connection RTC
  check_RTC();

  // Check the Hall sensor function
  hallSensorCheck();

  // check if lcd backlight must be turned off
  check_LcdBacklight();

}// End of LOOP


// ******************************************************************************
// ******************************************************************************
// ******************************************************************************
// ******************************************************************************



//******************************************************************************
// Finite State Machine
void change_states()
{
  // states
  switch (state)
  {
    //---------------------------------------
    case MAIN:
      display_time();
      displayFeedingAmouts();
      displayFeedingTimes();
      break;
    //---------------------------------------
    case MENU_EDIT_FEEDTIME1:
      display_menu_option_set_feedtime1();
      break;
    //---------------------------------------
    case MENU_EDIT_FEEDTIME2:
      display_menu_option_set_feedtime2();
      break;
    //---------------------------------------
    case MENU_EDIT_FEEDAMOUNT:
      display_menu_option_set_feed_amount();
      break;
    //---------------------------------------
    case MENU_EDIT_TIME:
      display_menu_option_set_time();
      break;
    //---------------------------------------
    case MENU_EDIT_DATE:
      display_menu_option_set_date();
      break;

    //---------------------------------------
    case EDIT_FEED_TIME1_HOUR:
      set_feeding1_time();
      break;
    //---------------------------------------
    case EDIT_FEED_TIME1_MINUTE:
      set_feeding1_time();
      break;
    //---------------------------------------
    case EDIT_FEED_TIME1_ON_OFF:
      set_feeding1_time();
      break;

    //---------------------------------------
    case EDIT_FEED_TIME2_HOUR:
      set_feeding2_time();
      break;
    //---------------------------------------
    case EDIT_FEED_TIME2_MINUTE:
      set_feeding2_time();
      break;
    //---------------------------------------
    case EDIT_FEED_TIME2_ON_OFF:
      set_feeding2_time();
      break;

    //---------------------------------------
    case EDIT_FEED_AMOUNT1:
      set_feedAmount();
      break;
    //---------------------------------------
    case EDIT_FEED_AMOUNT2:
      set_feedAmount();
      break;

    //---------------------------------------
    case EDIT_HOUR:
      set_time();
      break;
    //---------------------------------------
    case EDIT_MINUTE:
      set_time();
      break;
    //---------------------------------------
    case EDIT_DAY:
      set_date();
      break;
    //---------------------------------------
    case EDIT_MONTH:
      set_date();
      break;
    //---------------------------------------
    case EDIT_YEAR:
      set_date();
      break;
      //---------------------------------------
  }
}


//******************************************************************************
// Check INPUTS

void check_inputs()
{
  // first check if timeout has occurred
  if ( millis() - timeoutValue > MENU_TIMEOUT_VALUE )
  {
    userInput = trigTIMEOUT;
    transition(userInput);
  }

  // check state of buttons
  buttonSelect.read();
  buttonUp.read();
  buttonDown.read();
  buttonBack.read();
  buttonManual.read();
  buttonCancel1.read();
  buttonCancel2.read();

  // check manual cancel Feed1 button
  switch (buttonCancel1.wasPressed())
  {
    case 1:
      // invert variable value (true to false and vise versa)
      manualCancelFeed1 = !manualCancelFeed1;
      //turn on lcd backlight manually
      lcd_backlight_ON();

      // message when Cancel1 button is pressed
      if (manualCancelFeed1 == 1)
      {
        lcd.clear();
        lcd.setCursor(0, 0);
        //         0123456789012345 - LCD screen character counter
        lcd.print("Upcoming Feed #1");
        lcd.setCursor(0, 1);
        lcd.print("cancelled once  ");
        delay(2000);
        lcd.clear();
      }
      else if (manualCancelFeed1 == 0)
      {
        lcd.clear();
        lcd.setCursor(0, 0);
        //         0123456789012345 - LCD screen character counter
        lcd.print("Upcoming Feed #1");
        lcd.setCursor(0, 1);
        lcd.print("canceling undone");
        delay(2000);
        lcd.clear();
      }
      break;
  }

  // check manual cancel Feed2 button
  switch (buttonCancel2.wasPressed())
  {
    case 1:
      // invert variable value (true to false and vise versa)
      manualCancelFeed2 = !manualCancelFeed2;
      //turn on lcd backlight manually
      lcd_backlight_ON();
      // message when Cancel1 button is pressed
      if (manualCancelFeed2 == 1)
      {
        lcd.clear();
        lcd.setCursor(0, 0);
        //         0123456789012345 - LCD screen character counter
        lcd.print("Upcoming Feed #2");
        lcd.setCursor(0, 1);
        lcd.print("cancelled once  ");
        delay(2000);
        lcd.clear();
      }
      else if (manualCancelFeed2 == 0)
      {
        lcd.clear();
        lcd.setCursor(0, 0);
        //         0123456789012345 - LCD screen character counter
        lcd.print("Upcoming Feed #2");
        lcd.setCursor(0, 1);
        lcd.print("canceling undone");
        delay(2000);
        lcd.clear();
      }
      break;
  }

  // check manual Feed button
  switch (buttonManual.wasPressed())
  {
    case 1:
      manualFeed = true;
      //turn on lcd backlight manually
      lcd_backlight_ON();
      break;
  }

  // check MENU/SELECT button
  switch (buttonSelect.wasPressed())
  {
    case 1:
      userInput = btnSELECT;
      //turn on lcd backlight manually
      lcd_backlight_ON();
      transition(userInput);
      break;
  }
  // check UP button
  switch (buttonUp.wasPressed())
  {
    case 1:
      userInput = btnUP;
      transition(userInput);
      //turn on lcd backlight manually
      lcd_backlight_ON();
      break;
  }
  // check long press UP button
  switch (buttonUp.wasReleased())
  {
    case 1:
      long_press_button = false;
      rpt = REPEAT_FIRST;
      break;
  }
  switch (buttonUp.pressedFor(rpt))
  {
    case 1:
      // increment the long press interval
      rpt += REPEAT_INCR;
      long_press_button = true;
      userInput = btnUP;
      transition(userInput);
      break;
  }
  // check  DOWN button
  switch (buttonDown.wasPressed())
  {
    case 1:
      userInput = btnDOWN;
      transition(userInput);
      //turn on lcd backlight manually
      lcd_backlight_ON();
      break;
  }
  // check long press DOWN button
  switch (buttonDown.wasReleased())
  {
    case 1:
      long_press_button = false;
      rpt = REPEAT_FIRST;
      break;
  }
  switch (buttonDown.pressedFor(rpt))
  {
    case 1:
      // increment the long press interval
      rpt += REPEAT_INCR;
      long_press_button = true;
      userInput = btnDOWN;
      transition(userInput);
      break;
  }
  // check btnBACK button
  switch (buttonBack.wasPressed())
  {
    case 1:
      userInput = btnBACK;
      transition(userInput);
      //turn on lcd backlight manually
      lcd_backlight_ON();
      break;
  }

}


//******************************************************************************
// Check for state transition trigger

void transition(int trigger)
{
  switch (state)
  {
    //---------------------------------------
    case MAIN:

      // set time-out timr
      timeoutValue = millis();

      if (trigger == btnSELECT)
      {
        lcd.clear();
        state = MENU_EDIT_FEEDTIME1;
      }
      else if (trigger == btnBACK)
      {
        //lcd.clear();
        //state = ALARM1_AND_2_TIME;
      }
      break;
    //---------------------------------------
    case MENU_EDIT_FEEDTIME1:

      // set time-out timer
      timeoutValue = millis();
      // check for time-out 'button' trigger
      if (trigger == trigTIMEOUT)
      {
        lcd.clear();
        state = MAIN;
      }

      // Now check for button triggers
      if (trigger == btnUP)
      {
        //no action, this is the first menu
      }
      else if (trigger == btnDOWN)
      {
        lcd.clear();
        state = MENU_EDIT_FEEDTIME2;
      }
      if (trigger == btnSELECT)
      {
        lcd.clear();
        state = EDIT_FEED_TIME1_HOUR;
      }
      if (trigger == btnBACK)
      {
        lcd.clear();
        state = MAIN;
      }
      break;
    //---------------------------------------
    case MENU_EDIT_FEEDTIME2:

      // set time-out timer
      timeoutValue = millis();
      // check for time-out 'button' trigger
      if (trigger == trigTIMEOUT)
      {
        lcd.clear();
        state = MAIN;
      }

      // Now check for button triggers
      if (trigger == btnUP)
      {
        lcd.clear();
        state = MENU_EDIT_FEEDTIME1;
      }
      else if (trigger == btnDOWN)
      {
        lcd.clear();
        state = MENU_EDIT_FEEDAMOUNT;
      }
      if (trigger == btnSELECT)
      {
        lcd.clear();
        state = EDIT_FEED_TIME2_HOUR;
      }
      if (trigger == btnBACK)
      {
        lcd.clear();
        state = MAIN;
      }
      break;
    //---------------------------------------
    case MENU_EDIT_FEEDAMOUNT:

      // set time-out timer
      timeoutValue = millis();
      // check for time-out 'button' trigger
      if (trigger == trigTIMEOUT)
      {
        lcd.clear();
        state = MAIN;
      }

      // Now check for button triggers
      if (trigger == btnUP)
      {
        lcd.clear();
        state = MENU_EDIT_FEEDTIME2;
      }
      else if (trigger == btnDOWN)
      {
        lcd.clear();
        state = MENU_EDIT_TIME;
      }
      if (trigger == btnSELECT)
      {
        lcd.clear();
        state = EDIT_FEED_AMOUNT1;
      }
      if (trigger == btnBACK)
      {
        lcd.clear();
        state = MAIN;
      }
      break;
    //---------------------------------------
    case MENU_EDIT_TIME:

      // set time-out timer
      timeoutValue = millis();
      // check for time-out 'button' trigger
      if (trigger == trigTIMEOUT)
      {
        lcd.clear();
        state = MAIN;
      }

      // Now check for button triggers
      if (trigger == btnUP)
      {
        lcd.clear();
        state = MENU_EDIT_FEEDTIME2;
      }
      if (trigger == btnDOWN)
      {
        lcd.clear();
        state = MENU_EDIT_DATE;
      }
      if (trigger == btnSELECT)
      {
        lcd.clear();
        state = EDIT_HOUR;
      }
      if (trigger == btnBACK)
      {
        lcd.clear();
        state = MAIN;
      }
      break;
    //---------------------------------------
    case MENU_EDIT_DATE:

      // set time-out timer
      timeoutValue = millis();
      // check for time-out 'button' trigger
      if (trigger == trigTIMEOUT)
      {
        lcd.clear();
        state = MAIN;
      }

      // Now check for button triggers
      if (trigger == btnUP)
      {
        lcd.clear();
        state = MENU_EDIT_TIME;
      }
      else if (trigger == btnDOWN)
      {
        //no action, end of menu items!
      }
      if (trigger == btnSELECT)
      {
        lcd.clear();
        state = EDIT_DAY;
      }
      if (trigger == btnBACK)
      {
        lcd.clear();
        state = MAIN;
      }
      break;

    //---------------------------------------
    case EDIT_FEED_TIME1_HOUR:
      // set time-out timer
      timeoutValue = millis();
      // check for time-out 'button' trigger
      if (trigger == trigTIMEOUT)
      {
        lcd.clear();
        state = MAIN;
      }

      // Now check for button triggers
...

This file has been truncated, please download it to see its full contents.

Credits

Erik de Ruiter

Erik de Ruiter

8 projects • 130 followers
No electronics education but enjoying my new found hobby. Never thought it would be possible to make things myself but here we are...

Comments