STM32实战:基于STM32F103的迷迭香智慧种植系统(自动补光+滴灌)

文章目录

    • [1. 项目引言](#1. 项目引言)
    • [2. 系统整体设计](#2. 系统整体设计)
      • [2.1 系统功能](#2.1 系统功能)
      • [2.2 系统架构](#2.2 系统架构)
    • [3. 硬件准备与清单](#3. 硬件准备与清单)
    • [4. 硬件电路连接](#4. 硬件电路连接)
      • [4.1 电源部分连接](#4.1 电源部分连接)
      • [4.2 STM32与传感器/模块连接](#4.2 STM32与传感器/模块连接)
      • [4.3 执行器部分连接](#4.3 执行器部分连接)
    • [5. 软件开发环境搭建](#5. 软件开发环境搭建)
      • [5.1 安装Keil MDK-ARM](#5.1 安装Keil MDK-ARM)
      • [5.2 使用STM32CubeMX创建工程](#5.2 使用STM32CubeMX创建工程)
    • [6. 代码实现详解](#6. 代码实现详解)
      • [6.1 创建与应用相关的头文件](#6.1 创建与应用相关的头文件)
      • [6.2 创建与应用相关的源文件](#6.2 创建与应用相关的源文件)
      • [6.3 修改主函数文件](#6.3 修改主函数文件)
      • [6.4 修改中断服务函数文件(可选,用于系统滴答计时)](#6.4 修改中断服务函数文件(可选,用于系统滴答计时))
      • [6.5 重写printf函数支持串口打印(用于调试,可选但强烈推荐)](#6.5 重写printf函数支持串口打印(用于调试,可选但强烈推荐))
    • [7. 系统调试与校准](#7. 系统调试与校准)
      • [7.1 编译与下载](#7.1 编译与下载)
      • [7.2 硬件调试](#7.2 硬件调试)
      • [7.3 阈值校准](#7.3 阈值校准)
      • [7.4 功能联调](#7.4 功能联调)
    • [8. 总结与展望](#8. 总结与展望)

1. 项目引言

迷迭香是一种常见的香草植物,对光照和水分有特定需求。传统种植方式依赖人工观察和操作,效率低且难以精确控制。本项目基于STM32F103微控制器,设计并实现一套智慧种植系统,能够自动监测环境光照强度与土壤湿度,并据此自动执行补光与滴灌操作,实现迷迭香的智能化、精准化养护。

本教程面向零基础的嵌入式爱好者,将从硬件选型、电路搭建、软件编程到系统调试,提供完整、详实的步骤与代码,确保读者能够按图索骥,成功复现并落地该系统。

2. 系统整体设计

2.1 系统功能

  1. 环境监测:实时采集种植区域的光照强度与土壤湿度。
  2. 智能决策:根据预设的阈值,判断是否需要开启补光灯或启动滴灌。
  3. 自动控制:驱动补光LED灯带与微型水泵,执行相应的补光或浇水动作。
  4. 状态指示:通过LED灯指示系统当前工作模式(如正常、补光、浇水等)。

2.2 系统架构

系统以STM32F103C8T6最小系统板为核心,外接传感器模块与执行器模块,构成一个完整的闭环控制系统。




系统上电
STM32初始化
读取光照传感器
读取土壤湿度传感器
光照是否低于阈值?
湿度是否低于阈值?
开启补光灯
关闭补光灯
启动水泵
关闭水泵
状态指示灯更新
延时等待

流程图说明:系统上电后,STM32完成初始化,随后进入主循环。循环中,依次读取光照和土壤湿度传感器数据,并分别与预设阈值进行比较。根据比较结果,控制补光灯和水泵的开关。同时更新状态指示灯,最后经过一段延时后,开始下一次数据采集与控制循环,实现持续自动管理。

3. 硬件准备与清单

类别 名称 型号/规格 数量 备注
核心控制器 STM32最小系统板 STM32F103C8T6 (蓝色PCB) 1 核心处理单元
光照传感器 数字光强度传感器 BH1750FVI 1 I2C接口,测量范围0-65535 lux
湿度传感器 土壤湿度传感器 模拟输出款 1 输出0-3.3V模拟电压
执行器 补光LED灯带 12V WS2812B或普通白光LED 1 需配合MOS管驱动
执行器 微型直流水泵 5V或12V 1 用于滴灌,需配合继电器或MOS管
电源 直流降压模块 LM2596S 2 分别将12V降至5V(供STM32)和3.3V(供传感器)
电源 开关电源 12V 2A 1 系统总电源
驱动模块 继电器模块 5V高电平触发 1 控制水泵通断
驱动模块 MOS管模块 IRF520 1 控制LED灯带
其他 面包板、杜邦线 - 若干 用于连接电路
其他 电阻、LED灯 220Ω 若干 用于状态指示

购买建议:以上元件均可在主流电子商城(如淘宝、京东)找到。STM32F103C8T6最小系统板建议选择"蓝色PCB"款,其引脚定义较为标准。传感器和执行器选择最常见的型号即可,本教程将基于通用接口进行讲解。

4. 硬件电路连接

重要提示 :连接电路前,请确保所有电源处于断开状态。务必核对电压,避免将5V或12V接入STM32的3.3V引脚,否则会烧毁芯片。

4.1 电源部分连接

  1. 12V开关电源正极接至LM2596S输入正极(IN+) ,负极接至公共地(GND)
  2. 第一个LM2596S模块(输出5V):
    • OUT+ 接至STM32板子的 5V 引脚。
    • OUT- 接至公共地。
  3. 第二个LM2596S模块(输出3.3V):
    • OUT+ 接至面包板的 3.3V 电源轨。
    • OUT- 接至公共地。
  4. STM32板子的 GND 引脚接至公共地。

4.2 STM32与传感器/模块连接

将以下设备的信号线连接到STM32的对应引脚。

设备 引脚/线缆 STM32引脚 引脚模式 说明
BH1750光照传感器 VCC 面包板3.3V轨 - 供电
GND 公共地 - 接地
SCL PB6 I2C1_SCL 时钟线
SDA PB7 I2C1_SDA 数据线
土壤湿度传感器 VCC 面包板3.3V轨 - 供电
GND 公共地 - 接地
AO (模拟输出) PA0 ADC1_IN0 模拟信号输入
继电器模块 VCC 面包板5V轨 - 供电(注意电压)
GND 公共地 - 接地
IN (信号输入) PB5 GPIO_Output 控制水泵开关
IRF520 MOS管模块 VCC 面包板5V轨 - 供电(注意电压)
GND 公共地 - 接地
IN (信号输入) PB4 GPIO_Output 控制LED灯带开关
状态指示灯LED 阳极 (长脚) PB3 (串联220Ω电阻) GPIO_Output 绿色LED,指示系统运行
阴极 (短脚) 公共地 - 接地

4.3 执行器部分连接

  1. 补光LED灯带
    • 灯带 12V+ 接至 12V电源正极
    • 灯带 GND 接至 IRF520模块的 OUT-
    • IRF520模块的 OUT+ 接至 12V电源正极
    • 原理 :当STM32给IRF520的 IN 脚高电平时,MOS管导通,灯带回路接通,灯亮。
  2. 微型水泵
    • 水泵正极接至 12V电源正极
    • 水泵负极接至 继电器模块的 COM (公共端)
    • 继电器模块的 NO (常开端) 接至 12V电源负极
    • 原理 :当STM32给继电器 IN 脚高电平时,继电器吸合,COMNO接通,水泵回路接通,水泵工作。

5. 软件开发环境搭建

5.1 安装Keil MDK-ARM

  1. 访问ARM官网或国内镜像,下载并安装 Keil MDK-ARM (例如V5.36版本)。
  2. 安装过程中,需要注册。可以申请评估版,或寻找相关授权。
  3. 安装完成后,需要安装STM32F1系列的器件支持包(Device Family Pack)。
    • 打开Keil,点击 Pack Installer 图标。
    • Devices 标签页搜索 STM32F103C8,找到对应的系列。
    • Packs 标签页,找到 Keil::STM32F1xx_DFP,点击 Install 进行安装。

5.2 使用STM32CubeMX创建工程

STM32CubeMX是ST官方提供的图形化配置工具,可以极大简化引脚、时钟、外设的初始化工作。

  1. 下载安装STM32CubeMX
  2. 创建新工程 :选择 STM32F103C8Tx 芯片。
  3. 系统核心配置 (SYS)
    • Debug: 选择 Serial Wire。这样才可以使用ST-LINK进行调试和下载。
  4. 时钟配置 (RCC)
    • High Speed Clock (HSE): 选择 Crystal/Ceramic Resonator。我们的最小系统板外部接了8MHz晶振。
  5. 引脚分配与功能配置
    • 根据第4章的连接表,在芯片图形上点击对应引脚,选择其功能。
      • PB6: I2C1_SCL
      • PB7: I2C1_SDA
      • PA0: ADC1_IN0
      • PB5, PB4, PB3: 均设置为 GPIO_Output
  6. 外设参数配置
    • I2C1 : 模式选择 I2C,参数保持默认(标准模式,100kHz)。
    • ADC1 : 在 Analog 标签下,将 ADC1IN0 通道使能。在 Parameter Settings 中,配置为:
      • Resolution: 12 Bits
      • Scan Conversion Mode: Disabled
      • Continuous Conversion Mode: Disabled (我们采用单次转换)
      • DMA Continuous Requests: Disabled
  7. 时钟树配置
    • 在Clock Configuration标签页,将HCLK设置为72MHz(STM32F103的最高主频)。通常只需在 HCLK 输入框键入 72,然后回车,软件会自动配置PLL倍频参数。
  8. 工程管理
    • Project Manager -> Project
      • Project Name: Rosemary_Smart_Farm
      • Project Location: 选择一个你的工作目录。
      • Toolchain / IDE: 选择 MDK-ARM V5
    • Code Generator
      • 勾选 Generate peripheral initialization as a pair of '.c/.h' files per peripheral (为每个外设生成独立的初始化文件)。
      • 勾选 Backup previously generated files when re-generating (重生成时备份旧文件)。
  9. 生成代码 :点击右上角 GENERATE CODE。首次生成会提示安装固件库,点击确认即可。代码生成后,点击 Open Project,会自动在Keil中打开工程。

6. 代码实现详解

在STM32CubeMX生成的代码框架基础上,我们添加应用层逻辑代码。请勿修改 /* USER CODE BEGIN *//* USER CODE END */ 注释之外的生成代码,否则重新生成CubeMX配置时会被覆盖。

6.1 创建与应用相关的头文件

文件名:app_config.h

此文件用于定义系统参数、引脚映射和函数声明。

c 复制代码
/* app_config.h */
#ifndef __APP_CONFIG_H
#define __APP_CONFIG_H

#ifdef __cplusplus
extern "C" {
#endif

/* 包含必要的标准库与HAL库头文件 */
#include "main.h"
#include "i2c.h"
#include "adc.h"
#include "gpio.h"
#include <stdio.h>
#include <string.h>

/* 硬件引脚定义 (与CubeMX配置一致) */
#define LIGHT_SENSOR_SCL_Pin       GPIO_PIN_6
#define LIGHT_SENSOR_SCL_GPIO_Port GPIOB
#define LIGHT_SENSOR_SDA_Pin       GPIO_PIN_7
#define LIGHT_SENSOR_SDA_GPIO_Port GPIOB

#define SOIL_MOISTURE_ADC_Pin      GPIO_PIN_0
#define SOIL_MOISTURE_ADC_GPIO_Port GPIOA

#define PUMP_RELAY_Pin             GPIO_PIN_5
#define PUMP_RELAY_GPIO_Port       GPIOB

#define LED_STRIP_Pin              GPIO_PIN_4
#define LED_STRIP_GPIO_Port        GPIOB

#define STATUS_LED_Pin             GPIO_PIN_3
#define STATUS_LED_GPIO_Port       GPIOB

/* BH1750 I2C 设备地址 */
#define BH1750_ADDR_WRITE          0x46 // 写地址 (从机地址左移一位,最低位为0)
#define BH1750_ADDR_READ           0x47 // 读地址 (从机地址左移一位,最低位为1)

/* BH1750 指令集 */
#define BH1750_POWER_DOWN          0x00
#define BH1750_POWER_ON            0x01
#define BH1750_RESET               0x07
#define BH1750_CONT_H_RES_MODE     0x10 // 连续高分辨率模式,1lx分辨率,120ms
#define BH1750_CONT_H_RES_MODE2    0x11 // 连续高分辨率模式2,0.5lx分辨率,120ms
#define BH1750_CONT_L_RES_MODE     0x13 // 连续低分辨率模式,4lx分辨率,16ms
#define BH1750_ONE_TIME_H_RES_MODE 0x20 // 单次高分辨率模式
#define BH1750_ONE_TIME_H_RES_MODE2 0x21 // 单次高分辨率模式2
#define BH1750_ONE_TIME_L_RES_MODE 0x23 // 单次低分辨率模式

/* 系统控制阈值 (需根据实际环境校准) */
#define LIGHT_INTENSITY_THRESHOLD  3000.0 // 光照强度阈值,单位lux,低于此值补光
#define SOIL_MOISTURE_THRESHOLD    1500   // 土壤湿度ADC原始值阈值,高于此值浇水 (ADC值越大,湿度越小)
#define PUMP_WORK_TIME_MS          3000   // 水泵每次工作时间,单位毫秒
#define LED_WORK_TIME_MS           5000   // 补光灯每次工作时间,单位毫秒
#define SAMPLE_INTERVAL_MS         2000   // 传感器采样间隔,单位毫秒

/* 全局变量声明 */
extern volatile uint32_t system_tick; // 系统滴答计时,在main.c中定义

/* 函数声明 */
void SystemClock_Config(void);
void BH1750_Init(void);
float BH1750_ReadLightIntensity(void);
uint16_t Read_Soil_Moisture_ADC(void);
void Control_Pump(uint8_t state);
void Control_LED_Strip(uint8_t state);
void Control_Status_LED(uint8_t state);
void Delay_ms(uint32_t ms);

#ifdef __cplusplus
}
#endif

#endif /* __APP_CONFIG_H */

6.2 创建与应用相关的源文件

文件名:app_sensors_actuators.c

此文件包含传感器驱动和执行器控制的具体实现。

c 复制代码
/* app_sensors_actuators.c */
#include "app_config.h"

/* BH1750初始化 */
void BH1750_Init(void) {
    uint8_t cmd = BH1750_POWER_ON;
    HAL_I2C_Master_Transmit(&hi2c1, BH1750_ADDR_WRITE, &cmd, 1, 100);
    HAL_Delay(10);

    cmd = BH1750_CONT_H_RES_MODE;
    HAL_I2C_Master_Transmit(&hi2c1, BH1750_ADDR_WRITE, &cmd, 1, 100);
    HAL_Delay(180); // 等待首次测量完成
}

/* 读取BH1750光照强度值,单位lux */
float BH1750_ReadLightIntensity(void) {
    uint8_t data[2] = {0};
    float lux = 0.0;

    if (HAL_I2C_Master_Receive(&hi2c1, BH1750_ADDR_READ, data, 2, 100) == HAL_OK) {
        lux = (float)((data[0] << 8) | data[1]) / 1.2; // 根据数据手册公式计算
    } else {
        lux = -1.0; // 读取失败
    }
    return lux;
}

/* 读取土壤湿度ADC值 */
uint16_t Read_Soil_Moisture_ADC(void) {
    uint16_t adc_value = 0;
    ADC_ChannelConfTypeDef sConfig = {0};

    // 配置ADC通道 (已在CubeMX中配置,此处可省略,但显式配置更安全)
    sConfig.Channel = ADC_CHANNEL_0;
    sConfig.Rank = ADC_REGULAR_RANK_1;
    sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5;
    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
        Error_Handler();
    }

    // 启动ADC转换
    HAL_ADC_Start(&hadc1);
    // 等待转换完成,超时时间10ms
    if (HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK) {
        adc_value = HAL_ADC_GetValue(&hadc1);
    }
    HAL_ADC_Stop(&hadc1);

    return adc_value; // ADC为12位,返回值范围0-4095
}

/* 控制水泵继电器 */
void Control_Pump(uint8_t state) {
    if (state) {
        HAL_GPIO_WritePin(PUMP_RELAY_GPIO_Port, PUMP_RELAY_Pin, GPIO_PIN_SET); // 高电平触发继电器
        // 可以在此添加日志输出:printf("Pump ON\r\n");
    } else {
        HAL_GPIO_WritePin(PUMP_RELAY_GPIO_Port, PUMP_RELAY_Pin, GPIO_PIN_RESET);
        // printf("Pump OFF\r\n");
    }
}

/* 控制补光灯带 (通过MOS管) */
void Control_LED_Strip(uint8_t state) {
    if (state) {
        HAL_GPIO_WritePin(LED_STRIP_GPIO_Port, LED_STRIP_Pin, GPIO_PIN_SET); // 高电平导通MOS管
        // printf("LED Strip ON\r\n");
    } else {
        HAL_GPIO_WritePin(LED_STRIP_GPIO_Port, LED_STRIP_Pin, GPIO_PIN_RESET);
        // printf("LED Strip OFF\r\n");
    }
}

/* 控制状态指示灯 */
void Control_Status_LED(uint8_t state) {
    if (state) {
        HAL_GPIO_WritePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin, GPIO_PIN_SET); // LED亮
    } else {
        HAL_GPIO_WritePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin, GPIO_PIN_RESET); // LED灭
    }
}

/* 简易毫秒级延时函数 (基于HAL_Delay,但避免阻塞式) */
void Delay_ms(uint32_t ms) {
    uint32_t start_tick = system_tick;
    while ((system_tick - start_tick) < ms) {
        // 空循环,等待系统滴答计时器递增。system_tick需要在SysTick中断中更新。
    }
}

6.3 修改主函数文件

文件名:main.c

这是程序的主入口,包含初始化、主循环和核心控制逻辑。

c 复制代码
/* main.c */
#include "app_config.h"

/* 全局变量定义 */
volatile uint32_t system_tick = 0; // 系统滴答计时器,在SysTick中断中递增

/* 私有函数声明 */
static void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_I2C1_Init(void);

int main(void) {
    /* 复位所有外设,初始化Flash接口和Systick */
    HAL_Init();

    /* 配置系统时钟 */
    SystemClock_Config();

    /* 初始化所有已配置的外设 */
    MX_GPIO_Init();
    MX_ADC1_Init();
    MX_I2C1_Init();

    /* 初始化应用层模块 */
    BH1750_Init(); // 初始化光照传感器
    Control_Status_LED(1); // 上电后状态指示灯常亮,表示系统运行

    /* 主循环 */
    while (1) {
        float light_lux = 0.0;
        uint16_t soil_adc = 0;
        static uint32_t pump_start_time = 0;
        static uint32_t led_start_time = 0;
        static uint8_t pump_is_running = 0;
        static uint8_t led_is_running = 0;

        /* 1. 采集数据 */
        light_lux = BH1750_ReadLightIntensity();
        soil_adc = Read_Soil_Moisture_ADC();

        // 可以在此处通过串口打印数据,用于调试
        // printf("Light: %.2f lux, Soil ADC: %d\r\n", light_lux, soil_adc);

        /* 2. 智能决策与控制 - 补光逻辑 */
        if (light_lux > 0 && light_lux < LIGHT_INTENSITY_THRESHOLD) {
            // 光照不足,需要补光
            if (!led_is_running) {
                Control_LED_Strip(1); // 开启补光灯
                led_is_running = 1;
                led_start_time = system_tick; // 记录开启时间
                // printf("Light too low, LED ON.\r\n");
            }
        } else {
            // 光照充足,或读取失败
            // 如果灯正在亮,且已到达预设工作时间,则关闭
            if (led_is_running && ((system_tick - led_start_time) >= LED_WORK_TIME_MS)) {
                Control_LED_Strip(0);
                led_is_running = 0;
                // printf("LED work time reached, LED OFF.\r\n");
            }
        }

        /* 3. 智能决策与控制 - 滴灌逻辑 */
        if (soil_adc > SOIL_MOISTURE_THRESHOLD) { // ADC值大,表示土壤干燥
            if (!pump_is_running) {
                Control_Pump(1); // 启动水泵
                pump_is_running = 1;
                pump_start_time = system_tick;
                // printf("Soil too dry, Pump ON.\r\n");
            }
        } else {
            // 土壤湿度足够,或读取失败
            // 如果水泵正在运行,且已到达预设工作时间,则关闭
            if (pump_is_running && ((system_tick - pump_start_time) >= PUMP_WORK_TIME_MS)) {
                Control_Pump(0);
                pump_is_running = 0;
                // printf("Pump work time reached, Pump OFF.\r\n");
            }
        }

        /* 4. 状态指示灯闪烁 (系统心跳) */
        Control_Status_LED(1); // 常亮表示运行,也可改为闪烁模式
        // 闪烁示例:每500ms切换一次
        // static uint32_t led_toggle_time = 0;
        // if ((system_tick - led_toggle_time) > 500) {
        //     HAL_GPIO_TogglePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin);
        //     led_toggle_time = system_tick;
        // }

        /* 5. 延时,进入下一个控制周期 */
        Delay_ms(SAMPLE_INTERVAL_MS);
    }
}

/* SysTick中断回调函数,用于更新系统滴答计时 */
void HAL_SYSTICK_Callback(void) {
    system_tick++;
}

/* 以下函数由CubeMX自动生成,位于main.c尾部 */
void SystemClock_Config(void) { ... } // 具体代码由CubeMX生成
static void MX_GPIO_Init(void) { ... }
static void MX_ADC1_Init(void) { ... }
static void MX_I2C1_Init(void) { ... }
void Error_Handler(void) { ... }

6.4 修改中断服务函数文件(可选,用于系统滴答计时)

文件名:stm32f1xx_it.c

我们需要在SysTick中断服务程序中调用自定义的回调函数来更新 system_tick

找到 stm32f1xx_it.c 文件中的 SysTick_Handler 函数,在其内部添加对 HAL_SYSTICK_Callback 的调用。注意要在 USER CODE BEGINUSER CODE END 之间添加

c 复制代码
/* stm32f1xx_it.c (片段) */
/**
  * @brief This function handles System tick timer.
  */
void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */
  /* 调用自定义的滴答回调函数 */
  HAL_SYSTICK_Callback();
  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */
  /* USER CODE END SysTick_IRQn 1 */
}

同时,需要在 stm32f1xx_it.h 文件中声明这个回调函数(如果尚未声明)。

c 复制代码
/* stm32f1xx_it.h (在文件末尾的#ifdef __cplusplus之前添加) */
void HAL_SYSTICK_Callback(void);

6.5 重写printf函数支持串口打印(用于调试,可选但强烈推荐)

文件名:usart.c

为了方便调试,我们可以重定向 printf 到串口。假设你使用了USART1(PA9为TX,PA10为RX)。

  1. 首先在CubeMX中启用USART1,模式为 Asynchronous,参数默认即可。
  2. main.c 中包含 stdio.h
  3. usart.c 文件中添加以下代码:
c 复制代码
/* usart.c (在USER CODE BEGIN 0 和 USER CODE END 0 之间添加) */
#include <stdio.h>

#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif

PUTCHAR_PROTOTYPE {
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);
    return ch;
}
  1. 在Keil的工程选项中,勾选 Use MicroLIB(在 Target -> Code Generation 中)。MicroLIB是一个针对嵌入式系统优化的精简版C库,支持 printf 重定向。

完成以上步骤后,就可以在代码中使用 printf 来打印调试信息了。记得将串口模块的TX、RX引脚连接到USB转TTL模块,并在电脑上使用串口助手(如XCOM、Putty)查看打印信息。

7. 系统调试与校准

7.1 编译与下载

  1. 在Keil中,点击 Rebuild (F7) 编译整个工程。确保0错误,0警告。
  2. 使用ST-LINK/V2调试器连接STM32板子的 SWDIOSWCLK 引脚,并连接 3.3VGND
  3. 在Keil中,选择 Debug -> Settings,确保识别到ST-LINK。
  4. 点击 Load (F8) 将程序下载到STM32中。
  5. 下载完成后,按一下板子的复位键,程序开始运行。

7.2 硬件调试

  1. 电源检查 :用万用表测量STM32的 3.3V5V 引脚,确保电压正常。
  2. 指示灯:系统上电后,状态指示灯(PB3连接的LED)应常亮。
  3. 传感器测试
    • 光照传感器 :用手电筒照射BH1750,同时通过串口打印 light_lux 值,观察数值是否显著增大。
    • 土壤湿度传感器 :将传感器探头分别置于空气中和插入湿润的土壤中,通过串口打印 soil_adc 值。在空气中ADC值应接近4095(干燥),在湿土中ADC值应显著降低。
  4. 执行器测试
    • 可以临时修改代码,在主循环开始强制打开水泵或补光灯几秒钟,观察继电器和MOS管模块的指示灯是否亮起,水泵是否转动,LED灯带是否点亮。

7.3 阈值校准

这是项目成功的关键。你需要根据迷迭香的实际生长环境和传感器读数来确定最佳阈值。

  1. 光照阈值 LIGHT_INTENSITY_THRESHOLD
    • 在迷迭香所需的最佳光照环境下(例如,晴朗日子的窗边),用串口打印出此时的 light_lux 值,记为一个参考值 L_optimal
    • 将阈值设置为略低于 L_optimal 的值,例如 L_optimal * 0.7。这样当光照低于最佳值的70%时,系统开始补光。
  2. 土壤湿度阈值 SOIL_MOISTURE_THRESHOLD
    • 当土壤湿度 适宜 时(即手指触摸感觉湿润但不粘手),将传感器插入土壤,通过串口打印 soil_adc 值,记为 ADC_moist
    • 当土壤 干燥 需要浇水时,再次测量 soil_adc 值,记为 ADC_dryADC_dry 会明显大于 ADC_moist
    • 将阈值设置为 ADC_moistADC_dry 之间的一个值,例如 (ADC_moist + ADC_dry) / 2。当测量值 大于 此阈值时,表示土壤偏干,启动浇水。

7.4 功能联调

校准阈值后,将系统置于实际环境中运行。

  1. 遮挡光照传感器,观察补光灯是否自动点亮,并在 LED_WORK_TIME_MS 后自动关闭。
  2. 将土壤湿度传感器置于干燥环境中(或用手捏住探头使其干燥),观察水泵是否自动启动,并在 PUMP_WORK_TIME_MS 后自动停止。
  3. 测试同时需要补光和浇水的情况,观察两个执行器是否能独立工作。

8. 总结与展望

至此,一个完整的基于STM32F103的迷迭香智慧种植系统已经构建完成。本教程涵盖了从硬件选型、电路连接、软件环境搭建、代码编写到系统调试的全过程,所有代码均提供详细注释,力求让零基础的开发者也能一步步实现。

项目总结

  • 核心:利用STM32的ADC和I2C外设读取传感器数据,通过GPIO控制执行器。
  • 关键点:硬件电路的正确连接、CubeMX的工程配置、传感器阈值的现场校准。
  • 扩展性:本系统框架清晰,易于扩展更多功能。

未来优化方向

  1. 增加显示模块:添加OLED屏幕,实时显示光照、湿度数值及系统状态。
  2. 增加通信模块:加入Wi-Fi(如ESP8266)或蓝牙模块,将数据上传至手机APP或云平台,实现远程监控。
  3. 增加数据存储:使用EEPROM或SD卡,记录历史环境数据,便于分析植物生长规律。
  4. 优化控制算法:引入PID控制或模糊控制,使补光和滴灌更加平滑、精准,避免频繁启停。
  5. 增加更多传感器:如温湿度传感器(DHT11)、CO2传感器等,构建更全面的植物工厂环境监控系统。

希望本教程能成为你嵌入式学习之路上的一个扎实的实践项目。祝你成功!

相关推荐
SDAU200511 小时前
CH32V103C8T6的时钟操作
单片机·嵌入式硬件
不做无法实现的梦~11 小时前
SBUS 接收机到 STM32:为什么要做硬件反相、如何解析数据、如何接线与实现代码
stm32·单片机·嵌入式硬件
一路往蓝-Anbo11 小时前
第二章:隔离硬件 —— 利用 CMock 伪造 GPIO 与定时器
stm32·单片机·嵌入式硬件·软件工程·信息与通信·tdd
刘延林.12 小时前
esp32 s3+micpython快速验证ML307R 是否能正常连接4G
单片机·嵌入式硬件
不做无法实现的梦~18 小时前
86步进电机和DM860H驱动器的使用方法和记录
单片机·嵌入式硬件
Aaron158818 小时前
RFSOC+VU13P/VU9P+GPU多通道同步一体化解决方案
人工智能·嵌入式硬件·算法·matlab·fpga开发·硬件架构·基带工程
所见即所得1111119 小时前
stm32烧录过程中串口问题(串口被占用无法使用)
stm32·单片机·嵌入式硬件
Freak嵌入式19 小时前
WIZnet-EVB-Pico2开始,用MicroPython玩转以太网开发
arm开发·人工智能·python·嵌入式硬件·机器人·嵌入式·micropython
Ligocious19 小时前
stm32---1.两种开发方式点亮LED
stm32·单片机