目录

一、项目概述

二、实现功能

三、硬件介绍

四、程序设计

五、项目成品效果图

六、项目总结

七、资料说明

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


一、项目概述

     这次分享的是一个基于STM32F103C8T6做的智能环境监测小项目,能测空气质量、温湿度、PM2.5、甲醛和一氧化碳,超标了会自动开风扇报警,还能连Wi-Fi用手机远程看数据。

硬件方面用了一块STM32F103C8T6最小系统板做主控,外接0.96寸OLED屏幕显示数据,DHT11测温湿度,PM2.5粉尘传感器测颗粒物,三合一传感器测甲醛,MQ-7测一氧化碳,ESP8266连Wi-Fi,继电器控制风扇,再加个蜂鸣器和LED做报警。软件上把各传感器的驱动调通,OLED能正常显示,接入机智云平台实现手机远程查看和控制,本地按键和手机都能改报警值,超标自动触发风扇和报警,数据还会存到阿里云方便以后查历史。

整体代码不复杂,注释也都写清楚了,适合刚接触STM32和物联网的同学参考。实际跑起来效果挺稳定,数据准,联网也可靠,做个宿舍或家里的小型环境监测终端完全够用

二、实现功能

     1、功能详解:

  • 传感器检测:实时采集空气质量、光照强度、温湿度、PM2.5粉尘、三合一甲醛等环境数据。

  • 数据显示:通过0.96寸OLED屏幕直观显示全部传感器数据及对应阈值信息。

  • 执行机构:联动控制风扇与声光报警模块。

  • 接入云平台:通过ESP8266 Wi-Fi联网,接入机智云平台。

  • App远程监控:通过手机App远程查看全部传感器数据。

  • 阈值数据设定:可通过本地按键设定阈值,也可通过手机App远程设定。

  • 自动模式:当空气质量、PM2.5、甲醛等数据超标时,自动开启风扇通风并触发声光报警。

  • 历史数据记录:传感器数据上传并存储于阿里云平台,支持在云平台后台查看历史数据

  • 2、项目清单:

三、硬件介绍

  • PCB硬件设计:

四、程序设计

#include "delay.h"
#include "sys.h"
#include "bmp.h"
#include "usart.h"
#include "dht11.h"
#include "control.h"
#include "adc.h"
#include "IoData.h"
#include "key.h"
#include "kqm2800.h"
#include "timer.h"
#include "oled.h"

/****  数据变量  ****/
int temp_door_value = 30;        //温度阈值解析
int hum_door_value = 20;           //湿度阈值解析
int smoke_door_value = 500;        //烟雾阈值解析
int co2_door_value = 700;        //co2阈值解析
int pm25_door_value = 300;        //pm2.5阈值解析
int light_door_value = 3000;    //光照阈值解析

int auto_mode = 0;                //工作模式


/****  菜单变量  ****/
uint8_t keu_num = 0;
uint8_t page_num = 1;        //页面ID
uint8_t option = 0;            //阈值选项


/****  功能函数声明  ****/
void All_Pin_Init(void);        //系统初始化函数
void get_all_sensor_data();        //传感器数据采集
void Sensor_Data_Handle();        //不同模式下控制效果
void Key_event_handle(void);    //按键功能函数


void OLED_Show_FirstPage();        //第一屏显示内容
void OLED_Show_SecondPage();    //第二屏显示内容
void OLED_Show_ThirdPage();        //第三屏显示内容
void OLED_Show_FourthPage();    //第四屏显示内容

void All_Pin_Init(void)
{
    delay_init();        //系统延时函数初始化
    OLED_Init();        //屏幕初始化
    uart3_init(115200);    //串口3初始化,波特率115200
    uart1_init(115200);    //串口1初始化,波特率115200
    uart2_init(9600);    //串口2初始化,波特率9600,CO2
    DHT11_Init();        //DHT11温湿度初始化
    Control_Init();        //声光报警,照明初始化
    Adc_Init();            //烟雾浓度、pm2.5浓度、光照强度初始化
    TIME_Config();        //定时器初始化
    KEY_Init();            //按键初始化
    PM25_Init();        //PM2.5led引脚初始化
}

int main(void)
{
    All_Pin_Init();
    while(1)    
    {
        if(Time_Period[1]>1000)        //Time_Period[1] 在定时器中累加
        {
            get_all_sensor_data();    //传感器数据采集
            Time_Period[1] = 0;
        }
        Key_event_handle();            //按键监测
        Sensor_Data_Handle();        //数据处理
        if(page_num == 1){            //屏幕更新
            OLED_Show_FirstPage();
        }else if(page_num == 2){
            OLED_Show_SecondPage();
        }else if(page_num == 3){
            OLED_Show_ThirdPage();
        }

    }
}

void Key_event_handle(void)
{
    keu_num = KEY_Scan(0);        //按键扫描赋值
    switch(keu_num)
    {
        case 1:        //按键1按下
            page_num++;option = 0;
            if(page_num == 1){
                OLED_Clear();OLED_Show_FirstPage();
            }else if(page_num == 2){
                OLED_Clear();OLED_Show_SecondPage();
            }else if(page_num == 3){
                OLED_Clear();OLED_Show_ThirdPage();
            }else if(page_num == 4){
                page_num = 1;
                OLED_Clear();OLED_Show_FirstPage();
            }
            break;
        case 2:        //按键2按下
            if(page_num == 2){        //阈值选择
                option++;
                if(option == 5)option = 1;
                OLED_Show_SecondPage();
            }else if(page_num==1){
                auto_mode = !auto_mode;
            }else if(page_num == 3){
                option++;
                if(option == 3)option = 1;
                OLED_Show_ThirdPage();            
            }
            break;
        case 3:        //按键3按下
            if(page_num == 2){
                if(option == 1){
                    temp_door_value += 1;
                }else if(option == 2){
                    hum_door_value += 1;
                }else if(option ==3){
                    smoke_door_value += 15;
                }else if(option ==4){
                    pm25_door_value += 5;
                }
                OLED_Show_SecondPage();
            }else if(page_num == 3){
                if(option==1)co2_door_value += 15;
                else if(option==2)light_door_value += 15;
                OLED_Show_ThirdPage();
            }else    Wind = !Wind;
            break;
        case 4:        //按键4按下
            if(page_num == 2){
                if(option == 1){
                    temp_door_value -= 1;
                }else if(option == 2){
                    hum_door_value -= 1;
                }else if(option ==3){
                    smoke_door_value -= 15;
                }else if(option ==4){
                    pm25_door_value -= 5;
                }
                OLED_Show_SecondPage();
            }else if(page_num == 3){
                if(option==1)co2_door_value -= 15;
                else if(option==2)light_door_value -= 15;
                OLED_Show_ThirdPage();
            }else if(page_num==1){
            
            }
            break;
    }
}

void get_all_sensor_data()
{
    DHT11_Read_Data(&temp,&hum);        //获取温湿度数据
    Get_MQ_Value(&MQ_Value);            //获取烟雾数据
    Get_PM25_Value(&PM25_Value);        //获取PM2.5
    Get_Light_Value(&Light_Value);        //获取光照强度
    Get_CO2_Data();                        //获取CO2浓度
}


void Sensor_Data_Handle()
{
    //自动模式
    if(auto_mode == 1)  //如果开启了自动模式则可以实现根据数据的自动控制
    {
        //温度、湿度、烟雾浓度、pm2.5浓度、CO2浓度、光照强度,超过阈值蜂鸣器报警
        if(temp>temp_door_value||hum>hum_door_value||MQ_Value>smoke_door_value||PM25_Value>pm25_door_value||Kqzl.CO2>co2_door_value||Light_Value>light_door_value){
            Beep = 1;
        } else {
            Beep = 0;
        }
        //温度、湿度、烟雾浓度、pm2.5浓度、CO2浓度,超过阈值打开风扇通风
        if(temp>temp_door_value||hum>hum_door_value||MQ_Value>smoke_door_value||PM25_Value>pm25_door_value||Kqzl.CO2>co2_door_value){
            Wind = 1;
        } else {
            Wind = 0;
        }
    }else{
        //手动模式下,关闭蜂鸣器
        Beep = 0;
    }
}

/*
 温(0) 湿(1) 度(2) 烟(3) 雾(4) 浓(5) 度(6) ℃(7) 自(8) 手(9) 动(10) 模(11) 式(12) 阈(13) 值(14) 空(15) 
 气(16) 质(17) 量(18) 光(19) 照(20) 强(21) 度(22)
*/
void OLED_Show_FirstPage(){

    OLED_ShowString(16*0,0,"T:",16,1);
    OLED_ShowNum(16*1,0,temp,2,16,1);        //    temp
    OLED_ShowChinese(16*2,0,7,16,1);        //    “℃”
    
    OLED_ShowString(16*3+8,0,"PM2.5:",16,1);    //    “:”
    OLED_ShowNum(16*6+8,0,PM25_Value,3,16,1);    //
    
    OLED_ShowString(16*0,16,"H:  %RH",16,1);
    OLED_ShowNum(16*1,16,hum,2,16,1);        //    hum
    
    OLED_ShowString(16*4,16,"CO2:",16,1);
    OLED_ShowNum(16*6,16,Kqzl.CO2,4,16,1);        //    hum
    
    OLED_ShowChinese(16*0,32,19,16,1);        //光
    OLED_ShowChinese(16*1,32,20,16,1);        //照
    OLED_ShowChinese(16*2,32,21,16,1);        //强
    OLED_ShowChinese(16*3,32,22,16,1);        //度
    OLED_ShowChar(16*4,32,':',16,1);        //    “:”
    OLED_ShowNum(16*4+8,32,Light_Value,4,16,1);
    
    OLED_ShowChinese(16*0,48,15,16,1);        //空
    OLED_ShowChinese(16*1,48,16,16,1);        //气
    OLED_ShowChinese(16*2,48,17,16,1);        //质
    OLED_ShowChinese(16*3,48,18,16,1);        //量
    OLED_ShowChar(16*4,48,':',16,1);        //    “:”
    OLED_ShowNum(16*4+8,48,MQ_Value,4,16,1);                //    Soil_Value


    if(auto_mode == 1){
        OLED_ShowChinese(16*7,32,8,16,1);            //    “自”
        OLED_ShowChinese(16*7,48,10,16,1);            //    “动”
    }else if(auto_mode == 0){
        OLED_ShowChinese(16*7,32,9,16,1);            //    “手”
        OLED_ShowChinese(16*7,48,10,16,1);            //    “动”
    }
    
    OLED_Refresh();
}

void OLED_Show_SecondPage(){
    
    uint8_t a,b,c,d;
    if(option==1){a=0;b=1;c=1;d=1;}
    else if(option==2){a=1;b=0;c=1;d=1;}
    else if(option==3){a=1;b=1;c=0;d=1;}
    else if(option==4){a=1;b=1;c=1;d=0;}
    else{a=1;b=1;c=1;d=1;}
    
    OLED_ShowChinese(16*0,0,0,16,1);            //    “温”
    OLED_ShowChinese(16*1,0,2,16,1);            //    “度”
    OLED_ShowChinese(16*2,0,13,16,1);            //    “阈”
    OLED_ShowChinese(16*3,0,14,16,1);            //    “值”
    OLED_ShowChar(16*4,0,':',16,1);                //    “:”
    OLED_ShowNum(16*4+8,0,temp_door_value,3,16,a);        //    temp_door_value
    
    OLED_ShowChinese(16*0,16,1,16,1);            //    “湿”
    OLED_ShowChinese(16*1,16,2,16,1);              //    “度”
    OLED_ShowChinese(16*2,16,13,16,1);            //    “阈”
    OLED_ShowChinese(16*3,16,14,16,1);            //    “值”
    OLED_ShowChar(16*4,16,':',16,1);            //    “:”
    OLED_ShowNum(16*4+8,16,hum_door_value,3,16,b);        //    hum_door_value

    
    OLED_ShowChinese(16*0,32,15,16,1);        //    “空”
    OLED_ShowChinese(16*1,32,16,16,1);        //    “气”
    OLED_ShowChinese(16*2,32,13,16,1);        //    “阈”
    OLED_ShowChinese(16*3,32,14,16,1);        //    “值”
    OLED_ShowChar(16*4,32,':',16,1);            //    “:”
    OLED_ShowNum(16*4+8,32,smoke_door_value,4,16,c);        //    hum_door_value

    
    OLED_ShowChar(8*0,48,'P',16,1);                //    “P”
    OLED_ShowChar(8*1,48,'M',16,1);                //    “M”
    OLED_ShowChar(8*2,48,'2',16,1);                //    “2”
    OLED_ShowChar(8*3,48,'.',16,1);                //    “.”
    OLED_ShowChar(8*4,48,'5',16,1);                //    “5”
    OLED_ShowChinese(8*5,48,13,16,1);            //    “阈”
    OLED_ShowChinese(8*5+16,48,14,16,1);    //    “值”
    OLED_ShowChar(8*5+16*2,48,':',16,1);    //    “:”
    OLED_ShowNum(8*6+16*2,48,pm25_door_value,4,16,d);            //    PM25_Value

    OLED_Refresh();
}

void OLED_Show_ThirdPage(){
    
    uint8_t a,b,c,d;
    if(option==1){a=0;b=1;c=1;d=1;}
    else if(option==2){a=1;b=0;c=1;d=1;}
    else if(option==3){a=1;b=1;c=0;d=1;}
    else if(option==4){a=1;b=1;c=1;d=0;}
    else{a=1;b=1;c=1;d=1;}
    
    OLED_ShowString(16*0,0,"CO2",16,1);        //“:”
    OLED_ShowChinese(16*1+8,0,13,16,1);        //    “阈”
    OLED_ShowChinese(16*2+8,0,14,16,1);        //    “值”
    OLED_ShowChar(16*3+8,0,':',16,1);            //    “:”
    OLED_ShowNum(16*4,0,co2_door_value,4,16,a);        //    hum
    
    OLED_ShowChinese(16*0,16,19,16,1);            //    “光”
    OLED_ShowChinese(16*1,16,20,16,1);              //    “照”
    OLED_ShowChinese(16*2,16,13,16,1);            //    “阈”
    OLED_ShowChinese(16*3,16,14,16,1);            //    “值”
    OLED_ShowChar(16*4,16,':',16,1);            //    “:”
    OLED_ShowNum(16*4+8,16,light_door_value,4,16,b);        //    hum_door_value

    OLED_Refresh();
}

五、项目成品效果图

六、项目总结

这个项目从头到尾做下来,硬件焊接、代码编写、调试联测都走了一遍,最后所有功能都跑通了,总结一下:

  • 数据采集显示方面:温湿度、PM2.5、甲醛、一氧化碳都能正常读到数据,OLED屏上实时刷新显示所有数值和设定的报警阈值,看一眼就知道当前环境啥情况。

  • 自动控制方面:只要PM2.5、甲醛或者一氧化碳超了设定的值,风扇马上自己转起来通风,蜂鸣器响、LED灯闪,提醒效果到位,反应也挺快的。

  • 远程监控方面:ESP8266成功连上了机智云,手机App上所有数据都能看到,在家躺着也能知道房间空气质量咋样。报警值也能在App上直接改,不用蹲在设备前按按键。

  • 数据存储方面:数据定时往阿里云上传,后台能看到历史曲线,哪天空气不好一查就知道。

总的来说这个项目从硬件到软件到云端全流程打通了,既有学习价值也能实际用起来,成本不高,感兴趣的话还可以继续往上加功能,比如换更精准的传感器、加个外壳做成产品级的样子等等

七、资料说明

 1)本资料免费分享,获取全套资料请看主页,并将告诉助手需要资料的项目编号,助手收到消息后,会发送百度网盘链接。每人限领两份开源资料。

  2)需要实物或者定制的小伙伴可以添加工作室微信,发送项目需求,可以按照需求定制项目。定制包含源码、原理图、全套实物、模块参考资料、更详细的参考资料。

  3)重点!!!在本工作室定制的项目,提供一年的技术支持和答疑服务,定制功能范围内的代码和原理图工程师一对一解疑答惑!

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

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐