STM32项目开源:环境质量监测系统(代码+原理图+仿真)

文章目录


一、前言

实物项目成品:

仿真项目成品:

哔哩哔哩开源视频链接(复制浏览器打开):

https://www.bilibili.com/video/BV1sCY76kEEB/?vd_source=10da4d04d580bd6b34f7298120737c50

(资料分享见文末)

二、项目功能简介

【开源】STM32单片机环境质量监测系统(代码+原理图+仿真)-编号:CY26039

功能介绍:

(1) 传感器采集:采集环境温湿度、JW01 甲醛浓度、MQ-7 一氧化碳浓度以及 PM2.5 粉尘浓度数据。

(2) OLED 显示:OLED 屏幕实时刷新并展示全部环境检测数据。

(3) 按键阈值设置:按键支持对温湿度、甲醛、一氧化碳、PM2.5 各项参数独立设置报警阈值。

(4) 自动控制:当温湿度、甲醛、一氧化碳、PM2.5 中任意一项检测数据超出设定阈值,系统自动控制继电器开启风扇通风,同时驱动蜂鸣器进行报警提示。

(5) 机智云远程监控:通过机智云手机 APP,可以远程实时查看所有传感器环境数据,并且支持远程修改各项环境参数的报警阈值。

三、PCB设计

四、原理图设计

五、程序设计

代码如下():

c 复制代码
#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 "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)  //显示原始页面
{
//	  OLED_Fill_Row(0xff,0);    //反白显示
//	  OLED_Fill_Row(0xff,1);    //反白显示

	  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 Get_PM2_5(void)  //获取PM2.5值
{
    char i = 0;

	  STM32_Rx3Counter = 0;
    if(B_RX_OK == 1)              //串口数据接收完成
    {
        for(i = 0; i < 4; i++)
        {
					  pmBuf[i] = STM32_RX3_BUF[i];
        }
				/* 校验数据是否接收正确,校验方法:判断前面3个字节累加和取低7位是否和最后第4个字节相等 */
				if(((pmBuf[0]+pmBuf[1]+pmBuf[2])&0x7F) == pmBuf[3])  
				{
						PM25_Value = (unsigned int)((pmBuf[1]*128) + pmBuf[2]) * RATIO;   //计算PM2.5(ug/m3) = (pmBuf[1]*128) + pmBuf[2] ;
				}
        B_RX_OK = 0;
    }
}

void Get_CH2O(void)  //获取甲醛
{
    char i = 0;
    u16 sum1=0;
	  u8  sum2=0;
	
	  if(rev_stop == 1)                   //数据接收完成了
	  {
				for(i = 0; i < 8; i++)
				{
						sum1 += STM32_RX2_BUF[i];   //累加和
				}
				sum2=(unsigned char)sum1;
				if(sum2 == STM32_RX2_BUF[8])  //校验数据是否正确: 校验和(B8)=unit_8(B0+B1+B2+B3+B4+B5+B6+B7)
				{
						CH2O_mgvalue = (STM32_RX2_BUF[4]*256 + STM32_RX2_BUF[5]); //计算甲醛值 
				}
				rev_stop = 0;
	  }
}

void Get_MQ7_PPM(void)   //读取一氧化碳值
{
	 co_ppm = MQ7_readPpm();         //读取一氧化碳ppm值
	 if(co_ppm >= 1000)co_ppm = 1000; // 最大1000ppm
	
	 if((co_ppm>=setCoMaxValue) && shanshuo)   //co超过上限,液晶闪烁显示
	 {
		   OLED_ShowStr(71, 6, "    ppm", 2,0);
	 }
	 else
		 
	 {
		   if(co_ppm >= 1000)sprintf(display,"%04dppm",co_ppm); 
		   else  sprintf(display," %03dppm",co_ppm); 
			 OLED_ShowStr(71, 6, (u8 *)display, 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);              //清屏
						
//						  OLED_Fill_Row(0xFF,0);   //填充白色
//						  OLED_Fill_Row(0xFF,1);   //填充白色
							for(i=0;i<4;i++)OLED_ShowCN(i*16+32,0,i+6,0);//显示中文:设置温度
						  /* 显示直线框 */
//							OLED_DrawHorizLine(63,0,127);
//							OLED_DrawVerticaLine(0,2,8);
//							OLED_DrawVerticaLine(127,2,8);
						
						  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();                                            //显示设置的值
			}
	 }
}


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);
			}	
	  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 >= 10)
						 {
								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;}   //关闭风扇和蜂鸣器
						 }
				 }
			   delay_ms(10);
		}
}

void TIM3_IRQHandler(void)//定时器3中断服务程序,用于记录时间
{ 
	  static u16 timeCount1 = 0;
	  static u16 timeCount2 = 0;
	
		if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 
		{ 
				TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除中断标志位  

			  timeCount1 ++;
			  timeCount2 ++;
			  if(timeCount1 >= 300)  //300ms刷新标志置1
				{
						timeCount1 = 0;
					  shanshuo = !shanshuo;
					  shuaxin = 1;
				}
			  if(timeCount2 >= 1000)  //800ms发送数据标志置1
				{
						timeCount2 = 0;
					  sendFlag = 1;
				}
	  }
}

六、包含内容

七、资料分享

资料获取:请查看主页介绍搜索或观看开源视频获取

相关推荐
单片机仿真设计1 小时前
【proteus仿真】基于 STM32+DHT11 温湿度监测系统 Proteus 仿真设计
stm32·单片机·嵌入式硬件·proteus
国科安芯1 小时前
星链供电架构中的高集成度电源管理方案研究——基于ASP4644四通道降压稳压器在低轨卫星星座中的应用分析
大数据·单片机·嵌入式硬件·架构·低轨卫星·星间链路
wuyk5552 小时前
从零吃透 MQTT 通信|第 8 章 FreeRTOS 多任务架构下 MQTT 工程架构,任务拆分、队列解耦、临界区保护
c语言·开发语言·stm32·学习·架构
Riwuarua3 小时前
从近似0基础开始FPGA开发 -- part.10 verilog-ethernet开源UDP协议栈工程学习
fpga开发·udp·开源
xx~t3 小时前
嵌入式——51单片机1
linux·c语言·单片机·嵌入式硬件·51单片机
冬奇Lab4 小时前
一天一个开源项目(第215篇):Langflow - 可视化拖拽构建 AI 应用的低代码平台
人工智能·开源·资讯
GitCode官方4 小时前
本周 G-Star 开源项目推荐
开源·g-star·atomgit
保安大队王队长4 小时前
51单片机知识
单片机·嵌入式硬件·51单片机
ChampaignWolf4 小时前
YAAI 生态一周年:把 ABAP 变成 Agent 工具栈的开源组合拳
开源·abap·mcp·开源ai·yaai