STM32项目分享:基于STM32的空气净化器

目录

一、引言

二、硬件设计

三、软件设计

四、系统实现与测试

五、结论与展望

六、资料内容及获取


一、引言

基于STM32的空气净化器系统实现了智能化的环境监测与净化控制功能。该系统通过集成语音识别模块(SU-03T)、OLED显示屏和环境传感器,构建了一个完整的智能空气净化解决方案。

二、硬件设计

2.1 模块组成

使用模块:
STM32最小系统版
温湿度传感器
MQ7 一氧化碳检测模块
MQ2 烟雾检测模块
MQ135空气质量检测模块
PM2.5 检测模块
蜂鸣器
0.96OLED屏幕
WiFi模块
风扇
加湿器
驱动模块
按键

2.2  原理图

2.3  PCB

三、软件设计

3.1 功能

  1. 语音控制功能:通过SU-03T语音识别模块,用户可以使用自然语音指令(如"打开净化器"、"关闭净化器")直接控制设备开关,提供便捷的人机交互体验。

  2. 环境状态监测:系统能够实时监测室内空气质量参数,包括颗粒物浓度、有害气体含量等环境指标,为净化决策提供数据支持。

  3. 智能显示界面:OLED显示屏实时显示设备工作状态、环境质量数据和操作提示,让用户直观了解当前环境状况和设备运行情况。

  4. 多模式净化控制:系统支持手动和自动两种工作模式,可根据环境质量自动调整净化强度,实现智能化运行。

  5. 串口通信协议:设计了稳定的数据通信协议,确保STM32主控制器与各外设模块之间的可靠数据传输。

  6. 安全保护机制:具备异常状态检测和处理能力,当检测到环境异常(如空气质量严重污染)时自动触发相应的保护措施。

  7. APP数据查看、阈值下发、净化器控制

3.2 main代码

#include "delay.h"
#include "sys.h"
#include "led.h" //控制器
#include "oled.h"
#include "esp8266.h"
#include "Timer.h"
#include "Key.h"
#include "stmflash.h"
#include "su_03t.h"
// 传感/执行模块
#include "dht11.h"
#include "PM25.h"
#include "AD.h"
//C库
#include <string.h>
#include "stdio.h"
#include "math.h"
#include "stdbool.h"




/*********************************** 变量声明**********************************/
extern unsigned char esp8266_buf[buf_len];
// 定义在头文件中声明的外部变量
control_mode MODE = manual_mode;  // 初始化为手动模式
//阈值结构体
struct Set_data
{
  u16 temp_H;  //温度上限
	u16 temp_L;  //温度下限
	u16 air_H;  //空气质量上限
	u16 co_H;   //一氧化碳上限
	u16 pm25_H; //PM2.5上限
	u16 smoke_H; //烟雾浓度上限
};

struct Set_data Out_data={30,20,30,40,50,60};//初始化阈值

//数据获取
u16 temp_value=0;
u16 humi_value=0;
u16 co_value=0;
float air_value=0;
u16 pm25_value=0;
u16 smoke_value=0;

DHT11_Data_TypeDef DHT11_Data;//dht11添加变量 

////按键相关的变量
u8 key_num=0,Page_flag=1;
char TIMER_IT=0,WiFiInit_time,Flagout=1;

//oled相关变量
u8 oled_Fill_flag=1;//OLED清屏标志
char oled_str[100];//OLED显示缓存
char date[200];//esp8266发送缓存

bool beep_flag=false;//蜂鸣器标志位
//DOOR=false;//门锁状态
u8 alarm_flag=0;//报警标志位

//设备控制状态变量
bool fan_state=false;        //风扇状态
bool humidifier_state=false; //加湿器状态


bool need_purify;
u8 air_alarm;
u8 co_alarm;

u8 co_flag=0;
u8 air_flag=0;
int num;
/********************************函数声明**********************************/
// 在main函数前添加函数声明
void Page_data(void);    // 数据显示界面
void Page_control(void);    //控制外设
void Page_setting(void); // 设置界面
void APP_Control(void); //APP数据下发
void BI_BI(void); //哔哔提醒数据下发


int main(void){
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	DHT11_Init();//初始化DHT11
	
	LED_Init();
	BEEP=OFF;//蜂鸣器关闭
	purifier_state=false;
  Purifier_Control(OFF);
	
	PM25_Init();
	AD_Init();//模拟量模块
	Key_Init();//按键初始化
  SU_03T_Iint(9600);//SU03T  语言
	SU_03T_Iint(9600);//语音模块

	
  OLED_Init();//OLED初始化
  OLED_Clear(0);
	    
	do
	{
			OLED_ShowText(0, 0,(u8*) "是否需要联网?", 0);
			OLED_ShowText(8, 4,(u8*) "1.是  2.否", 0);
			key_num=KEY_Scan(0);//按键扫描
			if(key_num==1)//需要联网
			{
					OLED_Clear(0);
					Timer_Init();
					ESP8266_Init(115200);
					break;
			}
	}while(key_num!=2); 
		
   OLED_Clear(0);

    /*读出内存数据*/
    STMFLASH_Read(FLASH_SAVE_ADDR,    &Out_data.temp_H,1);
    delay_ms(100);
		STMFLASH_Read(FLASH_SAVE_ADDR+2,  &Out_data.temp_L,1);
    delay_ms(100);
    STMFLASH_Read(FLASH_SAVE_ADDR+6,  &Out_data.air_H,1);
    delay_ms(100);
		STMFLASH_Read(FLASH_SAVE_ADDR+4,  &Out_data.co_H,1);
    delay_ms(100);
		STMFLASH_Read(FLASH_SAVE_ADDR+8,  &Out_data.pm25_H,1);
    delay_ms(100);
		STMFLASH_Read(FLASH_SAVE_ADDR+10,  &Out_data.smoke_H,1);
    delay_ms(100);
   
   
   

	while(1)
	{
     /*********************************数据处理区*********************************/ 
						
					//获取温湿度 
					Read_DHT11(&DHT11_Data);    
					temp_value= DHT11_Data.temp_int; //获取温度
					humi_value= DHT11_Data.humi_int; //获取湿度
		
		     //获取一氧化碳
		     co_value= GetMQ7Value();
		
				 //获取空气质量
		     air_value=MQ135_GetData_PPM();
		
				 //获取PM2.5浓度
				 pm25_value = PM2_5_GetData();
		     
		     //获取烟雾浓度
		     smoke_value = GetMQ2Value();
		
		   
        /*******************向巴法云发送数据***************************************/
        if(TIMER_IT)
        {
            TIMER_IT=0;
            sprintf(date,"cmd=2&uid=%s&topic=data&msg=#%d#%d#%d#%d#%d#%d#sensordata#\r\n",\
            BEMFA_ID,
            MODE,(int)pm25_value,(int)smoke_value,(int)air_value,(int)co_value,(int)need_purify);
            ESP8266_SendData((unsigned char *)date);//ESP8266发送数据
        }	
   /*********************************人机交互区**************************************************/      
				key_num=KEY_Scan(0);//按键扫描
        if(key_num==1)//界面切换键
        {
            Page_flag++;
            Page_flag=Page_flag%3;
            OLED_Clear(0);//清屏
        }      
        //界面切换功能
        switch(Page_flag)
        {    
            case 1: 
                Page_data();    // 第一界面 - 数据显示
                break;
            case 2: 
                Page_control();    //控制外设; // 第三界面 - 设置界面
                break;
            case 0: 
                Page_setting(); // 第三界面 - 设置界面
                break;
        }

	/*********************************模式控制区*********************************/
  
	/******************APP指令下发********************************/
  APP_Control();//阈值下发  模式转换
    			
	/********************自动模式******************************/
			
			
	if(MODE==auto_mode){
		// 自动模式:当任一指标超过阈值时,开启净化器并报警
		bool pm25_over = (pm25_value > Out_data.pm25_H);
		bool smoke_over = (smoke_value > Out_data.smoke_H);
		bool co_over = (co_value > Out_data.co_H);
		bool air_over = ((int)air_value > Out_data.air_H);

		need_purify = pm25_over || smoke_over || co_over || air_over;

		// 设置报警状态(用于上报)
		co_alarm = co_over ? 1 : 0;
		air_alarm = air_over ? 1 : 0;

		if(need_purify){
			purifier_state = true;
			Purifier_Control(ON);   // 同时打开风扇与加湿器
			beep_flag = true;       // 蜂鸣器报警(在定时器中断内以闪烁方式执行)
			
			if(air_flag==1){
			SU_03T_SendArray(air_bad_TxPacket,5);
			air_flag=0;
			}
			
		}else{
			purifier_state = false;
			Purifier_Control(OFF);
			beep_flag = false;      // 关闭报警
			air_flag=1;
		}
	}//自动模式
		
	
		
  /********************手动模式*****************************/
			
	if(MODE==manual_mode)//手动模式
		{
			
		// 检查是否需要发送空气质量
		if(SU_03T_GetSendAirFlag==1)
		{
				// 发送帧头
				SU_03T_SendByte(0xAA);
				SU_03T_SendByte(0x55);
				
				// 发送命令字
				SU_03T_SendByte(0x01);
			
				int air_data[1];
				air_data[0] = (int)air_value;  //空气质量
			  
			
				// 调整发送顺序为低字节在后
				// 发送每个时间值(4字节)
				for(int i = 0; i < 1; i++)
				{
						// 调整发送顺序为低字节在后
						SU_03T_SendByte(air_data[i] & 0xFF);          // 最低字节
						SU_03T_SendByte((air_data[i] >> 8) & 0xFF);   // 次低字节
						SU_03T_SendByte((air_data[i] >> 16) & 0xFF);  // 次高字节
						SU_03T_SendByte((air_data[i] >> 24) & 0xFF);  // 最高字节
				}
			
					
				// 发送帧尾
				SU_03T_SendByte(0x55);
				SU_03T_SendByte(0xAA);
			
				
				
				SU_03T_GetSendAirFlag=0;  //重置标志位
			
		}	 //AIR
		

		
		
		// 检查是否需要发送空气质量
		if(SU_03T_GetSendTempFlag==1)
		{
				// 发送帧头
				SU_03T_SendByte(0xAA);
				SU_03T_SendByte(0x55);
				
				// 发送命令字
				SU_03T_SendByte(0x02);
			
				int air_data[1];
				air_data[0] = (int)temp_value;  //温度
			  
			
				// 调整发送顺序为低字节在后
				// 发送每个时间值(4字节)
				for(int i = 0; i < 1; i++)
				{
						// 调整发送顺序为低字节在后
						SU_03T_SendByte(air_data[i] & 0xFF);          // 最低字节
						SU_03T_SendByte((air_data[i] >> 8) & 0xFF);   // 次低字节
						SU_03T_SendByte((air_data[i] >> 16) & 0xFF);  // 次高字节
						SU_03T_SendByte((air_data[i] >> 24) & 0xFF);  // 最高字节
				}
			
					
				// 发送帧尾
				SU_03T_SendByte(0x55);
				SU_03T_SendByte(0xAA);
			
				SU_03T_GetSendTempFlag=0;  //重置标志位
			
		}	 //AIR
		
			
	
		
		
	

				
		}//手动模式

     
    }//while
}//main



void TIM2_IRQHandler(void)
{
 if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
    {
			
			
        TIMER_IT=1;
        
        if(beep_flag)
        {
            BEEP=!BEEP;
        }
        else
        {
            BEEP=0;
        }
        
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    }
}


void APP_Control(void)
{
   //模式切换
   if( strstr((const char *)esp8266_buf,"ZD")!=0 )
   { 
       MODE=auto_mode;
       BI_BI();//哔哔提醒
       ESP8266_Clear();//清除缓存
   }
   else if( strstr((const char *)esp8266_buf,"SD")!=0 )
   {
       MODE=manual_mode;
       beep_flag=false;
       BEEP=OFF;
			purifier_state=false;
       Purifier_Control(OFF);
		   BI_BI();//哔哔提醒
       ESP8266_Clear();//清除缓存
   } 
   

  
   
   // PM2.5阈值设置
   char *pm25_ptr = strstr((char *)esp8266_buf, "PM25");
   if (pm25_ptr != NULL && sscanf(pm25_ptr + 4, "=%hu", &Out_data.pm25_H) == 1) 
   {	
           
     BI_BI();//哔哔提醒
      ESP8266_Clear();//清除缓存
     STMFLASH_Write(FLASH_SAVE_ADDR+8, &Out_data.pm25_H, 1);

   }
   
   // 烟雾浓度阈值设置
   char *smoke_ptr = strstr((char *)esp8266_buf, "SMOKE");
   if (smoke_ptr != NULL && sscanf(smoke_ptr + 5, "=%hu", &Out_data.smoke_H) == 1) 
   {	
         
     BI_BI();//哔哔提醒
      ESP8266_Clear();//清除缓存
     STMFLASH_Write(FLASH_SAVE_ADDR+10, &Out_data.smoke_H, 1);
   }
   
   // CO阈值设置
   char *co_ptr = strstr((char *)esp8266_buf, "COH");
   if (co_ptr != NULL && sscanf(co_ptr + 3, "=%hu", &Out_data.co_H) == 1) 
   {	
     BI_BI();//哔哔提醒
     ESP8266_Clear();//清除缓存
     STMFLASH_Write(FLASH_SAVE_ADDR+4, &Out_data.co_H, 1);
   }
   
   // 空气质量阈值设置
   char *air_ptr = strstr((char *)esp8266_buf, "AIR");
   if (air_ptr != NULL && sscanf(air_ptr + 3, "=%hu", &Out_data.air_H) == 1) 
   {	
     BI_BI();//哔哔提醒
     ESP8266_Clear();//清除缓存
     STMFLASH_Write(FLASH_SAVE_ADDR+6, &Out_data.air_H, 1);
   }
   
//   // 风扇控制
//   if( strstr((const char *)esp8266_buf,"FAN_ON")!=0 )
//   {
//       fan_state=true;
//       FAN=ON;
//       BI_BI();//哔哔提醒
//       ESP8266_Clear();//清除缓存
//   }
//   else if( strstr((const char *)esp8266_buf,"FAN_OFF")!=0 )
//   {
//       fan_state=false;
//       FAN=OFF;
//       BI_BI();//哔哔提醒
//       ESP8266_Clear();//清除缓存
//   }
//   
//   // 加湿器控制
//   if( strstr((const char *)esp8266_buf,"HUM_ON")!=0 )
//   {
//       humidifier_state=true;
//       HUMIDIFIER=ON;
//       BI_BI();//哔哔提醒
//       ESP8266_Clear();//清除缓存
//   }
//   else if( strstr((const char *)esp8266_buf,"HUM_OFF")!=0 )
//   {
//       humidifier_state=false;
//       HUMIDIFIER=OFF;
//       BI_BI();//哔哔提醒
//       ESP8266_Clear();//清除缓存
//   }
   
   // 净化器控制
   if( strstr((const char *)esp8266_buf,"PUR_ON")!=0 )
   {
       purifier_state=true;
     Purifier_Control(ON);
       BI_BI();//哔哔提醒
       ESP8266_Clear();//清除缓存
   }
   else if( strstr((const char *)esp8266_buf,"PUR_OFF")!=0 )
   {
       purifier_state=false;
   Purifier_Control(OFF);
       BI_BI();//哔哔提醒
       ESP8266_Clear();//清除缓存
   }
  
}

// 数据显示界面
void Page_data(void)
{
		// 添加按键2的模式切换功能
    if(key_num==2)//模式切换键
    {
        MODE++;
        if(MODE > manual_mode) MODE = auto_mode; // 循环切换:自动->手动->自动
        
        // 切换到手动模式时关闭报警和设备
        if(MODE == manual_mode)
        {
            beep_flag=false;
            BEEP=OFF;
						purifier_state=false;
            Purifier_Control(OFF);
      
        }
    }
	
  
		//PM2.5浓度
		sprintf(oled_str,"PM2.5:%d ",(int)pm25_value);
    OLED_ShowText(0,0,(u8*)oled_str,0);
	  //一氧化碳浓度
	  sprintf(oled_str,"CO浓度:%4dppm",(int)co_value);
    OLED_ShowText(0,2,(u8*)oled_str,0);
		//空气质量
		sprintf(oled_str,"空气质量:%dppm  ",(int)air_value);
    OLED_ShowText(0,4,(u8*)oled_str,0);
	  //烟雾浓度
	  sprintf(oled_str,"烟雾浓度:%dppm  ",(int)smoke_value);
    OLED_ShowText(0,6,(u8*)oled_str,0);
		
		
		
	  //模式状态
    sprintf(oled_str,"%s",MODE?"手动":"自动");
    OLED_ShowText(95,0,(u8*)oled_str,0);
    
    
   
}

//控制界面
void Page_control(void)
{
    static u8 Index_flag=1;


    sprintf(oled_str,"净化器:%s",purifier_state?"ON ":"OFF");
    OLED_ShowText(16,0,(u8 *)oled_str,0);
    
    sprintf(oled_str,"返回主页");
    OLED_ShowText(16,2,(u8 *)oled_str,0);
    
    // 处理按键2选择逻辑
    if(key_num==2)
    {
        Index_flag++;
        if(Index_flag > 2) Index_flag = 1; // 循环选择
    }               
        
        // 箭头显示和控制逻辑
        switch(Index_flag)
        {   
            case 1:      
                OLED_ShowString(0,0,(u8 *)">",16) ; 
                OLED_ShowString(0,2,(u8 *)" ",16) ;
                OLED_ShowString(0,4,(u8 *)" ",16) ; 
                OLED_ShowString(0,6,(u8 *)" ",16) ;             
                break;
            case 2:      
                OLED_ShowString(0,0,(u8 *)" ",16) ; 
                OLED_ShowString(0,2,(u8 *)">",16) ;
                OLED_ShowString(0,4,(u8 *)" ",16) ; 
                OLED_ShowString(0,6,(u8 *)" ",16) ;             
                break; 
            case 3:      
                OLED_ShowString(0,0,(u8 *)" ",16) ; 
                OLED_ShowString(0,2,(u8 *)" ",16) ;
                OLED_ShowString(0,4,(u8 *)">",16) ; 
                OLED_ShowString(0,6,(u8 *)" ",16) ;             
                break;
            case 4:      
                OLED_ShowString(0,0,(u8 *)" ",16) ; 
                OLED_ShowString(0,2,(u8 *)" ",16) ;
                OLED_ShowString(0,4,(u8 *)" ",16) ; 
                OLED_ShowString(0,6,(u8 *)">",16) ;             
                break;  
        }    
        
        if(MODE==manual_mode)//手动模式下
        {
   
           // 净化器控制(同时控制风扇和加湿器)
          if(Index_flag==1&&key_num==3) 
            {
                purifier_state=true;
                Purifier_Control(ON);
            }
            if(Index_flag==1&&key_num==4) 
            {
                purifier_state=false;
                Purifier_Control(OFF);
            }
            
            // 返回主页
            if(Index_flag==2&&key_num==3) 
            {
                Page_flag=1; // 返回数据显示页面
            }
        }
}

// 设置界面
void Page_setting(void)
{
    static u8 Index_flag=1;
    // 显示设置参数
    sprintf(oled_str,"PM2.5阈值:%d  ",Out_data.pm25_H);
    OLED_ShowText(16,0,(u8 *)oled_str,0);
    sprintf(oled_str,"CO阈值:%d  ",Out_data.co_H);
    OLED_ShowText(16,2,(u8 *)oled_str,0);
    sprintf(oled_str,"空气质量:%d  ",Out_data.air_H);
    OLED_ShowText(16,4,(u8 *)oled_str,0);
    sprintf(oled_str,"烟雾阈值:%d  ",Out_data.smoke_H);
    OLED_ShowText(16,6,(u8 *)oled_str,0);
               
    // 处理参数调节逻辑
    if(key_num==2)
    {
        Index_flag++;
        Index_flag=Index_flag%4; // 修改为4个选项
    }               
    
    // 箭头显示和参数调节逻辑
    switch(Index_flag)
    {
        case 1:      
            OLED_ShowString(0,0,(u8 *)">",16) ; 
            OLED_ShowString(0,2,(u8 *)" ",16) ;
            OLED_ShowString(0,4,(u8 *)" ",16) ; 
            OLED_ShowString(0,6,(u8 *)" ",16) ;             
            break;
        case 2:      
            OLED_ShowString(0,0,(u8 *)" ",16) ; 
            OLED_ShowString(0,2,(u8 *)">",16) ;
            OLED_ShowString(0,4,(u8 *)" ",16) ; 
            OLED_ShowString(0,6,(u8 *)" ",16) ;             
            break;
        case 3:      
            OLED_ShowString(0,0,(u8 *)" ",16) ; 
            OLED_ShowString(0,2,(u8 *)" ",16) ;
            OLED_ShowString(0,4,(u8 *)">",16) ; 
            OLED_ShowString(0,6,(u8 *)" ",16) ;             
            break;
        case 0:      
            OLED_ShowString(0,0,(u8 *)" ",16) ; 
            OLED_ShowString(0,2,(u8 *)" ",16) ;
            OLED_ShowString(0,4,(u8 *)" ",16) ; 
            OLED_ShowString(0,6,(u8 *)">",16) ;             
            break; 						 
    }    

    // 处理参数调节
		
    //PM2.5阈值
    if(Index_flag==1&&key_num==3)  
    {
        Out_data.pm25_H < 300 ?  Out_data.pm25_H++ : 300;//PM2.5阈值不能超过300μg/m?
        STMFLASH_Write(FLASH_SAVE_ADDR+8, &Out_data.pm25_H,1);
    }
    if(Index_flag==1&&key_num==4)  
    {
        Out_data.pm25_H > 0 ?  Out_data.pm25_H-- : 0; //PM2.5阈值不能低于0
        STMFLASH_Write(FLASH_SAVE_ADDR+8, &Out_data.pm25_H,1);
    } 
		
    //CO阈值
    if(Index_flag==2&&key_num==3)  
    {
        Out_data.co_H < 200 ?  Out_data.co_H++ : 200;//CO阈值不能超过200ppm
        STMFLASH_Write(FLASH_SAVE_ADDR+4, &Out_data.co_H,1);
    } 
    if(Index_flag==2&&key_num==4)  
    {
        Out_data.co_H > 0 ?  Out_data.co_H-- : 0; //CO阈值不能低于0
        STMFLASH_Write(FLASH_SAVE_ADDR+4, &Out_data.co_H,1);
    }
    
    //空气质量阈值
    if(Index_flag==3&&key_num==3)  
    {
        Out_data.air_H < 100 ?  Out_data.air_H++ : 100;//空气质量阈值不能超过100ppm
        STMFLASH_Write(FLASH_SAVE_ADDR+6, &Out_data.air_H,1);
    }
    if(Index_flag==3&&key_num==4)  
    {
        Out_data.air_H > 0 ?  Out_data.air_H-- : 0; //空气质量阈值不能低于0
        STMFLASH_Write(FLASH_SAVE_ADDR+6, &Out_data.air_H,1);
    }
    
    //烟雾浓度阈值
    if(Index_flag==0&&key_num==3)  
    {
        Out_data.smoke_H < 100 ?  Out_data.smoke_H++ : 100;//烟雾浓度阈值不能超过100ppm
        STMFLASH_Write(FLASH_SAVE_ADDR+10, &Out_data.smoke_H,1);
    }
    if(Index_flag==0&&key_num==4)  
    {
        Out_data.smoke_H > 0 ?  Out_data.smoke_H-- : 0; //烟雾浓度阈值不能低于0
        STMFLASH_Write(FLASH_SAVE_ADDR+10, &Out_data.smoke_H,1);
    }
}


void BI_BI(void){
 BEEP=ON;
 delay_ms(150);
 BEEP=OFF;

}

四、系统实现与测试

4.1 B站视频介绍

STM32空气净化器

五、结论与展望

5.1  小结

可以拓展更多的执行器控制,丰富语音功能!

六、资料内容及获取

B站关注UP主,一键三联,私信博主!!!

基于STM32单片机空气净化器项目源码(毕业设计),个人经导师指导并认可通过的高分设计项目,评审分99分,代码完整确保可以运行,小白也可以亲自搞定,主要针对计算机相关专业的正在做毕业设计的学生和需要项目实战练习的学习者,可作为毕业设计、课程设计、期末大作业,代码资料完整,下载可用。 基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM32单片机空气净化器项目源码(毕业设计)基于STM3
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值