STM32 Project Sharing: Smart Wardrobe

Project finished product images:

STM32 Project Sharing: Smart Wardrobe

Bilibili video link:

https://www.bilibili.com/video/BV1CQkTYzEQ9/?share_source=copy_web&vd_source=097fdeaf6b6ecfed8a9ff7119c32faf2

(Material sharing can be found at the end of the article)

01

Project Introduction

1. Function Details

STM32 Smart Wardrobe

Functions are as follows:

  1. DHT11 detects temperature and humidity, sets thresholds for heating and ventilation

  2. RTC obtains real-time time and regularly performs UV disinfection

  3. Photoelectric sensor detects cabinet door status, disinfects when closed, and determines lighting based on illumination when opened

  4. Light sensor collects light intensity, displays environmental data, and determines whether to turn on the light based on this

  5. MQ2 smoke sensor detects smoke concentration; if exceeded, triggers buzzer alarm

  6. Buttons can adjust time and all threshold information and timing information

  7. Bluetooth app can remotely control the wardrobe system to execute heating, ventilation, lighting, and disinfection functions

  8. Bluetooth app can receive real-time environmental information data

2. Bill of Materials

  • STM32F103C8T6 microcontroller

  • OLED screen

  • DHT11 temperature and humidity sensor

  • BT04A Bluetooth module

  • Light sensor

  • Photoelectric infrared sensor

  • MQ-2 smoke sensor

  • Relay

  • Fan module

  • High-power LED light module

  • Active buzzer

  • Stepper motor

  • UV disinfection lamp module

  • Heating plate module

02

Schematic Design

STM32 Project Sharing: Smart Wardrobe

03

PCB Hardware Design

PCB Diagram

STM32 Project Sharing: Smart WardrobeSTM32 Project Sharing: Smart Wardrobe

04

Program Design

#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); // Configure interrupt priority group
  Delay_Init(); // Delay initialization
  Gpio_Init(); // IO initialization
  Key_Init(); // Key initialization
  Oled_Init(); // OLED initialization
  Oled_Clear_All(); // Clear screen
  Usart1_Init(9600); // Serial port 1 initialization
  Adc_Init(); // ADC initialization
  Step_Motor_Init(); // Stepper motor initialization
  while(RTC_Init()); // RTC initialization
  while(DHT11_Init()); // DHT11 initialization
  Delay_ms(1000);
  Delay_ms(1000);
  // DHT11_Init();
  while(1) {
    key_num = Chiclet_Keyboard_Scan(0); // Key scan
    if(key_num != 0) { // If a key is pressed
      switch(key_num) {
        case 1: // Key 1, switch to settings interface
          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(); // Clear screen
          break;
        case 2: // Key 2
          switch(flag_display) {
            case 0:
              if(flag_bujin_state == 0)
                flag_bujin_foreward = 1;
              break;
            case 1: // Interface 1: Modify year +1
              calendar.w_year++;
              RTC_Set(calendar.w_year,calendar.w_month ,calendar.w_date ,calendar.hour ,calendar.min ,calendar.sec);
              break;
            case 2: // Interface 2: Modify month +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: // Interface 3: Modify day +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: // Interface 4: Modify hour +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: // Interface 5: Modify minute +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: // Interface 6: Modify second +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: // Interface 7: Interval timing start hour +1
              time_shi_begin++;
              if(time_shi_begin >= 24)
                time_shi_begin = 0;
              break;
            case 8: // Interface 8: Interval timing start minute +1
              time_fen_begin++;
              if(time_fen_begin >= 60)
                time_fen_begin = 0;
              break;
            case 9: // Interface 9: Interval timing end hour +1
              time_shi_end++;
              if(time_shi_end >= 24)
                time_shi_end = 0;
              break;
            case 10: // Interface 10: Interval timing end minute +1
              time_fen_end++;
              if(time_fen_end >= 60)
                time_fen_end = 0;
              break;
            case 11: // Interface 11: Minimum temperature +1
              if(temp_min < 99)
                temp_min++;
              break;
            case 12: // Interface 12: Maximum humidity +1
              if(humi_max < 99)
                humi_max++;
              break;
            case 13: // Interface 13: Minimum light +1
              if(light_min < 99)
                light_min++;
              break;
            case 14: // Interface 14: Maximum smoke +1
              if(smog_max < 200)
                smog_max++;
              break;
            default:
              break;
          }
          break;
        case 3: // Key 3
          switch(flag_display) {
            case 0:
              if(flag_bujin_state == 1)
                flag_bujin_reversal = 1;
              break;
            case 1: // Interface 1: Modify year -1
              calendar.w_year--;
              RTC_Set(calendar.w_year,calendar.w_month ,calendar.w_date ,calendar.hour ,calendar.min ,calendar.sec);
              break;
            case 2: // Interface 2: Modify month -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: // Interface 3: Modify day -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: // Interface 4: Modify hour -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: // Interface 5: Modify minute -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: // Interface 6: Modify second -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: // Interface 7: Interval timing start hour -1
              time_shi_begin--;
              if(time_shi_begin < 0)
                time_shi_begin = 23;
              break;
            case 8: // Interface 8: Interval timing start minute -1
              time_fen_begin--;
              if(time_fen_begin < 0)
                time_fen_begin = 59;
              break;
            case 9: // Interface 9: Interval timing end hour -1
              time_shi_end--;
              if(time_shi_end < 0)
                time_shi_end = 23;
              break;
            case 10: // Interface 10: Interval timing end minute -1
              time_fen_end--;
              if(time_fen_end < 0)
                time_fen_end = 59;
              break;
            case 11: // Interface 11: Minimum temperature -1
              if(temp_min > 0)
                temp_min--;
              break;
            case 12: // Interface 12: Maximum humidity -1
              if(humi_max > 0)
                humi_max--;
              break;
            case 13: // Interface 13: Minimum light -1
              if(light_min > 0)
                light_min--;
              break;
            case 14: // Interface 14: Maximum smoke -1
              if(smog_max > 0)
                smog_max--;
              break;
            default:
              break;
          }
          break;
        default:
          break;
      }
    }
    if(flag_display == 0) // Measurement interface
    {
      if(time_num % 10 == 0) // Get data
      {
        DHT11_Read_Data(&temp_value,&humi_value); // Get temperature and humidity values
        light_value = 99-30*(Get_Adc_Average(1,3)*3.3/4096.0); // Get light intensity
        if(SMOG == 0)
          smog_value = 60*(Get_Adc_Average(0,3)*3.3/4096.0); // Get smoke value
        else
          smog_value = 0;
      }
      if(time_num % 30 == 0) // Send data
      {
        UsartPrintf(USART1,"Temperature: %d.%dC\r\n",temp_value/10,temp_value%10);
        UsartPrintf(USART1,"Humidity: %d.%dC\r\n",humi_value/10,humi_value%10);
        UsartPrintf(USART1,"Light: %dlux\r\n",light_value);
        UsartPrintf(USART1,"Smoke: %dPPM\r\n",smog_value);
      }
      if(USART1_WaitRecive() == 0) // If Bluetooth data is received
      {
        switch(usart1_buf[0])
        {
          case('A'): // A: Switch to automatic mode
            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) // Display different interfaces based on different display mode flags
    {
      case 0: // Interface 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: // Interface 1: Display set time year
        Oled_ShowCHinese(1,2,"Set Time");
        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: // Interface 2: Display set time month
        Oled_ShowCHinese(1,2,"Set Time");
        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: // Interface 3: Display set time day
        Oled_ShowCHinese(1,2,"Set Time");
        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: // Interface 4: Display set time hour
        Oled_ShowCHinese(1,2,"Set Time");
        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: // Interface 5: Display set time minute
        Oled_ShowCHinese(1,2,"Set Time");
        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: // Interface 6: Display set time second
        Oled_ShowCHinese(1,2,"Set Time");
        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: // Interface 7: Display set interval timing start hour
        Oled_ShowCHinese(1,0,"Set Timing Start Hour");
        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: // Interface 8: Display set interval timing start minute
        Oled_ShowCHinese(1,0,"Set Timing Start Minute");
        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: // Interface 9: Display set interval timing end hour
        Oled_ShowCHinese(1,0,"Set Timing End Hour");
        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: // Interface 10: Display set interval timing end minute
        Oled_ShowCHinese(1,0,"Set Timing End Minute");
        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: // Interface 11: Display set minimum temperature
        Oled_ShowCHinese(1,0,"Set Minimum Temperature");
        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: // Interface 12: Display set maximum humidity
        Oled_ShowCHinese(1,0,"Set Maximum Humidity");
        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: // Interface 13: Display set minimum light
        Oled_ShowCHinese(1,0,"Set Minimum Light");
        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: // Interface 14: Display set maximum smoke
        Oled_ShowCHinese(1,0,"Set Maximum Smoke");
        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; // Current time
    if(flag_display == 0) // Measurement interface
    {
      if(flag_mode == 0) {
        time_shi = calendar.hour; // Get current time
        time_fen = calendar.min;
        if(time_shi_begin*60+time_fen_begin > time_shi_end*60+time_fen_end) // Start time > End time
        {
          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)) // Current time not in set time
            flag_time_on = 0;
          else // Otherwise
            flag_time_on = 1;
        }
        else if(time_shi_begin*60+time_fen_begin < time_shi_end*60+time_fen_end) // Start time < End time
        {
          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)) // Current time in set time
            flag_time_on = 1;
          else // Otherwise
            flag_time_on = 0;
        }
        if(DOOR == 1) // If the wardrobe door is closed, turn off the light
        {
          RELAY_ZM = 0;
          if(flag_time_on == 1) // If within timing time, turn on disinfection
          {
            RELAY_XD = 1;
          }
          else // If outside timing time, turn off disinfection
          {
            RELAY_XD = 0;
          }
        }
        else // If the wardrobe door is open, turn off disinfection, if light is below minimum value, turn on light
        {
          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) // If temperature is below minimum value or humidity is above maximum value, then turn on heating, if humidity is above maximum value also need to ventilate
        {
          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) // Smoke value exceeds set maximum value, sound and light alarm
        {
          if(time_num % 3 == 0)
          {
            LED=~LED;
            BEEP=~BEEP;
          }
        }
        else
        {
          LED = 1;
          BEEP = 0;
        }
      }
    }
    else // Settings interface, turn off all relays
    {
      LED = 1;
      BEEP = 0;
      RELAY_ZM = 0;
      RELAY_TF = 0;
      RELAY_JR = 0;
      RELAY_XD = 0;
    }
    time_num++; // Timing variable +1
    Delay_ms(10);
    if(time_num %10 == 0)
      LED_SYS = ~LED_SYS;
    if(time_num >= 5000)
    {
      time_num = 0;
    }
} 

05

Experimental Results

STM32 Project Sharing: Smart WardrobeSTM32 Project Sharing: Smart Wardrobe

Material Sharing (Baidu Cloud)

https://pan.baidu.com/s/1aADIDQRNWVJwFHP4u-GZIg?pwd=9ekh Extraction code: 9ekh

(Or scan the QR code below to obtain)STM32 Project Sharing: Smart WardrobePurchase physical items by scanning the QR code belowSTM32 Project Sharing: Smart Wardrobe

Leave a Comment