【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元器件清单

  1. 主控STM32F103C8T6最小系统板
  2. OLED显示屏幕
  3. ESP8266联网WiFi模块
  4. DHT11温湿度传感器
  5. MQ-135空气质量传感器
  6. PM2.5粉尘颗粒传感器
  7. 光敏电阻光照传感器
  8. JW01`二氧化碳传感器
  9. 蜂鸣器
  10. 继电器+风扇
  11. 按键

四、主框图与软件流程图

主框图

流程图

五、硬件PCB展示

六、软件程序设计

cpp 复制代码
#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.5
								displaySetValue();                 //显示设置的值
						}
				}
				
				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,co
			  strcat(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.5
					 if(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);
		}
}

七、项目资料包内容

资料获取:查看主页介绍"充哥单片机设计"

相关推荐
夜月yeyue3 小时前
ART 加速器、流水线与指令预测的关系详解
linux·服务器·c语言·单片机·嵌入式硬件·性能优化·嵌入式高阶技巧
糖糖单片机设计5 小时前
硬件开发_基于物联网的生态环境检测系统
stm32·单片机·嵌入式硬件·物联网·51单片机
A9better5 小时前
嵌入式开发学习日志35——stm32之超声波测距
stm32·单片机·嵌入式硬件·学习
Janspran6 小时前
监控系统1 - 项目框架 | 线程邮箱
网络·单片机·嵌入式硬件·硬件架构
常州晟凯电子科技6 小时前
海思Hi3516CV610/Hi3516CV608开发笔记之环境搭建和SDK编译
人工智能·笔记·嵌入式硬件·物联网
qq_397562316 小时前
STC8H8K64,使用0.96寸oled屏幕. 进行硬件iic和硬件spi驱动(spi开启DMA)---(代码)
单片机·嵌入式硬件
弘毅 失败的 mian6 小时前
STM32 GPIO实战:LED与按键控制
经验分享·笔记·stm32·单片机·嵌入式硬件
国科安芯7 小时前
ASP3605电源芯片的性能优化与改进思路
网络·单片机·嵌入式硬件·安全·性能优化
lzj_pxxw8 小时前
FreeRTOS_API模块综合应用篇(八)
stm32·单片机·嵌入式硬件·mcu