文章目录
一、前言
实物项目成品:

仿真项目成品:

哔哩哔哩开源视频链接(复制浏览器打开):
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;
}
}
}
六、包含内容

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