易于制作的宠物喂食器
组件和用品
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 6 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 6 | ||||
| × | 1 |
应用和在线服务
|
关于这个项目
更新 2018-09-06
在过去的 7 个月里,我的两个宠物喂食器工作正常。我们当然会在白天照顾我们的宠物,但他们现在会定期喂食。对系统很满意!
为什么是另一个宠物喂食器?
我的宠物喂食器版本基于 Arduino 微控制器。使用的材料相对便宜,我认为它很容易建造!
当然有很多版本,但我找不到一个完整的项目,准备好用我需要的功能来构建,所以我从头开始。
这些是功能:
- *准确的份量*每次交付! (通过使用霍尔传感器)
- 一天两次喂食
- *极其*准确的实时时钟(仅适用于真正的 DS3231 芯片)
- 您可以为带显示屏和 LED 指示灯的两个计时器单独取消即将到来的喂食。设置时间过后,取消会自动重置。
- 手动进纸功能(每按一次按钮一份)
- 两次喂食时间均可调整份量(1-9 份)
- 主屏幕中所有设置参数的概述
- 易于导航的菜单系统
- 喂食成功的 LED 指示
- LCD 背光计时器(30 秒后关闭,按任意按钮开启)
- 时间和其他设置安全地存储在内存 (EEPROM) 中
演示视频:
视频请点击这里
更详细的讲解视频:点击这里
慢动作的宠物喂食器!点击这里
照片:
所需零件:
- 1x 谷物分配器(Ebay 上便宜)
- 一些(废)木头来建造谷物分配器支架
- 1x Arduino Uno
- 1x I2C DS3231(极其精确)或 DS1307 实时时钟
- 1x LCD 显示 16 个字符/2 行
- 1 个用于 LCD 显示器的 I2C 背包
- 1x 连续旋转伺服(买个好的!)
- 1 个霍尼韦尔 SS443R 单极霍尔传感器
- 1 个 12 伏/1 安培外部电源(壁挂式电源)
- 7 个按钮 - 瞬时
- 6 个 LED(2 个红色、3 个绿色、1 个黄色)
- 2x 电阻 1KΩ(用于红色 LED)
- 4x 电阻 560Ω(用于绿色和黄色 LED)
- 1x 电子设备外壳
- 电源插头母头和连接器,用于连接外部伺服和霍尔传感器
- 大量的热胶。
如果可能,最好为伺服使用更高的电压。更大的力量!我的 HSR-2645CRH 伺服可以承受 7.4 伏电压,所以如果您也想这样做,您需要:
- 性能板
- LM317T 可变电压调节器
- 3 个电阻来设置输出电压(1KΩ、150kΩ 和 4K7)
- 2 个极化电容器(220µF、10µF)
- 不需要散热器,舵机每天只旋转 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 螺栓固定在聚碳酸酯圆盘上。使用一些额外的螺母作为垫片,不要过度拧紧!
图> 图>现在伺服是进料器组件的一部分,因此我们可以将其放入木制支架并测量伺服下方的木片必须有多高。
图> 图>
霍尔传感器
我使用的霍尔传感器是 UNIPOLAR 类型的。如果磁铁靠近,它将提供低输出,并且不需要磁铁的反极性将输出再次重置为高。所以使用单极霍尔传感器,更容易。
<代码>!!!霍尔传感器需要一个10KΩ的上拉电阻。
我在霍尔传感器的顶部安装了一个 0805 SMD 电阻器,但您可以按照自己的方式进行。别忘了这个电阻!
然后我拿了一支旧圆珠笔,用塑料作为传感器的支架。
图> 图>
电子外壳
我使用了带法兰的 Hammond ABS 外壳。 120 x 65 x 40 毫米
图> 图> 图> 图> 图>对于外部连接,我使用了精密母头插座连接器,而不是廉价的中国连接器。我在所有项目中都经常使用这些。没有什么比连接不良导致(难以发现)故障更糟糕的了。
图> 图> 图> 图> 图> 图> 图> 图> 图> 图>为了更轻松地对 Arduino 进行编程,我有一个外部 FTDI 连接:
图>
前面板
我尝试了很多方法来制作一个便宜又好看的前面板......
首先,我使用 Mod Podge 在外壳正面粘贴纸质激光打印,并用更多 Mod Podge 覆盖它。 --> 失败
然后我尝试了一种基于聚氨酯丙烯酸酯分散体的透明清漆。干燥后非常耐用和坚固。我将纸张很好地粘在外壳上,并在前面板打印件的上侧上漆看起来非常好,但它不会粘附在打印件的激光打印机碳粉部分。 --> 失败
之后,我把前面板的激光打印出来,只用层压pcv层压顶部。非常漂亮的饰面,保护正面并漂亮地提升颜色。然后,我用清漆将层压纸粘在外壳上。我的想法是清漆会渗透纸张使其具有防水性。但是因为我使用了无法使用的厚纸并将其弄湿来测试防水性,所以纸从外壳上卷曲了。 --> 部分失败,有待进一步调查。
另一个尝试:我买了专门用于激光打印的铝箔。每张 2.25 欧元。结果很好,但我想用特殊的透明箔保护碳粉。那没有成功,因为我无法摆脱照片 1 上的瑕疵:
然后又一次尝试用清漆保护,它使铝箔光泽度非常高!但是......同样,清漆不会粘附在碳粉上,所以我永久放弃了清漆......
最后...我在没有保护的情况下使用了铝箔打印...经常处理时会显示 vinger 打印(查看本页顶部照片的 BACK 按钮下方,位于鸡饲料中)所以不理想但仍然很好对我来说足够了。
更多的照片显然是不允许的所以...
这就是所有人... 有 有趣!
代码
- Pet Feed-O-Matic v 1.1 - 20-02-2018
Pet Feed-O-Matic v 1.1 - 20-02-2018Arduino
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"/* _ _ /\ | | (_) / \ _ __ __| |_ _ _ _ __ ___ / /\ \ | '__/ _` | | | | | '_ \ / _ \ / ____ \| | | (_| | |_| | | | | (_) | /_/ \_\_| \__,_|\__,_|_|_| |_|\___/ _____ _ ______ _ | __ \ | | | ____| | | | |__) |__| |_ | |__ ___ ___ __| | ___ _ __ | ___/ _ \ __| | __/ _ \/ _ \/ _` |/ _ \ '__| | | | __/ |_ | | | __/ __/ (_| | __/ | |_| \___|\__| |_| \___|\___|\__,_|\___|_| Erik de Ruiter -------- -------------------------------------------------- ------------------- 要做: - 远程喂食? - 喂食器停止延迟作为菜单可编辑项最后一次更改:dinsdag 20 februari 2018 - 17:20:28 特点: - *每次准确的份量*!(通过使用霍尔传感器) - 两次喂食,每天一次 - *非常* 准确的实时时钟(仅适用于真正的 DS3231 芯片) - 为两个带显示屏和 LED 指示灯的定时器分别取消即将到来的喂食. 时间过后自动重置。 - 手动进料功能(每按一次按钮一份) - 两次进料时间中的每一个都可调整份量(1-9 份) - 主屏幕中所有设置参数的概览 - 易于导航的菜单系统 - 喂食成功时的 LED 指示 - LCD 背光定时器(30 秒后关闭,按下任何按钮时开启) - 霍尔传感器发生故障时的备份 - 如果霍尔传感器出现故障,哈斯传感器 LED 将闪烁至午夜已失败 - 时间和其他设置安全存储在 EEPROM 网站:LCD HD44780 字符生成器网站制作您自己的 lcd 符号 https://omerk.github.io/lcdchargen/ Arduino 草图 大字母评论生成器 http://patorjk.com /software/taag/#p=display&c=c%2B%2B&f=Big&t=评论修订:zondag 28 januari 2018 - 20:17:10 *//////////////// ////////////////////////////////////////////////// /////////////// 用户可更改变量//////////////////////////////// //////////////////////////////////////////////////用于霍尔传感器故障备份功能。// 间隔时间应稍大于 1 60 度// 送料器旋转(一部分)#define HALL_SENSOR_BACKUP_VALUE 300 // 送料后停止送料器伺服之前的延迟。这样你就可以//让旋转的脚踏轮停在正确的位置#define FEEDER_STOP_DELAY 100//按下按钮后液晶背光亮起时间#define LCD_BACKLIGHT_ON_TIME 30000//在ms中设置的时间超时后不保存退出菜单#define 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 // CONNECTIONS://// LCD (I2C module):// SCL - A5// SDA - A4// VCC// GND//中断hal传感器引脚#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_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 A2#define LED_SUCCESS2_PIN A3// 馈线伺服输出Pin#define SERVO_OUTPUT_PIN 传感器输入引脚Hall1 LED SERVO_OUT_PINH1 (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//声明buttonButton buttonSelect (BUTTON_SELECT_PIN, PULLUP , INVERT, DEBOUNCE_MS);ButtonButtonUp (BUTTON_UP_PIN, PULLUP, INVERT, DEBOUNCE_MS);ButtonButtonDown (BUTTON_DOWN_PIN, PULLUP, INVERT, DEBOUNCE_MS);Button buttonBack (BUTTON_BACK_PIN, PULLUP, INVERT, DEBOUNCE);按钮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); 按钮按钮Manual (BUTTON_MANUAL_PIN, PULLUP, INVERT, DEBOUNCE_MS); 调整后的数值////int 的次数;计数(初始化以确保它在//草图开始时不同)int lastCount =-1;//用于驱动长按重复的可变时间unsigned long rpt =REPEAT_FIRST;//用于菜单超时unsigned long timeoutValue =0;// 手动取消喂食次数变量boolean manualCancelFeed1 =false;boolean manualCancelFeed2 =false;// 手动喂食选项boolean manualFeed =false;// 喂食量(按份数)int feedAmount1 =1;int feedAmount2 =1;bool feederSuccess =false;// feederpartsintparts =0;int turn =0;// input actionsenum {btnSELECT, btnUP, btnDOWN, btnBACK, btnCANCEL1, btnCANCEL2, btnMANUAL, trigTIMEOUT};// 有限状态机(FSM)枚举状态{ 主要,菜单编辑_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 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;// 用于编辑值时的闪烁功能suint32_tblink_interval =500;uint32_ublink_tmblink_tmlinks_tm_tm 0;booleanblink_state =false;// 用于编辑值时闪烁功能suint32_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_thallSensorBackup_currentMillis =0;booleanhallSensorFail =false;//用于液晶背光timeruint32_t lcdBacklight_interval =LCD_BACKUP_currentMillis; // 为 LCD 显示定义自定义符号byte bell_symbol_Char[8] ={ B00100, B01110, B01110, B01110, B11111, B00100, B00000, B00000};byte reverse_one_Char[8] ={ 0b10,101010b,1010101010b10101010b , 0b10001, 0b11111};byte reverse_two_Char[8] ={ 0b11111, 0b11011, 0b10101, 0b11101, 0b11011, 0b10111, 0b10001, 110b TE arrow_up_Char [8] ={0b00100,0b01110,0b11111,0b01110,0b01110,0b01110,0b01110,0b00000};字节arrow_down_Char [8] ={0b00000,0b01110,0b01110,0b01110,0b01110,0b11111,0b01110,0b00100};字节inverted_p_Char [8] ={0b11111,0b10001,0b10101,0b10001,0b10111,0b10111,0b11111,0b00000};字节backslash_Char [8] ={0b00000,0b10000,0b01000,0b00100,0b00010,0b00001,0b00000,0b00000};字节thickDash_Char [8 ] ={ 0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b00000, 0b00000, 0b00000};volatile booleanhallSensorActivated =false;//中断1Activvoid HallSensorIsr; // 打开霍尔传感器 LED digitalWrite(LED_HALL_SENSOR_PIN, HIGH);}// 这些行是使这个草图成为 C++ 文件所必需的。// 我使用它是因为我用 Atom 编辑代码// 文本编辑器和 PlatformIO 添加-onvoid 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();voidmidnight_reset();void display_time();void displayFeedingAmouts();void displayFeedingTimes();void set_feedAmount();void set_time_set_time ();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);voidleading_zero(intdigits);voidblinkFunction();void displaySpinningWheel();void startFeederServo();void stopFeederServo();void activateFeeder(int部分);void check_LcdBacklight();void lcd_backlight_ON();void ledsAndLcdDisplayStartup();void HallSensorCheck();#line 355// ************************** ****************************************************** **// SETUPvoid setup(){ // 激活液晶屏lcd.begin(); // 打开液晶背光并启动背光关闭定时器 lcd_backlight_ON(); // 启动 I2C Wire.begin(); //霍尔传感器输入检测送料器的旋转/送料量输出检查 pinMode(HALL_SENSOR_PIN, INPUT_PULLUP); pinMode(LED_HALL_SENSOR_PIN,输出); pinMode(SERVO_OUTPUT_PIN, OUTPUT); pinMode(LED_CANCEL1_PIN,输出); pinMode(LED_CANCEL2_PIN,输出); pinMode(LED_SUCCESS1_PIN, OUTPUT); pinMode(LED_SUCCESS2_PIN,输出); // 将 LED 的默认状态设置为 OFF digitalWrite(LED_CANCEL1_PIN, LOW);数字写入(LED_CANCEL2_PIN,低);数字写入(LED_SUCCESS1_PIN,低);数字写入(LED_SUCCESS2_PIN,低);数字写入(LED_HALL_SENSOR_PIN,低); 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); // 设置供料器伺服为默认状态 OFF stopFeederServo(); Wire.begin(); // 将 RTC 设置为 Syncprovider setSyncProvider(RTC.get); // 与 RTC 重新同步的时间(以秒为单位) setSyncInterval(60); // 禁用 SQW 引脚的默认方波。 RTC.squareWave(SQWAVE_NONE); // 在霍尔传感器上附加一个中断(当 unput 变为低电平时)// 馈线轴旋转 60 度,霍尔传感器 // 应生成中断 attachInterrupt(INT1, HallSensorIsr, FALLING); // 显示测试 ledsAndLcdDisplayStartup(); // FSM 状态的初始状态 =MAIN; // 从 Arduino 内存中读取存储的警报值 get_feed_time1(); get_feed_time2();}// 结束设置// *************************************** ****************************************// LOOPvoid loop(){ // 改变状态FSM change_states(); // 检查输入(按钮) check_inputs(); // 检查警报是否被调用 check_alarm(); // 检查是否需要手动进给 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 Machinevoid 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 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);液晶显示器(); } 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);液晶显示器(); } 休息; } // 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);液晶显示器(); } 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);液晶显示器(); } 休息; } // 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 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(); 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; } 休息; //--------------------------------------- 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; } 休息; //--------------------------------------- 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; } 休息; //--------------------------------------- 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; } 休息; //--------------------------------------- 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; } 休息; //--------------------------------------- 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.
示意图
Arduino based Pet Feeder I used Arduino IDE 1.8.2. BE CAREFUL NOT TO HAVE TWO VERSIONS OF THE SAME LIBRARIES IN YOUR LIBRARIES FOLDER!! arduino_pet_feeder_final_eng_v1_0-ino_hex_libraries_dsoo0HscCr.zip制造工艺
- 宠物食品
- 使用 Arduino Nano RP 2040 的 DIY Photoshop 编辑控制台
- Arduino Spybot
- 鲜花 - Arduino Nano、CrazyCircuits、DFRobot
- 自制 16x8 矩阵上的 Arduino Nano 俄罗斯方块游戏
- Arduino Tamagotchi Clone - Digital Pet
- Arduino Nano:使用操纵杆控制 2 个步进电机
- 遥控宠物喂食器
- 带有 Arduino Nano 的手持盖革计数器
- Arduino Nano 的 TFT 扩展板 - 开始
- 带 3D 打印部件的宠物喂食器
- 用 Arduino Nano 制作吃饭机器人 |金螺丝