STM32项目开源:粮仓环境安防监测系统(代码 + 原理图 + 仿真)

文章目录


一、前言

实物项目成品:

仿真项目成品:

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

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

(资料分享见文末)

二、项目功能简介

【开源】STM32单片机粮仓环境安防监测系统(代码 + 原理图 + 仿真)-编号:CY26042

功能介绍:

(1)多参数监测:实时采集粮仓温湿度、光照强度、二氧化碳、烟雾、甲醛有毒气体浓度。

(2)OLED 显示:OLED 屏幕实时展示各项采集数据。

(3)超限联动:参数超过阈值,蜂鸣器报警,自动开启风扇排湿排气,APP 同步告警。

(4)防火监测:检测到火苗触发蜂鸣器报警,APP 推送火情提醒。

(5)防盗监测:检测到人员入侵,触发报警,APP 推送防盗提醒。

(6)按键设参:本地按键可修改各项参数安全阈值。

(7)APP 设参:手机 APP 远程设置各项安全阈值。

(8)APP 远程控制:APP 实时查看监测数据,可手动控制风扇开关。

三、PCB设计

四、原理图设计

五、程序设计

代码如下():

c 复制代码
#include "stm32f10x.h"                  // Device header
#include "iwdg.h"
#include "adcx.h"
#include "ldr.h"
#include "oled.h"
#include "dht11.h"
#include "led.h"
#include "key.h"
#include "tim2.h"   
#include "tim3.h"   
#include "usart3.h"   
#include "usart.h"
#include "yl_69.h"
#include "motor.h"
#include "sensormodules.h"
#include "flash.h"
#include "esp8266.h"
#include "stdio.h"
#include <string.h>
#include "stdarg.h"
#include "stdlib.h"
#include <stdlib.h>
#include <stdbool.h>
#define KEY_1	1
#define KEY_2	2
#define KEY_3	3
#define KEY_4	4

#define FLASH_START_ADDR	0x0801f000	//写入的起始地址

SensorModules sensorData;	//声明传感器数据结构体变量
SensorThresholdValue Sensorthreshold;	//声明传感器阈值结构体变量

uint8_t menu = 1;	//显示菜单变量
uint8_t OLED_Clear_Flag;	//阈值设置界面的清屏标志位
uint8_t sendFlag=0;
unsigned char SendString[30];		//向蓝牙发送的显示信息
uint8_t count = 1;
uint8_t SDflag = 0;
extern u8 shuaxing;
extern  vu16 USART1_RX_STA; 
extern const unsigned char BMP[]; 
extern const unsigned char BMP25[];

uint8_t beepflag1,beepflag2,beepflag3,beepflag4,beepflag5,beepflag6;
enum 
{
	display_page1 = 1, //主界面-
	settingsPage   //设置界面
	
}MenuPages;

// 改进的mid函数,增加安全性检查
char * mid(char *dst, size_t dst_size, char *src, int n, int m)
{
    if (dst == NULL || src == NULL || dst_size == 0) {
        return NULL;
    }
    
    int len = strlen(src);
    
    // 调整参数确保在有效范围内
    if (m < 0) m = 0;
    if (m > len) return NULL;
    if (n > len - m) n = len - m;
    if (n >= dst_size) n = dst_size - 1; // 保留空间给null终止符
    
    char *p = src + m;
    char *q = dst;
    
    while (n-- > 0) {
        *(q++) = *(p++);
    }
    *q = '\0'; // 添加字符串终止符
    
    return dst;
}

// 辅助函数:从字符串中提取数字值
int extract_value(char *data_ptr, const char *prefix)
{
    if (data_ptr == NULL) return 0;
    
    int prefix_len = strlen(prefix);
    char *value_ptr = data_ptr + prefix_len;
    char dest[32] = {0};
    int i = 0;
    
    // 跳过可能存在的空格
    while (*value_ptr == ' ') value_ptr++;
    
    // 提取数字部分
    while (*value_ptr >= '0' && *value_ptr <= '9' && i < sizeof(dest)-1) {
        dest[i++] = *value_ptr++;
    }
    dest[i] = '\0';
    
    return (strlen(dest) > 0) ? atoi(dest) : 0;
}
void Usart_SendString(USART_TypeDef *USARTx, unsigned char *str, unsigned short len)
{
	unsigned short count = 0;
	
	for(; count < len; count++)
	{
		USART_SendData(USARTx, *str++);									//发送数据
		while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);		//等待发送完成
	}

}
void Bluetooth_Analyse(void)
{
    if(USART1_RX_STA == 1)
    {
        // 查找温度数据
        char* temp_ptr = strstr((const char*)USART1_RX_BUF, "temp:");
        if(temp_ptr != NULL)
        {
            Sensorthreshold.tempValue = extract_value(temp_ptr, "temp:");
        }
        // 查找湿度数据
        char* humi_ptr = strstr((const char*)USART1_RX_BUF, "humi:");
        if(humi_ptr != NULL) 
        {
            Sensorthreshold.humiValue = extract_value(humi_ptr, "humi:");
        }
        // 查找光照数据
        char* GZ_ptr = strstr((const char*)USART1_RX_BUF, "light:");
        if(GZ_ptr != NULL) 
        {
            Sensorthreshold.luxValue = extract_value(GZ_ptr, "light:");
        }
        // 查找CO2数据
        char* CO2_ptr = strstr((const char*)USART1_RX_BUF, "co2:");
        if(CO2_ptr != NULL) 
        {
            Sensorthreshold.CO2Value = extract_value(CO2_ptr, "co2:");
        }
				// 查找烟雾数据
        char* MQ2_ptr = strstr((const char*)USART1_RX_BUF, "yanwu:");
        if(MQ2_ptr != NULL) 
        {
            Sensorthreshold.MQ2Value = extract_value(MQ2_ptr, "yanwu:");
        }
        // 清空缓冲区
        memset(USART1_RX_BUF, 0, sizeof(USART1_RX_BUF));
        USART1_RX_Count = 0;
        USART1_RX_STA = 0; 
    }
		if(sendFlag==1)    //800ms上传一次数据
		{
			sendFlag = 0;
			SendString[0]='m';
			SendString[1]='s';
			SendString[2]='g';
			SendString[3]='=';
			SendString[4]='#';
			SendString[5]=sensorData.temp /10+'0';
			SendString[6]=sensorData.temp %10+'0';
			SendString[7]='#';
			
			SendString[8]=sensorData.humi/10+'0';
			SendString[9]=sensorData.humi%10+'0';
			SendString[10]='#';
			
			SendString[11]=sensorData.lux/1000+'0';
			SendString[12]=sensorData.lux%1000/100+'0';
			SendString[13]=sensorData.lux%1000%100/10+'0';
			SendString[14]=sensorData.lux%10+'0';
			SendString[15]='#';
			
			SendString[16]=sensorData.CO2/1000+'0';
			SendString[17]=sensorData.CO2%1000/100+'0';
			SendString[18]=sensorData.CO2%1000%100/10+'0';
			SendString[19]=sensorData.CO2%10+'0';
			SendString[20]='#';
			
			SendString[21]=sensorData.MQ2/10+'0';
			SendString[22]=sensorData.MQ2%10+'0';
			SendString[23]='#';
			if(huo==1)
				SendString[24]=1+'0';
			else
				SendString[24]=0+'0';
			SendString[25]='#';
			Usart_SendString(USART1,SendString,26);
		}
}
/**
  * @brief  显示菜单1的固定内容
  * @param  无
  * @retval 无
  */
void OLED_Menu1(void)
{
	 static uint8_t crl_flag1=0,crl_flag2=0;
	 if(huo == 1||men==1)          //检测到火焰
	 {
		 if(crl_flag2==1)
			{
				crl_flag2=0;
				OLED_Clear();
			}
			Delay_ms(10);
			if(huo == 1)
			{
				OLED_DrawBMP(48,1,80,5,(unsigned char *)BMP);  //显示火焰图片
				OLED_ShowChinese(4, 2, 55);
				OLED_ShowChinese(4, 3, 56);	
				OLED_ShowChinese(4, 4, 57);
				OLED_ShowChinese(4, 5, 58);
				OLED_ShowChinese(4, 6, 59);
				OLED_ShowChinese(4, 7, 60);
			}
			if(men == 1)
			{
				OLED_DrawBMP(64,0,104,8,(unsigned char *)BMP25);
				OLED_ShowChinese(1, 2, 61);
				OLED_ShowChinese(1, 3, 62);	
				OLED_ShowChinese(2, 1, 63);
				OLED_ShowChinese(2, 2, 64);
				OLED_ShowChinese(2, 3, 65);
				OLED_ShowChinese(2, 4, 66);
			}
			crl_flag1=1;
	 }
	 
	else
	{
		crl_flag2=1;
		if(crl_flag1==1)
		{
			crl_flag1=0;
			OLED_Clear();
		}
		//显示"环境温度:  C"
		OLED_ShowChinese(1, 1, 8);
		OLED_ShowChinese(1, 2, 9);	
		OLED_ShowChar(1, 5, ':');
		OLED_ShowChar(1, 8, 'C');
		
		//显示"环境湿度:  %"
		OLED_ShowChinese(1, 5, 10);
		OLED_ShowChinese(1, 6, 9);	
		OLED_ShowChar(1, 13, ':');
		OLED_ShowChar(1, 16, '%');
		
		//显示"烟雾"
		OLED_ShowChinese(2, 1, 44);
		OLED_ShowChinese(2, 2, 45);	
		OLED_ShowChar(2, 5, ':');
		OLED_ShowChar(2, 8, '%');
		
		//显示"甲醛"
		OLED_ShowChinese(2, 5, 53);
		OLED_ShowChinese(2, 6, 54);	
		OLED_ShowChar(2, 13, ':');
		OLED_ShowChar(2, 16, '%');
		
		//显示"光照强度:  Lux"
		OLED_ShowChinese(3, 1, 15);
		OLED_ShowChinese(3, 2, 16);	
		OLED_ShowChinese(3, 3, 28);
		OLED_ShowChinese(3, 4, 29);	
		OLED_ShowChar(3, 9, ':');
		OLED_ShowString(3, 14, "Lux");
		
		//显示"二氧化碳: "
		OLED_ShowChinese(4, 1, 24);
		OLED_ShowChinese(4, 2, 25);
		OLED_ShowChinese(4, 3, 26);
		OLED_ShowChinese(4, 4, 27);
		OLED_ShowChar(4, 9, ':');
		OLED_ShowString(4, 14, "ppm");
	}
	
	
//	if(huo==1)       //发生火灾
//	{
//		OLED_ShowChinese(2, 5, 48);
//		OLED_ShowChinese(2, 6, 49);
//		OLED_ShowChinese(2, 7, 51);
//		OLED_ShowChinese(2, 8, 52);
//	}
//	else
//	{
//		OLED_ShowString(2, 9, "  ");
//		OLED_ShowChinese(2, 6, 50);
//		OLED_ShowChinese(2, 7, 51);
//		OLED_ShowChinese(2, 8, 52);
//	}
}

/**
  * @brief  显示菜单1的传感器数据
  * @param  无
  * @retval 无
  */
void SensorDataDisplay1(void)
{
	
	 if(huo == 1||men==1)  
	 {}
	else
	{
		//显示环境温度数据
		OLED_ShowNum(1, 6, sensorData.temp, 2);
		
		//显示环境湿度数据
		OLED_ShowNum(1, 14, sensorData.humi, 2);
		
		//显示烟雾数据
		OLED_ShowNum(2, 6, sensorData.MQ2, 2);
		
		//显示甲醛数据
		OLED_ShowNum(2, 14, sensorData.CH2O/20, 2);
		
		//显示光照强度数据
		OLED_ShowNum(3, 10, sensorData.lux, 4);
		
		//显示CO2浓度数据
		OLED_ShowNum(4, 10, sensorData.CO2, 4);
	}
}
/**
  * @brief  显示阈值设置界面1的固定内容
  * @param  无
  * @retval 无
  */
void OLED_settingsPage1(void)
{
	if(count>4)
	{
			//显示"烟雾"
			OLED_ShowChinese(1, 2, 44);
			OLED_ShowChinese(1, 3, 45);	
			OLED_ShowChar(1, 7, ':');
			//显示"甲醛"
			OLED_ShowChinese(2, 2, 53);
			OLED_ShowChinese(2, 3, 54);	
			OLED_ShowChar(2, 7, ':');
		}
		else
		{
			//显示"温度:"
			OLED_ShowChinese(1, 2, 13);
			OLED_ShowChinese(1, 3, 14);
			OLED_ShowChinese(1, 4, 8);
			OLED_ShowChinese(1, 5, 9);	
			OLED_ShowChar(1, 11, ':');

			//显示"湿度:"
			OLED_ShowChinese(2, 2, 13);
			OLED_ShowChinese(2, 3, 14);
			OLED_ShowChinese(2, 4, 10);
			OLED_ShowChinese(2, 5, 9);	
			OLED_ShowChar(2, 11, ':');

			//显示"光照强度:"
			OLED_ShowChinese(3, 2, 15);
			OLED_ShowChinese(3, 3, 16);
			OLED_ShowChinese(3, 4, 28);
			OLED_ShowChinese(3, 5, 29);	
			OLED_ShowChar(3, 11, ':');
			
			
			//显示"二氧化碳:"
			OLED_ShowChinese(4, 2, 24);
			OLED_ShowChinese(4, 3, 25);
			OLED_ShowChinese(4, 4, 26);
			OLED_ShowChinese(4, 5, 27);	
			OLED_ShowChar(4, 11, ':');
		}
}

/**
  * @brief  显示阈值界面1的传感器数据
  * @param  无
  * @retval 无
  */
void settingsThresholdDisplay1(void)
{
	if(count>4)
	{
		//显示烟雾阈值数据
		OLED_ShowNum(1, 8, Sensorthreshold.MQ2Value, 2);
		
		//显示甲醛阈值数据
		OLED_ShowNum(2, 8, Sensorthreshold.CH2OValue, 2);
	}
	else
	{
		//显示环境温度阈值数据
		OLED_ShowNum(1, 13, Sensorthreshold.tempValue, 2);
		
		//显示环境湿度阈值数据
		OLED_ShowNum(2, 13, Sensorthreshold.humiValue, 2);
		
		//显示光照强度阈值数据
		OLED_ShowNum(3, 13, Sensorthreshold.luxValue, 4);
		
		//显示CO2浓度阈值数据
		OLED_ShowNum(4, 13, Sensorthreshold.CO2Value, 4);
	}
}
/**
  * @brief  显示阈值界面的选择符号
  * @param  num 为显示的位置
  * @retval 无
  */
void OLED_Option(uint8_t num)
{
	switch(num)
	{
		case 1:	
			OLED_ShowChar(1,1,'>');
			OLED_ShowChar(2,1,' ');
			OLED_ShowChar(3,1,' ');
			OLED_ShowChar(4,1,' ');
			break;
		case 2:	
			OLED_ShowChar(1,1,' ');
			OLED_ShowChar(2,1,'>');
			OLED_ShowChar(3,1,' ');
			OLED_ShowChar(4,1,' ');
			break;
		case 3:	
			OLED_ShowChar(1,1,' ');
			OLED_ShowChar(2,1,' ');
			OLED_ShowChar(3,1,'>');
			OLED_ShowChar(4,1,' ');
			break;
		case 4:	
			OLED_ShowChar(1,1,' ');
			OLED_ShowChar(2,1,' ');
			OLED_ShowChar(3,1,' ');
			OLED_ShowChar(4,1,'>');
			break;
		case 5:	
			OLED_ShowChar(1,1,'>');
			OLED_ShowChar(2,1,' ');
			OLED_ShowChar(3,1,' ');
			OLED_ShowChar(4,1,' ');
			break;
		case 6:	
			OLED_ShowChar(1,1,' ');
			OLED_ShowChar(2,1,'>');
			OLED_ShowChar(3,1,' ');
			OLED_ShowChar(4,1,' ');
			break;
		default: break;
	}
}

/**
  * @brief  记录阈值界面下按KEY1的次数
  * @param  无
  * @retval 返回次数
  */
uint8_t SetSelection(void)
{
	if(KeyNum == KEY_2)
	{
		KeyNum = 0;
		count++;
		if (count >= 7)
		{
			count=1;
		}
		if (count == 5)
		{
			OLED_Clear();				//OLED清屏
		}
	}
	return count;
}

/**
  * @brief  对阈值界面的传感器阈值进行修改
  * @param  num 为当前用户需要更改的传感器阈值位置
  * @retval 无
  */
void ThresholdModification(uint8_t num)
{
	switch (num)
	{
		case 1:
			if (KeyNum == 3)
			{
				KeyNum = 0;
				Sensorthreshold.tempValue++;
				if (Sensorthreshold.tempValue > 99)
				{
					Sensorthreshold.tempValue = 1;
				}
			}
			else if (KeyNum == 4)
			{
				KeyNum = 0;
				Sensorthreshold.tempValue--;
				if (Sensorthreshold.tempValue < 1)
				{
					Sensorthreshold.tempValue = 99;
				}				
			}
			break;
		case 2:
			if (KeyNum == 3)
			{
				KeyNum = 0;
				Sensorthreshold.humiValue++;
				if (Sensorthreshold.humiValue > 99)
				{
					Sensorthreshold.humiValue = 1;
				}
			}
			else if (KeyNum == 4)
			{
				KeyNum = 0;
				Sensorthreshold.humiValue--;
				if (Sensorthreshold.humiValue < 1)
				{
					Sensorthreshold.humiValue = 99;
				}				
			}			
			break;		
		case 3:
			if (KeyNum == 3)
			{
				KeyNum = 0;
				Sensorthreshold.luxValue += 10;
				if (Sensorthreshold.luxValue > 2000)
				{
					Sensorthreshold.luxValue = 0;
				}
			}
			else if (KeyNum == 4)
			{
				KeyNum = 0;
				Sensorthreshold.luxValue -= 10;
				if (Sensorthreshold.luxValue > 2000)
				{
					Sensorthreshold.luxValue = 2000;
				}				
			}			
			break;
		case 4:
			if (KeyNum == 3)
			{
				KeyNum = 0;
				Sensorthreshold.CO2Value += 10;
				if (Sensorthreshold.CO2Value > 2000)
				{
					Sensorthreshold.CO2Value = 0;
				}
			}
			else if (KeyNum == 4)
			{
				KeyNum = 0;
				Sensorthreshold.CO2Value -= 10;
				if (Sensorthreshold.CO2Value > 2000)
				{
					Sensorthreshold.CO2Value = 2000;
				}				
			}
			break;
			case 5:
			if (KeyNum == 3)
			{
				KeyNum = 0;
				Sensorthreshold.MQ2Value ++;
				if (Sensorthreshold.MQ2Value > 99)
				{
					Sensorthreshold.MQ2Value = 99;
				}
			}
			else if (KeyNum == 4)
			{
				KeyNum = 0;
				if (Sensorthreshold.MQ2Value > 0)
				{
					Sensorthreshold.MQ2Value --;
				}				
			}
			break;
			case 6:
			if (KeyNum == 3)
			{
				KeyNum = 0;
				Sensorthreshold.CH2OValue ++;
				if (Sensorthreshold.CH2OValue > 99)
				{
					Sensorthreshold.CH2OValue = 99;
				}
			}
			else if (KeyNum == 4)
			{
				KeyNum = 0;
				if (Sensorthreshold.CH2OValue > 0)
				{
					Sensorthreshold.CH2OValue --;
				}				
			}
			break;
		default: break;		
	}
}
																																																	  
/**
  * @brief  获取二氧化碳数据
  * @param  *data 为数据传参
  * @retval 无
  */
void CO2GetData(uint16_t *data,uint16_t *data1)
{
	if (Usart3_RxFlag == 1)
	{
		Usart3_RxFlag = 0;
		*data = (Usart3_RxPacket[2] * 256 + Usart3_RxPacket[3]);
		*data1 = (Usart3_RxPacket[4] * 256 + Usart3_RxPacket[5]);
	}
}

/**
  * @brief  传感器数据扫描
  * @param  无
  * @retval 无
  */
void SensorScan(void)
{
	DHT11_Read_Data(&sensorData.humi, &sensorData.temp);
	LDR_LuxData(&sensorData.lux);
	CO2GetData(&sensorData.CO2,&sensorData.CH2O);  //获取二氧化碳和甲醛数据
	YW_LuxData(&sensorData.MQ2);
}
void Flash_Readdata(void)//读取阈值参数
{
	Sensorthreshold.CO2Value = FLASH_R(FLASH_START_ADDR);	//从指定页的地址读FLASH
	if(Sensorthreshold.CO2Value==65535||Sensorthreshold.CO2Value==0)
		 Sensorthreshold.CO2Value=2000;
	
	Sensorthreshold.luxValue = FLASH_R(FLASH_START_ADDR+2);	//从指定页的地址读FLASH
	if(Sensorthreshold.luxValue==65535||Sensorthreshold.luxValue==0)
		Sensorthreshold.luxValue=400;

		
	Sensorthreshold.tempValue = FLASH_R(FLASH_START_ADDR+4);	//从指定页的地址读FLASH
	if(Sensorthreshold.tempValue==255||Sensorthreshold.tempValue==0)
		 Sensorthreshold.tempValue = 35;
	
	Sensorthreshold.humiValue = FLASH_R(FLASH_START_ADDR+6);	//从指定页的地址读FLASH
	if(Sensorthreshold.humiValue==255||Sensorthreshold.humiValue==0)
		 Sensorthreshold.humiValue=75;
	
	Sensorthreshold.MQ2Value = FLASH_R(FLASH_START_ADDR+8);	//从指定页的地址读FLASH
	if(Sensorthreshold.MQ2Value==255||Sensorthreshold.MQ2Value==0)
		 Sensorthreshold.MQ2Value=65;
	
	Sensorthreshold.CH2OValue = FLASH_R(FLASH_START_ADDR+10);	//从指定页的地址读FLASH
	if(Sensorthreshold.CH2OValue==65535||Sensorthreshold.CH2OValue==0)
		 Sensorthreshold.CH2OValue=25;
}
void UsartSendReceiveData(void)                       //串口发送和接收数据,用于和手机APP通信
{
		static uint8_t num=0;
		unsigned char *dataPtr = NULL;
		char *str1=0,i;
	  int  setValue=0;
	  char setvalue[5]={0};
	  char SEND_BUF[200];            //发送数据缓存
	
	  dataPtr = ESP8266_GetIPD(0);   //接收数据
		if(dataPtr != NULL)           //手机端下发了数据
		{
				Buzzer_ON();
				Delay_ms(100);
				Buzzer_OFF();
				if(strstr((char *)dataPtr,"fengs:")!=NULL)       //接收到设置温度上限的指令
				{
					SDflag=1;
					num++;
					num%=2;
					if(num==1)
					{
						GPIO_SetBits(Relay_PROT, Relay1);
					}
					else
					{
						GPIO_ResetBits(Relay_PROT, Relay1);
					}
				}
				if(strstr((char *)dataPtr,"Stop:")!=NULL)       //接收到设置温度上限的指令
				{
					SDflag=0;	
				}
				if(strstr((char *)dataPtr,"temp:")!=NULL)       //接收到设置温度上限的指令
				{
						str1 = strstr((char *)dataPtr,"temp:");
						
						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)
						{
								Sensorthreshold.tempValue=setValue;        //设置温度上限
						}
				}			
				if(strstr((char *)dataPtr,"humi:")!=NULL)       //接收到设置湿度上限的指令
				{
						str1 = strstr((char *)dataPtr,"humi:");
						
						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)
						{
								Sensorthreshold.humiValue=setValue;        //设置湿度上限
						}
				}
				if(strstr((char *)dataPtr,"yanwu:")!=NULL)       //接收到设置烟雾上限的指令
				{
						str1 = strstr((char *)dataPtr,"yanwu:");
						
						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)
						{
								Sensorthreshold.MQ2Value=setValue;        //设置烟雾上限
						}
				}
				if(strstr((char *)dataPtr,"CHValue:")!=NULL)       //接收到设置甲醛上限的指令
				{
						str1 = strstr((char *)dataPtr,"CHValue:");
						
						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)
						{
								Sensorthreshold.CH2OValue=setValue;        //设置甲醛上限
						}
				}
				if(strstr((char *)dataPtr,"luxValue:")!=NULL)       //接收到设置光照的指令
				{
						str1 = strstr((char *)dataPtr,"luxValue:");
						
						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<=9999)
						{
								Sensorthreshold.luxValue=setValue;        //设置光照上限
						}
				}
				if(strstr((char *)dataPtr,"COValue:")!=NULL)       //接收到设置CO2的指令
				{
						str1 = strstr((char *)dataPtr,"COValue:");
						
						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<=9999)
						{
								Sensorthreshold.CO2Value=setValue;        //设置CO2上限
						}
				}
				ESP8266_Clear();									//清空缓存
		}
		if(sendFlag==1)    //800ms上传一次数据
		{
			  sendFlag = 0;		
				memset(SEND_BUF,0,sizeof(SEND_BUF));   			//清空缓冲区
				
				sprintf(SEND_BUF,"msg=#%d#%d#%d#%d#%d#%d#%d#%d#%d#%d#%d#%d#%d#%d#",sensorData.temp,sensorData.humi,sensorData.CH2O/20,sensorData.lux,sensorData.CO2,sensorData.MQ2,beepflag1,beepflag2,beepflag3,beepflag4,beepflag5,beepflag6,huo==1?1:0,men==1?1:0);//发送的数据装载:温度,湿度,甲醛,PM2.5,co
			  ESP8266_SendData((u8 *)SEND_BUF, strlen(SEND_BUF));   //ESP8266模块发送数据到手机端
			  ESP8266_Clear();                                          //清除接收数据的缓存
		}
}
int main(void)
{
	menu =0;
	ADCX_Init();
	Timer2_Init(9,14398);//定时器2初始化
	ESP8266_Init();//esp8266初始化
	Uart3_Init();
	huo_Init();//火焰传感器初始化
	men_Init();//门磁传感器初始化
	LDR_Init();//光敏电阻、烟雾传感器初始化
	OLED_Init(); //OLED初始化
	DHT11_Init();//温湿度初始化
	LED_Init();//LED初始化
	Buzzer_Init();//蜂鸣器初始化
	Relay_Init();//继电器初始化
	Key_Init();//按键初始化
	OLED_ShowChinese(2, 3, 40);//欢迎使用
	OLED_ShowChinese(2, 4, 41);
	OLED_ShowChinese(2, 5, 42);
	OLED_ShowChinese(2, 6, 43);	
	Delay_ms(1000);
	OLED_Clear();				//OLED清屏
	Flash_Readdata();//读取阈值参数
	GENERAL_TIM_Init();//定时器初始化
	SensorScan();	//获取传感器数据
	menu=1;
	while (1)
	{
		if(SDflag==0)   SensorScan();	//获取传感器数据
		UsartSendReceiveData();
		switch (menu)
		{
			case display_page1:
					SensorDataDisplay1();	//显示传感器1数据 
					OLED_Menu1();	//显示主页面1固定信息	
					if(KeyNum == 1)
					{
						KeyNum = 0;
						OLED_Clear_Flag = 1;
						menu = 2;
					}
					if(shuaxing==1)      //超出范围闪烁
					{
						shuaxing=0;
						if (sensorData.temp > Sensorthreshold.tempValue)
						{
							OLED_ShowString(1,6,"  "); beepflag1=1;
						}
						else    beepflag1=0;
							
						if (sensorData.humi > Sensorthreshold.humiValue)
						{
							OLED_ShowString(1,14,"  ");beepflag2=1;
						}
						else    beepflag2=0;
						
						if (sensorData.MQ2 > Sensorthreshold.MQ2Value)
						{
							OLED_ShowString(2,6,"  "); beepflag3=1;
						}
						else    beepflag3=0;
						
						if (sensorData.lux < Sensorthreshold.luxValue)
						{
							OLED_ShowString(3,10,"    ");beepflag4=1;
						}
						else    beepflag4=0;
						
						if (sensorData.CO2 > Sensorthreshold.CO2Value)
						{
							 OLED_ShowString(4,10,"    "); beepflag6=1;
						}
						else    beepflag5=0;
						
						if (sensorData.CH2O/20 > Sensorthreshold.CH2OValue)
						{
							 OLED_ShowString(2,14,"  ");beepflag5=1;
						}
						else    beepflag6=0;
					}
				break;			
			case settingsPage:
				//从主页面跳转至设置页面时进行一次清屏
				if (OLED_Clear_Flag)
				{
					OLED_Clear_Flag = 0;	//清除清屏标志位
					OLED_Clear();	//清屏
				}
				ThresholdModification(SetSelection());	//调节传感器阈值
				
				
				settingsThresholdDisplay1();	//显示传感器阈值1数据	
				OLED_settingsPage1();	//显示阈值设置界面1固定信息
				OLED_Option(SetSelection());	//获取按键次数,从而判断">"显示位置
	
				if (KeyNum == KEY_1)	//判断用户是否按下退出按键
				{
					KeyNum = 0;
					OLED_Clear();	//清屏
					menu = display_page1;	//回到主页面1
					//存储修改的传感器阈值至flash内
					FLASH_W(FLASH_START_ADDR, Sensorthreshold.CO2Value, Sensorthreshold.luxValue,
							Sensorthreshold.tempValue, Sensorthreshold.humiValue,
							Sensorthreshold.MQ2Value, Sensorthreshold.CH2OValue);
				}
				break;
			default: break;
		}				
	}
}

六、包含内容

七、资料分享

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

相关推荐
Bs_MoneyMagnet1 小时前
基于springboot+vue的旅游行程分享与推荐小程序的设计与实现 源码+文档
java·vue.js·spring boot·后端·微信小程序·毕业设计·计算机毕业设计
羊羊小栈1 小时前
基于「YOLO目标检测 + 多模态AI分析」的公共场所暴力安全智能检测分析预警系统
人工智能·算法·面试·毕业设计·大作业
智碳未来科技有限公司1 小时前
深度排查|InfluxDB浮点精度丢失:导致EMS能耗对账偏差的底层根因与生产根治方案
开源·能源管理系统·数字化能碳管理平台·数字化绿色化协同转型·双化协同
深圳市尚想信息技术有限公司1 小时前
HITENX海速芯TM52F1363-SSOP24 8KB Flash存储+EEPROM,国产8位MCU单片机
单片机·mcu·flask·芯片·控制器·海速芯
Niuguangshuo2 小时前
文本-音频时间戳对齐:5 个开源工具实测
算法·开源·音视频
mitugaoyang19932 小时前
Marvell88Q5152交换机开发(5)-烧录和调试
网络·嵌入式硬件·网络通信
zhangzhangkeji2 小时前
stm32, 4-1 : OLED 调试工具。 4-2: keil 调试
stm32
乱码三千2 小时前
关于让我的 AI 智能体去当三陪帮我打工赚钱这件事,需要从长计议
人工智能·开源·产品
m0_752753122 小时前
51单片机中的定时器和中断等
单片机·51单片机