1. 环境监测系统的基础搭建

做环境监测系统最头疼的就是传感器数据不准,我刚开始做的时候经常遇到温湿度读数飘忽不定,PM2.5数据跳来跳去的问题。后来才发现,问题出在电源和信号干扰上。STM32的环境监测系统要想稳定运行,硬件基础一定要打好。

我常用的配置是STM32F407系列开发板,这款板子资源丰富,性能足够处理多传感器数据。传感器选择上,温湿度用DHT22,PM2.5用GP2Y1010AU0F,气体检测用MQ-135,光照用BH1750。这些传感器都是经过市场验证的,性价比高且容易买到。

电源部分一定要重视,最好用独立的LDO给传感器供电。我吃过亏,曾经直接用开发板的3.3V给所有传感器供电,结果ADC读数全是噪声。后来改用AMS1117-3.3单独给模拟传感器供电,数字信号立刻干净多了。

接线时注意信号线的屏蔽,特别是模拟传感器。I2C总线要加上拉电阻,一般是4.7kΩ。UART通信要注意电平匹配,有些传感器是5V电平,需要电平转换模块。这些细节决定了系统的稳定性,千万别省事。

2. 传感器数据采集实战

数据采集是系统的基础,但每个传感器都有自己的特性。温湿度传感器DHT22是单总线协议,读数据时要严格时序。PM2.5传感器需要PWM驱动红外LED,还要处理模拟信号。气体传感器需要预热时间,刚上电读数不准。

先说说DHT22的驱动。这个传感器对时序要求很严格,每次读取前要先发送开始信号。我调试时用逻辑分析仪抓过波形,发现STM32的微秒级延时要用SysTick实现,用循环延时的话会因为中断被打断。

#define DHT22_PIN GPIO_PIN_0
#define DHT22_PORT GPIOA

void DHT22_Start(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = DHT22_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(DHT22_PORT, &GPIO_InitStruct);
    
    HAL_GPIO_WritePin(DHT22_PORT, DHT22_PIN, GPIO_PIN_RESET);
    HAL_Delay(1);
    HAL_GPIO_WritePin(DHT22_PORT, DHT22_PIN, GPIO_PIN_SET);
    HAL_Delay(30);
}

PM2.5传感器的驱动更复杂些。GP2Y1010AU0F需要用一个PWM信号驱动红外LED,然后读取ADC值。注意LED驱动和ADC采样之间的时序要匹配,最好用定时器触发ADC采样,这样读数更稳定。

气体传感器MQ-135需要预热时间,上电后要等几分钟读数才稳定。可以在程序里做个预热计时,预热完成后再开始采集数据。光照传感器BH1750是I2C接口,相对简单,但要注意测量模式的选择,连续测量和单次测量的精度不同。

3. 多传感器数据融合算法

单一传感器的数据往往不可靠,温度传感器会受辐射影响,PM2.5传感器会受湿度干扰。数据融合就是要综合利用多个传感器的信息,得到更准确的环境评估。

我常用的方法是加权融合,根据传感器的精度和可靠性分配权重。温湿度传感器精度高,权重可以大些;气体传感器容易受干扰,权重小些。权重要根据实测数据调整,不能凭感觉。

先做数据预处理,去掉明显异常的值。我用的是滑动窗口滤波,保存最近10次读数,去掉最大最小值后取平均。这样能滤掉突发干扰,又不会引入太大延迟。

#define WINDOW_SIZE 10

typedef struct {
    float buffer[WINDOW_SIZE];
    int index;
} FilterWindow;

float Filter_Update(FilterWindow* window, float new_value)
{
    window->buffer[window->index] = new_value;
    window->index = (window->index + 1) % WINDOW_SIZE;
    
    float sum = 0;
    float min = window->buffer[0];
    float max = window->buffer[0];
    
    for(int i=0; i<WINDOW_SIZE; i++) {
        sum += window->buffer[i];
        if(window->buffer[i] < min) min = window->buffer[i];
        if(window->buffer[i] > max) max = window->buffer[i];
    }
    
    return (sum - min - max) / (WINDOW_SIZE - 2);
}

对于相关性的传感器,可以用交叉验证。比如温湿度传感器读出的湿度值,和气体传感器的读数有相关性。当湿度很高时,气体传感器的读数会偏大,需要补偿校正。

我还试过卡尔曼滤波,效果确实好,但计算量大,STM32处理起来有点吃力。后来改用简化版的互补滤波,在精度和计算量之间取得平衡。实际应用中,不必追求完美的算法,稳定可靠更重要。

4. 系统稳定性优化技巧

环境监测系统要长时间运行,稳定性是关键。我遇到过内存泄漏、看门狗复位、传感器死机等各种问题,总结出一些实用技巧。

首先是电源管理,用定时器周期性地唤醒系统,采集数据后进入低功耗模式。这样既能省电,又能减少传感器发热对测量的影响。STM32的低功耗模式很多,要根据外设使用情况选择合适模式。

看门狗一定要用,但喂狗时机要仔细设计。我是在主循环和每个传感器采集函数中都喂狗,确保任何一个环节卡住都能复位。但注意喂狗间隔不能太短,否则起不到保护作用。

传感器偶尔会死机,需要有恢复机制。我给每个传感器都设计了软复位函数,连续几次读值异常就执行复位。比如DHT22容易时序错乱,发现异常后重新初始化就能恢复。

数据存储也要考虑稳定性,我用的是循环存储策略,避免频繁擦写Flash。重要数据加上CRC校验,读取时先校验再使用。网络传输的数据要加序列号,发现丢包能及时重传。

5. 实际应用中的问题解决

做项目总会遇到各种奇怪问题,分享几个我踩过的坑。有一次客户反映数据偶尔跳变,查了好久发现是电源纹波太大。后来在电源输入端加了π型滤波,问题就解决了。

还有一次是I2C总线锁死,STM32的I2C模块有这个老毛病。解决方法是用超时机制,检测到总线异常时执行软件复位。也可以在硬件上加上拉电阻,增强总线驱动能力。

电磁干扰也是常见问题,特别是工业环境。传感器信号线要用屏蔽线,模拟和数字地要分开布置。必要时加上磁珠滤波,能有效抑制高频干扰。

传感器校准也很重要,出厂校准用久了会漂移。我现在的做法是定期自动校准,比如用夜间最低温度作为参考点校准温度传感器。PM2.5传感器可以用洁净空气时的读数作为零点校准。

软件上要做好异常处理,传感器断开、数据异常都要有应对策略。不能因为一个传感器故障导致整个系统瘫痪。我用的方法是故障隔离,某个传感器异常就暂时禁用,定期尝试恢复。

Logo

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

更多推荐