1、系统功能介绍

  • 1、系统检测环境中温湿度,气压,一氧化碳,空气质量,烟雾浓度和光照强度,并把测量的值显示在屏幕上,数据上报云平台可以通过手机APP实时查看。

  • 2、通过光照强度传感器检测光照强度,当光照强度小于阈值,表明此时天黑了,自动点亮LED灯照明并且驱动步进电机顺时针旋转180度表示拉上窗帘。

  • 3、如果光照强度高,表示是白天,熄灭LED灯,并驱动步进电机逆时针旋转180度,表示拉开窗帘。

  • 4、系统设置有阈值,传感器监测数据不再阈值范围内启动蜂鸣器报警。

  • 根据本篇文章完成毕业设计的开题报告、任务书、设计、毕业论文等

2、演示视频

3、系统电路介绍

3.1、BMP280气压检测电路设计

  • BMP280 是 Bosch 推出的一款高精度数字气压和温度传感器,广泛应用于环境监测、气象站、海拔测量和物联网设备中。它支持 I²C 和 SPI 两种通信接口,供电电压范围通常为 1.71V~3.6V,推荐电压为 3.3V,部分模块通过集成稳压芯片和电平转换器可直接接 5V 系统。
  • BMP280 内部集成高精度压力和温度传感器,其输出为 24 位 ADC 数字信号,通过 I²C 或 SPI 总线传输给主控 MCU。在设计中应注意电源滤波,推荐在 VCC 端并联 0.1μF 去耦电容,确保电源稳定,防止噪声干扰导致测量误差。

电路原理图

实物图:

3.2、MQ135空气质量检测电路设计

  • MQ135 是一种常用的空气质量传感器,能够检测多种有害气体(如氨气、苯类化合物、烟雾、CO₂ 等)。它基于金属氧化物半导体气敏元件,电阻值会随着气体浓度变化,从而实现浓度检测。
  • 在实际应用中,MQ135 需要一定的预热时间(通常 24 至 48 小时)以达到稳定工作状态,其输出信号与气体浓度呈非线性关系,实际测量必须通过标定曲线进行换算。电路布局时,应注意信号线加 RC 滤波并避免靠近高电流元件,以提高抗干扰性能。该电路方案因结构简单、成本低,广泛用于室内空气质量监测、智能家居控制和环境监测系统,配合 STM32 等微控制器,可实现实时空气检测、数据显示以及阈值报警功能。

电路原理图:

实物图:

3.3、DHT11温湿度采集电路设计

  • DHT11 是一种集成了温湿度采集功能的数字传感器,具有低成本、易于使用的特点,广泛应用于环境监测和智能家居系统中。该传感器内部包括一个电容式湿度传感器和一个NTC温度传感器,通过单总线协议将采集到的温湿度数据以数字形式输出,避免了模拟信号传输中的干扰问题。其工作电压通常为 3.3V 至 5V,因而在 STM32 等 3.3V 系统中可以直接连接。
  • DHT11 的通信方式基于单总线协议,MCU 通过控制数据线电平发起启动信号,然后等待传感器响应,并按固定时序读取 40 位数据,其中包括湿度和温度的整数及小数部分,以及校验和。由于该协议对时序要求较高,通常需在程序中使用精确延时函数或定时器进行处理。在电路上,数据线长度应尽量缩短,避免过长的连接线引入信号衰减和干扰。

电路原理图:

实物图:

3.4、MQ7一氧化碳检测采集电路设计

  • MQ7 是一种基于金属氧化物半导体气敏元件的一氧化碳检测传感器,广泛应用于智能家居、环境安全和车载空气监测等领域。它通过检测气体与敏感材料接触时引起的电阻变化,间接获取气体浓度。MQ7 的工作原理要求周期性加热,采用不同的加热电压来实现检测和恢复,这一点在电路设计中需要特别注意。
  • 信号接口方面,AO 端通过电压值反映气体浓度,MCU 可以利用 ADC 通道进行采集;DO 端在超过设定阈值时输出低电平,可直接用于报警。若系统采用 STM32 作为主控,需将 AO 接入 ADC 引脚,DO 接至 GPIO 并启用外部中断,实现实时报警功能。由于输出电压随气体浓度变化的非线性特性,软件上应采用标定曲线或插值算法对 ADC 数据进行浓度换算。

电路原理图:

实物图:

4、程序设计

4.1、BMP280驱动程序

void bmp280GetData(float* pressure,float* temperature,float* asl)
{
    static float t;
    static float p;
	
	bmp280GetPressure();

	t=bmp280CompensateT(bmp280RawTemperature)/100.0;		
	p=bmp280CompensateP(bmp280RawPressure)/25600.0;		

	presssureFilter(&p,pressure);
	*temperature=(float)t;                                                   /*单位度*/
	*pressure=(float)p ;	                                                   /*单位hPa*/	
	
	*asl=bmp280PressureToAltitude(pressure);	                               /*转换成海拔*/	
}

#define CONST_PF 0.1902630958	                                               //(1/5.25588f) Pressure factor
#define FIX_TEMP 25				                                               // Fixed Temperature. ASL is a function of pressure and temperature, but as the temperature changes so much (blow a little towards the flie and watch it drop 5 degrees) it corrupts the ASL estimates.
								                                               // TLDR: Adjusting for temp changes does more harm than good.
/*
 * Converts pressure to altitude above sea level (ASL) in meters
*/
static float bmp280PressureToAltitude(float* pressure/*, float* groundPressure, float* groundTemp*/)
{
    if (*pressure>0)
    {
        return((pow((1015.7f/ *pressure),CONST_PF)-1.0f)*(FIX_TEMP+273.15f))/0.0065f;
    }
    else
    {
        return 0;
    }
}

4.2、OLED驱动程序

/**********************************************
// IIC Write byte
**********************************************/

void OLED_Write_IIC_Byte(unsigned char IIC_Byte)
{
	unsigned char i;
	unsigned char m,da;
	da=IIC_Byte;
	OLED_SCLK_Clr();
	for(i=0;i<8;i++)		
	{
		m=da;
		//	OLED_SCLK_Clr();
		m=m&0x80;
		if(m==0x80)
		{OLED_SDIN_Set();}
		else OLED_SDIN_Clr();
		da=da<<1;
		OLED_SCLK_Set();
		OLED_SCLK_Clr();
	}
}
/**********************************************
// IIC Write Command
**********************************************/
void OLED_Write_IIC_Command(unsigned char IIC_Command)
{
		OLED_IIC_Start();
		OLED_Write_IIC_Byte(0x78);            //Slave address,SA0=0
		OLED_IIC_Wait_Ack();	
		OLED_Write_IIC_Byte(0x00);			//write command
		OLED_IIC_Wait_Ack();	
		OLED_Write_IIC_Byte(IIC_Command); 
		OLED_IIC_Wait_Ack();	
		OLED_IIC_Stop();
}
/**********************************************
// IIC Write Data
**********************************************/
void OLED_Write_IIC_Data(unsigned char IIC_Data)
{
		OLED_IIC_Start();
		OLED_Write_IIC_Byte(0x78);			//D/C#=0; R/W#=0
		OLED_IIC_Wait_Ack();	
		OLED_Write_IIC_Byte(0x40);			//write data
		OLED_IIC_Wait_Ack();	
		OLED_Write_IIC_Byte(IIC_Data);
		OLED_IIC_Wait_Ack();	
		OLED_IIC_Stop();
}
void OLED_WR_Byte(unsigned dat,unsigned cmd)
{
	if(cmd)
	{
   OLED_Write_IIC_Data(dat);
	}
	else
	{
   OLED_Write_IIC_Command(dat);
	}
}


void OLED_ShowCH1(u8 a,u8 b,u8 c,u8 d,u8 e)
{      			    
	
}

void OLED_ShowCH2(u8 a,u8 b,u8 c,u8 d,u8 e)
{      			    
	
}
/********************************************
// fill_Picture
********************************************/
void fill_picture(unsigned char fill_Data)
{
	unsigned char m,n;
	for(m=0;m<8;m++)
	{
		OLED_WR_Byte(0xb0+m,0);		//page0-page1
		OLED_WR_Byte(0x00,0);		//low column start address
		OLED_WR_Byte(0x10,0);		//high column start address
		for(n=0;n<128;n++)
			{
				OLED_WR_Byte(fill_Data,1);
			}
	}
}


/***********************Delay****************************************/
void Delay_50ms(unsigned int Del_50ms)
{
	unsigned int m;
	for(;Del_50ms>0;Del_50ms--)
		for(m=6245;m>0;m--);
}

void Delay_1ms(unsigned int Del_1ms)
{
	unsigned char j;
	while(Del_1ms--)
	{	
		for(j=0;j<123;j++);
	}
}

//坐标设置

void OLED_Set_Pos(unsigned char x, unsigned char y) 
{ 	OLED_WR_Byte(0xb0+y,OLED_CMD);
	OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
	OLED_WR_Byte((x&0x0f),OLED_CMD); 
}   	  
//开启OLED显示    
void OLED_Display_On(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON
	OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
}
//关闭OLED显示     
void OLED_Display_Off(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF
	OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
}		   			 
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!	  
void OLED_Clear(void)  
{  
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{  
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
		OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
		for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA); 
	} //更新显示
}
void OLED_On(void)  
{  
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{  
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
		OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
		for(n=0;n<128;n++)OLED_WR_Byte(1,OLED_DATA); 
	} //更新显示
}

4.3、DHT11驱动程序

//从DHT11读取一个字节
//返回值:读到的数据
u8 DHT11_Read_Byte(void)    
{        
    u8 i,dat;
    dat=0;
	for (i=0;i<8;i++) 
	{
   		dat<<=1; 
	    dat|=DHT11_Read_Bit();
    }						    
    return dat;
}
//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
u8 DHT11_Read_Data(u8 *temp,u8 *humi)    
{        
 	u8 buf[5];
	u8 i;
	DHT11_Rst();
	if(DHT11_Check()==0)
	{
		for(i=0;i<5;i++)//读取40位数据
		{
			buf[i]=DHT11_Read_Byte();
		}
		if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
		{
			*humi=buf[0];
			*temp=buf[2];
		}
	}else return 1;
	return 0;	    
}
//初始化DHT11的IO口 DQ 同时检测DHT11的存在
//返回1:不存在
//返回0:存在    	 
u8 DHT11_Init(void)
{	 
 	GPIO_InitTypeDef  GPIO_InitStructure;
 	
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 //使能PG端口时钟
	
 	GPIO_InitStructure.GPIO_Pin = DHT11_PIN;				 //PG11端口配置
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(DHT11_IO, &GPIO_InitStructure);				 //初始化IO口
 	GPIO_SetBits(DHT11_IO,DHT11_PIN);						 //PG11 输出高
			    
	DHT11_Rst();  //复位DHT11
	return DHT11_Check();//等待DHT11的回应
} 

5、资料下载

  • 点击扫描下方二维码
Logo

更多推荐