Простая в сборке кормушка для домашних животных
Компоненты и расходные материалы
![]() |
| × | 1 | |||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 6 | ||||
![]() |
| × | 1 | |||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
![]() |
| × | 6 | |||
| × | 1 |
Приложения и онлайн-сервисы
|
Об этом проекте
Обновление 2018-09-06
Две мои кормушки для домашних животных работают безупречно последние 7 месяцев. Конечно, мы заботимся о наших питомцах в течение дня, но теперь они получают корм в обычное время. Очень доволен системой!
Зачем нужна еще одна кормушка для домашних животных?
Моя версия кормушки для домашних животных основана на микроконтроллере Arduino. Используемые материалы относительно дешевы, и я думаю, что их легко построить!
Конечно, существует множество версий, но я не смог найти полный проект, готовый к сборке с необходимыми мне функциями, поэтому я начал с нуля.
Это особенности:
- * Точные порции * доставляются каждый раз! (с помощью датчика Холла)
- Кормление два раза в день.
- * Чрезвычайно * точные часы реального времени (только с оригинальным чипом DS3231)
- Вы можете отменить предстоящее кормление индивидуально для обоих таймеров с дисплеем и светодиодным индикатором. Отмена автоматически сбрасывается по истечении установленного времени.
- Функция ручной подачи (одна порция на нажатие кнопки)
- Регулируемые порции для каждого из двух периодов кормления (1–9 порций).
- Обзор всех установленных параметров на главном экране.
- Простая навигация по системе меню.
- Светодиодная индикация успешного кормления
- Таймер подсветки ЖК-дисплея (выключается через 30 секунд, включается при нажатии любой кнопки)
- Время и другие настройки надежно хранятся в памяти (EEPROM).
Демонстрационные ВИДЕО:
для просмотра видео нажмите ЗДЕСЬ
видео с более подробным объяснением:нажмите ЗДЕСЬ
кормушка для домашних животных в замедленной съемке! нажмите ЗДЕСЬ
Фото:


Необходимые детали:
- 1x дозатор для злаков (дешево на Ebay)
- немного (металлолома) дерева для сборки держателя дозатора хлопьев.
- 1x Arduino Uno
- 1x I2C DS3231 (очень точный) или часы реального времени DS1307
- 1x ЖК-дисплей, 16 символов / 2 строки
- 1x рюкзак I2C для ЖК-дисплея.
- 1x Продолжает вращение Сервопривод (купите хороший!)
- 1x униполярный датчик Холла Honeywell SS443R
- 1x внешний источник питания 12 В / 1 А (настенная бородавка)
- 7 кнопок - мгновенно
- 6 светодиодных индикаторов (2 красных, 3 зеленых, 1 желтый)
- 2 резистора 1 кОм (для красных светодиодов)
- 4 резистора 560 Ом (для зеленого и желтого светодиода).
- 1x корпус для электроники
- розетка и разъемы для подключения внешнего сервопривода и датчика Холла.
- много-много ГОРЯЧЕГО КЛЕЯ.
По возможности лучше использовать для сервопривода более высокое напряжение. Больше силы! Мой сервопривод HSR-2645CRH может потреблять 7,4 Вольт, поэтому, если вы тоже хотите это сделать, вам понадобятся:
- Перфорированная доска
- Регулятор переменного напряжения LM317T
- 3 резистора для установки выходного напряжения (1 кОм, 150 кОм и 4 К7)
- 2 поляризованных конденсатора (220 мкФ, 10 мкФ)
- радиатор не нужен, сервопривод будет вращаться 1-2 секунды каждый день;)

В Интернете можно найти множество калькуляторов LM317.
Контейнер для корма для домашних животных
Самыми дешевыми и простыми в использовании являются диспенсеры для хлопьев, которые вы можете найти во многих магазинах и на Ebay. Я купил двойной диспенсер для хлопьев на Ebay за 15 евро, включая доставку (из Великобритании в Нидерланды)

Задача заключалась в том, чтобы сделать крепление для кормушки, и поиск в Интернете мне не очень помог, поэтому я огляделся в своем сарае и нашел несколько красивых кусочков кедрового дерева.
Деревянная пластина, на которой держится пластиковый дозатор для хлопьев, имеет толщину 3 см, так что не должно шататься! Вы должны быть уверены, что отверстие (моя фидерная база 86 мм) плотно затянуто, поэтому измерьте перед сверлением! Лучше просверлить отверстие меньшего размера и немного придать ему форму, чем слишком большое отверстие.
Посмотрите на фото, чтобы понять, почему и как они сочетаются друг с другом.

















Сервопривод и насадка на лопастное колесо дозатора
Обязательно купите хороший сервопривод. Сначала я купил сервопривод MG996R, который модифицировал для непрерывного вращения, но это была пустая трата денег ... Потом я купил качественные, в моем случае сервопривод HSR-2645CRH
Это ДОЛЖНА БЫТЬ модель с непрерывным вращением !! Не пытайтесь модифицировать обычный сервопривод, как это сделал я. Он работал недостаточно хорошо, и при остановке не сразу.
видео испытания сервопривода:нажмите ЗДЕСЬ
Подключение сервопривода к лопастному колесу дозатора
Возник вопрос:как подключить сервопривод к лопастному колесу питателя? Сначала это казалось самой сложной частью проекта, но на самом деле это было очень просто.
Я взял кусок поликарбоната 5 мм и лобзиком вырезал круглый диск примерно 6 см. В центре просверлил отверстие 8 мм (толщина оси питателя. Эта пластиковая ось снимается с лопастного колеса)

Снаружи просверливаю 6 отверстий по 3 мм, толщиной под магниты. Они используются, чтобы дать Arduino обратную связь о положении педального колеса питателя.

Поскольку на лопаточном колесе было 6 резиновых лопастей, я использовал 6 магнитов и разделил их по краю поликарбонатного диска. 360 градусов, разделенные на 6, составляют 60 градусов. Стержневые магниты плотно прилегают.
Датчик Холла обнаружит каждый из 6 магнитов, поэтому мы можем использовать эту информацию для точного позиционирования и остановки лопастного колеса. Переменная времени задержки останова сервопривода используется для добавления задержки после кормление, перед остановкой сервопривод. Таким образом, с помощью этой задержки вы можете настроить точное положение лопастного колеса. Это важно, потому что, если положение «стоп» неправильное, подача не будет полностью выходить из лопастного колеса. Также в вашем случае положение датчика холла может отличаться. Эту проблему решит настройка переменной времени задержки остановки сервопривода.

Теперь мы можем приклеить ось гребного колеса к диску из поликарбоната.




Белый круглый рог сервопривода прикручен к диску из поликарбоната 3 болтами M3. используйте дополнительные гайки в качестве распорок и не затягивайте слишком сильно!



Теперь сервопривод является частью узла питателя, поэтому мы можем вставить его в деревянную опору и измерить, какой высоты должна быть деревянная деталь под сервоприводом.



Датчик Холла
Я использовал датчик Холла УНИПОЛЯРНОГО типа. Он даст НИЗКИЙ выход, если рядом находится магнит, и НЕ ТРЕБУЕТСЯ обратной полярности магнита, чтобы снова сбросить выход на ВЫСОКИЙ. Так что использовать униполярный датчик Холла намного проще.
<код> !!! Для датчика Холла требуется подтягивающий резистор 10 кОм.
Я установил SMD-резистор 0805 прямо на датчик Холла, но вы можете сделать это по-своему. Не забудьте этот резистор!
Затем я взял старую шариковую ручку и использовал пластик в качестве держателя для датчика.



Корпус для электроники
Я использовал корпус Hammond ABS с фланцем. 120 х 65 х 40 мм






для внешних подключений я использовал прецизионные гнездовые разъемы, а не дешевые китайские. Я часто использую их во всех своих проектах. Нет ничего хуже, чем плохое соединение, вызывающее (трудно найти) сбои.












Чтобы упростить программирование Arduino, у меня есть внешнее соединение FTDI:


Передняя панель
Я много пробовал сделать дешевую и красивую переднюю панель ...
Сначала я использовал Mod Podge, чтобы наклеить бумажный лазерный принт на переднюю часть корпуса и покрыть его большим количеством Mod Podge. -> ОТКАЗ
Потом попробовала прозрачный лак на основе дисперсии полиуретанакрилата. Очень прочный и прочный при высыхании. Я очень хорошо приклеил бумагу к корпусу, и лакировка верхней стороны отпечатка передней панели выглядела очень хорошо, НО она не прилипала к частям отпечатка, нанесенным тонером лазерного принтера. -> ОТКАЗ
После этого я снял лазерную печать передней панели и ламинировал только верх с ламинированием pcv. очень красивая отделка, защищающая лицевую часть и красиво подчеркивающая цвета. Затем я снова приклеил ламинированную бумагу к корпусу лаком. Моя идея заключалась в том, чтобы лак пропитал бумагу, делая ее водонепроницаемой. Но поскольку я использовал толстую бумагу, которая не годилась и намочила ее для проверки водонепроницаемости, бумага скручивалась с корпуса. -> ЧАСТИЧНО ОТКАЗАНО, подлежит дальнейшему расследованию.
Еще одна попытка:купил специальную алюминиевую фольгу для лазерной печати. 2,25 евро за лист. Результат был отличным, но я хотел защитить тонер специальной прозрачной фольгой. Это не увенчалось успехом, потому что я не мог избавиться от недостатков, как видно на фото 1:

Затем еще одна попытка защитить прозрачным лаком, она сделала алюминиевую фольгу очень глянцевой! НО ... опять же, лак не держался на тонере, поэтому я отказался от лака навсегда ...
НАКОНЕЦ ... Я использовал печать на фольге без защиты ... При частом обращении с ней будут видны отпечатки Вингера (посмотрите под кнопку НАЗАД на фотографии вверху этой страницы, в корме для кур), так что не идеально, но все же хорошо мне хватит.
Больше фото не разрешено, так что ...
Это все, ребята ... есть весело!
Код
- Pet Feed-O-Matic v 1.1 - 20 февраля 2018 г.
Pet Feed-O-Matic v 1.1 - 20.02.2018 Arduino
v 1.1:нажатие кнопок Cancel1 или 2 покажет объяснение// c ++ stuff ... // # include// # line 1 // # line 1 "/ Users / Erik / Documents / PlatformIO / Projects / 180202-151127-uno / src / Pet_Feeder_1_1_ENG.cpp "/ * _ _ / \ | | (_) / \ _ __ __ | | _ _ _ _ __ ___ / / \ \ | '__ / _` | | | | | '_ \ / _ \ / ____ \ | | | (_ | | | _ | | | | | | (_) | / _ / \ _ \ _ | \ __, _ | \ __, _ | _ | _ | | _ | \ ___ / _____ _ ______ _ | __ \ | | | ____ | | | | | __) | __ | | _ | | __ ___ ___ __ | | ___ _ __ | ___ / _ \ __ | | __ / _ \ / _ \ / _` | / _ \ '__ | | | | __ / | _ | | | __ / __ / (_ | | __ / | | _ | \ ___ | \ __ | | _ | \ ___ | \ ___ | \ __, _ | \ ___ | _ | Эрик де Руйтер -------- -------------------------------------------------- ------------------- Для выполнения:- дистанционное кормление? - задержка остановки кормораздатчика как редактируемый элемент меню последнее изменение:dinsdag 20 februari 2018 - 17:20:28 ОСОБЕННОСТИ:- * Точные порции * каждый раз! (С помощью датчика Холла) - Два времени кормления, один раз в день - * Чрезвычайно * точные часы реального времени (только с оригинальным чипом DS3231) - Отмена предстоящего кормления индивидуально для обоих таймеров с дисплеем и светодиодным индикатором . Автоматический сброс по истечении времени. - Функция ручной подачи (одна порция на нажатие кнопки) - Регулируемые порции для каждого из двух периодов кормления (1-9 порций) - Обзор всех установленных параметров на главном экране - Простое навигационное меню система - Светодиодная индикация, если кормление прошло успешно - Таймер подсветки ЖК-дисплея (выключен через 30 секунд, включается при нажатии любой кнопки) - Резервное копирование в случае неисправности датчика Холла - Светодиод датчика Hass будет мигать до полуночи, если датчик Холла не удалось - Время и другие настройки надежно хранятся на ВЕБ-САЙТАХ EEPROM:Веб-сайт генератора символов LCD HD44780 для создания собственных ЖК-символов https://omerk.github.io/lcdchargen/ Эскиз Arduino Генератор комментариев больших букв http://patorjk.com / software / taag / # p =display &c =c% 2B% 2B &f =Big &t =Комментарий Редакции:zondag 28 января 2018 г. - 20:17:10 * ////////////////// ////////////////////////////////////////////////// /////////////// ПОЛЬЗОВАТЕЛЬСКИЕ ИЗМЕНЯЕМЫЕ ПЕРЕМЕННЫЕ //////////////////////////////// ////////////////////////////////////////////////// используется для резервной функции при сбое датчика Холла. // интервал времени должен быть несколько больше, чем один 60-градусный // поворот питателя (одна порция) #define HALL_SENSOR_BACKUP_VALUE 300 // задержка перед остановкой сервопривода питателя после подачи. Таким образом вы можете // позволить вращающемуся педальному колесу остановиться в правильном положении # define FEEDER_STOP_DELAY 100 // время включения подсветки ЖК-дисплея после нажатия кнопки # define LCD_BACKLIGHT_ON_TIME 30000 // выйти из меню без сохранения по истечении времени, установленного здесь в мс # определить MENU_TIMEOUT_VALUE 7000 ///////////////////////////////////////////////// ////////////////////////////////// https:// github.com/fdebrabander/Arduino-LiquidCrystal-I2C- library # include // https:// github.com/JChristensen/Button#include // http:// github.com/JChristensen/DS3232RTC#include // http:// www.arduino.cc/playground/Code/Time#include // http:// arduino.cc/en/Reference/Wire (входит в состав Arduino IDE) #include #include // ПОДКЛЮЧЕНИЯ://// LCD (модуль I2C):// SCL - A5 // SDA - A4 // VCC // GND // вывод датчика Hal прерывания # define HALL_SENSOR_PIN 3 # define BUTTON_BACK_PIN 4 # определить BUTTON_UP_PIN 5 # определить BUTTON_DOWN_PIN 6 # определить BUTTON_SELECT_PIN 7 # определить BUTTON_CANCEL1_PI N 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 LCD #define LED_SUCCESS2_PIN A3 // фидер Servo output Pin # define SERVO_ORTPALL_PIN # определить SERVO_ORTPALL_PIN # определить SERVO_ORUT_PALL (16x2) 0x27 или 0x3FLiquidCrystal_I2C lcd (0x3F, 16, 2); // определение настроек библиотеки кнопок // время устранения дребезга в 20 миллисекунд обычно хорошо работает // для тактильных кнопочных переключателей. # Define DEBOUNCE_MS 20 // мс требуется перед повторением включения долгое нажатие # define REPEAT_FIRST 1000 // интервал повторения для длительного нажатия # define REPEAT_INCR 200 // Для простоты мы используем внутренний подтягивающий резистор Arduino. #define PULLUP true # define INVERT true // Объявить кнопки , INVERT, DEBOUNCE_MS); Кнопка buttonUp (BUTTON_UP_PIN, PULLUP, INVERT, DEBOUNCE_MS); Кнопка buttonDown (BUTTON_DOWN_PIN, PULLUP, INVERT, DEBOUNCE_MS); Кнопка buttonBack (BUTTON_BACK_PIN, 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, PULLBUP, // число изменено; // число изменено; count (инициализировано, чтобы убедиться, что оно другое при // запуске скетча) int lastCount =-1; // переменное время, которое используется для управления повторами для длинных нажатийunsigned long rpt =REPEAT_FIRST; // используется для тайм-аута меню без знака long timeoutValue =0; // ручная отмена переменных времени кормленияboolean manualCancelFeed1 =false; логическое manualCancelFeed2 =false; // Ручная опция подачиboolean manualFeed =false; // Количество корма (порциями) int feedAmount1 =1; int feedAmount2 =1; boolfederSuccess =false; // порции фидера int portions =0; int turn =0; // ввод действияsenum {btnSELECT, btnUP, btnDOWN, btnBACK, btnCANCEL1, btnCANCEL2, btnMANUAL, trigTIMEOUT}; // Состояния конечного автомата (FSESM) enum {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,}; // Содержит текущее состояние состояния systemSTATES; 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; // используется для функции мигания при редактировании значений uint32_t blink_interval_Minterval_ 500; uint32_t blink_interval_M_Interval =500; uint32_T 0; boolean blink_state =false; // используется для функция мигания при редактировании значений uint32_t spinningWheel_interval =170; uint32_t spinningWheel_previousMillis =0; uint32_t spinningWheel_currentMillis =0; int spinningWheelSymbol =0; // используется для функции резервного копирования при сбое датчика Холла // время интервала должно быть несколько больше одного поворота на 60 градусов фидера (один участок) .uint32_t hallSensorBackup_interval =HALL_SENSOR_BACKUP_VALUE; uint32_t hallSensorBackup_currentMillis =0; булево hallSensorFail =false; // используется для подсветки ЖК-дисплея timeruint32_t lcdBacklight_interval =LCD_BACKLIGHT_ON_TIME; uint32_t lcdBacklight_currentMillis =0; булево RTC_error =TRUE; булево long_press_button =ложь; // Определение пользовательских символов для ЖК-дисплеяbyte bell_symbol_Char [8] ={B00100, B01110, B01110, B01110, B11111, B00100, B00000, B00000}; байт инвертированный_one_Char [8] ={0b11111, 0b11011, 0b10011, 0b11011, 0b11110 , 0b10001, 0b11111}; byte Inverted_two_Char [8] ={0b11111, 0b11011, 0b10101, 0b11101, 0b11011, 0b10111, 0b10001, 0b11111}; by te arrow_up_Char [8] ={0b00100, 0b01110, 0b11111, 0b01110, 0b01110, 0b01110, 0b01110, 0b00000}; байт arrow_down_Char [8] ={0b00000, 0b01110, 0b01110, 0b100_11011, 0b011110, 0b011110, 0b011110, 0b011110, 0b01110, 0b01101110, 0b [8] ={0b11111, 0b10001, 0b10101, 0b10001, 0b10111, 0b10111, 0b11111, 0b00000}; байтовая обратная косая черта_Char [8] ={0b00000, 0b10000, 0b01000, 0b00100, 0b00010, 0b000000; ] ={0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b00000, 0b00000, 0b00000}; изменчивое логическое значение hallSensorActivated =false; // Прервать 1void HallSensorIsr () {hallSensorActivated =true; // включаем светодиод датчика Холла digitalWrite (LED_HALL_SENSOR_PIN, HIGH);} // Эти строки нужны, чтобы сделать этот скетч файлом C ++. // Я использую его, потому что редактирую код с помощью текстового редактора Atom // и добавления PlatformIO -onvoid HallSensorIsr (); void setup (); void loop (); void change_states (); void check_inputs (); void transition (int триггер); void check_alarm (); void check_manual_feed (); void display_menu_option_set_feedtime_set_set_uid display2 (); 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 displayFeedingAmouts (); void displayFeedingAmouts (); void displayFeedingAmouts); (); 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_feed (); void write_feedamount_feed (); (); void get_feed_time1 (); void get_feed_time2 (); void check_RTC (); byte decToBcd (byte val); byte bcdToDec (byte val); void lead_zero (int digits); void blinkFunction (); void displaySpinningWheel (); void startFeederServo (); void stopFeederServo (); void activateFeeder (int check_LcdBacklight (); void lcd_backlight_ON (); void ledsAndLcdDisplayStartup (); void hallSensorCheck (); # строка 355 // ************************** ************************************************* ** // НАСТРОЙКАvoid setup () {// активируем жк-экран lcd.begin (); // включаем подсветку жк-дисплея и запускаем таймер выключения подсветки lcd_backlight_ON (); // запускаем I2C Wire.begin (); // вход датчика Холла для определения вращения подающего устройства / проверка количества корма pinMode (HALL_SENSOR_PIN, INPUT_PULLUP); pinMode (LED_HALL_SENSOR_PIN, ВЫХОД); pinMode (SERVO_OUTPUT_PIN, ВЫХОД); pinMode (LED_CANCEL1_PIN, ВЫХОД); pinMode (LED_CANCEL2_PIN, ВЫХОД); pinMode (LED_SUCCESS1_PIN, ВЫХОД); pinMode (LED_SUCCESS2_PIN, ВЫХОД); // установить состояние светодиодов по умолчанию на 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, обратная косая черта); lcd.createChar (3, инвертированный_p_Char); lcd.createChar (4, инвертированный_one_Char); lcd.createChar (5, инвертированный_two_Char); lcd.createChar (6, arrow_up_Char); lcd.createChar (7, arrow_down_Char); // установить сервопривод фидера в состояние по умолчанию OFF stopFeederServo (); Wire.begin (); // установить RTC как Syncprovider setSyncProvider (RTC.get); // время в секундах повторной синхронизации с RTC setSyncInterval (60); // Отключаем прямоугольную волну по умолчанию для вывода SQW. RTC.squareWave (SQWAVE_NONE); // Прикрепите прерывание к датчику Холла (когда unput становится LOW) // каждый раз при повороте вала питателя на 60 градусов датчик Холла // должен генерировать прерывание attachInterrupt (INT1, HallSensorIsr, FALLING); // отображаем тестовые ledsAndLcdDisplayStartup (); // Начальное состояние конечного автомата state =MAIN; // считываем сохраненное значение сигнала тревоги из памяти Arduino get_feed_time1 (); get_feed_time2 ();} // Конец НАСТРОЙКИ // ************************************** ************************************** // LOOPvoid loop () {// изменение состояний автомата change_states (); // проверяем входы (кнопки) check_inputs (); // проверяем, была ли вызвана тревога check_alarm (); // проверяем, не требовалась ли подача вручную check_manual_feed (); // в полночь сбрасываем некоторые переменные 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 Machinevoid change_states(){ // states switch (state) { //--------------------------------------- case MAIN:display_time(); displayFeedingAmouts(); displayFeedingTimes(); ломать; //--------------------------------------- case MENU_EDIT_FEEDTIME1:display_menu_option_set_feedtime1(); ломать; //--------------------------------------- case MENU_EDIT_FEEDTIME2:display_menu_option_set_feedtime2(); ломать; //--------------------------------------- case MENU_EDIT_FEEDAMOUNT:display_menu_option_set_feed_amount(); ломать; //--------------------------------------- case MENU_EDIT_TIME:display_menu_option_set_time(); ломать; //--------------------------------------- case MENU_EDIT_DATE:display_menu_option_set_date(); ломать; //--------------------------------------- case EDIT_FEED_TIME1_HOUR:set_feeding1_time(); ломать; //--------------------------------------- case EDIT_FEED_TIME1_MINUTE:set_feeding1_time(); ломать; //--------------------------------------- case EDIT_FEED_TIME1_ON_OFF:set_feeding1_time(); ломать; //--------------------------------------- case EDIT_FEED_TIME2_HOUR:set_feeding2_time(); ломать; //--------------------------------------- case EDIT_FEED_TIME2_MINUTE:set_feeding2_time(); ломать; //--------------------------------------- case EDIT_FEED_TIME2_ON_OFF:set_feeding2_time(); ломать; //--------------------------------------- case EDIT_FEED_AMOUNT1:set_feedAmount(); ломать; //--------------------------------------- case EDIT_FEED_AMOUNT2:set_feedAmount(); ломать; //--------------------------------------- case EDIT_HOUR:set_time(); ломать; //--------------------------------------- case EDIT_MINUTE:set_time(); ломать; //--------------------------------------- case EDIT_DAY:set_date(); ломать; //--------------------------------------- case EDIT_MONTH:set_date(); ломать; //--------------------------------------- case EDIT_YEAR:set_date(); ломать; //--------------------------------------- }}//******************************************************************************// Check INPUTSvoid 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 "); задержка (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"); задержка (2000); lcd.clear (); } ломать; } // 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 "); задержка (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"); задержка (2000); lcd.clear (); } ломать; } // check manual Feed button switch (buttonManual.wasPressed()) { case 1:manualFeed =true; //turn on lcd backlight manually lcd_backlight_ON(); ломать; } // check MENU/SELECT button switch (buttonSelect.wasPressed()) { case 1:userInput =btnSELECT; //turn on lcd backlight manually lcd_backlight_ON(); transition(userInput); ломать; } // check UP button switch (buttonUp.wasPressed()) { case 1:userInput =btnUP; transition(userInput); //turn on lcd backlight manually lcd_backlight_ON(); ломать; } // check long press UP button switch (buttonUp.wasReleased()) { case 1:long_press_button =false; rpt =REPEAT_FIRST; ломать; } switch (buttonUp.pressedFor(rpt)) { case 1:// increment the long press interval rpt +=REPEAT_INCR; long_press_button =true; userInput =btnUP; transition(userInput); ломать; } // check DOWN button switch (buttonDown.wasPressed()) { case 1:userInput =btnDOWN; transition(userInput); //turn on lcd backlight manually lcd_backlight_ON(); ломать; } // check long press DOWN button switch (buttonDown.wasReleased()) { case 1:long_press_button =false; rpt =REPEAT_FIRST; ломать; } switch (buttonDown.pressedFor(rpt)) { case 1:// increment the long press interval rpt +=REPEAT_INCR; long_press_button =true; userInput =btnDOWN; transition(userInput); ломать; } // check btnBACK button switch (buttonBack.wasPressed()) { case 1:userInput =btnBACK; transition(userInput); //turn on lcd backlight manually lcd_backlight_ON(); ломать; }}//******************************************************************************// Check for state transition triggervoid 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; } ломать; //--------------------------------------- case MENU_EDIT_FEEDTIME1:// set time-out timer timeoutValue =millis(); // check for time-out 'button' trigger if (trigger ==trigTIMEOUT) { lcd.clear(); состояние =ГЛАВНЫЙ; } // 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(); состояние =ГЛАВНЫЙ; } ломать; //--------------------------------------- case MENU_EDIT_FEEDTIME2:// set time-out timer timeoutValue =millis(); // check for time-out 'button' trigger if (trigger ==trigTIMEOUT) { lcd.clear(); состояние =ГЛАВНЫЙ; } // 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(); состояние =ГЛАВНЫЙ; } ломать; //--------------------------------------- case MENU_EDIT_FEEDAMOUNT:// set time-out timer timeoutValue =millis(); // check for time-out 'button' trigger if (trigger ==trigTIMEOUT) { lcd.clear(); состояние =ГЛАВНЫЙ; } // 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(); состояние =ГЛАВНЫЙ; } ломать; //--------------------------------------- case MENU_EDIT_TIME:// set time-out timer timeoutValue =millis(); // check for time-out 'button' trigger if (trigger ==trigTIMEOUT) { lcd.clear(); состояние =ГЛАВНЫЙ; } // 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(); состояние =ГЛАВНЫЙ; } ломать; //--------------------------------------- case MENU_EDIT_DATE:// set time-out timer timeoutValue =millis(); // check for time-out 'button' trigger if (trigger ==trigTIMEOUT) { lcd.clear(); состояние =ГЛАВНЫЙ; } // 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(); состояние =ГЛАВНЫЙ; } ломать; //--------------------------------------- case EDIT_FEED_TIME1_HOUR:// set time-out timer timeoutValue =millis(); // check for time-out 'button' trigger if (trigger ==trigTIMEOUT) { lcd.clear(); состояние =ГЛАВНЫЙ; } // Now check for button triggers...This file has been truncated, please download it to see its full contents.
Схема
Arduino based Pet Feeder
Производственный процесс
- Корм для домашних животных
- Консоль редактирования DIY Photoshop с использованием Arduino Nano RP 2040
- Arduino Spybot
- Цветы - Arduino Nano, CrazyCircuits, DFRobot
- Игра Arduino Nano Tetris на самодельной матрице 16x8
- Клон Arduino Tamagotchi - цифровой питомец
- Arduino Nano:управление двумя шаговыми двигателями с помощью джойстика
- Кормушка для домашних животных с дистанционным управлением
- Портативный счетчик Гейгера с Arduino Nano
- TFT Shield для Arduino Nano - запуск