目录

一、设计背景和意义

1.1设计背景

1.2设计意义

二、实物效果展示

2.1实物图片

2.2实物演示视频

三、硬件功能简介

3.1项目功能详解

3.2元器件清单

四、主框图与软件流程图

五、硬件PCB展示

六、软件程序设计

七、项目资料包内容

         资料获取:查看主页介绍“充哥单片机设计”


一、设计背景和意义

1.1设计背景

        随着社会发展和生活节奏加快,宠物饲养已成为现代家庭的重要组成部分。然而,由于工作繁忙或短期出行,许多宠物主人难以保证宠物的规律饮食和舒适生活环境。传统的喂食方式依赖人工操作,存在投喂时间不固定、喂食量不精确、无法实时监控环境等问题,长期可能导致宠物健康隐患。此外,市场上现有的智能喂食设备功能较为单一,大多仅支持定时投喂或简单远程控制,缺乏对宠物生活环境的综合监测(如温湿度、光照、水质等),且数据交互能力较弱,难以满足用户对智能化、精细化宠物管理的需求。

1.2设计意义

        提升宠物饲养的智能化水平:通过多传感器融合和自动化控制,减少人工干预,确保宠物饮食和环境的稳定性;优化用户体验:支持手机APP远程监控和手动控制,适应不同使用场景,提高系统的易用性和灵活性;推动智能家居技术应用:本系统的模块化设计和物联网架构可为其他智能设备(如智能鱼缸、智能植物养护系统等)提供参考;促进嵌入式与物联网技术融合:通过STM32与ESP8266的协同工作,探索低成本、高效率的物联网终端设备实现方案。本研究的成果不仅可应用于家庭宠物喂养,还可扩展至宠物店、动物养殖场等场景,具有较高的实用价值和社会意义。

二、实物效果展示

2.1实物图片

2.2实物演示视频

【开源】基于STM32的智能宠物喂食系统

三、硬件功能简介

3.1项目功能详解

  1. 传感器检测:检测温湿度、光照强度、水位传感器等数据。
  2. 食物称重:HX711可以实时检测宠物的食物重量。
  3. 数据显示:0.96OLED屏幕显示全部的传感器数据以及传感器的阈值等数据。
  4. 执行机构:步进电机(模拟喂食)、水泵(补充水分)、灯光。
  5. 定时喂食:采用时钟模块可以设定实时时间,同时可以设定自动喂食的时间。
  6. 接入云平台:系统通过ESP8266 WIFI联网后,接入机智云平台。
  7. App远程监控:通过App远程监控全部传感器数据;App远程控制、喂食、水泵、灯光。
  8. 阈值数据设定:系统通过按键设定阈值,也可以通过手机App远程设定。
  9. 模式切换:可以通过按键或者手机App实现自动/手动模式的切换。
  10. 手动模式:通过手机App或小程序控制喂食、补充水分、灯光等
  11. 自动模式:根据设定的食物重量阈值,低于阈值,自动开启补充食物;设定水位阈值,低于水位阈值将会自动开启水泵补水;设定光照阈值,低于光照阈值将会自动开启补光灯。

3.2元器件清单

  1. 主控STM32F103C8T6单片机
  2. ESP8266联网WiFi
  3. 0.96OLED显示屏幕
  4. 光敏电阻光照传感器
  5. 水位传感器
  6. DHT11温湿度传感器
  7. HX711称重传感器
  8. DS1302时钟模块
  9. 步进电机、水泵、LED灯片。

四、主框图与软件流程图

主框图

流程图

五、硬件PCB展示

六、软件程序设计

#include "delay.h"
#include "sys.h"
#include "adc.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "control.h"
#include "dht11.h"
#include "hx711.h"
#include "uln2003.h"
#include "timer.h"
#include "ds1302.h"

/****  数据变量  ****/
uint16_t timeone = 0;		//喂食 小时
uint16_t timetwo = 0;		//喂食 分钟

uint8_t food_flag = 0;		//喂食
uint8_t water_flag = 0;		//补水
uint8_t led_flag = 0;		//补光

uint8_t auto_mode = 0;		//自动模式开关	0关闭	1开启

int temp_door=30;
int hum_door=20;
int level_door = 0;
int weight_door = 500;
int light_door = 3000;

/****  菜单变量  ****/
uint8_t option = 0;
uint8_t keu_num = 0;
uint8_t page_num = 1;

/****  功能函数声明  ****/
void Key_event_handle(void);	//按键功能函数
void get_all_sensor_data();		//传感器数据采集
void Sensor_Data_Handle();		//不同模式下控制效果

void OLED_Show_FirstPage();		//第一屏显示内容
void OLED_Show_SecondPage();	//第二屏显示内容
void OLED_Show_ThirdPage();		//第三屏显示内容

int value;
float weight;
int32_t reset;
u8 bufff[30];
u16 light;

float Weights=38642.0;  //100g
int32_t Weights_100=8493860;  //100g

int main(void)
{
//	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	delay_init();				//系统延时函数初始化
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//改变指定管脚的映射,JTAG-DP 禁用 + SW-DP 使能
	OLED_Init();				//屏幕初始化
	uart3_init(9600);			//串口3初始化,波特率9600
	uart1_init(115200);			//串口1初始化,波特率115200
	HX711_Init();				//称重模块初始化
	reset = HX711_GetData();	//称重数据归零(去皮)
	KEY_Init();					//按键初始化
	DHT11_Init();				//DHT11温湿度初始化
	Adc_Init();					//水位、光照强度初始化
	Control_Init();				//水泵、补光灯初始化
	DS1302_Init(&SysDate);		//DS1302时钟初始化
	DS1302_DateSet(&SysDate);	//DS1302时钟设置
	LED=0;
	Uln2003_Init();				//步进电机初始化
	TIME_Config();				//定时器初始化
	while(1)
	{
		if(Time_Period[0]>1000){		//Time_Period[1] 在定时器中累加
			get_all_sensor_data();		//传感器数据采集
			Time_Period[0]=0;			
			printf("温度:%d℃,湿度:%d%%RH\r\n",temp,hum);
			printf("水位:%d%%,光照:%dLux\r\n",Water_Value,Light_Value);
			printf("食物重量:%dg\r\n",(int)weight);
		}
		Key_event_handle();			//按键监测
		if(page_num == 1){			//屏幕更新
			OLED_Show_FirstPage();
		}else if(page_num == 2){
			OLED_Show_SecondPage();
		}else if(page_num == 3){
			OLED_Show_ThirdPage();
		}
		Sensor_Data_Handle();		//数据处理
	}
}
  
void Sensor_Data_Handle()
{
	//手动模式开关控制
	if(auto_mode==0){
		if(water_flag==1){	//水泵开关
			water = 1;
		}else water = 0;
		
		if(led_flag==1){	//照明开关
			LED = 1;
		}else LED = 0;
		
		if(food_flag==1){	//喂食开关
			Stepper_RotateByLoop(1,1,1);
			food_flag=0;
		}
		//定时喂食
		if(SysDate.hour==timeone&&SysDate.min==timetwo&&SysDate.sec==0)food_flag=1;

	}else if(auto_mode==1){
		//食物重量低于阈值,步进电机转动喂食
		if(weight<weight_door)Stepper_RotateByLoop(1,1,1);
		//水位低于阈值,打开水泵补水
		if(Water_Value<level_door)water=1;
		else water=0;
		//光照强度低于阈值,打开补光灯
		if(Light_Value<light_door)LED=1;
		else LED=0;
	}
}

void get_all_sensor_data()
{
	DHT11_Read_Data(&temp,&hum);    	//获取温湿度数据
	value = HX711_GetData();			//获取称重数据
	weight=(float)(value-reset)*Weights/(float)(Weights_100-reset);
	Get_Water_Value(&Water_Value);		//获取水位数据
	Get_Light_Value(&Light_Value);		//获取光照强度数据
	DS1302_DateRead(&SysDate);			//读时间
}

void Key_event_handle(void)
{
	keu_num = KEY_Scan(0);		//按键扫描赋值
	switch(keu_num)
	{
		case 1:		//按键1按下
			if(page_num==1){
				page_num=2;
				OLED_Clear();OLED_Show_SecondPage();
			}else if(page_num==2){
				option++;
				if(option==6){
					option=0;page_num=3;
					OLED_Clear();OLED_Show_ThirdPage();
				}else OLED_Show_SecondPage();
			}else if(page_num==3){
				option++;
				if(option==4){
					option=0;page_num=1;
					OLED_Clear();OLED_Show_FirstPage();
				}else OLED_Show_ThirdPage();
			}
			break;
		case 2:		//按键2按下
			if(page_num==1){
				auto_mode = 1;
			}else if(page_num==2){
				if(option==1){
					level_door++;
				}else if(option==2){
					weight_door+=10;
				}else if(option==3){
					light_door+=15;
				}else if(option==4){
					timeone++;
					if(timeone==24)timeone=0;
				}else if(option==5){
					timetwo++;
					if(timetwo==60)timetwo=0;
				}
			}else if(page_num==3){
				if(option==1){
					led_flag=1;
				}else if(option==2){
					water_flag=1;
				}else if(option==3){
					food_flag=1;
				}			
			}
			break;
		case 3:		//按键3按下
			if(page_num==1){
				auto_mode = 0;
			}else if(page_num==2){
				if(option==1){
					if(level_door>0)level_door--;
				}else if(option==2){
					if(weight_door>0)weight_door-=10;
				}else if(option==3){
					if(light_door>0)light_door-=15;
				}else if(option==4){
					timeone--;
					if(timeone>24)timeone=23;
				}else if(option==5){
					timetwo--;
					if(timetwo>60)timetwo=59;
				}
			}else if(page_num==3){
				if(option==1){
					led_flag=0;
				}else if(option==2){
					water_flag=0;
				}else if(option==3){
					food_flag=1;
				}			
			}
			break;
		case 4:		//按键4按下
			break;
	}
}

/*
 氨(0) 气(1) 浓(2) 度(3) 温(4) 水(5) 位(6) 自(7) 动(8) 喂(9) 食(10) 补(11) 水(12) 间(13) 隔(14) 次(15)
 数(16) 时(17) 长(18) 开(19) 关(20) ℃(21) 饲(22) 料(23) 设(24) 置(25) 最(26) 低(27) 高(28 重(29) 量(30)
 质(31) 光(32) 照(33) AUTO(34) 定(35) 有(36) 害(37) 气(38) 体(39) 湿(40) 阈(41) 值(42) 自(43) 手(44) 动(45)
*/
void OLED_Show_FirstPage(){

	OLED_ShowChar(8*8,0,SysDate.year/10+'0',8,1);
	OLED_ShowChar(8*9,0,SysDate.year%10+'0',8,1);
	OLED_ShowChar(8*10,0,'/',8,1);
	OLED_ShowChar(8*11,0,SysDate.mon/10+'0',8,1);
	OLED_ShowChar(8*12,0,SysDate.mon%10+'0',8,1);
	OLED_ShowChar(8*13,0,'/',8,1);
	OLED_ShowChar(8*14,0,SysDate.day/10+'0',8,1);
	OLED_ShowChar(8*15,0,SysDate.day%10+'0',8,1);
	
	OLED_ShowChar(8*8,8,SysDate.hour/10+'0',8,1);
	OLED_ShowChar(8*9,8,SysDate.hour%10+'0',8,1);
	OLED_ShowChar(8*10,8,':',8,1);
	OLED_ShowChar(8*11,8,SysDate.min/10+'0',8,1);
	OLED_ShowChar(8*12,8,SysDate.min%10+'0',8,1);
	OLED_ShowChar(8*13,8,':',8,1);
	OLED_ShowChar(8*14,8,SysDate.sec/10+'0',8,1);
	OLED_ShowChar(8*15,8,SysDate.sec%10+'0',8,1);

	OLED_ShowChar(8*0,0,'T',16,1);
	OLED_ShowChar(8*1,0,':',16,1);
	OLED_ShowNum(16*1,0,temp,2,16,1);
	OLED_ShowChinese(16*2,0,21,16,1);
	
	OLED_ShowChar(8*0,16,'H',16,1);
	OLED_ShowChar(8*1,16,':',16,1);
	OLED_ShowNum(16*1,16,hum,2,16,1);
	OLED_ShowChar(16*2,16,'%',16,1);

	OLED_ShowChinese(16*3+8,16,32,16,1);			//光照
	OLED_ShowChinese(16*4+8,16,33,16,1);
	OLED_ShowChar(16*5+8,16,':',16,1);
	OLED_ShowNum(16*6,16,Light_Value,4,16,1);

	OLED_ShowChinese(16*0,32,5,16,1);			//水位
	OLED_ShowChinese(16*1,32,6,16,1);
	OLED_ShowChar(16*2,32,':',16,1);
	OLED_ShowNum(16*2+8,32,Water_Value,2,16,1);
	
	OLED_ShowChinese(16*0,48,10,16,1);		//食重
	OLED_ShowChinese(16*1,48,29,16,1);
	OLED_ShowChar(16*2,48,':',16,1);
	OLED_ShowNum(16*2+8,48,weight,4,16,1);
	OLED_ShowChar(16*4+8,48,'g',16,1);
	
	if(auto_mode==1){
		OLED_ShowChinese(16*6,48,43,16,1);
	}else{
		OLED_ShowChinese(16*6,48,44,16,1);
	}	
	OLED_ShowChinese(16*7,48,45,16,1);

	OLED_Refresh();
}

void OLED_Show_SecondPage(){



	OLED_ShowChinese(16*0,0,5,16,1);	//水位阈值
	OLED_ShowChinese(16*1,0,6,16,1);
	OLED_ShowChinese(16*2,0,41,16,1);
	OLED_ShowChinese(16*3,0,42,16,1);
	OLED_ShowChar(16*4,0,':',16,1);
	if(option==1)OLED_ShowNum(16*4+8,0,level_door,3,16,0);
	else OLED_ShowNum(16*4+8,0,level_door,3,16,1);
	
	OLED_ShowChinese(16*0,16,10,16,1);	//食重阈值
	OLED_ShowChinese(16*1,16,29,16,1);
	OLED_ShowChinese(16*2,16,41,16,1);
	OLED_ShowChinese(16*3,16,42,16,1);
	OLED_ShowChar(16*4,16,':',16,1);
	if(option==2)OLED_ShowNum(16*4+8,16,weight_door,4,16,0);
	else OLED_ShowNum(16*4+8,16,weight_door,4,16,1);
	
	OLED_ShowChinese(16*0,32,32,16,1);	//光照阈值
	OLED_ShowChinese(16*1,32,33,16,1);
	OLED_ShowChinese(16*2,32,41,16,1);
	OLED_ShowChinese(16*3,32,42,16,1);
	OLED_ShowChar(16*4,32,':',16,1);
	if(option==3)OLED_ShowNum(16*4+8,32,light_door,4,16,0);
	else OLED_ShowNum(16*4+8,32,light_door,4,16,1);	

	OLED_ShowChinese(16*0,48,35,16,1);	//定时喂食
	OLED_ShowChinese(16*1,48,17,16,1);
	OLED_ShowChinese(16*2,48,9,16,1);
	OLED_ShowChinese(16*3,48,10,16,1);
	OLED_ShowChar(16*4,48,':',16,1);
	if(option==4)OLED_ShowNum(16*4+8,48,timeone,2,16,0);
	else OLED_ShowNum(16*4+8,48,timeone,2,16,1);
	OLED_ShowChar(16*5+8,48,':',16,1);
	if(option==5)OLED_ShowNum(16*6,48,timetwo,2,16,0);
	else OLED_ShowNum(16*6,48,timetwo,2,16,1);
	
	OLED_Refresh();
	
}
void OLED_Show_ThirdPage(){

	//补光开关
	if(option==1){
		OLED_ShowChinese(16*0,0,11,16,0);
		OLED_ShowChinese(16*1,0,32,16,0);
	}else{
		OLED_ShowChinese(16*0,0,11,16,1);
		OLED_ShowChinese(16*1,0,32,16,1);
	}
	OLED_ShowChar(16*2,0,':',16,1);
	if(led_flag==1)OLED_ShowChinese(16*2+8,0,19,16,1);
	else OLED_ShowChinese(16*2+8,0,20,16,1);

	//补水开关
	if(option==2){
		OLED_ShowChinese(16*0,16,11,16,0);
		OLED_ShowChinese(16*1,16,5,16,0);
	}else{
		OLED_ShowChinese(16*0,16,11,16,1);
		OLED_ShowChinese(16*1,16,5,16,1);
	}
	OLED_ShowChar(16*2,16,':',16,1);
	if(water_flag==1)OLED_ShowChinese(16*2+8,16,19,16,1);
	else OLED_ShowChinese(16*2+8,16,20,16,1);
	
	//喂食
	if(option==3){
		OLED_ShowChinese(16*0,32,9,16,0);
		OLED_ShowChinese(16*1,32,10,16,0);
	}else{
		OLED_ShowChinese(16*0,32,9,16,1);
		OLED_ShowChinese(16*1,32,10,16,1);
	}
	OLED_Refresh();
}

七、项目资料包内容

         资料获取:查看主页介绍“充哥单片机设计”

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐