🍓 草莓生长对比实验

实验组 (实时监测 + AI分析)  vs  对照组 (标准生长参考)
--:--:-- · 传感器未连接
🔌 传感器连接 未连接 需要 Chrome/Edge
✋ 手动输入: 温度°C 湿度% TDSppm

🔬 实验组

实时监测 + AI
📷点击上传 / 拍照
AI 分析中...
🔬
等待数据
请上传照片进行分析
0
-
健康分
-
绿色率%
-
果实率%
-
花朵率%
-
黄化率%

📡 实时传感器

温度: -- °C   湿度: -- %   TDS: -- ppm

AI 分析 & 养护建议

等待上传照片进行分析

🍓 对照组

标准生长参考
对照组
🍓
结果期 · 阶段 3/4
果实饱满红润,植株健壮
90
90
健康分
62%
绿色率
15.5%
果实率
2.8%
花朵率
3.0%
黄化率

标准环境参数 & 养护要点

📚 参考文献

[1] 中国植物志编委会. 中国植物志(第37卷)·蔷薇科[M]. 北京: 科学出版社, 1985.
[2] 邓明琴, 雷家军. 中国果树志·草莓卷[M]. 北京: 中国林业出版社, 2005.
[3] 张运涛, 王桂霞. 草莓标准化栽培技术[J]. 中国果树, 2021(3): 15-22.
[4] 赵密珍, 钱亚明. 不同营养液配方对草莓生长与果实品质的影响[J]. 园艺学报, 2020, 47(8): 1523-1534.
[5] 刘凤之, 王海波. 温度与光周期对草莓花芽分化的影响[J]. 果树学报, 2019, 36(4): 512-520.
[6] 李莉, 张青. 土壤电导率与草莓产量及品质的相关性研究[J]. 土壤通报, 2021, 52(3): 621-628.
[7] 陈昆松, 徐昌杰. 园艺产品贮藏加工学(第三版)[M]. 北京: 中国农业出版社, 2019: 203-218.
[8] 张志宏, 代红艳. 草莓黄叶病害诊断与综合防治技术[J]. 植物保护学报, 2022, 49(2): 345-353.

🔧 硬件系统架构

GY-SHT31-D
温湿度传感器
TDS 探头
电导率传感器
│ I2C / ADC 采集
STM32F103C8T6 主控
← 输入
SHT31 I2C
TDS ADC
→ 输出
OLED 显示
CH340 串口
│ JSON 串口输出 (115200bps)
CH340 USB-TTL → 电脑 → 浏览器 Web Serial API

📸 硬件实物照片

📋 硬件模块详解

1. GY-SHT31-D 温湿度传感器

🌡 感知层

I2C 数字温湿度传感器,精度 ±0.3°C / ±2%RH。通过 I2C 接口(SCL/PB6, SDA/PB7)连接 STM32,每 100ms 采集一次环境温湿度。草莓生长适宜温度 18-25°C,适宜湿度 60-80%。实时数据通过串口 JSON 上传至浏览器。

2. TDS 电导率探头

💧 感知层

模拟量 TDS 传感器,通过 STM32 ADC(PA0)采样后经温度补偿算法换算为 ppm 值。草莓苗期适宜 400-700 ppm,花果期需 800-1200 ppm。系统根据实时 TDS 值与阶段标准对比,自动生成施肥建议。

3. CH340 USB 转串口模块

🔌 通信层

USB 转 TTL 串口芯片,连接 STM32 的 PA9(TX)/PA10(RX),115200 bps 速率传输 JSON 数据。配合浏览器 Web Serial API,无需安装驱动即可在 Chrome 中直接读取串口数据,实现真正的"零安装"体验。

4. ST-LINK/V2 下载调试器

💻 编程工具

SWD 接口(SWCLK/SWDIO/GND/3.3V)连接 STM32,Keil MDK 一键编译+下载。支持断点调试、变量查看。4 根杜邦线连接即可,无需额外配置。固件源码位于 E:\keli5\greentest\2-1stm32\

5. 0.96寸 OLED 显示屏

📺 本地显示

SSD1306 驱动,128×64 分辨率,I2C 接口(地址 0x3C)。本地实时显示温度 / 湿度 / TDS 数值,方便不连接电脑时也能查看传感器数据。10Hz 刷新频率。

6. 面包板 & 连接线

🔧 结构件

MB-102 面包板 + 跳线 + 杜邦线 + 飞线,用于搭建传感器与 STM32 的电路连接原型。无需焊接,方便快速迭代和实验调整。

🔌 引脚接线表

STM32引脚连接外设类型说明
PB6SHT31 SCLI2C1_SCL温湿度传感器时钟线
PB7SHT31 SDAI2C1_SDA温湿度传感器数据线
PA0TDS 探头 AOADC1_IN0电导率模拟采样,12位分辨率
PB0OLED SCLGPIO (软I2C)软件模拟 I2C 时钟
PB1OLED SDAGPIO (软I2C)软件模拟 I2C 数据
PA9CH340 RXUSART1_TX串口发送 JSON 数据 (115200bps)
PA10CH340 TXUSART1_RX串口接收 (备用)
PA13ST-LINK SWDIOSWD程序下载/调试数据线
PA14ST-LINK SWCLKSWD程序下载/调试时钟线

⚙ 系统工作流程

STM32 上电复位
初始化 I2C / ADC / UART / OLED
每100ms循环
读SHT31
温湿度
读TDS
电导率
OLED
本地显示
UART
输出JSON
CH340 → 浏览器 Web Serial API → 实时显示
零驱动 · 零安装 · 打开网页就能用
循环回到"每100ms" → 无限采集

🧠 软件系统设计

状态机设计

🟢 初始化 (INIT)

  • I2C1 初始化 (100kHz)
  • ADC1 初始化 (12MHz/12bit)
  • USART1 初始化 (115200/8N1)
  • SSD1306 OLED 初始化
  • SHT31 上电自检

🔵 采集 (ACQUIRING)

  • 每100ms 读SHT31 (温度+湿度)
  • 每100ms 读TDS ADC → 温度补偿 → ppm
  • 串口输出 JSON: {"temp","humi","tds"}
  • OLED 刷新显示三行数据

🟡 故障 (ERROR)

  • SHT31 无应答 → 串口输出 {"error":"sht31"}
  • TDS 超量程(>3000ppm) → 告警
  • OLED 显示 "ERR" 闪烁
  • 3秒间隔自动尝试恢复

时序控制

⏰ SysTick 毫秒定时器

主循环用 SysTick 中断产生 1ms 基准,HAL_GetTick() 提供毫秒级时间戳。主循环间隔 100ms = 10Hz 采集频率。

📡 SHT31 I2C 通信协议

标准 I2C 协议,地址 0x44。发送 0x2C06 命令触发单次测量,等待 15ms 后读取 6 字节温湿度原始数据,按公式换算为 °C 和 %RH。

📊 TDS ADC 采样

PA0 引脚 ADC1_IN0,12位分辨率(0-4095)。连续采样 10 次取平均值,温度补偿公式换算为 ppm 值。TDS = ADC_avg × 系数 ÷ (1 + 0.02 × (temp - 25))。

📺 OLED 软 I2C 驱动

SSD1306 驱动芯片,PB0(SCL)/PB1(SDA) 软件模拟 I2C。128×64 分辨率,三行显示:温度 / 湿度 / TDS,10Hz 刷新率。

💻 核心代码模块

SHT31 I2C 温湿度读取

u8 SHT31_Read(float *temp, float *humi) {
    u8 buf[6]; u16 raw_t, raw_h;

    I2C_Start();                                     // 启动信号
    I2C_SendByte(0x44 << 1);                         // SHT31 地址 0x44, 写模式
    I2C_SendByte(0x2C); I2C_SendByte(0x06);         // 高精度测量命令
    I2C_Stop();

    delay_ms(15);                                       // 等待测量完成

    I2C_Start();
    I2C_SendByte(0x44 << 1 | 1);                  // 读模式
    for (int i = 0; i < 5; i++) {
        buf[i] = I2C_ReadByte(1);                 // ACK
    }
    buf[5] = I2C_ReadByte(0);                     // NACK + Stop

    // SHT31 公式: temp = -45 + 175 × raw_t / (2^16-1)
    raw_t = (buf[0] << 8) | buf[1];
    raw_h = (buf[3] << 8) | buf[4];
    *temp = -45.0 + 175.0 * raw_t / 65535.0;
    *humi = 100.0 * raw_h / 65535.0;
    return 0;
}

TDS ADC 采样 + 温度补偿

u16 TDS_Read(float temp) {
    u32 adc_sum = 0;

    for (int i = 0; i < 10; i++) {                      // 10次采样取平均
        ADC_SoftwareStartConvCmd(ADC1, ENABLE);     // 启动ADC
        while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));// 等转换完成
        adc_sum += ADC_GetConversionValue(ADC1);     // 读12bit值
    }
    float adc_avg = adc_sum / 10.0;

    // 电压换算: V = adc × 3.3V / 4096
    float voltage = adc_avg * 3.3 / 4096.0;

    // TDS 计算(含温度补偿): TDS = V × coeff / (1 + 0.02×(temp-25))
    float compensation = 1.0 + 0.02 * (temp - 25.0);
    u16 tds = (u16)(voltage * 500.0 / compensation);  // 系数500

    return tds;
}

主循环 — JSON 串口输出

int main(void) {
    System_Init();                                 // 时钟72MHz
    I2C_Init();    ADC_Init();    UART1_Init(115200);
    OLED_Init();                                    // SSD1306

    float temp, humi; u16 tds;
    char json[128];

    while (1) {
        SHT31_Read(&temp, &humi);                    // I2C 读温湿度
        tds = TDS_Read(temp);                        // ADC 读电导率

        // OLED 本地显示 (三行)
        OLED_Clear();
        OLED_Printf(0, 0, "Temp: %.1f C", temp);
        OLED_Printf(0, 2, "Humi: %.1f %%", humi);
        OLED_Printf(0, 4, "TDS : %d ppm", tds);

        // 串口 JSON 输出 → 浏览器 Web Serial API 读取
        sprintf(json, "{\"temp\":%.1f,\"humi\":%.1f,\"tds\":%d}\r\n",
                temp, humi, tds);
        UART1_SendString(json);

        delay_ms(100);                               // 10Hz 采集频率
    }
}

Web Serial API — 浏览器端数据接收

async function connectSerial() {
    const port = await navigator.serial.requestPort();
    await port.open({ baudRate: 115200 });

    const reader = port.readable.getReader();
    let buffer = '';

    while (true) {
        const { value, done } = await reader.read();
        if (done) break;
        buffer += new TextDecoder().decode(value);

        // 按行分割 JSON
        const lines = buffer.split('\n');
        buffer = lines.pop();                        // 保留不完整行

        for (const line of lines) {
            if (line.startsWith('{"temp"')) {
                sensor = JSON.parse(line.trim());  // 解析传感器数据
                updateSensorDisplay();              // 更新页面
            }
        }
    }
}

🛡 数据质量保障

🔢

ADC 多次采样均值

TDS 电导率连续采样 10 次取平均值,消除电源纹波和随机噪声干扰。

🌡

温度补偿算法

TDS 值随温度漂移,采用标准补偿公式 TDS = V × K / (1 + 0.02×(T-25)) 消除温度影响。

🔄

串口自动重连

Web Serial API 检测到串口断开后,3 秒间隔自动重连,无需人工干预。

📋

串口过滤机制

STM32 启动时自动扫描所有 COM 口,过滤发送全零数据的无效端口,精确匹配 CH340 数据端口。

JSON 校验

仅解析以 {"temp" 开头的合法 JSON 行,忽略噪声数据和乱码,确保数据完整性。

📱

手动输入降级

浏览器不支持 Web Serial API 时,自动显示手动输入面板,输入温湿度/TDS 即可继续使用。

⚡ 技术亮点

🌐 Web Serial API

浏览器原生串口通信,零驱动、零安装。替代传统 pyserial + EXE 方案,彻底解决华为电脑兼容性问题。

📡 I2C + ADC 双通道采集

SHT31 数字温湿度 (I2C) + TDS 模拟电导率 (ADC),100ms 周期同步采集,10Hz 刷新率。

🧠 千问 VL-Plus 多模态AI

四任务并行分析:生长阶段判断 + 植株测量(以果实为天然标尺) + 果实颗粒度三级识别 + 营养故事生成。

📊 对照组动态匹配

4 阶段预设参考数据,根据 AI 检测结果自动切换对照组,实现真正意义上的"对比实验"。

📥 Excel 一键导出

SheetJS 纯前端生成,传感器历史 + AI分析记录 + 汇总信息三个Sheet,蓝表头+斑马纹。

🔐 API Key 服务端保护

千问 API Key 仅存于服务端 .env,前端通过 POST /api/analyze 代理调用,密钥永不暴露。

📋 软件基础设置信息

IDEKeil MDK v5 (uVision V5.06)
编译器ARMCC V5.06 update 5 (build 528)
主控芯片STM32F103C8T6 (Cortex-M3, 64KB Flash, 20KB SRAM)
时钟HSE 8MHz → PLL 9x → 72MHz
标准库STM32F10x Standard Peripheral Library V3.5.0
C语言标准C99 (--c99)
MicroLIB已启用 (精简 math 库)
工程定义STM32F10X_MD, USE_STDPERIPH_DRIVER
启动文件startup_stm32f10x_md.s (中等密度)
编程器ST-LINK/V2 (SWD接口)
开发语言Python 3.10+ (服务端), JavaScript ES6+ (前端), C99 (固件)
核心依赖Flask, Requests, Web Serial API, SheetJS, openpyxl
AI 模型千问 Qwen-VL-Plus 多模态视觉语言模型
传感器采样率STM32 端 10Hz (100ms/次), 浏览器端 1Hz 显示刷新
串口速率115200 bps, 8N1, JSON 行协议
部署架构Ubuntu 22.04 + systemd + nginx HTTPS 反向代理