STM32智能家用垃圾桶(升级版)

目录

一、前言

二、项目简介

1.功能详解

2.主要器件

三、原理图设计

四、PCB硬件设计

[PCB图 ​编辑​编辑](#PCB图 编辑编辑)

五、程序设计

[六、实验效果 ​编辑](#六、实验效果 编辑)

七、包含内容

项目分享


一、前言

项目成品图片:

哔哩哔哩视频链接:

https://www.bilibili.com/video/BV1syXoBPEhn/?spm_id_from=333.1387.homepage.video_card.click&vd_source=199aed5297a00e80e1faf7e270afe8d7

(资料分享见文末)

二、项目简介

1.功能详解

基于STM32的智能家用垃圾桶(升级版)

功能如下:

  1. 环境采集:超声波传感器检测垃圾桶剩余容量,将垃圾桶剩余容量映射为百分比显示;光电红外传感器检测是否有人靠近,火焰传感器检测是否发生火灾。
  2. 显示功能:OLED屏幕显示采集到的信息数据
  3. 模式切换:可通过按键切换自动模式和手动模式
  4. 自动模式:自动模式下如果垃圾桶未满则指示灯1点亮,如果垃圾桶已满则指示灯2点亮并且蓝牙APP接收信息"垃圾桶已满";如果有人且垃圾桶未满则打开垃圾桶桶盖,如果垃圾桶已满则不打开桶盖且蜂鸣器报警提醒;通过火焰传感器检测是否发生火灾,如果发生火灾则蜂鸣器报警且两个指示灯同时亮起;垃圾桶桶盖关闭且消毒模式打开时开启消毒灯进行消毒,压力传感器检测到压力时,开始计时,超过阈值蜂鸣器报警
  5. 手动模式:手动模式下可通过按键控制垃圾桶桶盖和消毒灯的开关
  6. 阈值调节:可以通过按键调节垃圾桶的距离阈值以及控制消毒模式是否打开、计时阈值调节
  7. 蓝牙APP:通过蓝牙APP可接收环境信息数据和控制指令下发
  8. 语音控制:可通过语音控制模式切换,打开垃圾桶、消毒灯

2.主要器件

  • STM32F103C8T6最小系统板
  • OLED显示屏(4针IIC协议)
  • 光电红外传感器
  • SNR8016语音模块
  • FSR402压力传感器
  • 火焰传感器
  • HC-SR04超声波传感器
  • BT04-A蓝牙模块
  • UV紫外线消毒灯
  • 有源蜂鸣器
  • 垃圾桶模型
  • 继电器
  • 舵机

三、原理图设计

四、PCB硬件设计

PCB图

五、程序设计

cpp 复制代码
#include "stm32f10x.h"
#include "led.h"
#include "beep.h"
#include "usart.h"
#include "delay.h"
#include "oled.h"
#include "key.h"
#include "Modules.h"
#include "TIM2.h"
#include "adcx.h"
#include "flash.h"
#include "usart2.h"
#include "usart3.h"
#include "ultrasonic.h"
#include "IR.h"
#include "HW.h"
#include "servo.h"
#include "timer.h"

/****************异方辰电子工作室******************
				     STM32
											
 * 项目			:	STM32智能家用垃圾桶                  
 * 版本			: V2.0
 * 日期			: 2025.11.07
 * 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	//写入的起始地址

 SensorModules sensorData;								//声明传感器数据结构体变量
 SensorThresholdValue Sensorthreshold;		//声明传感器阈值结构体变量
 DriveModules driveData;									//声明驱动器状态结构体变量

uint8_t mode = 1;	//系统模式  1自动  2手动  3设置
u8 dakai;//串口3使用的传递变量
u8 Flag_dakai;//串口3接收标志位
uint8_t is_secondary_menu = 0;  // 0一级菜单,1二级菜单
uint8_t secondary_pos = 1;      // 二级菜单光标位置(1-3对应时/分/秒)
uint8_t secondary_type = 0;   // 二级菜单类型:0=RTC时间,1=定时开启,2=定时关闭
//uint8_t send_data[] = "A7:00001";//语音播放曲目1
//uint8_t send_data1[] = "A7:00002";//语音播放曲目2

extern u8 Res;


float Angle;			//定义角度变量

//static uint8_t last_pressure_state = 0; 
//系统静态变量
static uint8_t count_a = 1;  //自动模式按键数
static uint8_t count_m = 1;  //手动模式按键数
static uint8_t count_s = 1;	 //设置模式按键数
//static uint8_t last_mode = 0;      // 记录上一次的模式
//static uint8_t last_count_s = 0;   // 记录设置模式内上一次的页面
/**
  * @brief  显示菜单内容
  * @param  无
  * @retval 无
  */
enum 
{
	AUTO_MODE = 1,
	MANUAL_MODE,
	SETTINGS_MODE
	
}MODE_PAGES;


int main(void)
{ 
    SystemInit();//配置系统时钟为72M	
    delay_init(72);  // 系统时钟72MHz
    ADCx_Init();
    LED_Init();
	  LED1_Init();
	  LED1_On();
	  LED2_Init();
    BEEP_Init();
    BEEP_OFF;
    USART1_Config();//串口1初始化PC
    USART2_Init(); //串口3初始化蓝牙
    USART3_Config();//串口2初始化//语音模块
    Key_Init();
    OLED_Init();
    OLED_Clear();//清屏
    Ultrasonic_Init();//超声波初始化
		IR_Init();
	  HW_Init();
	  Servo_Init();
    FLASH_ReadThreshold();

    
    // 添加的状态管理变量
    static uint8_t last_mode = 0;  // 记录上一次模式
    static uint32_t last_sensor_time = 0; // 传感器扫描时间控制
    static uint32_t last_display_time = 0; // 显示刷新时间控制
    // 新增:保存当前自动模式的页码,避免重复定义
    static uint8_t auto_page = 1; 

    
    TIM2_Init(72-1,1000-1);  // 2ms定时中断
    printf("Start \n");

    
    while (1)
    {	
			
        // ==================== 优先处理按键和通信 ====================
        USART2_ProcessCmd();  // 先处理串口命令
        USART3_ProcessCmd();
        // ==================== 获取当前系统时间 ====================
        uint32_t current_time = delay_get_tick(); // 使用系统滴答计数
        
        // ==================== 优化传感器扫描频率 ====================
        if(current_time - last_sensor_time > 100) // 每200ms扫描一次传感器 (100 * 2ms = 200ms)
        {
            SensorScan(); 	//获取传感器数据
	//          printf("距离:%d\r\n",sensorData.distance);
	//				  printf("有无压力:%s\r\n",sensorData.pressure  ? "是" : "否");
	//					printf("是否有人:%s\r\n",sensorData.value  ? "是" : "否");
	//				  printf("是否着火:%s\r\n",sensorData.fire  ? "是" : "否");
//					printf("---------------------------\r\n");
            last_sensor_time = current_time;
        }
        
        // ==================== 立即处理按键 ====================
        uint8_t current_key_num = KeyNum; // 保存当前按键值
        
        // 模式切换按键立即处理
        if(current_key_num != 0)
        {
            switch(mode)
            {
                case AUTO_MODE:
									 // 修复:将auto_page赋值移到这里,且只在按键触发时更新
									 auto_page = SetAuto(); 
				      if(auto_page == 1)
                {
									OLED_Clear();
                    OLED_autoPage1();	//显示自动模式第一页固定内容
                    SensorDataDisplay1();	//显示第一页传感器数据
                }
                else if(auto_page == 2)
                {
									OLED_Clear();
                    OLED_autoPage2();	//显示自动模式第二页固定内容
                    SensorDataDisplay2();	//显示第二页传感器数据
                }
								
								AutoControl();
								
                    if(current_key_num == KEY_1)
                    {
                        mode = MANUAL_MODE;
                        count_m = 1;
                        // 切换到手动模式时关闭灯和蜂鸣器
                        driveData.LED_Flag = 1;
											  driveData.LED1_Flag = 1;
											  driveData.LED2_Flag = 0;
                        driveData.BEEP_Flag = 0;
											
                        KeyNum = 0; // 立即清除按键
                    }
                    else if(current_key_num == KEY_Long1)
                    {
                        mode = SETTINGS_MODE;
                        count_s = 1;
                        KeyNum = 0; // 立即清除按键
                    }
                   break;
                    
                case MANUAL_MODE:
                    if(current_key_num == KEY_1)
                    {
                        mode = AUTO_MODE;
                        KeyNum = 0; // 立即清除按键
                    }
                    break;
                    
                case SETTINGS_MODE:
                    // 设置模式内部按键在各自模式中处理
                    break;
            }
        }
        
        // ==================== 模式切换优化 ====================
        if(last_mode != mode)
        {
            OLED_Clear();
            last_mode = mode;
            
            // 立即绘制新模式的固定内容
            switch(mode)
            {
                case AUTO_MODE:
                    // 修复:模式切回自动时,默认显示第一页
                    auto_page = 1;
                    OLED_autoPage1();
                    SensorDataDisplay1();
                    break;
                case MANUAL_MODE:
                    OLED_manualPage1();
                    break;
                case SETTINGS_MODE:
                    OLED_settingsPage1();
                    break;
            }
            OLED_Refresh(); // 立即刷新显示
        }
        
        // ==================== 模式处理 ====================
        switch(mode)
        {
            case AUTO_MODE:
                // 修复:移除了原有的 SensorDataDisplay1() 无条件调用
                // 改为根据当前auto_page显示对应数据
                if(auto_page == 1)
                {
                    SensorDataDisplay1();	//显示第一页传感器数据
                }
                else if(auto_page == 2)
                {
									
                    SensorDataDisplay2();	//显示第二页传感器数据
                }
                AutoControl();
                Control_Manager();
                break;
                
            // 手动模式、设置模式代码不变,此处省略...
            case MANUAL_MODE:
            {
                // 原有手动模式代码(无修改)
                static uint8_t manual_page_initialized = 0;
                static uint8_t last_manual_count = 0;
                static uint8_t last_LED_Flag = 1;
                static uint8_t last_BEEP_Flag = 0;
                static uint8_t force_refresh = 0;  // 强制刷新标志
                
                if(last_mode != mode)
                {
                    manual_page_initialized = 0;
                    last_manual_count = 0;
                    last_LED_Flag = driveData.LED_Flag;
                    last_BEEP_Flag = driveData.BEEP_Flag;
                    force_refresh = 1;  
                    
                    count_m = 1;
                    driveData.LED_Flag = 0;
                    driveData.BEEP_Flag = 0;
                }
                
                uint8_t current_manual_count = SetManual();
                
                uint8_t need_refresh = 0;
                if(driveData.LED_Flag != last_LED_Flag || driveData.BEEP_Flag != last_BEEP_Flag)
                {
                    need_refresh = 1;
                    last_LED_Flag = driveData.LED_Flag;
                    last_BEEP_Flag = driveData.BEEP_Flag;
                }
                
                if(!manual_page_initialized || current_manual_count != last_manual_count || need_refresh || force_refresh)
                {
                    OLED_manualPage1();          
                    OLED_manualOption(current_manual_count); 
                    ManualSettingsDisplay1();    
                    manual_page_initialized = 1;
                    last_manual_count = current_manual_count;
                    force_refresh = 0;  
                    OLED_Refresh(); 
                }
                
                if(current_key_num != 0)
                {
                    ManualControl(current_manual_count);
                    OLED_manualPage1();          
                    OLED_manualOption(current_manual_count); 
                    ManualSettingsDisplay1();    
                    OLED_Refresh(); 
                    KeyNum = 0; 
                }
                
                OLED_manualPage1();          
                OLED_manualOption(current_manual_count); 
                ManualSettingsDisplay1();    
                
                Control_Manager();
                break;
            }
						
            case SETTINGS_MODE:
            {
                static uint8_t is_threshold_page_inited = 0;
                uint8_t curr_count_s = SetSelection();
                
                if(current_key_num != 0)
                {
                    if (is_secondary_menu == 1)
                    {
                        if (current_key_num == KEY_2 || current_key_num == KEY_3 || current_key_num == KEY_4)
                        {
                            OLED_Refresh();
                            KeyNum = 0;
                        }
                        else if (current_key_num == KEY_1)
                        {
                            is_secondary_menu = 0;
                            secondary_pos = 1;
                            OLED_Clear();
                            OLED_settingsPage1();
                            SettingsThresholdDisplay1();
                            OLED_settingsOption(curr_count_s);
                            OLED_Refresh();
                            KeyNum = 0;
                        }
                    }
                    else
                    {
                        if (current_key_num == KEY_3 || current_key_num == KEY_4)
                        {
                            ThresholdSettings(curr_count_s);
                            SettingsThresholdDisplay1();
                            OLED_Refresh();
                            KeyNum = 0;
                        }
                        else if (current_key_num == KEY_1)
                        {
                            mode = AUTO_MODE;
                            is_threshold_page_inited = 0;
                           FLASH_W(FLASH_START_ADDR,
            Sensorthreshold.distance_threshold,  
            Sensorthreshold.led2_enabled,
						Sensorthreshold.time);                               
													  mode = AUTO_MODE;
                is_threshold_page_inited = 0;
                            KeyNum = 0;
                        }
                    }
                }
                
                if (is_secondary_menu == 1)
                {
                   
                }
                else
                {
                    if (curr_count_s >= 1 && curr_count_s <= 4)
                    {
                        if (is_threshold_page_inited == 0)
                        {
                            OLED_settingsPage1();
                            is_threshold_page_inited = 1;
                        }
                    }
                    OLED_settingsOption(curr_count_s);
                    SettingsThresholdDisplay1();
                }
                break;
            }
        }
        
        // ==================== 限制显示刷新频率 ====================
        if(current_time - last_display_time > 25) 
        {
            OLED_Refresh();
            last_display_time = current_time;
        }
    }
}

六、实验效果

七、包含内容

项目分享

相关推荐
qq_150841992 小时前
浅析光模块固件之PC-MCU-Driver构架下的二级I2C从机的透传编程(再续)
单片机·嵌入式硬件
惶了个恐2 小时前
嵌入式硬件第六弹——ARM(3)
arm开发·stm32·嵌入式硬件·arm
学工科的皮皮志^_^2 小时前
RS485学习
经验分享·笔记·单片机·嵌入式硬件·学习
wearegogog1232 小时前
基于STM32的数据采集+心率检测仪设计
stm32·单片机·嵌入式硬件
没有医保李先生2 小时前
mcu中cpu通用和特殊寄存器
单片机·嵌入式硬件
C^h2 小时前
RT thread中断管理学习记录
单片机·嵌入式硬件·学习
桌面运维家2 小时前
Windows 10 USB鼠标失灵:驱动、电源问题排查指南
windows·单片机·计算机外设
思茂信息3 小时前
基于 CST 的方向图可重构天线仿真分析
网络·人工智能·单片机·算法·重构·cst·电磁仿真
senijusene3 小时前
从启动到中断:基于i.MX6UL的ARM Cortex-A7中断系统详解
arm开发·嵌入式硬件