Product images of the project:

Bilibili video link:
https://www.bilibili.com/video/BV1DEC5YuEvh/?share_source=copy_web&vd_source=097fdeaf6b6ecfed8a9ff7119c32faf2
(See the end of the article for data sharing)
01
—
Project Introduction
1. Function Details
STM32 Air Quality Detection System
The functions are as follows:
-
DHT11 temperature and humidity sensor detects air temperature and humidity information
-
MQ-7 carbon monoxide sensor detects carbon monoxide content
-
Formaldehyde sensor detects formaldehyde concentration
-
PM2.5 sensor detects dust content
-
OLED display shows real-time temperature, humidity, carbon monoxide, formaldehyde, and PM2.5 information
-
Abnormal air quality triggers sound and light alarms and activates the fan for ventilation
-
Buttons can adjust the threshold range
-
WIFI connection to the app allows remote viewing of air quality data
-
The app can adjust the threshold values
2. Bill of Materials
-
STM32F103C8T6 microcontroller
-
OLED screen
-
DHT11 temperature and humidity sensor
-
ESP8266 (WIFI) module
-
Three-in-one formaldehyde sensor
-
PM2.5 dust sensor
-
MQ-7 carbon monoxide sensor
-
Relay
-
Fan module
-
Active buzzer
-
LED light
02
—
Schematic Design

03
—
PCB Hardware Design
PCB Diagram


04
—
Program Design
#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 "esp8266.h"
#include "usart2.h"
#include "usart3.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define STM32_RX2_BUF Usart2RecBuf // Serial port 2 receive buffer
#define STM32_Rx2Counter Rx2Counter // Serial port 2 receive byte count
#define STM32_RX2BUFF_SIZE USART2_RXBUFF_SIZE // Serial port 2 receive buffer size
#define STM32_RX3_BUF Usart3RecBuf // Serial port 3 receive buffer
#define STM32_Rx3Counter Rx3Counter // Serial port 3 receive byte count
#define STM32_RX3BUFF_SIZE USART3_RXBUFF_SIZE // Serial port 3 receive buffer size
#define RATIO 1.0 // Calibration coefficient, choose range 0.1~1.0 (sensors generally do not need calibration, choose 1.0)
u16 PM25_Value = 0; // PM2.5
u16 PM25_Value_max = 200; // PM2.5 alarm value
u8 pmBuf[5]; // PM2.5 data buffer array
u8 ch2oBuf[8]; // Formaldehyde data buffer array
char display[16];unsigned char setn=0; // Record the number of times the setting button is pressed
unsigned char temperature=0; // Temperature variable
unsigned char humidity=0; // Humidity variable
unsigned int CH2O_mgvalue = 0; // Formaldehyde variable
unsigned char setTempValue=35; // Temperature setting value
unsigned char setHumiValue=75; // Humidity setting value
unsigned int setCH2OValue=10; // Formaldehyde setting value
unsigned char i=0;
unsigned int co_ppm = 0; // CO value
unsigned int setCoMaxValue=200; // CO upper limit
bool shuaxin = 1; // Refresh data flag
bool shanshuo = 0; // LCD flicker flag
bool sendFlag = 1; // Serial port send data flag
int main(void){
u16 timeCount=200;
bool delay_600ms=1;
delay_init(); // Delay function initialization
NVIC_Configuration(); // Interrupt priority configuration
KEY_GPIO_Init(); // Key pin initialization
delay_ms(300);
I2C_Configuration(); // IIC initialization
OLED_Init(); // OLED LCD initialization
OLED_CLS(0); // Clear screen
KEY_GPIO_Init(); // Key pin initialization
OLED_ShowStr(0, 2, " loading... ", 2,0);// Display loading
while(DHT11_Init())
{
OLED_ShowStr(0, 2, " DHT11 Init! ", 2,0);// Display DHT11 initialization!
delay_ms(500);
}
ESP8266_Init(); // ESP8266 initialization
delay_ms(1000);
Adc_Init(); // ADC initialization
OLED_CLS(0); // Clear screen
USART2_Init(9600); // Serial port 2 initialization
USART3_Init(9600); // Serial port 3 initialization
displayOriginalInt(); // Display original interface
TIM3_Init(99,719); // Timer initialization, timing 1ms
//Tout = ((arr+1)*(psc+1))/Tclk ;
//Tclk: Timer input frequency (in MHZ)
//Tout: Timer overflow time (in us)
while(1)
{
keyscan(); // Key scan
if(setn == 0) // Not in setting state
{
timeCount ++;
if(timeCount >= 180)
{
timeCount = 0;
DHT11_Read_Data(&temperature,&humidity); // Read temperature and humidity
}
if(shuaxin == 1) // Refresh approximately every 300ms
{
shuaxin = 0;
delay_600ms = !delay_600ms;
if(temperature >= setTempValue && shanshuo) // Temperature exceeds upper limit, LCD flickers
{
OLED_ShowChar(32,0,' ',2,0);
OLED_ShowChar(40,0,' ',2,0);
}
else
{
OLED_ShowChar(32,0,temperature/10+'0',2,0); // Display temperature
OLED_ShowChar(40,0,temperature%10+'0',2,0);
}
if(humidity >= setHumiValue && shanshuo) // Humidity exceeds upper limit, LCD flickers
{
OLED_ShowChar(103,0,' ',2,0);
OLED_ShowChar(111,0,' ',2,0);
}
else
{
OLED_ShowChar(103,0,humidity/10+'0',2,0); // Display humidity
OLED_ShowChar(111,0,humidity%10+'0',2,0);
}
Get_MQ7_PPM(); // Read carbon monoxide value
Get_CH2O(); // Read formaldehyde
if((CH2O_mgvalue/10) >= setCH2OValue && shanshuo) // Formaldehyde exceeds upper limit, LCD flickers
{
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); // Display formaldehyde
}
if(delay_600ms)
{
Get_PM2_5(); // Read PM2.5
if(PM25_Value >999)PM25_Value=999;
}
if(PM25_Value >= PM25_Value_max && shanshuo) // PM2.5 exceeds upper limit, LCD flickers
{
OLED_ShowStr(56, 2, " ug/m3", 2,0);
}
else
{
sprintf(display,"%03dug/m3",PM25_Value);
OLED_ShowStr(56, 2, (u8 *)display, 2,0); // Display PM2.5
}
if(temperature >= setTempValue || humidity >= setHumiValue || (CH2O_mgvalue/10) >= setCH2OValue || PM25_Value >= PM25_Value_max || co_ppm >= setCoMaxValue)
{BEEP = 1; RELAY=1;} // Exceeds upper limit, buzzer reminder. Turn on fan
else
{BEEP = 0; RELAY=0;} // Turn off fan and buzzer
}
}
UsartSendReceiveData(); // Serial port send and receive data, used for communication with mobile APP
delay_ms(10);
}}
05
—
Experimental Results


Data Sharing (Baidu Cloud)
https://pan.baidu.com/s/1P84UxUnRFRwHLL3nYW-fmA?pwd=its3 Extraction code: its3
(Or scan the QR code below to obtain)
For physical purchase, scan the QR code below