STM32项目分享:智能衣柜

目录

一、前言

二、项目简介

1.功能详解

2.主要器件

三、原理图设计

四、PCB硬件设计

PCB图 

五、程序设计 

六、实验效果 

七、资料内容

项目分享


一、前言

项目成品图片:

哔哩哔哩视频链接:

STM32智能衣柜

(资料分享见文末) 

二、项目简介

1.功能详解

基于STM32智能衣柜

功能如下:

  1. DHT11检测温湿度、设置阈值进行加热和通风
  2. RTC获取实时时间,并定时进行紫外线UV消毒
  3. 通过光电传感器检测柜门状态,关门时消毒,开门时判断光照开灯
  4. 光敏传感器采集光强,显示环境数据并根据此判断是否需要开灯
  5. MQ2烟雾传感器检测烟雾浓度是否超标,超标触发蜂鸣器声光报警
  6. 按键可调节时间和全部的阈值信息与定时信息
  7. 蓝牙APP可远程控制衣柜系统进行执行加热、通风、照明和消毒的功能
  8. 蓝牙APP可接收环境的实时信息数据

2.主要器件

  • STM32F103C8T6单片机
  • OLED 屏幕
  • DHT11温湿度传感器
  • BT04A蓝牙模块
  • 光敏传感器
  • 光电红外传感器
  • MQ-2烟雾传感器
  • 继电器
  • 风扇模块
  • 大功率LED灯模块
  • 有源蜂鸣器
  • 步进电机
  • UV消毒灯模块
  • 加热片模块
     

三、原理图设计

四、PCB硬件设计

PCB图 

五、程序设计 

#include "sys.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "math.h"
#include "delay.h"
#include "gpio.h"
#include "key.h"
#include "oled.h"
#include "usart.h"
#include "rtc.h"
#include "dht11.h"
#include "adc.h"
#include "motor_bujin.h"


int main(void)
{
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置中断优先分组
	Delay_Init();	    	 								//延时初始化	  
	Gpio_Init();		  									//IO初始化
	Key_Init();		  										//按键初始化
	Oled_Init();		  									//OLED初始化
	Oled_Clear_All();										//清屏
	Usart1_Init(9600);    							//串口1初始化
	Adc_Init();													//ADC初始化
	Step_Motor_Init();									//步进电机初始化
  while(RTC_Init());									//RTC初始化
  while(DHT11_Init());								//DHT11初始化
	Delay_ms(1000);
	Delay_ms(1000);
//	DHT11_Init();
	while(1)
	{
		key_num = Chiclet_Keyboard_Scan(0);		//按键扫描
	if(key_num != 0)											//有按键按下
	{
		switch(key_num)
		{
			case 1:								            //按键1,切换设置界面
				flag_display++;
				if(flag_display >= 15)
					flag_display = 0;
				if(flag_display >= 1 && flag_display <= 6)
				{
					RTC_ITConfig(RTC_IT_SEC, DISABLE);
				}
				else
				{
					RTC_Set(calendar.w_year,calendar.w_month,calendar.w_date,calendar.hour,calendar.min,calendar.sec);
					RTC_ITConfig(RTC_IT_SEC, ENABLE);
				}
				Oled_Clear_All();					      //清屏
			break;

			case 2:											      //按键2
				switch(flag_display)
				{
					
					case 0:
						if(flag_bujin_state == 0)
							flag_bujin_foreward = 1;
					break;
					case 1:												//界面1:修改年+1
						calendar.w_year ++;
						RTC_Set(calendar.w_year,calendar.w_month ,calendar.w_date ,calendar.hour ,calendar.min ,calendar.sec);
					break;
					
					case 2:												//界面2:修改月+1
						calendar.w_month ++;
						if(calendar.w_month > 12)
							calendar.w_month = 1;
						RTC_Set(calendar.w_year,calendar.w_month ,calendar.w_date ,calendar.hour ,calendar.min ,calendar.sec);
					break;
					
					case 3:												//界面3:修改日+1
						calendar.w_date ++;
						if(calendar.w_date > 31)
							calendar.w_date = 1;
						RTC_Set(calendar.w_year,calendar.w_month ,calendar.w_date ,calendar.hour ,calendar.min ,calendar.sec);
					break;
					
					case 4:												//界面4:修改时+1
						calendar.hour ++;
						if(calendar.hour > 23)
							calendar.hour = 0;
						RTC_Set(calendar.w_year,calendar.w_month ,calendar.w_date ,calendar.hour ,calendar.min ,calendar.sec);
					break;
					
					case 5:												//界面5:修改分+1
						calendar.min ++;
						if(calendar.min > 59)
							calendar.min = 0;
						RTC_Set(calendar.w_year,calendar.w_month ,calendar.w_date ,calendar.hour ,calendar.min ,calendar.sec);
					break;

					case 6:												//界面6:修改秒+1
						calendar.sec ++;
						if(calendar.sec > 59)
							calendar.sec = 0;
						RTC_Set(calendar.w_year,calendar.w_month ,calendar.w_date ,calendar.hour ,calendar.min ,calendar.sec);
					break;
					
					case 7:												      //界面7:区间定时开始时+1
						time_shi_begin++;
						if(time_shi_begin >= 24)
							time_shi_begin = 0;
					break;
						
					case 8:												      //界面8:区间定时开始分+1
						time_fen_begin++;
						if(time_fen_begin >= 60)
							time_fen_begin = 0;
					break;
						
					case 9:												    	//界面9:区间定时结束时+1
						time_shi_end++;
						if(time_shi_end >= 24)
							time_shi_end = 0;
					break;
						
					case 10:												    //界面10:区间定时结束分+1
						time_fen_end++;
						if(time_fen_end >= 60)
							time_fen_end = 0;
					break;

					case 11:														//界面11:温度最小值+1
						if(temp_min < 99)
							temp_min++;
					break;

					case 12:														//界面12:湿度最大值+1
						if(humi_max < 99)
							humi_max++;
					break;

					case 13:														//界面13:光照最小值+1
						if(light_min < 99)
							light_min++;
					break;
            
          case 14:														//界面14:烟雾最大值+1
						if(smog_max < 200)
							smog_max++;
					break;
					default:
					break;
				}
			break;

			case 3:														//按键3
				switch(flag_display)
				{
					
					case 0:
						if(flag_bujin_state == 1)
							flag_bujin_reversal = 1;
					break;
					case 1:												//界面1:修改年-1
						calendar.w_year --;
						RTC_Set(calendar.w_year,calendar.w_month ,calendar.w_date ,calendar.hour ,calendar.min ,calendar.sec);
					break;
					
					case 2:												//界面2:修改月-1
						calendar.w_month --;
						if(calendar.w_month <1)
							calendar.w_month = 12;
						RTC_Set(calendar.w_year,calendar.w_month ,calendar.w_date ,calendar.hour ,calendar.min ,calendar.sec);
					break;
					
					case 3:												//界面3:修改日-1
						calendar.w_date --;
						if(calendar.w_date < 1)
							calendar.w_date = 31;
						RTC_Set(calendar.w_year,calendar.w_month ,calendar.w_date ,calendar.hour ,calendar.min ,calendar.sec);
					break;
					
					case 4:												//界面4:修改时-1
						if(calendar.hour == 0)
							calendar.hour = 23;
						else 
						calendar.hour --;
						RTC_Set(calendar.w_year,calendar.w_month ,calendar.w_date ,calendar.hour ,calendar.min ,calendar.sec);
					break;
					
					case 5:												//界面5:修改分-1
						if(calendar.min == 0)							
							calendar.min = 59;
						else 
							calendar.min --;
						RTC_Set(calendar.w_year,calendar.w_month ,calendar.w_date ,calendar.hour ,calendar.min ,calendar.sec);
					break;
					
					case 6:												//界面6:修改秒-1
						if(calendar.sec == 0)
							calendar.sec = 59;	
						else
							calendar.sec --;							
						RTC_Set(calendar.w_year,calendar.w_month ,calendar.w_date ,calendar.hour ,calendar.min ,calendar.sec);
					break;
		
					case 7:												      //界面7:区间定时开始时-1
						time_shi_begin--;
						if(time_shi_begin < 0)
							time_shi_begin = 23;
					break;
						
					case 8:												      //界面8:区间定时开始分-1
						time_fen_begin--;
						if(time_fen_begin < 0)
							time_fen_begin = 59;
					break;
						
					case 9:												    	//界面9:区间定时结束时-1
						time_shi_end--;
						if(time_shi_end < 0)
							time_shi_end = 23;
					break;
						
					case 10:												    //界面10:区间定时结束分-1
						time_fen_end--;
						if(time_fen_end < 0)
							time_fen_end = 59;
					break;
					
					case 11:														//界面11:温度最小值-1
						if(temp_min > 0)
							temp_min--;
					break;

					case 12:														//界面12:湿度最大值-1
						if(humi_max > 0)
							humi_max--;
					break;

					case 13:														//界面13:光照最小值-1
						if(light_min > 0)
							light_min--;
					break;
            
          case 14:														//界面14:烟雾最大值-1
						if(smog_max > 0)
							smog_max--;
					break;

					default:
					break;
				}
			break;

			default:
				
			break;
		}
	}
	if(flag_display == 0)									//测量界面
	{
		if(time_num % 10 == 0)							//获取数据
		{
			DHT11_Read_Data(&temp_value,&humi_value);		//获取温湿度值
			light_value = 99-30*(Get_Adc_Average(1,3)*3.3/4096.0);	//获取光照强度
			if(SMOG == 0)
				smog_value = 60*(Get_Adc_Average(0,3)*3.3/4096.0);	//获取烟雾值
			else
				smog_value = 0;
		}
		
		if(time_num % 30 == 0)							//发送数据
		{
			UsartPrintf(USART1,"温度:%d.%dC\r\n",temp_value/10,temp_value%10);
			UsartPrintf(USART1,"湿度:%d.%dC\r\n",humi_value/10,humi_value%10);
			UsartPrintf(USART1,"光照:%dlux\r\n",light_value);
			UsartPrintf(USART1,"烟雾:%dPPM\r\n",smog_value);
		}
		
		if(USART1_WaitRecive() == 0)				//如果接收到蓝牙数据
		{
			switch(usart1_buf[0])
			{
				case('A'):											//A:切换自动模式
					flag_mode = 0;
				break;   

				case('B'):											//B:PA7					
					flag_mode = 1;
					RELAY_TF = !RELAY_TF;
				break;
				
				case('C'):											//C:PA6
					flag_mode = 1;
					RELAY_JR =!RELAY_JR;
				break;

				case('D'):											//D:PA5
					flag_mode = 1;
					RELAY_XD =!RELAY_XD;
				break;
				
				case('E'):											//E:PA4
					flag_mode = 1;
					RELAY_ZM =!RELAY_ZM;
				break;
				default:
				
				break;
			}	
			USART1_Clear();
		}
	}
		switch(flag_display)									//根据不同的显示模式标志位,显示不同的界面
	{
		case 0:									      			//界面0:
			sprintf(display_buf,"%d-%d%d-%d%d",calendar.w_year,calendar.w_month/10,calendar.w_month%10,calendar.w_date/10,calendar.w_date%10);
			Oled_ShowString(1, 2, display_buf);
			sprintf(display_buf,"%d%d:%d%d:%d%d",calendar.hour/10,calendar.hour%10,calendar.min/10,calendar.min%10,calendar.sec/10,calendar.sec%10);
			Oled_ShowString(2, 3, display_buf);
		
			Oled_ShowString(3,0,"T:");
			sprintf(display_buf,"%d.%dC ",temp_value/10,temp_value%10);
			Oled_ShowString(3,2,display_buf);
			Oled_ShowString(3,8,"H:");
			sprintf(display_buf,"%d.%dC ",humi_value/10,humi_value%10);
			Oled_ShowString(3,10,display_buf);
			Oled_ShowString(4,0,"L:");
			sprintf(display_buf,"%dlux ",light_value);
			Oled_ShowString(4,2,display_buf);
			Oled_ShowString(4,8,"S:");
			sprintf(display_buf,"%dppm  ",smog_value);
			Oled_ShowString(4,10,display_buf);
		
		break;
		
		case 1:																					//界面1:显示设置时间年
			Oled_ShowCHinese(1,2,"设置时间");
			if(time_num % 5 == 0)
			{
				sprintf(display_buf,"%d-%d%d-%d%d",calendar.w_year,calendar.w_month/10,calendar.w_month%10,calendar.w_date/10,calendar.w_date%10);
				Oled_ShowString(2, 2, display_buf);
				sprintf(display_buf,"%d%d:%d%d:%d%d",calendar.hour/10,calendar.hour%10,calendar.min/10,calendar.min%10,calendar.sec/10,calendar.sec%10);
				Oled_ShowString(3, 3, display_buf);
			}
			if(time_num % 10 == 0)
			{
				Oled_ShowString(2, 2, "    ");
			}
		break;
			
		case 2:																					//界面2:显示设置时间月
			Oled_ShowCHinese(1,2,"设置时间");
			if(time_num % 5 == 0)
			{
				sprintf(display_buf,"%d-%d%d-%d%d",calendar.w_year,calendar.w_month/10,calendar.w_month%10,calendar.w_date/10,calendar.w_date%10);
				Oled_ShowString(2, 2, display_buf);
				sprintf(display_buf,"%d%d:%d%d:%d%d",calendar.hour/10,calendar.hour%10,calendar.min/10,calendar.min%10,calendar.sec/10,calendar.sec%10);
				Oled_ShowString(3, 3, display_buf);
			}
			if(time_num % 10 == 0)
			{
				Oled_ShowString(2, 7, "  ");
			}
		break;

		case 3:																						//界面3:显示设置时间日
			Oled_ShowCHinese(1,2,"设置时间");
			if(time_num % 5 == 0)
			{
				sprintf(display_buf,"%d-%d%d-%d%d",calendar.w_year,calendar.w_month/10,calendar.w_month%10,calendar.w_date/10,calendar.w_date%10);
				Oled_ShowString(2, 2, display_buf);
				sprintf(display_buf,"%d%d:%d%d:%d%d",calendar.hour/10,calendar.hour%10,calendar.min/10,calendar.min%10,calendar.sec/10,calendar.sec%10);
				Oled_ShowString(3, 3, display_buf);
			}
			if(time_num % 10 == 0)
			{
				Oled_ShowString(2, 10, "  ");
			}
		break;				
			
		case 4:																						//界面4:显示设置时间时
			Oled_ShowCHinese(1,2,"设置时间");
			if(time_num % 5 == 0)
			{
				sprintf(display_buf,"%d-%d%d-%d%d",calendar.w_year,calendar.w_month/10,calendar.w_month%10,calendar.w_date/10,calendar.w_date%10);
				Oled_ShowString(2, 2, display_buf);
				sprintf(display_buf,"%d%d:%d%d:%d%d",calendar.hour/10,calendar.hour%10,calendar.min/10,calendar.min%10,calendar.sec/10,calendar.sec%10);
				Oled_ShowString(3, 3, display_buf);
			}
			if(time_num % 10 == 0)
			{
				Oled_ShowString(3, 3, "  ");
			}
		break;	

		case 5:																						//界面5:显示设置时间分
			Oled_ShowCHinese(1,2,"设置时间");
			if(time_num % 5 == 0)
			{
				sprintf(display_buf,"%d-%d%d-%d%d",calendar.w_year,calendar.w_month/10,calendar.w_month%10,calendar.w_date/10,calendar.w_date%10);
				Oled_ShowString(2, 2, display_buf);
				sprintf(display_buf,"%d%d:%d%d:%d%d",calendar.hour/10,calendar.hour%10,calendar.min/10,calendar.min%10,calendar.sec/10,calendar.sec%10);
				Oled_ShowString(3, 3, display_buf);
			}
			if(time_num % 10 == 0)
			{
				Oled_ShowString(3, 6, "  ");
			}
		break;				
			
		case 6:																						//界面6:显示设置时间秒
			Oled_ShowCHinese(1,2,"设置时间");
			if(time_num % 5 == 0)
			{
				sprintf(display_buf,"%d-%d%d-%d%d",calendar.w_year,calendar.w_month/10,calendar.w_month%10,calendar.w_date/10,calendar.w_date%10);
				Oled_ShowString(2, 2, display_buf);
				sprintf(display_buf,"%d%d:%d%d:%d%d",calendar.hour/10,calendar.hour%10,calendar.min/10,calendar.min%10,calendar.sec/10,calendar.sec%10);
				Oled_ShowString(3, 3, display_buf);
			}
			if(time_num % 10 == 0)
			{
				Oled_ShowString(3, 9, "  ");
			}
		break;
		
			case 7:															         	 			//界面7:显示设置区间定时开始时
			Oled_ShowCHinese(1,0,"设置定时开始时");
			if(time_num % 5 == 0)
			{
				Oled_ShowNum_2(2,5,time_shi_begin);
				Oled_ShowNum_2(2,8,time_fen_begin);
				Oled_ShowString(2,7,":");
			}
			if(time_num % 10 == 0)
			{
				Oled_ShowString(2,5,"  :");
			}
		break;

		case 8:															         	 			//界面8:显示设置区间定时开始分
			Oled_ShowCHinese(1,0,"设置定时开始分");
			if(time_num % 5 == 0)
			{
				Oled_ShowNum_2(2,5,time_shi_begin);
				Oled_ShowNum_2(2,8,time_fen_begin);
				Oled_ShowString(2,7,":");
			}
			if(time_num % 10 == 0)
			{
				Oled_ShowString(2,7,":  ");
			}
		break;

		case 9:															         	 			//界面9:显示设置区间定时结束时
			Oled_ShowCHinese(1,0,"设置定时结束时");
			if(time_num % 5 == 0)
			{
				Oled_ShowNum_2(2,5,time_shi_end);
				Oled_ShowNum_2(2,8,time_fen_end);
				Oled_ShowString(2,7,":");
			}
			if(time_num % 10 == 0)
			{
				Oled_ShowString(2,5,"  :");
			}
		break;

		case 10:															         	 		//界面10:显示设置区间定时结束分
			Oled_ShowCHinese(1,0,"设置定时结束分");
			if(time_num % 5 == 0)
			{
				Oled_ShowNum_2(2,5,time_shi_end);
				Oled_ShowNum_2(2,8,time_fen_end);
				Oled_ShowString(2,7,":");
			}
			if(time_num % 10 == 0)
			{
				Oled_ShowString(2,7,":  ");
			}
		break;
			
		case 11:																						//界面11:显示设置温度最小值
			Oled_ShowCHinese(1,0,"设置温度最小值");
			if(time_num % 5 == 0)
			{
				sprintf(display_buf,"%d  ",temp_min);
				Oled_ShowString(2, 7, display_buf);
			}
			if(time_num % 10 == 0)
			{
				Oled_ShowString(2, 7, "    ");
			}
		break;

		case 12:																						//界面12:显示设置湿度最大值
			Oled_ShowCHinese(1,0,"设置湿度最大值");
			if(time_num % 5 == 0)
			{
				sprintf(display_buf,"%d  ",humi_max);
				Oled_ShowString(2, 7, display_buf);
			}
			if(time_num % 10 == 0)
			{
				Oled_ShowString(2, 7, "    ");
			}
		break;

		case 13:																						//界面13:显示设置光照最小值
			Oled_ShowCHinese(1,0,"设置光照最小值");
			if(time_num % 5 == 0)
			{
				sprintf(display_buf,"%d  ",light_min);
				Oled_ShowString(2, 7, display_buf);
			}
			if(time_num % 10 == 0)
			{
				Oled_ShowString(2, 7, "    ");
			}
		break;

		case 14:																						//界面14:显示设置烟雾最大值
			Oled_ShowCHinese(1,0,"设置烟雾最大值");
			if(time_num % 5 == 0)
			{
				sprintf(display_buf,"%d  ",smog_max);
				Oled_ShowString(2, 7, display_buf);
			}
			if(time_num % 10 == 0)
			{
				Oled_ShowString(2, 7, "    ");
			}
		break;
		default:
			
		break;
	}
		u8 time_shi,time_fen;              //当前时间

	if(flag_display == 0)																			//测量界面
	{
		if(flag_mode == 0)
		{
			time_shi = calendar.hour;												        //获取当前时间
			time_fen = calendar.min;
			if(time_shi_begin*60+time_fen_begin > time_shi_end*60+time_fen_end)						//开始时间>结束时间
			{
				if((time_shi_end*60+time_fen_end <= time_shi*60+time_fen) && (time_shi*60+time_fen < time_shi_begin*60+time_fen_begin))		//当前时间不在设置的时间内
					flag_time_on = 0;
				else																																				//否则
					flag_time_on = 1;
			}
			else if(time_shi_begin*60+time_fen_begin < time_shi_end*60+time_fen_end)			//开始时间<结束时间
			{
				if((time_shi_begin*60+time_fen_begin <= time_shi*60+time_fen) && (time_shi*60+time_fen < time_shi_end*60+time_fen_end))		//当前时间在设置的时间内
					flag_time_on = 1;
				else																																				//否则
					flag_time_on = 0;
			}
			if(DOOR == 1)        			//如果衣柜门是关闭的,关照明灯
      {
        RELAY_ZM = 0;
        if(flag_time_on == 1)   //如果在定时时间之内,开消毒
        {
          RELAY_XD = 1;
        }  
        else                    //如果在定时时间之外,关消毒
        {
          RELAY_XD = 0;
        }        
      }
      else                      //如果衣柜门是打开的,关消毒,如果光照低于最小值开照明灯
      {
        RELAY_XD = 0;
        if(light_value < light_min)
        {
          RELAY_ZM = 1;
        }
        else
        {
          RELAY_ZM = 0;
        }
      }
			if(temp_value < temp_min*10 || humi_value > humi_max*10)
      {                             //如果温度低于最小值或湿度大于最大值,那么打开加热,如果是湿度大于最小值还需开通风
        RELAY_JR = 1;
        if(humi_value > humi_max*10)
          RELAY_TF = 1;
        else
          RELAY_TF = 0;
      }
      else
      {
        RELAY_JR = 0;
        RELAY_TF = 0;
      }
      if(smog_value > smog_max)	//烟雾值大于设置的最大值,声光报警
      {
        if(time_num % 3 == 0)
        {
          LED=~LED;
          BEEP=~BEEP;
        }
      }
      else
      {
        LED = 1;
        BEEP = 0;
      }
		}
	}
	else																											//设置界面,关闭所有继电器
	{
		LED = 1;
    BEEP = 0;
		RELAY_ZM = 0;
    RELAY_TF = 0;
    RELAY_JR = 0;
    RELAY_XD = 0;
	}

		time_num++;												//计时变量+1
		Delay_ms(10);
		if(time_num %10 == 0)
			LED_SYS = ~LED_SYS;
		if(time_num >= 5000)
		{
			time_num = 0;
		}
	}
}

六、实验效果 

七、资料内容

项目分享

猜你喜欢

转载自blog.csdn.net/qq_44016222/article/details/146046542
今日推荐