1. 项目概述与环境准备

智能环境监测系统是我在实际项目中经常用到的一种解决方案,特别适合家庭、办公室或者小型工作场所。这个系统通过STM32微控制器采集各种环境数据,然后利用ESP8266 Wi-Fi模块将数据上传到云端,最终实现远程监控和数据可视化。我自己在家里和工作室都部署了这样的系统,实测下来非常稳定,能够实时反映环境变化。

硬件准备清单:

  • STM32F103C8T6开发板(核心控制器)
  • ESP8266-01S Wi-Fi模块(数据上传)
  • DHT22温湿度传感器(环境监测)
  • MQ-135空气质量传感器(有害气体检测)
  • BH1750光照强度传感器(光线监测)
  • 0.96寸OLED显示屏(本地数据显示)
  • LED指示灯和蜂鸣器(报警提示)

软件环境搭建: 首先需要安装Keil MDK开发环境,我推荐使用V5.32版本,这个版本对STM32F1系列的支持最稳定。然后安装STM32CubeMX,用于引脚配置和代码生成。最后还要准备串口调试助手,用于调试ESP8266模块。

注意:在连接硬件时,一定要先断开电源,避免短路烧毁元件。我刚开始做项目时就因为粗心烧坏过一个ESP8266模块,这都是经验教训。

2. 系统架构设计与硬件连接

整个系统的架构可以分为三个层次:数据采集层、数据处理层和数据传输层。STM32作为主控制器,负责管理所有传感器数据采集和本地处理,ESP8266则专门负责与云平台的通信。

传感器连接详解:

温湿度传感器DHT22的连接相对简单:

  • VCC → 3.3V
  • GND → GND
  • DATA → PA1(需要上拉电阻)

MQ-135气体传感器的连接:

  • VCC → 5V
  • GND → GND
  • AO → PA0(ADC输入)

光照传感器BH1750使用I2C接口:

  • VCC → 3.3V
  • GND → GND
  • SCL → PB6
  • SDA → PB7

ESP8266的连接很重要,需要特别注意:

  • VCC → 3.3V(绝对不能接5V)
  • GND → GND
  • TX → PA10(STM32的RX)
  • RX → PA9(STM32的TX)

我在实际连接时,还会在ESP8266的电源引脚并联一个100μF的电容,这样可以避免电压波动导致模块重启。OLED显示屏同样使用I2C接口,可以和其他I2C设备共用总线。

3. STM32端代码实现

系统初始化是第一步,需要配置所有外设和接口:

#include "stm32f1xx_hal.h"
#include "dht22.h"
#include "mq135.h"
#include "bh1750.h"
#include "oled.h"
#include "wifi.h"

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC_Init(void);
static void MX_I2C1_Init(void);
static void MX_USART1_Init(void);

int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_ADC_Init();
    MX_I2C1_Init();
    MX_USART1_Init();
    
    // 外设初始化
    DHT22_Init();
    MQ135_Init();
    BH1750_Init();
    OLED_Init();
    WiFi_Init();
    
    while (1) {
        // 主循环处理
        Read_Sensors();
        Process_Data();
        Display_Local();
        Upload_Cloud();
        HAL_Delay(5000);  // 5秒采集一次
    }
}

传感器数据采集代码:

每个传感器的读取都需要特定的时序和处理。以DHT22为例:

typedef struct {
    float temperature;
    float humidity;
} DHT22_Data;

DHT22_Data DHT22_Read() {
    DHT22_Data data = {0};
    // 启动信号
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
    HAL_Delay(1);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
    Delay_us(30);
    
    // 等待响应
    // ... 具体读取逻辑
    return data;
}

对于MQ-135传感器,需要读取ADC值并转换为实际浓度:

uint16_t MQ135_ReadRaw() {
    HAL_ADC_Start(&hadc1);
    HAL_ADC_PollForConversion(&hadc1, 50);
    return HAL_ADC_GetValue(&hadc1);
}

float MQ135_ReadPPM() {
    uint16_t raw = MQ135_ReadRaw();
    float voltage = raw * 3.3 / 4096.0;
    // 根据校准曲线计算PPM值
    return voltage * 200;  // 简化计算,实际需要校准
}

4. ESP8266通信与云端对接

ESP8266的配置是关键环节,需要先进行AT指令测试:

void WiFi_Init() {
    uint8_t retry = 0;
    while (retry++ < 10) {
        if (ESP8266_SendAT("AT", "OK", 1000)) {
            break;
        }
        HAL_Delay(500);
    }
    
    // 设置模式
    ESP8266_SendAT("AT+CWMODE=1", "OK", 2000);
    
    // 连接WiFi
    char cmd[64];
    sprintf(cmd, "AT+CWJAP=\"%s\",\"%s\"", WIFI_SSID, WIFI_PASSWORD);
    ESP8266_SendAT(cmd, "OK", 5000);
}

云端数据上传:

我通常使用MQTT协议上传数据到云平台,这里以阿里云为例:

void MQTT_Publish() {
    char message[128];
    sprintf(message, "{\"temp\":%.1f,\"humi\":%.1f,\"gas\":%d,\"light\":%d}",
            sensor_data.temperature, sensor_data.humidity, 
            sensor_data.gas_ppm, sensor_data.light_level);
    
    char cmd[256];
    sprintf(cmd, "AT+MQTTPUB=0,\"/topic/sensor\",\"%s\",0,0", message);
    ESP8266_SendAT(cmd, "OK", 1000);
}

在实际项目中,我还添加了重连机制和心跳包功能,确保长时间稳定运行:

void WiFi_KeepAlive() {
    static uint32_t last_check = 0;
    if (HAL_GetTick() - last_check > 30000) {
        if (!ESP8266_CheckConnection()) {
            WiFi_Reconnect();
        }
        last_check = HAL_GetTick();
    }
}

5. 数据可视化与远程监控

云端数据可视化我推荐使用Node-RED或者简单的Web界面。Node-RED配置简单,拖拽几个节点就能完成数据展示:

// 简单的Web Socket显示示例
const ws = new WebSocket('ws://your-server:1880/ws/sensor');
ws.onmessage = function(event) {
    const data = JSON.parse(event.data);
    document.getElementById('temperature').innerText = data.temperature + '°C';
    document.getElementById('humidity').innerText = data.humidity + '%';
    document.getElementById('gas').innerText = data.gas_ppm + 'PPM';
    updateChart(data);  // 更新趋势图表
};

对于移动端访问,可以开发简单的微信小程序或者React Native应用。我在自己的项目中用了Flutter,一套代码可以同时运行在iOS和Android上:

class SensorDataPage extends StatefulWidget {
  @override
  _SensorDataPageState createState() => _SensorDataPageState();
}

class _SensorDataPageState extends State<SensorDataPage> {
  late MqttClient client;
  SensorData _data = SensorData();
  
  void _connectMQTT() async {
    client = MqttClient('your-mqtt-server', '');
    await client.connect();
    client.subscribe('sensor/data', MqttQos.atMostOnce);
    client.updates!.listen((List<MqttReceivedMessage<MqttMessage>> c) {
      final recvMsg = c[0].payload as MqttPublishMessage;
      final message = MqttPublishPayload.bytesToStringAsString(recvMsg.payload.message);
      setState(() {
        _data = SensorData.fromJson(json.decode(message));
      });
    });
  }
}

6. 实际应用与优化建议

在家庭环境中,这个系统可以放在客厅或者卧室,监测室内空气质量。当检测到有害气体浓度超标时,系统会自动触发蜂鸣器报警,并通过手机推送通知用户。我在自己的孩子房间就部署了一套,当CO2浓度过高时会提醒开窗通风。

办公室应用时,可以部署多套系统组成监测网络。通过比较不同区域的数据,可以优化空调和新风系统的运行策略。我曾经为一个客户部署了5个监测点,帮助他们节省了20%的空调能耗。

常见问题处理:

传感器读数不准是最常见的问题。我的经验是定期校准传感器,特别是MQ系列的气体传感器,容易受环境影响。温湿度传感器要避免直接对着空调出风口或者窗户。

Wi-Fi连接不稳定可以通过以下方式改善:

  1. 增加重连机制
  2. 优化天线位置
  3. 设置静态IP避免DHCP冲突
  4. 使用看门狗定时器检测网络状态
void Watchdog_Refresh() {
    if (WiFi_Timeout()) {
        System_Reboot();  // 严重超时后重启系统
    }
}

电源管理也很重要,如果使用电池供电,需要优化功耗:

void Enter_LowPower() {
    // 关闭不必要的外设
    HAL_ADC_Stop(&hadc1);
    HAL_I2C_DeInit(&hi2c1);
    
    // 设置睡眠模式
    HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
}

在实际部署中,我还建议添加SD卡存储功能,在网络异常时本地缓存数据,等网络恢复后再上传到云端。这样就不会丢失任何监测数据了。

整个系统搭建完成后,最好进行72小时连续测试,确保稳定性。我自己的系统已经连续运行半年多,除了偶尔的网络波动,基本上没有出现过问题。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐