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

二、硬件设计
2.1 模块组成
使用模块:
STM32最小系统版
温湿度传感器
MQ7 一氧化碳检测模块
MQ2 烟雾检测模块
MQ135空气质量检测模块
PM2.5 检测模块
蜂鸣器
0.96OLED屏幕
WiFi模块
风扇
加湿器
驱动模块
按键
2.2 原理图

2.3 PCB

三、软件设计
3.1 功能
-
语音控制功能:通过SU-03T语音识别模块,用户可以使用自然语音指令(如"打开净化器"、"关闭净化器")直接控制设备开关,提供便捷的人机交互体验。
-
环境状态监测:系统能够实时监测室内空气质量参数,包括颗粒物浓度、有害气体含量等环境指标,为净化决策提供数据支持。
-
智能显示界面:OLED显示屏实时显示设备工作状态、环境质量数据和操作提示,让用户直观了解当前环境状况和设备运行情况。
-
多模式净化控制:系统支持手动和自动两种工作模式,可根据环境质量自动调整净化强度,实现智能化运行。
-
串口通信协议:设计了稳定的数据通信协议,确保STM32主控制器与各外设模块之间的可靠数据传输。
-
安全保护机制:具备异常状态检测和处理能力,当检测到环境异常(如空气质量严重污染)时自动触发相应的保护措施。
-
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主,一键三联,私信博主!!!
2337

被折叠的 条评论
为什么被折叠?



