一、系统概述

设计以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 设备接入配置

  1. 创建产品:登录阿里云IoT平台,创建“智能环境监测”产品,选择“数据格式”为JSON。

  2. 添加设备:为每个监测节点创建设备,获取ProductKeyDeviceNameDeviceSecret

  3. 定义物模型:添加属性(温度、湿度、光照、空气质量、噪声)和报警事件。

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卡)和边缘计算(异常检测算法)。

Logo

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

更多推荐