目录
[六、实验效果 编辑](#六、实验效果 编辑)
一、前言
项目成品图片:

哔哩哔哩视频链接:
(资料分享见文末)
二、项目简介
1.功能详解
基于STM32的智能家居语音系统
功能如下:
- 温湿度采集:DHT11检测宠物窝的温湿度。
- 宠物靠近检测:光电红外传感器检测是否有宠物靠近。
- 重量检测:HX711称重模块检测投喂食物的重量
- 水位检测:通过水位传感器检测喂水水位
- 屏幕显示:OLED屏实时显示当前时间、宠物窝的温度、湿度,食物重量和水位。
- 投喂控制:步进电机模拟进行喂食控制
- 自动模式:达到定时时间后开启自动喂食同时扬声器播报语音并伴随蜂鸣器提醒,喂食后重量达到设定值再返回结束喂食;当宠物靠近且水位低于阈值时候自动喂水
- 手动模式:手动模式下通过按键可控制喂食和喂水的开关功能
- 模式切换:按键可切换自动模式和手动模式
- 阈值调节:按键可设置当前时间、3个定时喂食的时间、食物重量阈值和水位阈值
- 手机APP:通过蓝牙连接手机APP可接收当前环境信息数据,可切换模式和完成控制指令下发
2.主要器件
- STM32F103C8T6单片机
- DHT11温湿度传感器
- OLED 屏幕
- HX711称重模块
- 光电红外传感器
- BT04A(蓝牙)
- LED灯
- 步进电机
- ULN2003步进电机驱动芯片
- JR6001语音模块
- 水位传感器
- 有源蜂鸣器
- 扬声器
- 继电器
- 水泵
三、原理图设计

四、PCB硬件设计
PCB图


五、程序设计
cpp
#include "stm32f10x.h"
#include "led.h"
#include "beep.h"
#include "usart.h"
#include "usart2.h"
#include "usart3.h"
#include "delay.h"
#include "dht11.h"
#include "oled.h"
#include "key.h"
#include "Modules.h"
#include "TIM2.h"
#include "adcx.h"
#include "flash.h"
#include "stepmotor.h"
#include "bump.h"
#include "HW.h"
#include "hx711.h"
#include "water.h"
#include "relay.h"
#include "rtc.h"
/****************异方辰电子工作室******************
STM32
* 项目 : 智能宠物喂食系统(蓝牙升级版)
* 版本 : V2.0
* 日期 : 2026.4.10
* MCU : STM32F103C8T6
* 接口 : 见代码
* IP账号 : 异方辰电子/辰哥单片机设计(同BILIBILI|抖音|快手|小红书|CSDN|公众号|视频号等)
* 作者 : 辰哥
* 工作室 : 异方辰电子工作室
* 授权IP : 辰哥单片机设计、异方辰电子、YFC电子、异方辰系列
* 官方网站 : www.yfcdz.cn
**********************BEGIN***********************/
#define KEY_Long1 11
#define KEY_1 1
#define KEY_2 2
#define KEY_3 3
#define KEY_4 4
#define FLASH_START_ADDR 0x0801f000 //写入的起始地址
uint8_t dakai = 0; // 建议初始化,避免随机值
uint8_t Flag_dakai = 0; // 同时定义 Flag_dakai(如果也报同样错误)
extern uint8_t rtc_get_flag;
SensorModules sensorData; //声明传感器数据结构体变量
SensorThresholdValue Sensorthreshold; //声明传感器阈值结构体变量
DriveModules driveData; //声明驱动器状态结构体变量
uint8_t mode = 1; //系统模式 1自动 2手动 3设置
int32_t reset;
uint8_t location = 1; // 时间位置
static uint8_t count_w = 1; //设置阈值位置按键数
uint8_t set_flag = 1;
uint8_t ss_flag = 1;
uint8_t count = 0;
uint8_t date;
float Pi_weight;
uint8_t food_flag_1 = 0;
uint8_t food_flag_2 = 0;
uint8_t food_flag_3 = 0;
uint8_t bobao_flag = 1;
uint32_t time_num = 1;
_calendar_obj set_time;
//系统静态变量
static uint8_t count_a = 1; //自动模式按键数
static uint8_t count_m = 1; //手动模式按键数
static uint8_t count_s = 1; //设置模式按键数
//static uint8_t LED_Flag = 0;
//static uint8_t Curtain_Flag = 0;
//static uint8_t Window_Flag = 0;
//static uint8_t Fan_Flag = 0;
//static uint8_t Humidifier_Flag = 0;
//static uint8_t Bump_Flag = 0;
//static uint8_t NOW_Curtain_Flag = 0;
//static uint8_t NOW_Window_Flag = 0;
//void Public(void);
void Flag_Writer(void);
/**
* @brief 显示菜单内容
* @param 无
* @retval 无
*/
enum
{
AUTO_MODE = 1,
MANUAL_MODE,
SETTINGS_MODE
}MODE_PAGES;
/**
* @brief 显示菜单1的固定内容
* @param 无
* @retval 无
*/
void OLED_autoPage1(void) //自动模式菜单第一页
{
//显示"环境温度: C"
OLED_ShowChinese(0,16,13,16,1); //环
OLED_ShowChinese(16,16,14,16,1); //境
OLED_ShowChinese(32,16,0,16,1); //温
OLED_ShowChinese(48,16,2,16,1); //度
OLED_ShowChar(64,16,':',16,1);
//显示"环境湿度: %"
OLED_ShowChinese(0,32,13,16,1); //环
OLED_ShowChinese(16,32,14,16,1);//境
OLED_ShowChinese(32,32,1,16,1); //湿
OLED_ShowChinese(48,32,2,16,1); //度
OLED_ShowChar(64,32,':',16,1);
OLED_ShowChinese(0,48,24,16,1); //质
OLED_ShowChinese(16,48,25,16,1);//量
OLED_ShowChar(64,48,':',16,1);
OLED_Refresh();
}
void OLED_autoPage2(void) //自动模式菜单第二页
{
OLED_ShowChinese(0,0,38,16,1); //水
OLED_ShowChinese(16,0,44,16,1);//位
OLED_ShowChar(64,0,':',16,1);
OLED_Refresh();
}
void SensorDataDisplay1(void) //传感器数据显示第一页
{
char display_buf[48];
sprintf(display_buf,"%02d:%02d:%02d",sensorData.calendarData.hour,sensorData.calendarData.min,sensorData.calendarData.sec);
OLED_ShowString(32,0,(uint8_t*)display_buf,16,1);
//显示温度数据
OLED_ShowNum(90,16,sensorData.temp,2,16,1);
//显示湿度数据
OLED_ShowNum(90,32,sensorData.humi,2,16,1);
OLED_ShowNum(90,48,sensorData.weight,4,16,1);
OLED_Refresh();
char all_data[128]; // 足够大的缓冲区容纳所有数据
const char* person_status = sensorData.HW ? "是" : "否";
// 一次性格式化所有数据到同一个字符串
sprintf(all_data, " 温度: %d\r\n 湿度: %d \r\n 质量: %.0f\r\n 水位:%d \r\n 宠物靠近: %s\r\n",
sensorData.temp, // p 是字符串,用 %s 输出
sensorData.humi,
sensorData.weight,
sensorData.water,
person_status
);
USART2_SendString(all_data); // 一次发送所有数据
printf("温度:%d\r\n",sensorData.temp);
printf("湿度:%d\r\n",sensorData.humi);
printf("重量:%.0f\r\n",sensorData.weight);
printf("是否有宠物:%s\r\n",sensorData.HW ? "是" : "否");
}
void SensorDataDisplay2(void) //传感器数据显示第二页
{
//显示水位数据
OLED_ShowNum(90,0,sensorData.water,4,16,1);
OLED_Refresh();
char all_data[128]; // 足够大的缓冲区容纳所有数据
const char* person_status = sensorData.HW ? "是" : "否";
// 一次性格式化所有数据到同一个字符串
sprintf(all_data, " 温度: %d\r\n 湿度: %d \r\n 质量: %.0f\r\n 水位:%d \r\n 宠物靠近: %s\r\n",
sensorData.temp, // p 是字符串,用 %s 输出
sensorData.humi,
sensorData.weight,
sensorData.water,
person_status
);
USART2_SendString(all_data); // 一次发送所有数据
}
/**
* @brief 显示手动模式设置界面1
* @param 无
* @retval 无
*/
void OLED_manualPage1(void)
{
//显示"喂食"
OLED_ShowChinese(16,16,45,16,1);
OLED_ShowChinese(32,16,46,16,1);
OLED_ShowChar(64,16,':',16,1);
//显示"水泵"
OLED_ShowChinese(16,0,38,16,1);
OLED_ShowChinese(32,0,39,16,1);
OLED_ShowChar(64,0,':',16,1);
OLED_Refresh();
}
/**
* @brief 显示手动模式设置界面2
* @param 无
* @retval 无
*/
void OLED_manualPage2(void)
{
}
/**
* @brief 显示手动模式设置参数界面1
* @param 无
* @retval 无
*/
void ManualSettingsDisplay1(void)
{
if(driveData.Water_Flag)
{
OLED_ShowChinese(96,0,40,16,1); //开
}
else
{
OLED_ShowChinese(96,0,42,16,1); //关
}
if(driveData.Food_Flag)
{
OLED_ShowChinese(96,16,40,16,1); //开
}
else
{
OLED_ShowChinese(96,16,42,16,1); //关
}
OLED_Refresh();
}
/**
* @brief 显示手动模式设置参数界面2
* @param 无
* @retval 无
*/
void ManualSettingsDisplay2(void)
{
}
/**
* @brief 显示系统阈值设置界面1
* @param 无
* @retval 无
*/
void OLED_settingsPage1(void)
{
//显示"时间"
OLED_ShowChinese(16,0,49,16,1);
OLED_ShowChinese(32,0,47,16,1);
OLED_ShowChar(48,0,':',16,1);
OLED_ShowChinese(16,16,48,16,1);
OLED_ShowChinese(32,16,49,16,1);
OLED_ShowChar(48, 16, '1', 16, 1);
OLED_ShowChar(64,16,':',16,1);
OLED_ShowChinese(16,32,48,16,1);
OLED_ShowChinese(32,32,49,16,1);
OLED_ShowChar(48, 32, '2', 16, 1);
OLED_ShowChar(64,32,':',16,1);
OLED_ShowChinese(16,48,48,16,1);
OLED_ShowChinese(32,48,49,16,1);
OLED_ShowChar(48, 48, '3', 16, 1);
OLED_ShowChar(64,48,':',16,1);
OLED_Refresh();
}
void OLED_settingsPage2(void)
{
//显示"食物阈值"
OLED_ShowChinese(16,0,46,16,1);
OLED_ShowChinese(32,0,50,16,1);
OLED_ShowChinese(48,0,26,16,1);
OLED_ShowChinese(64,0,27,16,1);
OLED_ShowChar(80,0,':',16,1);
//显示"水位阈值"
OLED_ShowChinese(16,16,38,16,1);
OLED_ShowChinese(32,16,44,16,1);
OLED_ShowChinese(48,16,26,16,1);
OLED_ShowChinese(64,16,27,16,1);
OLED_ShowChar(80,16,':',16,1);
OLED_Refresh();
}
void SettingsThresholdDisplay1(void)
{
uint8_t display_buf[48];
// 显示时间
sprintf((char*)display_buf,"%02d:%02d:%02d",set_time.hour,set_time.min,set_time.sec);
OLED_ShowString(64, 0, display_buf, 16, 1);
// 显示开启时间
sprintf((char*)display_buf,"%02d:%02d",Sensorthreshold.time_Value_1.hour, Sensorthreshold.time_Value_1.min);
OLED_ShowString(88, 16, display_buf, 16, 1);
sprintf((char*)display_buf,"%02d:%02d",Sensorthreshold.time_Value_2.hour, Sensorthreshold.time_Value_2.min);
OLED_ShowString(88, 32, display_buf, 16, 1);
sprintf((char*)display_buf,"%02d:%02d",Sensorthreshold.time_Value_3.hour, Sensorthreshold.time_Value_3.min);
OLED_ShowString(88, 48, display_buf, 16, 1);
OLED_Refresh();
}
void SettingsThresholdDisplay2(void)
{
//显示喂食阈值数值
OLED_ShowNum(88, 0, Sensorthreshold.weight_Value, 4, 16, 1);
//显示水位阈值数值
OLED_ShowNum(88, 16, Sensorthreshold.water_Value, 4, 16, 1);
OLED_Refresh();
}
/**
* @brief 记录自动模式界面下按KEY2的次数
* @param 无
* @retval 返回次数
*/
uint8_t SetAuto(void)
{
if(KeyNum == KEY_2)
{
KeyNum = 0;
count_a++;
if (count_a > 2)
{
count_a = 1;
}
OLED_Clear();
}
return count_a;
}
/**
* @brief 记录手动模式界面下按KEY2的次数
* @param 无
* @retval 返回次数
*/
uint8_t SetManual(void)
{
if(KeyNum == KEY_2)
{
KeyNum = 0;
count_m++;
// if (count_m == 5)
// {
// OLED_Clear();
// }
if (count_m > 2) //一共可以控制的外设数量
{
OLED_Clear();
count_m = 1;
}
}
return count_m;
}
/**
* @brief 记录阈值界面下按KEY2的次数
* @param 无
* @retval 返回次数
*/
uint8_t SetSelection(void)
{
if(KeyNum == KEY_2)
{
KeyNum = 0;
count_s++;
if (count_s == 5)
{
OLED_Clear();
}
else if (count_s > 6)
{
OLED_Clear();
count_s = 1;
}
}
return count_s;
}
/**
* @brief 显示手动模式界面的选择符号
* @param num 为显示的位置
* @retval 无
*/
void OLED_manualOption(uint8_t num)
{
switch(num)
{
case 1:
OLED_ShowChar(0, 0,'>',16,1);
OLED_ShowChar(0,16,' ',16,1);
OLED_ShowChar(0,32,' ',16,1);
OLED_ShowChar(0,48,' ',16,1);
break;
case 2:
OLED_ShowChar(0, 0,' ',16,1);
OLED_ShowChar(0,16,'>',16,1);
OLED_ShowChar(0,32,' ',16,1);
OLED_ShowChar(0,48,' ',16,1);
break;
default: break;
}
}
/**
* @brief 显示阈值界面的选择符号
* @param num 为显示的位置
* @retval 无
*/
void OLED_settingsOption(uint8_t num)
{
switch(num)
{
case 1:
OLED_ShowChar(0, 0,'>',16,1);
OLED_ShowChar(0,16,' ',16,1);
OLED_ShowChar(0,32,' ',16,1);
OLED_ShowChar(0,48,' ',16,1);
break;
case 2:
OLED_ShowChar(0, 0,' ',16,1);
OLED_ShowChar(0,16,'>',16,1);
OLED_ShowChar(0,32,' ',16,1);
OLED_ShowChar(0,48,' ',16,1);
break;
case 3:
OLED_ShowChar(0, 0,' ',16,1);
OLED_ShowChar(0,16,' ',16,1);
OLED_ShowChar(0,32,'>',16,1);
OLED_ShowChar(0,48,' ',16,1);
break;
case 4:
OLED_ShowChar(0, 0,' ',16,1);
OLED_ShowChar(0,16,' ',16,1);
OLED_ShowChar(0,32,' ',16,1);
OLED_ShowChar(0,48,'>',16,1);
break;
case 5:
OLED_ShowChar(0, 0,'>',16,1);
OLED_ShowChar(0,16,' ',16,1);
OLED_ShowChar(0,32,' ',16,1);
OLED_ShowChar(0,48,' ',16,1);
break;
case 6:
OLED_ShowChar(0, 0,' ',16,1);
OLED_ShowChar(0,16,'>',16,1);
OLED_ShowChar(0,32,' ',16,1);
OLED_ShowChar(0,48,' ',16,1);
default: break;
}
}
/**
* @brief 自动模式控制函数
* @param 无
* @retval 无
*/
void AutoControl(void)
{
if ((sensorData.calendarData.hour == Sensorthreshold.time_Value_1.hour && sensorData.calendarData.min == Sensorthreshold.time_Value_1.min)
&& (food_flag_1 == 0))
{
driveData.Food_Flag = 1;
food_flag_1 = 1;
driveData.Beep_Flag = 1;
}
if ((sensorData.calendarData.hour == Sensorthreshold.time_Value_2.hour && sensorData.calendarData.min == Sensorthreshold.time_Value_2.min)
&& (food_flag_2 == 0))
{
driveData.Food_Flag = 1;
food_flag_2 = 1;
driveData.Beep_Flag = 1;
}
if ((sensorData.calendarData.hour == Sensorthreshold.time_Value_3.hour && sensorData.calendarData.min == Sensorthreshold.time_Value_3.min)
&& (food_flag_3 == 0))
{
driveData.Food_Flag = 1;
food_flag_3 = 1;
driveData.Beep_Flag = 1;
}
if (abs((int)sensorData.weight) >= Sensorthreshold.weight_Value)
{
driveData.Food_Flag = 0;
}
if (date != sensorData.calendarData.w_date)
{
date = sensorData.calendarData.w_date;
food_flag_1 = 0;
food_flag_2 = 0;
food_flag_3 = 0;
}
if ((sensorData.water < Sensorthreshold.water_Value) && (sensorData.HW == 1))
{
driveData.Water_Flag = 1;
}
else
{
driveData.Water_Flag = 0;
}
}
/**
* @brief 手动模式控制函数
* @param 无
* @retval 无
*/
void ManualControl(uint8_t num)
{
switch(num)
{
case 1:
if (KeyNum == KEY_3)
{
driveData.Water_Flag = 1;
KeyNum = 0;
}
if (KeyNum == KEY_4)
{
driveData.Water_Flag = 0;
KeyNum = 0;
}
break;
case 2:
if (KeyNum == KEY_3)
{
driveData.Food_Flag = 1;
KeyNum = 0;
}
if (KeyNum == KEY_4)
{
driveData.Food_Flag = 0;
// date = sensorData.calendarData.w_date;
// food_flag_1 = 0;
// food_flag_2 = 0;
// food_flag_3 = 0;
KeyNum = 0;
}
break;
default: break;
}
}
/**
* @brief 控制函数
* @param 无
* @retval 无
*/
void Control_Manager(void)
{
if (driveData.Beep_Flag)
{
if (count < 3)
{
if (ss_flag)
{
ss_flag = 0;
BEEP_On();
}
else
{
ss_flag = 1;
BEEP_Off();
}
count++;
}
else
{
count = 0;
driveData.Beep_Flag = 0;
}
}
else
{
BEEP_Off();
}
if (driveData.Food_Flag)
{
if (driveData.Now_Food_Flag == 0)
{
if (bobao_flag)
{
//music_play(1);
USART3_SendString("A7:00002");
bobao_flag = 0;
}
driveData.Now_Food_Flag = 1;
MOTOR_Direction_Angle(0,0,180,1);
}
}
else
{
bobao_flag = 1;
if (driveData.Now_Food_Flag == 1)
{
driveData.Now_Food_Flag = 0;
MOTOR_Direction_Angle(1,0,180,1);
}
}
if (driveData.Water_Flag)
{
RELAY_ON;
}
else
{
RELAY_OFF;
}
}
void OLED_Show_SettingTime()
{
if (location == 1)
{
OLED_ShowString(64, 0, (uint8_t*)" ", 16, 1);
}
else if (location == 2)
{
OLED_ShowString(88, 0, (uint8_t*)" ", 16, 1);
}
else if (location == 3)
{
OLED_ShowString(112, 0, (uint8_t*)" ", 16, 1);
}
else if (location == 4)
{
OLED_ShowString(88, 16, (uint8_t*)" ", 16, 1);
}
else if (location == 5)
{
OLED_ShowString(112, 16, (uint8_t*)" ", 16, 1);
}
else if (location == 6)
{
OLED_ShowString(88, 32, (uint8_t*)" ", 16, 1);
}
else if (location == 7)
{
OLED_ShowString(112, 32, (uint8_t*)" ", 16, 1);
}
else if (location == 8)
{
OLED_ShowString(88, 48, (uint8_t*)" ", 16, 1);
}
else if (location == 9)
{
OLED_ShowString(112, 48, (uint8_t*)" ", 16, 1);
}
}
/**
* @brief 阈值设置函数
* @param 无
* @retval 无
*/
void ThresholdSettings(uint8_t num)
{
if (num <= 4)
{
OLED_settingsPage1(); //显示阈值设置界面1固定信息
SettingsThresholdDisplay1(); //显示传感器阈值1数据
}
else //否则显示设置页面2
{
OLED_settingsPage2(); //显示阈值设置界面2固定信息
SettingsThresholdDisplay2(); //显示传感器阈值2数据
}
OLED_settingsOption(num); //实现阈值设置页面的选择功能
switch (num)
{
case 1:
OLED_settingsPage1();
while (1)
{
OLED_Show_SettingTime();
if (KeyNum == KEY_3 )
{
KeyNum = 0;
if (location == 1)
{
set_time.hour += 1;
if (set_time.hour > 23)
{
set_time.hour = 0;
}
}
if (location == 2)
{
set_time.min += 1;
if (set_time.min > 59)
{
set_time.min = 0;
}
}
if (location == 3)
{
set_time.sec += 1;
if (set_time.sec > 59)
{
set_time.sec = 0;
}
}
}
if (KeyNum == KEY_4 )
{
KeyNum = 0;
if (location == 1)
{
set_time.hour -= 1;
if (set_time.hour > 23)
{
set_time.hour = 23;
}
}
if (location == 2)
{
set_time.min -= 1;
if (set_time.min > 59)
{
set_time.min = 59;
}
}
if (location == 3)
{
set_time.sec -= 1;
if (set_time.sec > 59)
{
set_time.sec = 59;
}
}
}
if (KeyNum == KEY_2 )
{
KeyNum = 0;
location++;
if (location > 3)
{
++count_w;
// OLED_settingsOption(++count_w);
break;
}
}
if (KeyNum == KEY_1)
{
count_a = 1;
Flag_Writer();
break;
}
SettingsThresholdDisplay1();
}
break;
case 2:
while (1)
{
OLED_Show_SettingTime();
if (KeyNum == KEY_3 )
{
KeyNum = 0;
if (location == 4)
{
Sensorthreshold.time_Value_1.hour += 1;
food_flag_1 = 0;
if (Sensorthreshold.time_Value_1.hour > 23)
{
Sensorthreshold.time_Value_1.hour = 0;
}
}
if (location == 5)
{
Sensorthreshold.time_Value_1.min += 1;
food_flag_1 = 0;
if (Sensorthreshold.time_Value_1.min > 59)
{
Sensorthreshold.time_Value_1.min = 0;
}
}
}
else if (KeyNum == KEY_4 )
{
KeyNum = 0;
if (location == 4)
{
Sensorthreshold.time_Value_1.hour -= 1;
food_flag_1 = 0;
if (Sensorthreshold.time_Value_1.hour > 23)
{
Sensorthreshold.time_Value_1.hour = 23;
}
}
if (location == 5)
{
Sensorthreshold.time_Value_1.min -= 1;
food_flag_1 = 0;
if (Sensorthreshold.time_Value_1.min > 59)
{
Sensorthreshold.time_Value_1.min = 59;
}
}
}
else if (KeyNum == KEY_2)
{
KeyNum = 0;
location++;
if (location > 5)
{
++count_w;
break;
}
}
if (KeyNum == KEY_1)
{
count_a = 1;
set_flag = 1;
Flag_Writer();
break;
}
SettingsThresholdDisplay1();
}
break;
case 3:
while (1)
{
OLED_Show_SettingTime();
if (KeyNum == KEY_3 )
{
KeyNum = 0;
if (location == 6)
{
Sensorthreshold.time_Value_2.hour += 1;
food_flag_2 = 0;
if (Sensorthreshold.time_Value_2.hour > 23)
{
Sensorthreshold.time_Value_2.hour = 0;
}
}
if (location == 7)
{
Sensorthreshold.time_Value_2.min += 1;
food_flag_2 = 0;
if (Sensorthreshold.time_Value_2.min > 59)
{
Sensorthreshold.time_Value_2.min = 0;
}
}
}
else if (KeyNum == KEY_4 )
{
KeyNum = 0;
if (location == 6)
{
Sensorthreshold.time_Value_2.hour -= 1;
food_flag_2 = 0;
if (Sensorthreshold.time_Value_2.hour > 23)
{
Sensorthreshold.time_Value_2.hour = 23;
}
}
if (location == 7)
{
Sensorthreshold.time_Value_2.min -= 1;
food_flag_2 = 0;
if (Sensorthreshold.time_Value_2.min > 59)
{
Sensorthreshold.time_Value_2.min = 59;
}
}
}
else if (KeyNum == KEY_2 )
{
KeyNum = 0;
location++;
if (location > 7)
{
// OLED_settingsOption(++count_w);
++count_w;
break;
}
}
if (KeyNum == KEY_1)
{
count_a = 1;
set_flag = 1;
Flag_Writer();
break;
}
SettingsThresholdDisplay1();
}
break;
case 4:
while (1)
{
OLED_Show_SettingTime();
if (KeyNum == KEY_3)
{
KeyNum = 0;
if (location == 8)
{
Sensorthreshold.time_Value_3.hour += 1;
food_flag_3 = 0;
if (Sensorthreshold.time_Value_3.hour > 23)
{
Sensorthreshold.time_Value_3.hour = 0;
}
}
if (location == 9)
{
Sensorthreshold.time_Value_3.min += 1;
food_flag_3 = 0;
if (Sensorthreshold.time_Value_3.min > 59)
{
Sensorthreshold.time_Value_3.min = 0;
}
}
}
else if (KeyNum == KEY_4 )
{
KeyNum = 0;
if (location == 8)
{
Sensorthreshold.time_Value_3.hour -= 1;
food_flag_3 = 0;
if (Sensorthreshold.time_Value_3.hour > 23)
{
Sensorthreshold.time_Value_3.hour = 23;
}
}
if (location == 9)
{
Sensorthreshold.time_Value_3.min -= 1;
food_flag_3 = 0;
if (Sensorthreshold.time_Value_3.min > 59)
{
Sensorthreshold.time_Value_3.min = 59;
}
}
}
else if (KeyNum == KEY_2 )
{
KeyNum = 0;
location++;
if (location > 9)
{
// OLED_settingsOption(++count_w);
++count_w;
location = 1;
OLED_Clear();
break;
}
}
if (KeyNum == KEY_1)
{
count_a = 1;
set_flag = 1;
break;
}
SettingsThresholdDisplay1();
}
case 5:
if (KeyNum == KEY_3 )
{
KeyNum = 0;
Sensorthreshold.weight_Value += 10;
if (Sensorthreshold.weight_Value >= 9000)
{
Sensorthreshold.weight_Value = 0;
}
}
else if (KeyNum == KEY_4 )
{
KeyNum = 0;
Sensorthreshold.weight_Value -= 10;
if (Sensorthreshold.weight_Value >= 9000)
{
Sensorthreshold.weight_Value = 9000;
}
}
else if (KeyNum == KEY_2 )
{
KeyNum = 0;
++count_w;
}
case 6:
if (KeyNum == KEY_3 )
{
KeyNum = 0;
Sensorthreshold.water_Value += 1;
if (Sensorthreshold.water_Value >= 100)
{
Sensorthreshold.water_Value = 0;
}
}
else if (KeyNum == KEY_4 )
{
KeyNum = 0;
Sensorthreshold.water_Value -= 1;
if (Sensorthreshold.water_Value >= 100)
{
Sensorthreshold.water_Value = 100;
}
}
else if (KeyNum == KEY_2 )
{
KeyNum = 0;
count_w = 1;
location = 1;
OLED_Clear();
}
default: break;
}
}
void Flag_Writer(void)
{
FLASH_W(FLASH_START_ADDR, Sensorthreshold.time_Value_1.hour, Sensorthreshold.time_Value_1.min,
Sensorthreshold.time_Value_2.hour, Sensorthreshold.time_Value_2.min,
Sensorthreshold.time_Value_3.hour, Sensorthreshold.time_Value_3.min,
Sensorthreshold.weight_Value, Sensorthreshold.water_Value);
RTC_Set(sensorData.calendarData.w_year, sensorData.calendarData.w_month, sensorData.calendarData.w_date, set_time.hour, set_time.min, set_time.sec);
sensorData.calendarData.hour = set_time.hour;
sensorData.calendarData.min = set_time.min;
sensorData.calendarData.sec = set_time.sec;
rtc_get_flag = 1;
}
void Flash_Time_Init(void)
{
Sensorthreshold.time_Value_1.hour = FLASH_R(FLASH_START_ADDR);
Sensorthreshold.time_Value_1.min = FLASH_R(FLASH_START_ADDR + 2);
Sensorthreshold.time_Value_2.hour = FLASH_R(FLASH_START_ADDR + 4);
Sensorthreshold.time_Value_2.min = FLASH_R(FLASH_START_ADDR + 6);
Sensorthreshold.time_Value_3.hour = FLASH_R(FLASH_START_ADDR + 8);
Sensorthreshold.time_Value_3.min = FLASH_R(FLASH_START_ADDR + 10);
Sensorthreshold.weight_Value = FLASH_R(FLASH_START_ADDR + 12);
Sensorthreshold.water_Value = FLASH_R(FLASH_START_ADDR + 14);
if (Sensorthreshold.time_Value_1.hour > 24 || Sensorthreshold.time_Value_1.min > 60
|| Sensorthreshold.time_Value_2.hour > 24 || Sensorthreshold.time_Value_2.min > 60
|| Sensorthreshold.time_Value_3.hour > 24 || Sensorthreshold.time_Value_3.min > 60)
{
FLASH_W(FLASH_START_ADDR, 12, 01, 12, 02, 12, 03, 800, 80);
}
Sensorthreshold.time_Value_1.hour = FLASH_R(FLASH_START_ADDR);
Sensorthreshold.time_Value_1.min = FLASH_R(FLASH_START_ADDR + 2);
Sensorthreshold.time_Value_2.hour = FLASH_R(FLASH_START_ADDR + 4);
Sensorthreshold.time_Value_2.min = FLASH_R(FLASH_START_ADDR + 6);
Sensorthreshold.time_Value_3.hour = FLASH_R(FLASH_START_ADDR + 8);
Sensorthreshold.time_Value_3.min = FLASH_R(FLASH_START_ADDR + 10);
Sensorthreshold.weight_Value = FLASH_R(FLASH_START_ADDR + 12);
Sensorthreshold.water_Value = FLASH_R(FLASH_START_ADDR + 14);
}
void USART2_ProcessCmd(void) // 串口2接收函数
{
if (USART2_GetReceivedFlag())
{
uint8_t* rx_buf = USART2_GetRxBuffer();
switch(rx_buf[0])
{
case 'A': // 模式切换
if (mode == AUTO_MODE)
{
mode = MANUAL_MODE;
OLED_Clear();
count_m = 1;
driveData.Water_Flag = 0;
driveData.Food_Flag = 0;
}
else if (mode == MANUAL_MODE)
{
mode = AUTO_MODE;
OLED_Clear();
// 修复警告:移除未使用的 count_a
}
break;
case 'B':
if (mode == MANUAL_MODE)
{
driveData.Water_Flag = ! driveData.Water_Flag;
count_m = 1;
}
break;
case 'C':
if (mode == MANUAL_MODE)
{
driveData.Food_Flag = !driveData.Food_Flag;
count_m = 2;
}
break;
default:
break;
}
USART2_ClearReceivedFlag();
}
}
int main(void)
{
SystemInit();//配置系统时钟为72M
delay_init(72);
ADCX_Init();
LED_Init();
LED_On();
Key_Init();
MOTOR_Init();
BUMP_Init();
OLED_Init();
DHT11_Init();
HW_Init();
RTC_Init();
BEEP_Init();
HX711_Init();
WATER_Init();
RELAY_Init();
OLED_Clear();
Pi_weight = Get_Tare();
TIM2_Init(9,14398);
USART1_Config();//串口初始化
USART2_Init();
USART3_Config();//串口初始化
printf("Start \n");
USART3_SendString("AF:30");
delay_ms(300);
USART3_SendString("A7:00001");
delay_ms(1000);
OLED_Clear();
Flash_Time_Init();
reset = HX711_GetData();
date = sensorData.calendarData.w_date;
//delay_ms(1000);
while (1)
{
USART2_ProcessCmd();
SensorScan(); //获取传感器数据
switch(mode)
{
case AUTO_MODE:
if(SetAuto() ==1 )
{
OLED_autoPage1(); //显示主页面1固定信息
SensorDataDisplay1(); //显示传感器1数据
}
else
{
OLED_autoPage2(); //显示主页面2固定信息
SensorDataDisplay2(); //显示传感器2数据
}
AutoControl();
/*按键1按下时切换模式*/
if (KeyNum == KEY_1) //系统模式mode 1自动 2手动 3设置
{
KeyNum = 0;
mode = MANUAL_MODE;
count_m = 1;
OLED_Clear();
}
if (KeyNum == KEY_Long1)
{
KeyNum = 0;
mode = SETTINGS_MODE;
count_s = 1;
OLED_Clear();
}
Control_Manager();
break;
case MANUAL_MODE:
OLED_manualOption(SetManual());
ManualControl(SetManual());
OLED_manualPage1();
ManualSettingsDisplay1();
if (KeyNum == KEY_1) //系统模式mode 0手动 1自动(默认)
{
KeyNum = 0;
mode = AUTO_MODE;
count_a = 1;
OLED_Clear();
}
Control_Manager();
break;
case SETTINGS_MODE:
if (set_flag)
{
set_time = sensorData.calendarData;
set_flag = 0;
location = 1;
count_w = 1;
rtc_get_flag = 0;
}
ThresholdSettings(count_w); //实现阈值调节功能
//判断是否退出阈值设置界面
if (KeyNum == KEY_1)
{
KeyNum = 0;
mode = AUTO_MODE; //跳转到主界面
count_a = 1;
OLED_Clear(); //清屏
//存储修改的传感器阈值至flash内
Flag_Writer();
}
break;
default: break;
}
time_num++; //计时变量+1
if (time_num % 2 == 0)
delay_ms(10);
if(time_num >= 5000)
{
time_num = 0;
}
}
}
六、实验效果 
七、包含内容
