【STM32项目】基于 STM32L475 的智慧农业大棚环境检测与自动控制系统

前言

本项目是《嵌入式系统与接口技术课程设计》的期末大作业,使用正点原子潘多拉IoT开发板,以 STM32L475VET6 为核心控制器,设计并实现了一套智慧农业大棚环境检测系统。

系统接入DHT11温湿度传感器、光敏传感器、酒精传感器、PIR人体红外传感器和超声波传感器,可对温湿度、光照强度、模拟气体浓度、人员状态和水位距离进行检测。

在数据采集的基础上,系统还实现了自动补光、人员状态指示、水位异常判断、蜂鸣器报警、LCD分页显示和串口数据输出等功能,形成了完整的:

传感器采集 → 数据处理 → 阈值判断 → 执行器控制 → 状态显示 → 异常报警

项目综合使用了GPIO、ADC、单总线通信、超声波时序测量、串口通信、LCD显示、按键输入、继电器控制和蜂鸣器报警等嵌入式接口技术。


一、项目功能介绍

本系统主要实现以下功能:

  1. 使用 DHT11 采集环境温度和湿度;
  2. 使用酒精传感器模拟检测空气异常气体浓度;
  3. 使用光敏传感器检测当前环境光照强度;
  4. 当光照强度低于 35% 时,自动控制继电器开启补光;
  5. 使用 PIR 人体红外传感器模拟人员进入和离开;
  6. 使用红灯和绿灯显示当前人员状态;
  7. 使用超声波模块测量距离,模拟水箱水位;
  8. 当水位距离小于 3 cm 或大于 25 cm 时,判断水位异常;
  9. 使用 KEY0 切换 LCD 显示页面;
  10. 使用KEY1开启或关闭蜂鸣器报警;
  11. 使用蜂鸣器对气体异常和水位异常进行周期报警;
  12. 使用USART1向串口调试助手输出完整运行数据。

系统最终实现了环境数据采集、自动控制、人机交互和异常报警等功能。


二、系统总体方案

系统整体可以划分为三个层次:

1. 传感器采集层

负责采集农业大棚中的各类环境信息,包括:

  • DHT11:温度和湿度;
  • 酒精传感器:模拟空气异常气体浓度;
  • 光敏传感器:光照强度;
  • PIR 人体红外传感器:人员触发状态;
  • 超声波传感器:水箱液面距离。

2. STM32主控处理层

STM32L475VET6 主要负责:

  • 读取传感器数据;
  • 对 ADC 数据进行换算;
  • 根据设定阈值判断异常;
  • 管理人员进入和离开状态;
  • 控制继电器、LED 和蜂鸣器;
  • 管理 LCD 显示页面;
  • 周期输出串口数据。

3. 显示与执行层

输出设备包括:

  • LCD显示屏;
  • 继电器模块;
  • 红色和绿色LED;
  • 蜂鸣器;
  • 串口调试助手。

系统整体运行流程如下:

系统初始化
    ↓
按键扫描
    ↓
传感器数据采集
    ↓
数据换算与状态判断
    ↓
继电器、LED和蜂鸣器控制
    ↓
LCD页面显示
    ↓
串口数据输出
    ↓
返回主循环

农业大棚系统技术路线图农业大棚系统技术路线图

三、硬件组成

本项目使用的主要硬件如下。

硬件模块 主要作用
STM32L475VET6 开发板 系统主控制器
DHT11 检测温度和湿度
酒精传感器 模拟检测异常气体浓度
光敏传感器 检测光照强度
PIR人体红外传感器 检测人员触发信号
超声波传感器 测量距离并模拟水位
继电器模块 模拟控制大棚补光灯
LCD显示屏 分页显示系统数据
蜂鸣器 异常报警
KEY0、KEY1 页面切换和报警控制
红色、绿色 LED 显示人员状态
USB 下载线 程序下载与供电

需要说明的是:

酒精传感器在本项目中主要用于模拟空气异常气体浓度检测,并不是专业的农业气体检测设备。

同样,超声波模块通过检测目标面的距离来模拟水箱水位状态。


四、软件开发环境

本项目的软件开发环境如下:

  • STM32CubeMX;
  • Keil MDK-ARM;
  • STM32 HAL 库;
  • 串口调试助手;
  • ST-Link 或开发板板载下载器。

其中:

  • STM32CubeMX 负责芯片型号、时钟、GPIO、ADC 和 USART 等外设配置;
  • Keil 负责代码编写、工程编译和程序下载;
  • HAL 库负责外设驱动;
  • 串口调试助手负责观察系统运行数据。

五、引脚分配

本项目的主要引脚分配如下:

功能模块 STM32引脚 功能说明
DHT11 PB8 单总线温湿度读取
PIR人体红外 PB9 GPIO输入检测
超声波Trig PB10 发送触发脉冲
超声波Echo PB11 接收回波信号
酒精传感器 PC4 ADC模拟量采集
光敏传感器 PA4 ADC模拟量采集
继电器 PD12 控制补光灯
蜂鸣器 PB2 异常报警
KEY0 PD10 LCD页面切换
KEY1 PD9 报警使能控制
红绿LED PE7、PE8 人员状态指示
USART1 TX/RX PA9、PA10 串口数据输出

以上引脚需要在 STM32CubeMX 中完成对应配置。

引脚分配图片


六、系统软件结构

为了便于调试和维护,程序采用模块化设计。

主要模块包括:

main.c
├── 按键扫描模块
├── ADC采集模块
├── DHT11温湿度模块
├── PIR人体检测模块
├── 超声波测距模块
├── 继电器控制模块
├── LED状态指示模块
├── 蜂鸣器报警模块
├── LCD显示模块
└── 串口输出模块

主函数主要负责:

  1. 初始化各个外设;
  2. 调用不同传感器模块;
  3. 完成阈值判断;
  4. 控制执行器状态;
  5. 更新LCD页面;
  6. 输出串口数据。

主循环调用关系可以简化为:

while (1)
{
    Key_Direct_Scan();

    GH_ADC_Update();

    pir_state = PIR_GetState();
    PIR_Event_Process();

    if (light_percent < LIGHT_LOW_THRESHOLD)
    {
        Relay_On();
    }
    else
    {
        Relay_Off();
    }

    DHT11_ReadData(&dht_temp, &dht_humi);

    Ultrasonic_ReadDistance(&water_distance);

    Alarm_Check();
    Buzzer_Task();

    LCD_Display_Update();
}

实际程序中,不同模块并不是每次循环都同时执行。

例如:

  • DHT11每 2 秒更新一次;
  • 超声波每 1 秒测距一次;
  • ADC和按键按照更短周期更新;
  • LCD根据当前页面周期刷新。

程序可以使用 HAL_GetTick() 实现不同任务的周期调度,避免所有任务同时运行造成阻塞。


七、核心功能实现

7.1 DHT11 温湿度采集

DHT11采用单总线通信方式,通过一个数据引脚完成温度和湿度数据传输。

本项目将 DHT11 数据引脚连接到 PB8。

采集完成后,将温度和湿度分别保存到变量中:

uint8_t dht_temp = 0;
uint8_t dht_humi = 0;

DHT11_ReadData(&dht_temp, &dht_humi);

为了避免读取过于频繁导致数据不稳定,程序设置 DHT11 每 2 秒读取一次。

示例周期调度逻辑如下:

if (HAL_GetTick() - dht_last_tick >= 2000)
{
    dht_last_tick = HAL_GetTick();

    DHT11_ReadData(&dht_temp, &dht_humi);
}

读取完成后,温湿度数据同时显示在 LCD 和串口调试助手中。


7.2 ADC 模拟量采集

酒精传感器和光敏传感器均输出模拟电压,因此需要使用 STM32 的 ADC 外设进行采集。

本项目中:

  • 酒精传感器连接PC4;
  • 光敏传感器连接PA4。

ADC 读取到的原始数据范围通常为:

0 ~ 4095

为了方便LCD显示和阈值判断,程序将ADC原始值换算为百分比:

gas_percent = gas_adc_value * 100 / 4095;
light_percent = light_adc_value * 100 / 4095;

转换完成后:

  • gas_percent表示模拟气体浓度百分比;
  • light_percent表示光照强度百分比。

相比直接显示ADC原始值,百分比形式更加直观。


7.3 气体异常判断

系统设定:

气体浓度大于 75% 时,判断为空气异常。

对应代码如下:

#define GAS_ALARM_THRESHOLD 75

gas_alarm = (gas_percent > GAS_ALARM_THRESHOLD);

gas_percent 大于 75 时:

gas_alarm = 1;

否则:

gas_alarm = 0;

该状态会参与蜂鸣器报警判断。

需要注意的是,酒精传感器在本项目中主要用于验证:

  • ADC 采集;
  • 百分比换算;
  • 阈值判断;
  • 报警联动。

7.4 光照检测与自动补光

光敏传感器用于检测当前环境光照强度。

系统设定:

光照强度低于 35% 时,自动开启继电器。

对应代码如下:

#define LIGHT_LOW_THRESHOLD 35

if (light_percent < LIGHT_LOW_THRESHOLD)
{
    Relay_On();
}
else
{
    Relay_Off();
}

当用手遮挡光敏传感器时,光照百分比会下降。

如果光照低于 35%:

  • 继电器吸合;
  • LCD 显示 Lamp Status: ON
  • 模拟补光灯开启。

当光照恢复到 35% 以上:

  • 继电器断开;
  • LCD 显示 Lamp Status: OFF
  • 模拟补光灯关闭。

该功能实现了:

光照采集 → 阈值判断 → 继电器控制

这是系统中的一个典型闭环控制功能。


7.5 PIR 人员状态检测

PIR 人体红外传感器可以检测人体经过时产生的触发信号。

如果直接将 PIR 高电平理解为“有人”,可能会受到传感器高电平保持时间的影响。

例如,人体经过后 PIR 可能持续输出一段时间高电平。如果程序每次循环都进行状态切换,就会导致人员状态不断变化。

因此,本项目采用:

PIR 每触发一次,人员状态切换一次。

核心代码如下:

if ((last_pir_state == PIR_SAFE) &&
    (pir_state == PIR_DETECTED))
{
    pir_trigger_count++;

    if (people_state == PEOPLE_OUT)
    {
        people_state = PEOPLE_IN;
    }
    else
    {
        people_state = PEOPLE_OUT;
    }

    People_LED_Update(people_state);
}

last_pir_state = pir_state;

这里判断的是PIR信号从:

Safe → Detect

的变化瞬间,也就是信号上升沿。

只有在上升沿到来时,程序才切换一次人员状态。

这样可以避免一次PIR高电平持续期间产生多次误切换。


7.6 红绿灯人员状态指示

人员状态通过红灯和绿灯进行显示。

系统规则如下:

人员状态 红灯 绿灯
People Outside
People Inside

示例代码:

void People_LED_Update(uint8_t people_state)
{
    if (people_state == PEOPLE_IN)
    {
        Red_LED_Off();
        Green_LED_On();
    }
    else
    {
        Green_LED_Off();
        Red_LED_On();
    }
}

系统上电后默认为无人状态:

People Outside

此时红灯点亮。

PIR 第一次触发后:

People Inside

绿灯点亮。

PIR 再次触发后,状态重新变为:

People Outside

7.7 超声波测距

超声波模块使用 Trig 和 Echo 两个信号引脚。

本项目中:

  • Trig 连接 PB10;
  • Echo 连接 PB11。

测距过程如下:

  1. Trig 输出一个短高电平脉冲;
  2. 超声波模块发射声波;
  3. Echo引脚输出高电平;
  4. 测量Echo高电平持续时间;
  5. 根据时间换算距离。

发送触发脉冲:

HAL_GPIO_WritePin(TRIG_PORT,
                  TRIG_PIN,
                  GPIO_PIN_SET);

DWT_Delay_us(20);

HAL_GPIO_WritePin(TRIG_PORT,
                  TRIG_PIN,
                  GPIO_PIN_RESET);

距离换算公式为:

距离(cm) ≈ Echo高电平时间(us) ÷ 58

代码如下:

*distance_cm = (uint16_t)((echo_time_us + 29) / 58);

在整数运算中,先加29再除以58,可以实现近似四舍五入。


7.8 水位异常判断

本项目使用超声波距离模拟水箱水位。

如果超声波模块安装在水箱顶部,那么:

  • 距离越小,表示水位越高;
  • 距离越大,表示水位越低。

系统设定:

距离小于 3 cm:水位过高
距离大于 25 cm:水位过低

判断代码如下:

if ((water_distance < 3) ||
    (water_distance > 25))
{
    water_alarm = 1;
}
else
{
    water_alarm = 0;
}

两种情况都会触发水位异常标志。

在实际测试时,需要保持超声波模块方向固定,并尽量使用平整目标面,以提高测距稳定性。


7.9 KEY0 页面切换

KEY0 用于切换 LCD 显示页面。

系统设计了四个页面:

页面编号 页面名称 显示内容
0 Environment 温度、湿度、气体浓度
1 Light Control 光照、继电器、水位
2 People Status 人员状态、红绿灯、触发次数
3 Warning Monitor 报警使能、蜂鸣器、报警原因

按键检测代码如下:

if ((key0_last_level == GPIO_PIN_SET) &&
    (key0_now == GPIO_PIN_RESET))
{
    lcd_page = (lcd_page + 1) % 4;
    lcd_force_update = 1;
}

其中:

lcd_page = (lcd_page + 1) % 4;

可以使页面编号在以下范围内循环:

0 → 1 → 2 → 3 → 0

相比将所有数据显示在同一个页面,多页面显示更加清晰,也更适合项目演示。


7.10 KEY1 报警使能

KEY1 用于控制蜂鸣器报警功能。

按一次 KEY1:

Warning Enable

再次按下:

Warning Disable

对应代码如下:

if ((key1_last_level == GPIO_PIN_SET) &&
    (key1_now == GPIO_PIN_RESET))
{
    buzzer_warning_enable =
        !buzzer_warning_enable;

    if (buzzer_warning_enable == 0)
    {
        Buzzer_Stop();
    }
}

使用报警使能开关后,即使传感器检测到异常,也可以手动关闭蜂鸣器。

但是 LCD 仍然保留异常原因,便于查看当前故障状态。


7.11 蜂鸣器报警逻辑

蜂鸣器报警由两个条件共同控制:

  1. KEY1已经开启报警;
  2. 气体或水位出现异常。

首先合并报警条件:

alarm_condition = (gas_alarm || water_alarm);

然后判断是否允许报警:

if ((buzzer_warning_enable == 0) ||
    (alarm_condition == 0))
{
    Buzzer_Stop();
    return;
}

只有报警使能且存在异常时,蜂鸣器才开始工作。

为了避免蜂鸣器一直长鸣,系统采用周期短响方式:

if ((HAL_GetTick() - buzzer_last_period_tick)
    >= BUZZER_PERIOD_TIME)
{
    buzzer_last_period_tick = HAL_GetTick();

    Buzzer_Start_Beep();
}

使用 HAL_GetTick() 进行周期控制,相比直接使用长时间 HAL_Delay(),不会长时间阻塞主循环。


7.12 LCD 分页显示

系统使用 LCD 显示不同模块的数据。

Environment 页面

主要显示:

Temperature
Humidity
Air Level

Light Control 页面

主要显示:

Light Level
Lamp Status
Water

People Status 页面

主要显示:

People Inside / Outside
Red Light / Green Light
PIR Count

Warning Monitor 页面

主要显示:

Warning Enable / Disable
Buzzer Active / Silent
Reason

LCD 分页显示可以提高信息层次,避免过多内容集中在同一页面。


7.13 串口数据输出

USART1 用于向串口调试助手输出系统运行数据。

串口配置如下:

参数 配置
波特率 115200
数据位 8 位
校验位 None
停止位 1 位

串口输出内容包括:

Temperature
Humidity
Air Level
Light Level
Lamp Status
Water
People
PIR Sensor
Warning
Alarm
ADC Status
LCD Page

示例输出:

========== GreenHouse Data ==========

Temperature : 30
Humidity    : 62%
Air Level   : 85%
Light Level : 100%
Lamp Status : OFF
Water       : 15cm
People      : Outside
PIR Sensor  : Safe
Warning     : Enable
Alarm       : Gas=Normal | Water=Normal
LCD Page    : 0

=====================================

串口数据可以用于判断:

  • 传感器是否正常采集;
  • LCD 显示是否正确;
  • 报警条件是否成立;
  • 继电器状态是否正确;
  • 当前页面编号是否正确。

八、系统运行步骤

8.1 检查硬件连接

按照引脚分配表完成接线,重点检查:

  • 电源是否正确;
  • GND 是否共地;
  • 信号线是否接反;
  • ADC 模块输出是否连接到正确引脚;
  • 超声波 Trig 和 Echo 是否接反;
  • 继电器模块供电是否正常。

8.2 配置STM32CubeMX

在 STM32CubeMX 中完成:

  1. 选择 STM32L475VET6;
  2. 配置系统时钟;
  3. 配置 GPIO 输入和输出;
  4. 配置 ADC 通道;
  5. 配置 USART1;
  6. 配置调试接口;
  7. 生成Keil工程。

8.3 编译并下载程序

使用 Keil 打开工程后:

  1. 点击编译;
  2. 确认无错误;
  3. 连接开发板;
  4. 点击Download;
  5. 将程序下载到 STM32L475。

8.4 测试 LCD 页面

系统上电后默认显示 Environment 页面。

按下 KEY0,页面依次切换:

Environment
    ↓
Light Control
    ↓
People Status
    ↓
Warning Monitor

8.5 测试光照联动

使用手遮挡光敏传感器。

当光照低于 35% 时:

Lamp Status: ON

继电器吸合。

移开遮挡物后:

Lamp Status: OFF

继电器断开。


8.6 测试人员状态

在 PIR 传感器前移动。

第一次触发:

People Inside
Green Light ON

第二次触发:

People Outside
Red Light ON

8.7 测试水位报警

改变超声波传感器与目标物之间的距离。

当距离:

小于 3 cm

或者:

大于 25 cm

系统判断为水位异常。

按下KEY1开启报警后,蜂鸣器开始周期短响。


8.8 观察串口数据

打开串口调试助手并设置:

115200
8
None
1

连接后,可以观察系统周期输出的各项数据和状态。


九、系统运行效果

经过测试,系统实现了以下功能:

  • DHT11 温湿度采集正常;
  • 气体浓度 ADC 采集正常;
  • 光照低于 35% 时继电器能够自动开启;
  • PIR 每触发一次可切换一次人员状态;
  • 红灯和绿灯能够同步显示人员状态;
  • 超声波距离能够用于模拟水位;
  • 水位异常时能够触发报警;
  • KEY0可以切换四个LCD页面;
  • KEY1可以控制报警使能;
  • 串口能够周期输出系统状态。

典型测试数据如下。

测试场景 关键数据或状态 系统响应
环境数据采集 Temperature=30℃,Humidity=62% LCD和串口正常显示
模拟气体异常 Air Level=85% 气体异常标志置位
正常光照 Light Level=100% 继电器关闭
人员外出 People Outside 红灯亮
人员进入 People Inside 绿灯亮
水位异常 Water Error 蜂鸣器报警
报警关闭 Warning Disable 蜂鸣器停止

项目测试结果表明,各传感器、执行器、LCD页面和按键功能基本能够按照预期逻辑运行。


十、调试过程中遇到的问题

10.1 多个模块引脚冲突

问题现象

将多个独立实验整合到同一个项目后,部分传感器、LCD、串口和按键使用了相同引脚。

原因分析

不同例程通常按照自己的默认引脚配置,直接组合时容易产生资源冲突。

解决方法

重新规划引脚资源,统一在STM32CubeMX中配置:

PB8  → DHT11
PB9  → PIR
PB10 → Trig
PB11 → Echo
PC4  → 酒精传感器
PA4  → 光敏传感器
PD12 → 继电器

同时检查这些引脚是否与LCD和串口资源冲突。


10.2 LCD显示内容过多

问题现象

如果将所有传感器数据放在同一页面,显示内容拥挤,不便于观察。

解决方法

将LCD划分为四个页面,并使用KEY0切换。

这样不仅提高了界面可读性,也便于现场逐项展示功能。


10.3 PIR触发一次却多次切换

问题现象

人体经过PIR后,人员状态在进入和离开之间快速切换多次。

原因分析

PIR检测到人体后,高电平会持续一段时间。

如果程序直接判断:

if (pir_state == PIR_DETECTED)
{
    people_state = !people_state;
}

那么在高电平持续期间,主循环会重复执行状态翻转。

解决方法

检测PIR的上升沿:

Safe → Detect

只有在状态变化瞬间执行一次切换。


10.4 蜂鸣器一直鸣响

问题现象

异常状态持续时,蜂鸣器一直响,影响调试和演示。

解决方法

增加KEY1报警使能开关。

只有满足以下两个条件时才报警:

Warning Enable
+
存在气体异常或水位异常

同时使用HAL_GetTick()实现周期短响。


10.5 超声波测距不稳定

问题现象

测距数据偶尔跳变,或者出现错误值。

可能原因

  • 目标面不平整;
  • 传感器角度倾斜;
  • 接线松动;
  • Echo信号测量超时;
  • 目标距离超过有效范围;
  • 供电不稳定。

解决方法

  1. 固定传感器方向;
  2. 使用平整目标面;
  3. 检查Trig和Echo接线;
  4. 增加超时判断;
  5. 对连续多次测量结果进行平均或中值滤波;
  6. 在串口中输出原始回波时间和错误状态。

十一、项目总结

本项目完成了一套基于STM32L475VET6的智慧农业大棚环境检测与自动控制系统。

系统综合使用了:

  • GPIO输入输出;
  • ADC模拟量采集;
  • DHT11单总线通信;
  • 超声波时序测量;
  • 串口通信;
  • LCD显示;
  • 按键输入;
  • 继电器控制;
  • LED状态指示;
  • 蜂鸣器报警。

项目不仅实现了多个传感器的数据采集,还进一步实现了:

  • 光照不足自动补光;
  • 人员进出状态切换;
  • 水位异常判断;
  • 气体异常判断;
  • 多页面数据显示;
  • 报警使能控制;
  • 周期蜂鸣器报警。

最终形成了完整的嵌入式系统运行流程:

数据采集
    ↓
数据处理
    ↓
阈值判断
    ↓
执行器控制
    ↓
状态显示
    ↓
异常报警

通过本项目,可以进一步理解STM32多外设协同工作、模块化程序设计和非阻塞周期任务调度的基本方法。


十二、后续优化方向

目前系统仍然存在一定的优化空间。

1. 替换专业农业传感器

可以将酒精传感器替换为:

  • CO₂传感器;
  • 氨气传感器;
  • 甲烷传感器;
  • 空气质量传感器。

这样能够提高项目与农业场景的匹配程度。

2. 增加土壤湿度检测

增加土壤湿度传感器后,可以检测土壤含水量。

当土壤湿度过低时,自动控制水泵进行灌溉。

3. 增加自动灌溉

增加:

  • 水泵;
  • 电磁阀;
  • MOS管或继电器驱动模块。

可以实现:

土壤湿度检测
    ↓
湿度低于阈值
    ↓
开启水泵
    ↓
湿度恢复
    ↓
关闭水泵

4. 增加无线通信

可以加入:

  • ESP8266;
  • ESP32;
  • LoRa;
  • 蓝牙;
  • 4G通信模块。

将采集数据上传到网页、手机或云平台。

5. 增加远程监控

后续可以接入:

  • MQTT服务器;
  • 阿里云物联网平台;
  • OneNET;
  • 自建Flask服务器;
  • WebSocket网页。

实现远程查看温湿度、光照、水位和报警状态。

6. 未来优化LCD界面

可以增加:

  • 图标;
  • 进度条;
  • 折线图;
  • 不同颜色的报警提示;
  • 中文显示;
  • 触摸操作。

使系统更加接近实际农业监控终端。


文章说明

本文项目来源于《嵌入式系统与接口技术课程设计》期末大作业,主要用于学习STM32多传感器采集、状态判断、执行器控制和人机交互。

项目中的酒精传感器和超声波模块主要用于模拟异常气体和水箱水位场景,当前系统更侧重于嵌入式接口技术和控制逻辑验证,并未直接达到实际农业生产环境的部署标准。


Logo

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

更多推荐