【毕设实战】基于STM32的空气质量监测系统:温湿度+甲醛+PM2.5+CO五合一,ESP8266上云+安卓APP远程控阈值(附完整方案)

一篇把「毕设从0到1」讲透的技术复盘:硬件选型、原理图、驱动移植、通信协议、APP联调、调试踩坑全覆盖。适合嵌入式/物联网方向的毕设、课设、电子竞赛同学直接参考。

一、为什么要做这样一台"空气体检仪"

刚装修完的房子能不能住?办公室里二手烟有没有超标?车里空气干不干净?这些问题,商用空气检测仪动辄大几百上千,而且大多只能本地看数,没法远程盯、没法超限自动处理。

于是毕设选了这个题目:做一台低成本、多参数、能联网、能自动排风报警的空气质量监测终端。最终落地的这套系统,把 5 个空气质量关键参数量化到一块 0.96 寸 OLED 上,同时通过 ESP8266 把数据推到安卓 APP,人不在现场也能看到家里空气到底"脏不脏"。

先放一下最终的功能清单(也是答辩 PPT 里那张"功能列表"):

监测参数传感器单位默认报警阈值
温度DHT11℃35
湿度DHT11%RH75
甲醛 CH₂O三合一VOC模块mg/m³0.10
PM2.5红外粉尘传感器μg/m³200
一氧化碳 COMQ-7ppm200

阈值不是写死的——设备上三个按键可以本地改,APP 上也能远程下发,双向同步。


二、系统总体方案

整套系统分三层:感知层 → 主控层 → 应用层。

 ┌─────────────┐   ┌──────────────────────────────┐   ┌──────────────┐
 │  感知层      │   │         主控层 STM32          │   │   应用层      │
 │ DHT11温湿度  │──▶│  采集 → 滤波 → 显示 → 判定     │──▶│  OLED 本地屏  │
 │ MQ-7 CO     │──▶│  超限 → 蜂鸣器/继电器排风      │──▶│  安卓 APP    │
 │ PM2.5粉尘   │──▶│  800ms 组帧 → ESP8266 上传    │──▶│  远程阈值下发 │
 │ 甲醛VOC模块 │──▶│                              │   │              │
 └─────────────┘   └──────────────────────────────┘   └──────────────┘
                            ▲
                            │ I2C
                       ┌────┴────┐
                       │ 0.96"  │
                       │ OLED    │
                       └─────────┘
  • 主控:STM32F103C8T6 最小系统板(Cortex-M3,72MHz,64KB Flash,毕设性价比之王)
  • 通信:ESP8266-01S(串口转 WiFi,透传模式连路由器)
  • 执行机构:5V 继电器控制风扇排风 + 有源蜂鸣器声光报警
  • 人机交互:0.96 寸 OLED(SSD1306,I2C)+ 3 个独立按键

硬件 BOM、原理图、PCB、Keil5 工程、Android Studio 工程、各模块 datasheet 全部归档在项目里,后面调试时查起来非常方便。
在这里插入图片描述


三、硬件选型与接线思路

1. 为什么选这几颗传感器

  • DHT11:单总线协议,温湿度一起出,便宜(~5块),精度对毕设足够(温度±2℃、湿度±5%RH)。
  • MQ-7:半导体气敏元件,专门测 CO,需要 ADC 采集分压电压,再用经验曲线换算成 ppm。代码里做了 1000ppm 上限截断,防止 ADC 抖跳成负数。
  • 红外 PM2.5(类似 GP2Y/SDS011 类):串口输出,9600bps,自带校验和。读 4 个字节,按 (buf[1]*128 + buf[2]) * 校准系数 换算成 μg/m³。
  • 三合一 VOC/甲醛模块:串口输出 9 字节帧,带字节和校验,直接给 mg/m³ 数值,省去了 VOC 曲线标定的麻烦。
  • ESP8266-01S:体积小、够用,AT 指令透传,STM32 通过 USART1 对接。

2. 串口分配(这步最容易踩坑)

串口波特率接谁
USART1115200调试 printf
USART29600甲醛/VOC 模块
USART39600PM2.5 模块
另一组 GPIO(软件串口或复用)115200ESP8266

⚠️ 坑点提醒:ESP8266 默认波特率是 115200,但很多出厂固件是 9600。上电第一件事就是串口助手打 AT,看回不回 OK,不回就换波特率试,别上来就写驱动。

3. 继电器/蜂鸣器

继电器和蜂鸣器各接一个推挽 GPIO,用 NPN 三极管驱动(5V 继电器线圈电流大,不能直接用 STM32 IO 驱动)。代码里统一用一个 BEEP 和一个 RELAY 宏控,方便移植。


四、软件设计:主循环干了几件事

Keil5 + 标准固件库(StdPeriph_Lib),工程按 User / Driver / System / Libraries 分目录,Driver 目录下放每个模块的 .c/.h:dht11.c / MQ7.c / esp8266.c / OLED_I2C.c / adc.c / timer.c / usart2.c / usart3.c。

主循环的核心逻辑其实就四句话:

while(1)
{
    keyscan();                          // ① 按键扫描(阈值设置)

    if(setn == 0)                       // ② 非设置页才采集+显示+判定
    {
        timeCount++;
        if(timeCount >= 180)            // 每 ~1.8s 读一次 DHT11(它本来就慢)
            DHT11_Read_Data(&temperature, &humidity);

        if(shuaxin == 1)                // TIM3 每 300ms 置位一次,刷新 OLED
        {
            shuaxin = 0;
            Get_MQ7_PPM();              // 读 CO
            Get_CH2O();                 // 读甲醛
            Get_PM2_5();                // 读 PM2.5
            /* 刷新 OLED + 超限闪烁 */
            if(温度/湿度/甲醛/PM2.5/CO 任一超限) { BEEP = 1; RELAY = 1; }
            else                                { BEEP = 0; RELAY = 0; }
        }
    }

    UsartSendReceiveData();             // ③ 与 ESP8266 收发(APP 通信)
    delay_ms(10);
}

定时器 TIM3 做了两件事:

if(timeCount1 >= 300) { shanshuo = !shanshuo; shuaxin = 1; }  // 300ms 刷新屏
if(timeCount2 >= 800) { sendFlag = 1; }                      // 800ms 上传一次

为什么不用阻塞延时? 因为 DHT11 读一次要 ~20ms,PM2.5 和甲醛是异步串口帧,如果都放在主循环里死等,按键就会卡。所以用定时器中断置标志位,主循环看到标志再干活——这是嵌入式里最朴素也最有效的"前后台系统"。


五、WiFi 上云:和安卓 APP 的通信协议

这是整个毕设**最有"物联网味"**的部分,也是答辩老师最爱问的。

1. 设备 → APP(主动上报)

每 800ms 组一帧,格式设计成"键值对 + 特殊分隔符",方便 APP 端正则/字符串截取:

temp_warn,humi_warn,pm2.5_warn,ch2o_warn,co_warn,$temp:26#,$humi:55#,$ch2o:0.035#,$pm2.5:32#,$co:12#
  • 前缀部分是报警位:哪个参数超限了,就把对应的 xxx_warn, 拼进去;没超限就不拼。APP 一看前缀就知道要不要弹窗。
  • 后面 5 个 $key:value# 是实时数据。

2. APP → 设备(远程改阈值)

APP 下发字符串,STM32 端用 strstr 匹配关键字:

if(strstr((char *)dataPtr, "temp_max:")  != NULL) { /* 解析温度上限 */ }
if(strstr((char *)dataPtr, "humi_max:")  != NULL) { /* 解析湿度上限 */ }
if(strstr((char *)dataPtr, "chIIo:")     != NULL) { /* 解析甲醛上限 */ }
if(strstr((char *)dataPtr, "pm_max:")    != NULL) { /* 解析 PM2.5 上限 */ }
if(strstr((char *)dataPtr, "co_max:")    != NULL) { /* 解析 CO 上限 */ }

解析完立刻写回全局变量并刷新 OLED,设备和 APP 两端阈值保持一致——这一点在答辩时被老师夸了一句"通信闭环做完整了"。

工程上小细节:解析数字时先跳过非数字字符,再连续读 0-9,遇到 , \r . 就停。这样 APP 端不管怎么拼字符串都不容易把 STM32 解析崩。


六、按键设置:三键完成全部参数配置

设备面板上就 3 个按键,没加触摸屏也够用:

  • KEY1:切换设置项(温度→湿度→甲醛→PM2.5→CO→退出)
  • KEY2:当前项 +1
  • KEY3:当前项 -1

进入设置页时 OLED 清空,顶部显示"设置温度/设置湿度/…",第 4 行显示当前值。不用串口助手、不用上位机,现场就能调——这对演示现场特别友好。


七、调试踩坑记录(干货在这)

  1. DHT11 初始化死等:DHT11 上电后需要 1s 稳定,代码里 while(DHT11_Init()) 失败就一直刷"DHT11 Init!",如果硬件接线松了会卡在 loading。建议加个超时计数,失败 10 次就跳过,别把整个系统拖死。
  2. PM2.5 校验和:必须验 (buf[0]+buf[1]+buf[2]) & 0x7F == buf[3],否则串口上偶尔串出来的脏数据会让 PM2.5 跳到 999。
  3. 甲醛模块字节序:是 buf[4]*256 + buf[5],不是小端,初次读出来差 256 倍,排查了半宿。
  4. MQ-7 加热特性:MQ-7 需要周期性加热,刚上电前 2~3 分钟读数飘得厉害,演示前一定要提前开机预热,别现场才发现 CO 读数乱跳。
  5. ESP8266 上电时序:STM32 先跑起来再初始化 ESP8266,要 delay_ms(1000) 等模块就绪,否则前几条 AT 指令石沉大海。
  6. 蜂鸣器和继电器共地:5V 继电器一开,整个电源被拉低,OLED 会闪一下。建议继电器线圈两端加续流二极管,电源入口加大电容。

八、总结

这套毕设我最大的收获,不是焊了多少块板、调通了多少个传感器,而是把**“感知 → 决策 → 执行 → 联网”**这条物联网链路完整跑通了一遍:

  • 会用了 GPIO / 单总线 / I2C / ADC / USART / 定时器中断
  • 学会了自定义通信协议 + 字符串解析
  • 理解了前后台系统、标志位消抖、异步串口帧处理
  • 体验了从硬件到 APP 的全栈联调

如果你也在做类似题目,下面这份资料清单可以直接照着搭:

  • STM32F103C8T6 最小系统板
  • DHT11 / MQ-7 / GP2Y 类 PM2.5 / 三合一甲醛VOC 模块
  • ESP8266-01S
  • 0.96 寸 OLED(SSD1306, I2C)
  • 5V 继电器模块 + 有源蜂鸣器 + 5V 风扇
  • Keil5 + STM32F10x 标准库
  • Android Studio(APP 用 ESP8266 做 TCP Server,手机连同一个 WiFi 即可)

如果这篇文章对你有帮助,欢迎 点赞 + 收藏 + 关注,后面我会把 OLED 显示驱动、ESP8266 透传配置、安卓 APP 通信这几个子模块单独拆出来写,毕竟毕设这事儿,一个人踩坑不如大家一起趟。有问题评论区聊,看到都会回 👋


标签:STM32 毕业设计 物联网 ESP8266 空气质量监测 嵌入式 Android MQ-7 DHT11 PM2.5 创客

更多推荐