温湿度+CO2+光照+土壤湿度四路采集,MQTT上云手机远程控制,百元成本搭出智慧大棚

搞过种植的朋友都懂:大棚最怕的不是设备贵,是人不在棚里。中午棚温冲到 40 度烧苗、夜里 CO2 施肥过了头、浇水全凭手感——一个疏忽一茬菜就没了。市面上的大棚环控动辄几千上万,其实用 STM32 加几个传感器,一百多块就能搭一套「自动补光 + 风扇降温 + 水泵浇水 + 通风排 CO2 + 手机远程看数据」的监控系统。这篇文章就把整套方案拆开讲透:选型为什么这么选、接线怎么接、代码怎么写、以及我踩过(和论文里藏着)的那些坑。

一、功能拆解:这套系统到底干了什么

功能模块具体动作触发条件
环境采集温度、湿度、CO2 浓度、光照强度、土壤湿度 五参数实时读取主循环周期采集
本地显示OLED 屏轮流显示各参数当前值采集完成即刷新
自动补光打开 LED 植物灯光照低于阈值
自动降温启动风扇温度超过阈值
自动浇水水泵启动土壤湿度低于阈值
自动通风通风设备启动CO2 浓度超过阈值
超限报警蜂鸣器报警 + 报警信息推送到手机任一参数超限
远程监控数据上云,手机 APP 实时查看、远程开关设备、改阈值ESP8266 Wi-Fi 常连接

核心逻辑一句话:传感器读数 → 超阈值判断 → 继电器动作 + 蜂鸣器报警 → 数据推云 → 手机可看可控

二、器件选型:每一颗料都有讲究

主控:STM32F103C8T6(淘汰 NXP LPC1768)

对比项STM32F103C8T6NXP LPC1768
内核/主频Cortex-M3 / 72MHzCortex-M3 / 120MHz
Flash/RAM64KB / 20KB512KB / 64KB
GPIO37 个70 个
价格~10 元~40 元

LPC1768 性能确实强,但本项目就五路采集加四路控制,STM32F103 的 37 个 IO、5 路 12 位 ADC、3 个串口绰绰有余,开发资料还多得多。性能过剩不加分,成本翻四倍是减分

传感器全家桶

传感器测什么为什么选它淘汰方案
DHT11温度/湿度3 块钱,单总线一根线搞定SHT40(精度 ±0.3°C 但 15 元起,大棚不需要)
YL-69土壤湿度电阻式,几块钱,模块自带 ADC 输出AM2120 电容式(耐用抗腐蚀但贵一倍)
MQ-135CO2便宜、模拟量直接进 ADCMH-Z19 红外(精度高,但要 40+ 元)
GL5528光照1 块钱光敏电阻,判断"够不够亮"足够TSL2561 数字光感(精度高,判断开关量用不上)
OLED12864显示I2C 两根线,自发光对比度高ST7735 彩屏(好看但占 IO、费电)
ESP8266-01S上云自带 Wi-Fi 直连路由器nRF905(433MHz 距离远,但不能连互联网)

整套 BOM 估算:主控板 15 + 传感器约 25 + OLED 10 + ESP8266 10 + 继电器模块 8 + 蜂鸣器 2 + 水泵风扇 LED 约 30 ≈ 100 元出头

两个选型提醒(论文里不会告诉你的)

1. MQ-135 的量程坑。 论文给的测量范围是 10~1000ppm。问题来了:大气本底 CO2 就有 420ppm 左右,而大棚为提高产量搞 CO2 施肥时,棚内浓度普遍要维持在 800~1200ppm 甚至更高——正好卡在 MQ-135 的量程上限附近。也就是说,你最需要精确控制的区间,它恰恰测不准。预算够的话,MH-Z19B(0~5000ppm,NDIR 红外)才是大棚 CO2 的正解;用 MQ-135 就得接受"只看趋势不看绝对值"。

2. DHT11 的湿度量程。 20~80%RH——大棚里午间通风差时湿度轻松破 80%,读数直接顶格。好在超限报警逻辑是"温度为主、湿度参考",影响可控。追求准确的湿度数据请上 SHT40(0~100%RH)。

三、接线方案:一张表讲清楚

模块模块引脚STM32 引脚备注
DHT11DATAPC15单总线,需 4.7K 上拉
YL-69AOPA4(ADC)模块 VCC 接 5V
MQ-135AOPB0(ADC)DO 脚不用接
GL5528AOPB1(ADC)光敏模块模拟输出
OLED12864SCL / SDAI2C SCL / SDA3.3V 供电
ESP8266-01STXD / RXDUSART2 RX / TX115200bps,3.3V
蜂鸣器控制脚PB8低电平触发,三极管驱动
LED 补光灯继电器 INPA11(或经继电器)继电器接 PA0/PA1/PA5
风扇/水泵/通风继电器 IN ×3PA0 / PA1 / PA5继电器隔离驱动
按键 ×3PB12 / PB13 / PB14本地手动/设置用

接线的三个坑

  • ESP8266 必须独立 3.3V 供电。 它发射瞬间电流能冲到 300mA+,直接从 STM32 板载 3.3V 取电,Wi-Fi 一连上就掉电重启,症状是"模块反复打印 ready"。加一块 AMS1117 稳压或独立 3.3V,问题消失。
  • 模拟传感器走线远离 ESP8266 天线。 Wi-Fi 发射时的射频干扰会串进 ADC 采样,土壤湿度读数会莫名跳动 5% 左右。采样线尽量短,有条件用屏蔽线。
  • 继电器别接在传感器电源上。 水泵继电器吸合瞬间电源抖动,MQ-135 这种敏感模拟器件读数会跳。继电器线圈电源和传感器电源分开走。

四、软件设计

主框架

系统上电后依次完成外设初始化(ADC×3、单总线、I2C、串口 2、定时器、继电器、ESP8266 入网),然后进入主循环:采集 → OLED 刷新 → 云端上报 → 检查串口指令 → 阈值判断与联动控制。

#include "sys.h"
#include "delay.h"
#include "OLED_I2C.h"

int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    delay_init();
    TIM4_Init(300, 7200);          /* 定时器: 周期采样与报警节拍 */
    OLED_Init();
    KEY_Init();                    /* PB12~PB14 本地按键 */

    while (DHT11_Init()) {}        /* PC15, DHT11 就绪前阻塞 */

    Adc_Init1();                   /* PB1  光照   */
    Adc_Init2();                   /* PB0  CO2    */
    Adc_Init3();                   /* PA4  土壤湿度 */
    Beep_init();                   /* PB8  蜂鸣器  */
    Relay_init();                  /* PA0/PA1/PA5 继电器 */

    OLED_CLS();
    ALi_ESP8266_GPIO_Init();       /* ESP8266 复位脚 */
    MQTT_Buff_Init();              /* MQTT 报文缓冲 */
    AliIoT_Parameter_Init();       /* 阿里云三元组参数 */

    while (1)
    {
        Sensor_Scan();             /* 五参数采集(带滤波) */
        OLED_Display_Cotrol();     /* 分屏刷新显示 */
        Ali_Send_Payload();        /* JSON 上报云端 */
        Uart_Cmd_Handle();         /* APP 下行指令解析 */
        Threshold_Control();       /* 阈值判断+继电器联动 */
    }
}

关键子程序 1:DHT11 单总线读取

DHT11 的时序是"起步容易、细节要命":主机拉低 1~2ms 发起,松开后传感器回 80µs 低 + 80µs 高的应答,然后连续发 40 位数据(湿度整数/小数、温度整数/小数、校验和)。每一位靠高电平持续时间区分 0 和 1(约 26µs 为 0,70µs 为 1)。

u8 DHT11_Read_Data(u8 *temp, u8 *humi)
{
    u8 buf[5], i;
    DHT11_Rst();                       /* 主机拉低 >18ms 再释放 */
    if (DHT11_Check() == 0) return 1;  /* 无应答 */

    for (i = 0; i < 5; i++)
        buf[i] = DHT11_Read_Byte();    /* 每字节8位, 高电平宽度判0/1 */

    if (buf[0] + buf[1] + buf[2] + buf[3] == buf[4])
    {
        *humi = buf[0];                /* DHT11 小数位恒为0 */
        *temp = buf[2];
        return 0;
    }
    return 1;                          /* 校验失败丢弃本次 */
}

关键子程序 2:ADC 多次采样取平均

土壤湿度、CO2、光照都是模拟量,单次读取噪声大。采 10 次取平均是最便宜的软件滤波:

u16 Get_Adc_Average(u8 ch, u8 times)
{
    u32 temp_val = 0;
    u8 i;
    for (i = 0; i < times; i++)
    {
        temp_val += Get_Adc(ch);
        delay_ms(5);
    }
    return (u16)(temp_val / times);
}

/* 土壤湿度: ADC值转百分比(干土壤校准值~湿土壤校准值线性映射) */
u8 Soil_Moisture_Percent(u16 adc)
{
    u32 percent = (ADC_DRY - adc) * 100 / (ADC_DRY - ADC_WET);
    if (percent > 100) percent = 100;
    return (u8)percent;
}

注意 YL-69 是湿度越大电压越低(电阻式,水多导电好),所以是 ADC_DRY - adc。每个模块的干湿两端值不一样,上电后先拿干土、湿土各标定一次,写死这两个常数。

关键子程序 3:阈值联动控制(带回差)

最朴素的写法是"超阈值开、低于阈值关",但参数在阈值附近抖动时,继电器会每秒啪啪响个不停,水泵风扇很快就废了。加一个回差(hysteresis):

#define TEMP_ON   32     /* 高于32度开风扇 */
#define TEMP_OFF  29     /* 降回29度才关  */

void Threshold_Control(void)
{
    /* 温度 -> 风扇, 回差3度 */
    if (g_temp > TEMP_ON)      FAN = 0;      /* 继电器低电平吸合 */
    else if (g_temp < TEMP_OFF) FAN = 1;

    /* 光照 -> LED补光, 回差 */
    if (g_light < LIGHT_MIN)   LED_LIGHT = 0;
    else if (g_light > LIGHT_MAX) LED_LIGHT = 1;

    /* 土壤湿度 -> 水泵 */
    if (g_soil < SOIL_MIN)     PUMP = 0;
    else if (g_soil > SOIL_MAX) PUMP = 1;

    /* CO2 -> 通风 */
    if (g_co2 > CO2_MAX)       VENT = 0;
    else if (g_co2 < CO2_MIN)  VENT = 1;

    Alarm_Check();   /* 任一超限: 蜂鸣器短鸣 + 报警标志上云 */
}

关键子程序 4:ESP8266 上云链路

这里有个原论文前后打架的地方,先看它正文怎么写的:

“发送 AT+CIPSTART 连接到 TCP 服务器,检查缓冲区是否包含 CONNECT 以验证与 TCP 服务器的连接。”

再看它附录的代码:

ALi_ESP8266_GPIO_Init();
MQTT_Buff_Init();
AliIoT_Parameter_Init();

——压根不是裸 TCP,是阿里云物联网平台的 MQTT 接入(三元组认证 + MQTT_Buff 组包)。正文那段 AT 流程描述的是透传调试阶段的玩法,真正的成品走的是 MQTT。以代码为准,实际流程是:

ESP8266 复位 → 等 "ready"
AT+CWMODE=1                设置STA模式
AT+CWJAP="SSID","PASSWD"   连接路由器, 等 "OK"
AT+CIPMUX=0                单连接
AT+CIPSTART="TCP","域名",1883   连MQTT端口
AT+CIPSEND                 进入透传
→ 发送 MQTT CONNECT 报文(带阿里云三元组计算出的密码)
→ 订阅属性下发主题, 发布数据主题

上报的 JSON 大致长这样:

{"id":1,"params":{"Temperature":26.5,"Humidity":68,"CO2":780,"Light":45,"Soil":52},"version":"1.0"}

手机 APP 端通过阿里云的物模型界面(或 linkage 平台)就能看到实时数据、下发"开风扇/关水泵"的属性设置指令,单片机在串口中断里解析并执行——这就是"手机远程控制"的全部秘密,没有自建服务器,没有写 APP,白嫖云平台

五、调试验证:每一路怎么测

测试项方法预期结果
温湿度手捏 DHT11 或哈气温度读数上升,湿度明显升高
土壤湿度探针从干土插到湿土百分比读数平滑上升(多次平均后无跳变)
CO2对着 MQ-135 呼气浓度迅速攀升并触发通风(人呼气 CO2 约 40000ppm)
光照手掌遮住光敏电阻光照值跌落,LED 补光灯亮起
自动降温捂热 DHT11 至超阈值风扇继电器吸合 + 蜂鸣器报警
远程监控APP 下发"开灯"指令3 秒内继电器动作,云端状态回读一致
断网恢复拔路由器 1 分钟再上电ESP8266 自动重连,数据续传

六、常见坑汇总(含论文纠错)

  1. MQ-135 前后描述打架:选型章节说它"基于电化学传感器技术",硬件章节又说敏感材料是 SnO2 金属氧化物——后者才是对的,MQ 系列全是半导体加热型,通电后要预热 24~48 小时读数才稳定。别拿刚开机的读数当真。
  2. "LM398 分压核心"是笔误:光敏模块的分压/比较电路用的应是 LM393(比较器)或 LM358(运放),LM398 是采样保持芯片,和分压八竿子打不着。画原理图抄参数时务必核对。
  3. CO2 量程不够用:前面说过,1000ppm 上限正好卡死大棚施肥区间。方案一:换 MH-Z19;方案二:把 MQ-135 当"趋势仪表",阈值设在 800ppm 提前通风。
  4. 光照"光强值"没有物理单位ADC×5/4096×100 算出来的只是个相对值,不是 lux。对开关量控制够用,但论文里若写"精确光照强度检测"就是夸大。要 lux 请上 BH1750(十几块,I2C 直读 lux)。
  5. 继电器抖动:没加回差时,温度在阈值附近波动会导致风扇每秒开关数次,机械触点寿命按小时计。回差 2~3°C/5%RH 起步。
  6. DHT11 读数全是 0:八成是单总线时序被中断打断(尤其是 ESP8266 串口中断)。DHT11 读取期间要么关中断,要么把读取放在主循环、串口数据处理只置标志位。
  7. 流程图编号错乱:原论文里土壤湿度流程图和 CO2 流程图都标了"图4.3"——写毕设的同学注意,图表编号用 Word 的题注自动编号,别手填,查重前统稿一遍。

七、可扩展方向

  • 换 LoRa 远距离版:温室集群场景,ESP8266 换 SX1278 LoRa,网关集中上云,覆盖几公里省流量。
  • 加执行端 PID:风扇调速从"开/关"升级为 PWM+PID 控温,棚温波动从 ±3°C 收窄到 ±0.5°C。
  • 历史数据 + 曲线:云端把上报数据落库,画温度/CO2 日变化曲线,施肥和通风策略就有数据依据了。
  • 多棚组网:一套主控管一棚,MQTT 主题按棚号区分,一个 APP 管全部。
  • 太阳能供电:大棚普遍拉电不便,STM32 低功耗停机 + 太阳能板 + 18650,采集间隔拉长到 10 分钟,一套系统功耗不到 1W。

八、资料内容完整工程资料(原理图、PCB、代码、元件清单)


九、资料获取方式

Logo

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

更多推荐