基于STM32的智能环境监测系统设计
一、系统概述
设计以STM32F103C8T6(Cortex-M3,72MHz)为核心,集成多传感器模块、无线通信、数据显示和云端交互,实现环境参数实时监测(温湿度、光照、空气质量、噪声等)、数据存储、阈值报警和远程监控。系统支持本地显示与手机APP/Web端远程查看,适用于智能家居、农业大棚、工业环境监测等场景。
二、系统架构
2.1 整体框图
┌─────────────────────────────────────────────────────────────┐
│ 智能环境监测系统 │
├─────────────┬─────────────┬─────────────┬─────────────┤
│ 传感器层 │ 控制层 │ 通信层 │ 应用层 │
├─────────────┼─────────────┼─────────────┼─────────────┤
│ 温湿度 │ STM32F103 │ WiFi/4G │ 本地显示 │
│ 光照强度 │ (主控) │ (ESP8266) │ (OLED/LCD) │
│ 空气质量 │ │ 蓝牙 │ 手机APP │
│ 噪声 │ │ (HC-05) │ Web平台 │
│ 气压/海拔 │ │ LoRa │ 云端存储 │
│ 土壤湿度 │ │ (SX1278) │ 数据分析 │
└─────────────┴─────────────┴─────────────┴─────────────┘
2.2 核心组件选型
| 模块 | 型号/参数 | 功能说明 |
|---|---|---|
| 主控 | STM32F103C8T6(64KB Flash,20KB RAM) | 传感器数据采集、处理、通信控制 |
| 温湿度 | DHT22(AM2302,数字单总线) | 温度(-4080℃,±0.5℃),湿度(0100%RH,±2%) |
| 光照 | BH1750(I2C,数字输出) | 光照强度(0~65535 lux,1 lux分辨率) |
| 空气质量 | MQ-135(模拟输出)+ADC | 检测CO2、苯、氨等有害气体(0~5V模拟量) |
| 噪声 | MAX9814(模拟输出)+ADC | 环境噪声检测(20~20kHz,带AGC) |
| 气压/海拔 | BMP280(I2C/SPI,数字输出) | 气压(3001100hPa),海拔(-5009000m) |
| 土壤湿度 | FC-28(模拟输出)+ADC | 土壤湿度检测(0~100%RH) |
| 显示 | 0.96寸OLED(I2C,SSD1306) | 实时显示环境参数(128×64像素) |
| 无线通信 | ESP8266(WiFi,AT指令) | 连接云平台(阿里云/腾讯云),MQTT协议 |
| 存储 | AT24C02(I2C EEPROM,2KB) | 存储报警阈值、校准参数 |
| 报警 | 蜂鸣器+LED(红/绿) | 超阈值声光报警(温湿度、空气质量、噪声) |
三、硬件设计
3.1 硬件连接表
| 传感器/模块 | STM32引脚 | 通信方式 | 说明 |
|---|---|---|---|
| DHT22 | PA0 | 单总线(GPIO) | 温湿度数据线(需4.7kΩ上拉) |
| BH1750 | PB6(SCL),PB7(SDA) | I2C | 光照强度传感器 |
| MQ-135 | PA1 | ADC1_CH1 | 空气质量模拟量(0~3.3V) |
| MAX9814 | PA2 | ADC1_CH2 | 噪声模拟量(0~3.3V) |
| BMP280 | PB6(SCL),PB7(SDA) | I2C | 气压/海拔传感器(共用I2C) |
| FC-28 | PA3 | ADC1_CH3 | 土壤湿度模拟量(0~3.3V) |
| OLED | PB6(SCL),PB7(SDA) | I2C | 显示模块(共用I2C) |
| ESP8266 | PA9(TX),PA10(RX) | UART1 | WiFi模块(AT指令) |
| AT24C02 | PB6(SCL),PB7(SDA) | I2C | EEPROM(共用I2C) |
| 蜂鸣器 | PB8 | GPIO | 报警输出(低电平触发) |
| LED | PB9(红),PB10(绿) | GPIO | 状态指示(红:报警,绿:正常) |
四、软件设计(STM32 HAL库)
4.1 开发环境
-
IDE:STM32CubeIDE 1.13.0+
-
库:STM32Cube_FW_F1_V1.8.0(HAL库)
-
通信协议:MQTT(云平台)、JSON(数据格式)
4.2 核心模块驱动
4.2.1 DHT22温湿度传感器(单总线)
#include "dht22.h"
// DHT22数据读取(返回湿度、温度,单位:%RH、℃)
HAL_StatusTypeDef DHT22_Read(float *humidity, float *temperature) {
uint8_t data[5] = {0};
uint8_t i, j;
// 主机拉低18ms,然后拉高20~40μs
HAL_GPIO_WritePin(DHT22_GPIO_Port, DHT22_Pin, GPIO_PIN_RESET);
HAL_Delay(18);
HAL_GPIO_WritePin(DHT22_GPIO_Port, DHT22_Pin, GPIO_PIN_SET);
delay_us(30); // 延时30μs
// 从机响应:拉低80μs,然后拉高80μs
if (HAL_GPIO_ReadPin(DHT22_GPIO_Port, DHT22_Pin) == GPIO_PIN_RESET) {
while (HAL_GPIO_ReadPin(DHT22_GPIO_Port, DHT22_Pin) == GPIO_PIN_RESET); // 等待从机拉高
while (HAL_GPIO_ReadPin(DHT22_GPIO_Port, DHT22_Pin) == GPIO_PIN_SET); // 等待从机拉低
// 读取40位数据(16位湿度+16位温度+8位校验和)
for (i=0; i<5; i++) {
for (j=0; j<8; j++) {
while (HAL_GPIO_ReadPin(DHT22_GPIO_Port, DHT22_Pin) == GPIO_PIN_RESET); // 等待50μs低电平
delay_us(40); // 延时40μs后判断高电平持续时间
if (HAL_GPIO_ReadPin(DHT22_GPIO_Port, DHT22_Pin) == GPIO_PIN_SET) {
data[i] |= (1 << (7-j)); // 高电平持续>40μs表示1
while (HAL_GPIO_ReadPin(DHT22_GPIO_Port, DHT22_Pin) == GPIO_PIN_SET); // 等待高电平结束
}
}
}
// 校验和验证
if (data[4] == (data[0]+data[1]+data[2]+data[3])) {
*humidity = (float)((data[0]<<8)|data[1]) / 10.0f;
*temperature = (float)((data[2]<<8)|data[3]) / 10.0f;
return HAL_OK;
}
}
return HAL_ERROR;
}
4.2.2 BH1750光照传感器(I2C)
#include "bh1750.h"
// BH1750初始化(连续高分辨率模式,1 lux分辨率)
void BH1750_Init(void) {
uint8_t cmd = BH1750_POWER_ON;
HAL_I2C_Master_Transmit(&hi2c1, BH1750_ADDR, &cmd, 1, 100);
cmd = BH1750_CONTINUOUS_HIGH_RES_MODE;
HAL_I2C_Master_Transmit(&hi2c1, BH1750_ADDR, &cmd, 1, 100);
}
// 读取光照强度(单位:lux)
float BH1750_ReadLight(void) {
uint8_t data[2] = {0};
HAL_I2C_Master_Receive(&hi2c1, BH1750_ADDR, data, 2, 100);
return (float)((data[0]<<8)|data[1]) / 1.2f; // 转换公式:lux = raw/1.2
}
4.2.3 MQ-135空气质量传感器(ADC)
#include "adc.h"
// MQ-135读取(返回PPM浓度)
float MQ135_ReadPPM(void) {
uint32_t adc_value = 0;
float voltage, rs, ratio, ppm;
// 读取ADC值(12位,0~4095)
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 100);
adc_value = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
// 计算电压(0~3.3V)
voltage = adc_value * 3.3f / 4095.0f;
// 计算传感器电阻(RL=10kΩ)
rs = (3.3f - voltage) * 10000.0f / voltage;
// 计算气体浓度(需根据校准曲线调整参数)
ratio = rs / 7600.0f; // 在洁净空气中Rs/R0≈1(R0=7.6kΩ)
ppm = 116.602f * pow(ratio, -2.769f); // 苯类气体近似公式
return ppm;
}
4.2.4 ESP8266 WiFi模块(MQTT上传)
#include "esp8266.h"
// ESP8266初始化(连接WiFi,配置MQTT)
void ESP8266_Init(void) {
char cmd[100];
// 重启模块
HAL_UART_Transmit(&huart1, (uint8_t*)"AT+RST\r\n", 8, 1000);
HAL_Delay(2000);
// 连接WiFi
sprintf(cmd, "AT+CWJAP=\"%s\",\"%s\"\r\n", WIFI_SSID, WIFI_PASSWORD);
HAL_UART_Transmit(&huart1, (uint8_t*)cmd, strlen(cmd), 1000);
HAL_Delay(5000);
// 连接MQTT服务器(以阿里云为例)
sprintf(cmd, "AT+MQTTUSERCFG=0,1,\"NULL\",\"%s&%s\",\"%s\",0,0,\"\"\r\n",
DEVICE_NAME, PRODUCT_KEY, DEVICE_SECRET);
HAL_UART_Transmit(&huart1, (uint8_t*)cmd, strlen(cmd), 1000);
HAL_Delay(1000);
sprintf(cmd, "AT+MQTTCONN=0,\"%s.iot-as-mqtt.cn-shanghai.aliyuncs.com\",1883,1\r\n", PRODUCT_KEY);
HAL_UART_Transmit(&huart1, (uint8_t*)cmd, strlen(cmd), 1000);
HAL_Delay(2000);
}
// 上传环境数据(JSON格式)
void ESP8266_UploadData(float temp, float hum, float light, float air, float noise) {
char json[200], topic[100], cmd[300];
// 构建JSON数据
sprintf(json, "{\"Temperature\":%.1f,\"Humidity\":%.1f,\"Light\":%.0f,\"AirQuality\":%.1f,\"Noise\":%.1f}",
temp, hum, light, air, noise);
// 构建MQTT主题
sprintf(topic, "/sys/%s/%s/thing/event/property/post", PRODUCT_KEY, DEVICE_NAME);
// 发送MQTT消息
sprintf(cmd, "AT+MQTTPUB=0,\"%s\",\"%s\",1,0\r\n", topic, json);
HAL_UART_Transmit(&huart1, (uint8_t*)cmd, strlen(cmd), 1000);
}
4.2.5 主程序框架(FreeRTOS任务)
#include "main.h"
#include "cmsis_os.h"
// 全局变量(环境参数)
float temperature = 0, humidity = 0, light = 0, air_quality = 0, noise = 0;
// 任务1:传感器数据采集(每2秒一次)
void SensorTask(void const *argument) {
while (1) {
// 读取所有传感器
DHT22_Read(&humidity, &temperature);
light = BH1750_ReadLight();
air_quality = MQ135_ReadPPM();
noise = MAX9814_ReadNoise(); // 类似MQ-135的ADC读取
// 阈值报警检测
if (temperature > TEMP_MAX || temperature < TEMP_MIN ||
humidity > HUM_MAX || humidity < HUM_MIN ||
air_quality > AIR_MAX || noise > NOISE_MAX) {
HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET); // 蜂鸣器报警
HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_Pin, GPIO_PIN_SET); // 红灯亮
} else {
HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_SET); // 绿灯亮
}
osDelay(2000); // 2秒间隔
}
}
// 任务2:数据显示(OLED刷新,每1秒一次)
void DisplayTask(void const *argument) {
char buffer[32];
while (1) {
OLED_Clear();
sprintf(buffer, "Temp:%.1fC Hum:%.1f%%", temperature, humidity);
OLED_ShowString(0, 0, buffer);
sprintf(buffer, "Light:%.0flux", light);
OLED_ShowString(0, 16, buffer);
sprintf(buffer, "Air:%.1fppm", air_quality);
OLED_ShowString(0, 32, buffer);
sprintf(buffer, "Noise:%.1fdB", noise);
OLED_ShowString(0, 48, buffer);
osDelay(1000); // 1秒刷新
}
}
// 任务3:数据上传(每10秒一次)
void UploadTask(void const *argument) {
ESP8266_Init(); // 初始化WiFi模块
while (1) {
ESP8266_UploadData(temperature, humidity, light, air_quality, noise);
osDelay(10000); // 10秒上传一次
}
}
// 主函数(FreeRTOS初始化)
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
MX_ADC1_Init();
MX_USART1_UART_Init();
// 创建FreeRTOS任务
osThreadDef(SensorTask, SensorTask, osPriorityNormal, 0, 128);
osThreadCreate(osThread(SensorTask), NULL);
osThreadDef(DisplayTask, DisplayTask, osPriorityNormal, 0, 128);
osThreadCreate(osThread(DisplayTask), NULL);
osThreadDef(UploadTask, UploadTask, osPriorityNormal, 0, 256);
osThreadCreate(osThread(UploadTask), NULL);
osKernelStart(); // 启动RTOS内核
while (1) {}
}
参考代码 基于stm32智能环境监测系统 www.youwenfan.com/contentcst/182687.html
五、云端平台对接(以阿里云IoT为例)
5.1 设备接入配置
-
创建产品:登录阿里云IoT平台,创建“智能环境监测”产品,选择“数据格式”为JSON。
-
添加设备:为每个监测节点创建设备,获取ProductKey、DeviceName、DeviceSecret。
-
定义物模型:添加属性(温度、湿度、光照、空气质量、噪声)和报警事件。
5.2 数据可视化
-
Web端:使用阿里云IoT Studio创建可视化大屏,实时显示环境数据曲线。
-
手机APP:通过阿里云IoT SDK开发Android/iOS APP,或使用现成应用(如“云智能”)。
六、关键问题与解决方案
6.1 传感器数据稳定性
-
问题:模拟传感器(MQ-135、FC-28)受温度、湿度影响,读数漂移。
-
解决:
-
软件滤波:采用滑动平均滤波(取10次采样平均值);
-
定期校准:在洁净空气中校准MQ-135的R0值(上电预热24小时)。
6.2 多I2C设备冲突
-
问题:BH1750、BMP280、OLED、AT24C02共用I2C总线,地址冲突。
-
解决:
-
地址区分:BH1750(0x23/0x5C)、BMP280(0x76/0x77)、AT24C02(0xA0);
-
分时复用:每个设备操作后释放总线,避免长时间占用。
6.3 低功耗设计
-
问题:7×24小时运行,功耗较高。
-
解决:
-
休眠模式:STM32进入Stop模式,定时唤醒(RTC闹钟);
-
传感器断电:通过MOSFET控制传感器电源,采样时上电。
七、系统测试
7.1 功能测试
| 测试项 | 方法 | 预期结果 |
|---|---|---|
| 温湿度 | 对比温湿度计(±2℃/±5%RH) | 误差<±1℃/±3%RH |
| 光照 | 对比照度计(0~2000 lux) | 误差<±5% |
| 空气质量 | 对比CO2检测仪(400~2000 ppm) | 误差<±10% |
| 无线传输 | 距离测试(室内/室外) | 室内30m稳定,丢包率<1% |
| 报警功能 | 模拟超阈值(如温度>40℃) | 蜂鸣器响,红灯亮,APP推送报警 |
7.2 性能指标
-
采样频率:传感器2秒/次,上传10秒/次;
-
显示刷新:OLED 1秒/次;
-
无线传输:WiFi(ESP8266),支持802.11 b/g/n;
-
供电:5V/2A DC(或锂电池+太阳能板);
-
工作温度:-20~60℃。
八、总结
系统基于STM32F103实现了多参数环境监测,核心是多传感器数据融合、实时显示与云端交互。通过模块化设计,可灵活扩展更多传感器(如PM2.5、甲醛)、本地存储(SD卡)和边缘计算(异常检测算法)。
更多推荐


所有评论(0)