【STM32项目开源】基于STM32的智能家居环境(空气质量)检测系统
目录
一、设计背景和意义
1.1设计背景
1.2设计意义
二、实物效果展示
2.1实物图片
2.2实物演示视频
三、硬件功能简介
3.1项目功能详解
3.2元器件清单
四、主框图与软件流程图
五、硬件PCB展示
六、软件程序设计
七、项目资料包内容
资料获取:查看主页介绍“充哥单片机设计”
一、设计背景和意义
1.1设计背景
近年来,随着城市化进程加快以及工业活动日益频繁,环境污染问题日益严重,尤其是在空气质量方面的隐患愈发突出。诸如PM2.5颗粒物、二氧化碳、甲醛、氨气等有害气体的浓度升高,不仅影响人们的日常生活与工作效率,更对人体健康构成了潜在威胁。同时,随着人们生活品质的不断提升,公众对于居住和工作环境中的空气质量、温湿度、光照等指标提出了更高要求。传统的环境检测手段多依赖人工采集或单一传感器监测,存在信息滞后、响应不及时、功能单一和缺乏远程交互等显著不足,难以满足现代社会“智能化”“互联化”的发展趋势。
1.2设计意义
本课题的研究不仅有助于提高环境感知技术在智能家居场景中的普及度与实用性,也为计算机与电子信息工程专业学生提供一个涵盖嵌入式开发、传感器应用、物联网通信与云平台交互的综合实践平台。其实现过程充分锻炼了项目分析、系统设计、软硬件调试、逻辑控制与通信编程等多方面能力,具有重要的学习价值与推广意义。未来,该系统还可根据需求扩展更多功能,如数据可视化分析、联动控制多种设备,为构建更加智能、绿色、安全的室内环境提供可行技术路径与应用基础。
二、实物效果展示
2.1实物图片
2.2实物演示视频
【开源】基于STM32的智能环境监测系统
三、硬件功能简介
3.1项目功能详解
1)传感器检测:空气质量、光照强度、温湿度、PM2.5粉尘传感器、CO2浓度传感器
2)数据显示:0.96OLED屏幕
3)执行机构:控制风扇、声光报警
4)接入云平台:系统通过ESP8266 WIFI联网后,接入机智云平台
5)App远程监控:通过App远程监控全部传感器数据
6)阈值设定:系统通过按键设定阈值,也可以通过手机App远程设定
7)自动模式:当空气质量、PM2.5、CO2、温湿度等数据超过阈值,自动打开风扇并且开启声光报警
3.2元器件清单
- 主控STM32F103C8T6最小系统板
- OLED显示屏幕
- ESP8266联网WiFi模块
- DHT11温湿度传感器
- MQ-135空气质量传感器
- PM2.5粉尘颗粒传感器
- 光敏电阻光照传感器
- JW01`二氧化碳传感器
- 蜂鸣器
- 继电器+风扇
- 按键
四、主框图与软件流程图
主框图
流程图
五、硬件PCB展示
六、软件程序设计
#include "sys.h"
#include "delay.h"
#include "adc.h"
#include "gpio.h"
#include "OLED_I2C.h"
#include "timer.h"
#include "MQ7.h"
#include "dht11.h"
#include "esp8266.h"
#include "usart2.h"
#include "usart3.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>#define STM32_RX2_BUF Usart2RecBuf //串口2接收缓存区
#define STM32_Rx2Counter Rx2Counter //串口2接收字节计数
#define STM32_RX2BUFF_SIZE USART2_RXBUFF_SIZE //串口2接收缓存大小#define STM32_RX3_BUF Usart3RecBuf //串口3接收缓存区
#define STM32_Rx3Counter Rx3Counter //串口3接收字节计数
#define STM32_RX3BUFF_SIZE USART3_RXBUFF_SIZE //串口3接收缓存大小#define RATIO 1.0 //校准系数,选择范围0.1~1.0 (传感器一般不需要校准,选择1.0即可)
u16 PM25_Value = 0; //PM2.5
u16 PM25_Value_max = 200; //PM2.5报警值
u8 pmBuf[5]; //pm2.5数据缓存数组
u8 ch2oBuf[8]; //甲醛数据缓存数组char display[16];
unsigned char setn=0; //记录设置键按下的次数
unsigned char temperature=0; //温度变量
unsigned char humidity=0; //湿度变量
unsigned int CH2O_mgvalue = 0; //甲醛变量
unsigned char setTempValue=35; //温度设置值
unsigned char setHumiValue=75; //湿度设置值
unsigned int setCH2OValue=10; //甲醛设置值
unsigned char i=0;unsigned int co_ppm = 0; //co值
unsigned int setCoMaxValue=200; //CO上限bool shuaxin = 1; //刷新数据标志
bool shanshuo = 0; //液晶闪烁标志
bool sendFlag = 1; //串口发送数据标志void displayOriginalInt(void) //显示原始页面
{for(i=0;i<2;i++)OLED_ShowCN(i*16+0,0,i+18,0);//显示中文:温度for(i=0;i<2;i++)OLED_ShowCN(i*16+71,0,i+20,0);//显示中文:湿度for(i=0;i<4;i++)OLED_ShowCN(i*16+0,6,i+24,0);//显示中文:一氧化碳for(i=0;i<2;i++)OLED_ShowCN(i*16+0,4,i+4,0);//显示中文:甲醛OLED_ShowStrPm(0, 2, 2,0);OLED_ShowStr(16, 2, "2.5:", 2,0);OLED_ShowChar(64,6,':',2,0);OLED_ShowChar(32,4,':',2,0);OLED_ShowCentigrade(48, 0,0);OLED_ShowChar(119,0,'%',2,0);
}void displaySetValue(void) //显示设置的值
{if(setn == 1){/*显示温度上限*/OLED_ShowChar(52,4,setTempValue/10+'0',2,0);OLED_ShowChar(60,4,setTempValue%10+'0',2,0);OLED_ShowCentigrade(70, 4,0);}if(setn == 2){/*显示湿度上限*/OLED_ShowChar(52,4,setHumiValue/10+'0',2,0);OLED_ShowChar(60,4,setHumiValue%10+'0',2,0);OLED_ShowChar(68,4,'%',2,0);OLED_ShowChar(76,4,' ',2,0);}if(setn == 3){/*显示甲醛上限*/sprintf(display,"%4.2fmg/m3",(float)setCH2OValue/100);OLED_ShowStr(28, 4, (u8 *)display, 2,0);}if(setn == 4){/*显示PM2.5上限*/sprintf(display,"%03dug/m3 ",PM25_Value_max);OLED_ShowStr(28, 4, (u8 *)display, 2,0);}if(setn == 5){/*显示CO上限*/sprintf(display," %dppm ",setCoMaxValue); OLED_ShowStr(27, 4, (u8 *)display, 2,0);}
}void keyscan(void) //按键扫描
{if(KEY1 == 0) //设置按键按下{delay_ms(20);if(KEY1 == 0){while(KEY1 == 0);BEEP=0;setn ++;if(setn == 1){OLED_CLS(0); //清屏for(i=0;i<4;i++)OLED_ShowCN(i*16+32,0,i+6,0);//显示中文:设置温度 delay_ms(150);}if(setn == 2){for(i=0;i<4;i++)OLED_ShowCN(i*16+32,0,i+10,0);//显示中文:设置湿度 }if(setn == 3){for(i=0;i<4;i++)OLED_ShowCN(i*16+32,0,i+14,0);//显示中文:设置甲醛 }if(setn == 4){for(i=0;i<2;i++)OLED_ShowCN(i*16+24,0,i+14,0);//显示中文:设置OLED_ShowStrPm(56, 0, 2,0);OLED_ShowStr(72, 0, "2.5", 2,0);}if(setn == 5){for(i=0;i<6;i++)OLED_ShowCN(i*16+16,0,i+22,0);//显示中文:设置一氧化碳 }if(setn >= 6) //设置按键按下6次,退出设置{setn = 0;OLED_CLS(0); //清屏displayOriginalInt(); //显示主页}displaySetValue(); //显示设置的值}}if(KEY2 == 0) //加键按下{delay_ms(80);if(KEY2 == 0){if(setTempValue<99 && setn==1)setTempValue++; //温度上限加if(setHumiValue<99 && setn==2)setHumiValue++; //湿度上限加if(setCH2OValue<999 && setn==3)setCH2OValue++; //甲醛上限加if(PM25_Value_max<999 && setn==4)PM25_Value_max++; //PM2.5上限加if(setCoMaxValue<1000 && setn==5)setCoMaxValue++; //一氧化碳上限加displaySetValue(); //显示设置的值}}if(KEY3 == 0) //减键按下{delay_ms(80);if(KEY3 == 0){if(setTempValue>0 && setn==1)setTempValue--; //温度上限减if(setHumiValue>0 && setn==2)setHumiValue--; //湿度上限减if(setCH2OValue>0 && setn==3)setCH2OValue--; //甲醛上限减if(PM25_Value_max>0 && setn==4)PM25_Value_max--; //pm2.5上限减if(setCoMaxValue>0 && setn==5)setCoMaxValue--; //一氧化碳上限减displaySetValue(); //显示设置的值}}
}void UsartSendReceiveData(void) //串口发送和接收数据,用于和手机APP通信
{unsigned char *dataPtr = NULL;char *str1=0,i;int setValue=0;char setvalue[5]={0};char SEND_BUF[200]; //发送数据缓存char TEMP_BUF[100]; //临时缓存数组dataPtr = ESP8266_GetIPD(0); //接收数据if(dataPtr != NULL) //手机端下发了数据{if(strstr((char *)dataPtr,"temp_max:")!=NULL) //接收到设置温度上限的指令{BEEP = 1;delay_ms(80);BEEP = 0;str1 = strstr((char *)dataPtr,"temp_max:");while(*str1 < '0' || *str1 > '9') //判断是不是0到9有效数字{str1 = str1 + 1;delay_ms(10);}i = 0;while(*str1 >= '0' && *str1 <= '9') //判断是不是0到9有效数字{setvalue[i] = *str1;i ++; str1 ++;if(*str1 == ',')break; //换行符,直接退出while循环delay_ms(10);}setvalue[i] = '\0'; //加上结尾符setValue = atoi(setvalue);if(setValue>=0 && setValue<=99){setTempValue=setValue; //设置温度上限displaySetValue(); //显示设置的值}} if(strstr((char *)dataPtr,"humi_max:")!=NULL) //接收到设置湿度上限的指令{str1 = strstr((char *)dataPtr,"humi_max:");while(*str1 < '0' || *str1 > '9') //判断是不是0到9有效数字{str1 = str1 + 1;delay_ms(10);}i = 0;while(*str1 >= '0' && *str1 <= '9') //判断是不是0到9有效数字{setvalue[i] = *str1;i ++; str1 ++;if(*str1 == ',')break; //换行符,直接退出while循环delay_ms(10);}setvalue[i] = '\0'; //加上结尾符setValue = atoi(setvalue);if(setValue>=0 && setValue<=99){setHumiValue=setValue; //设置湿度上限displaySetValue(); //显示设置的值}}if(strstr((char *)dataPtr,"chIIo:")!=NULL) //接收到设置甲醛上限的指令{str1 = strstr((char *)dataPtr,"chIIo:");while(*str1 < '0' || *str1 > '9') //判断是不是0到9有效数字{str1 = str1 + 1;delay_ms(10);}i = 0;while(*str1 >= '0' && *str1 <= '9') //判断是不是0到9有效数字{setvalue[i] = *str1;str1 ++;i ++;if(*str1 == '.')break; //小数点,直接退出while循环delay_ms(10);}if(*str1 == '.'){str1 = str1 + 1;}while(*str1 >= '0' && *str1 <= '9'){setvalue[i] = *str1;i ++; str1 ++;}setvalue[i] = '\0'; //加上结尾符setValue = atoi(setvalue);if(i==2)setValue=setValue*10;if(i==1)setValue=setValue*100;if(setValue>=0 && setValue<=999){setCH2OValue = setValue; //设置的甲醛上限displaySetValue(); //显示设置的值}}if(strstr((char *)dataPtr,"pm_max:")!=NULL) //接收到设置pm2.5的指令{str1 = strstr((char *)dataPtr,"pm_max:");while(*str1 < '0' || *str1 > '9') //判断是不是0到9有效数字{str1 = str1 + 1;delay_ms(10);}i = 0;while(*str1 >= '0' && *str1 <= '9') //判断是不是0到9有效数字{setvalue[i] = *str1;i ++; str1 ++;if(*str1 == '\r')break; //换行符,直接退出while循环delay_ms(10);}setvalue[i] = '\0'; //加上结尾符setValue = atoi(setvalue);if(setValue>=0 && setValue<=999){PM25_Value_max=setValue; //设置pm2.5displaySetValue(); //显示设置的值}}if(strstr((char *)dataPtr,"co_max:")!=NULL) //接收到设置CO上限的指令{str1 = strstr((char *)dataPtr,"co_max:");while(*str1 < '0' || *str1 > '9') //判断是不是0到9有效数字{str1 = str1 + 1;delay_ms(10);}i = 0;while(*str1 >= '0' && *str1 <= '9') //判断是不是0到9有效数字{setvalue[i] = *str1;i ++; str1 ++;if(*str1 == ',')break; //换行符,直接退出while循环delay_ms(10);}setvalue[i] = '\0'; //加上结尾符setValue = atoi(setvalue);if(setValue>=0 && setValue<=1000){setCoMaxValue=setValue; //设置CO上限displaySetValue(); //显示设置的值}}ESP8266_Clear(); //清空缓存}if(sendFlag==1) //800ms上传一次数据{sendFlag = 0; memset(SEND_BUF,0,sizeof(SEND_BUF)); //清空缓冲区memset(TEMP_BUF,0,sizeof(TEMP_BUF)); //清空缓冲区if(temperature>=setTempValue)strcat(SEND_BUF,"temp_warn,"); if(humidity>=setHumiValue)strcat(SEND_BUF,"humi_warn,"); if(PM25_Value>=PM25_Value_max)strcat(SEND_BUF,"pm2.5_warn,"); if((CH2O_mgvalue/10)>=setCH2OValue)strcat(SEND_BUF,"ch2o_warn,"); if(co_ppm>=setCoMaxValue)strcat(SEND_BUF,"co_warn,"); sprintf(TEMP_BUF,"$temp:%d#,$humi:%d#,$ch2o:%.3f#,$pm2.5:%d#,$co:%d#",temperature,humidity,(float)CH2O_mgvalue/1000,PM25_Value,co_ppm);//发送的数据装载:温度,湿度,甲醛,PM2.5,costrcat(SEND_BUF,TEMP_BUF);ESP8266_SendData((u8 *)SEND_BUF, strlen(SEND_BUF)); //ESP8266模块发送数据到手机端ESP8266_Clear(); //清除接收数据的缓存}
}int main(void)
{u16 timeCount=200;bool delay_600ms=1;delay_init(); //延时函数初始化 NVIC_Configuration(); //中断优先级配置KEY_GPIO_Init(); //按键引脚初始化 delay_ms(300); I2C_Configuration(); //IIC初始化OLED_Init(); //OLED液晶初始化OLED_CLS(0); //清屏KEY_GPIO_Init(); //按键引脚初始化 OLED_ShowStr(0, 2, " loading... ", 2,0);//显示加载中while(DHT11_Init()){OLED_ShowStr(0, 2, " DHT11 Init! ", 2,0);//显示DHT11初始化!delay_ms(500);}ESP8266_Init(); //ESP8266初始化 delay_ms(1000);Adc_Init(); //ADC初始化OLED_CLS(0); //清屏USART2_Init(9600); //串口2初始化USART3_Init(9600); //串口3初始化displayOriginalInt(); //显示原始界面TIM3_Init(99,719); //定时器初始化,定时1ms//Tout = ((arr+1)*(psc+1))/Tclk ; //Tclk:定时器输入频率(单位MHZ)//Tout:定时器溢出时间(单位us)while(1){ keyscan(); //按键扫描if(setn == 0) //不在设置状态下{timeCount ++;if(timeCount >= 180){timeCount = 0;DHT11_Read_Data(&temperature,&humidity); //读取温湿度}if(shuaxin == 1) //大概300ms刷新一下{ shuaxin = 0;delay_600ms = !delay_600ms;if(temperature>=setTempValue && shanshuo) //温度超过上限,液晶闪烁显示{OLED_ShowChar(32,0,' ',2,0);OLED_ShowChar(40,0,' ',2,0);}else{OLED_ShowChar(32,0,temperature/10+'0',2,0); //显示温度OLED_ShowChar(40,0,temperature%10+'0',2,0);}if(humidity>=setHumiValue && shanshuo) //湿度超过上限,液晶闪烁显示{OLED_ShowChar(103,0,' ',2,0);OLED_ShowChar(111,0,' ',2,0);}else{OLED_ShowChar(103,0,humidity/10+'0',2,0); //显示湿度OLED_ShowChar(111,0,humidity%10+'0',2,0);}Get_MQ7_PPM(); //读取一氧化碳值Get_CH2O(); //读取甲醛if((CH2O_mgvalue/10)>=setCH2OValue && shanshuo)//甲醛超过上限,液晶闪烁显示{OLED_ShowStr(46, 4, " mg/m3", 2,0);} else {sprintf(display,"%.3fmg/m3",(float)CH2O_mgvalue/1000); OLED_ShowStr(46, 4, (u8 *)display, 2,0); //显示甲醛}if(delay_600ms) {Get_PM2_5(); //读取PM2.5if(PM25_Value>999)PM25_Value=999;}if(PM25_Value>=PM25_Value_max && shanshuo) //pm2.5超过上限,液晶闪烁显示{OLED_ShowStr(56, 2, " ug/m3", 2,0);} else {sprintf(display,"%03dug/m3",PM25_Value);OLED_ShowStr(56, 2, (u8 *)display, 2,0); //显示PM2.5}if(temperature>=setTempValue || humidity>=setHumiValue || (CH2O_mgvalue/10)>=setCH2OValue || PM25_Value>=PM25_Value_max || co_ppm>=setCoMaxValue){BEEP = 1; RELAY=1;} //超出上限,蜂鸣器提醒。开启风扇else{BEEP = 0; RELAY=0;} //关闭风扇和蜂鸣器}}UsartSendReceiveData(); //串口发送接收数据,用于和手机APP通信delay_ms(10);}
}