文章目录
-
- [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 系统功能
- 环境监测:实时采集种植区域的光照强度与土壤湿度。
- 智能决策:根据预设的阈值,判断是否需要开启补光灯或启动滴灌。
- 自动控制:驱动补光LED灯带与微型水泵,执行相应的补光或浇水动作。
- 状态指示:通过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 电源部分连接
- 12V开关电源正极接至LM2596S输入正极(IN+) ,负极接至公共地(GND)。
- 第一个LM2596S模块(输出5V):
OUT+接至STM32板子的5V引脚。OUT-接至公共地。
- 第二个LM2596S模块(输出3.3V):
OUT+接至面包板的3.3V电源轨。OUT-接至公共地。
- 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 执行器部分连接
- 补光LED灯带 :
- 灯带
12V+接至 12V电源正极。 - 灯带
GND接至 IRF520模块的OUT-。 - IRF520模块的
OUT+接至 12V电源正极。 - 原理 :当STM32给IRF520的
IN脚高电平时,MOS管导通,灯带回路接通,灯亮。
- 灯带
- 微型水泵 :
- 水泵正极接至 12V电源正极。
- 水泵负极接至 继电器模块的
COM(公共端)。 - 继电器模块的
NO(常开端) 接至 12V电源负极。 - 原理 :当STM32给继电器
IN脚高电平时,继电器吸合,COM与NO接通,水泵回路接通,水泵工作。
5. 软件开发环境搭建
5.1 安装Keil MDK-ARM
- 访问ARM官网或国内镜像,下载并安装 Keil MDK-ARM (例如V5.36版本)。
- 安装过程中,需要注册。可以申请评估版,或寻找相关授权。
- 安装完成后,需要安装STM32F1系列的器件支持包(Device Family Pack)。
- 打开Keil,点击
Pack Installer图标。 - 在
Devices标签页搜索STM32F103C8,找到对应的系列。 - 在
Packs标签页,找到Keil::STM32F1xx_DFP,点击Install进行安装。
- 打开Keil,点击
5.2 使用STM32CubeMX创建工程
STM32CubeMX是ST官方提供的图形化配置工具,可以极大简化引脚、时钟、外设的初始化工作。
- 下载安装STM32CubeMX。
- 创建新工程 :选择
STM32F103C8Tx芯片。 - 系统核心配置 (SYS) :
Debug: 选择Serial Wire。这样才可以使用ST-LINK进行调试和下载。
- 时钟配置 (RCC) :
High Speed Clock (HSE): 选择Crystal/Ceramic Resonator。我们的最小系统板外部接了8MHz晶振。
- 引脚分配与功能配置 :
- 根据第4章的连接表,在芯片图形上点击对应引脚,选择其功能。
PB6:I2C1_SCLPB7:I2C1_SDAPA0:ADC1_IN0PB5,PB4,PB3: 均设置为GPIO_Output。
- 根据第4章的连接表,在芯片图形上点击对应引脚,选择其功能。
- 外设参数配置 :
- I2C1 : 模式选择
I2C,参数保持默认(标准模式,100kHz)。 - ADC1 : 在
Analog标签下,将ADC1的IN0通道使能。在Parameter Settings中,配置为:Resolution: 12 BitsScan Conversion Mode: DisabledContinuous Conversion Mode: Disabled (我们采用单次转换)DMA Continuous Requests: Disabled
- I2C1 : 模式选择
- 时钟树配置 :
- 在Clock Configuration标签页,将HCLK设置为72MHz(STM32F103的最高主频)。通常只需在
HCLK输入框键入72,然后回车,软件会自动配置PLL倍频参数。
- 在Clock Configuration标签页,将HCLK设置为72MHz(STM32F103的最高主频)。通常只需在
- 工程管理 :
Project Manager->Project:Project Name:Rosemary_Smart_FarmProject 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(重生成时备份旧文件)。
- 勾选
- 生成代码 :点击右上角
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 BEGIN 和 USER 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)。
- 首先在CubeMX中启用USART1,模式为
Asynchronous,参数默认即可。 - 在
main.c中包含stdio.h。 - 在
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;
}
- 在Keil的工程选项中,勾选
Use MicroLIB(在Target->Code Generation中)。MicroLIB是一个针对嵌入式系统优化的精简版C库,支持printf重定向。
完成以上步骤后,就可以在代码中使用 printf 来打印调试信息了。记得将串口模块的TX、RX引脚连接到USB转TTL模块,并在电脑上使用串口助手(如XCOM、Putty)查看打印信息。
7. 系统调试与校准
7.1 编译与下载
- 在Keil中,点击
Rebuild(F7) 编译整个工程。确保0错误,0警告。 - 使用ST-LINK/V2调试器连接STM32板子的
SWDIO和SWCLK引脚,并连接3.3V和GND。 - 在Keil中,选择
Debug->Settings,确保识别到ST-LINK。 - 点击
Load(F8) 将程序下载到STM32中。 - 下载完成后,按一下板子的复位键,程序开始运行。
7.2 硬件调试
- 电源检查 :用万用表测量STM32的
3.3V和5V引脚,确保电压正常。 - 指示灯:系统上电后,状态指示灯(PB3连接的LED)应常亮。
- 传感器测试 :
- 光照传感器 :用手电筒照射BH1750,同时通过串口打印
light_lux值,观察数值是否显著增大。 - 土壤湿度传感器 :将传感器探头分别置于空气中和插入湿润的土壤中,通过串口打印
soil_adc值。在空气中ADC值应接近4095(干燥),在湿土中ADC值应显著降低。
- 光照传感器 :用手电筒照射BH1750,同时通过串口打印
- 执行器测试 :
- 可以临时修改代码,在主循环开始强制打开水泵或补光灯几秒钟,观察继电器和MOS管模块的指示灯是否亮起,水泵是否转动,LED灯带是否点亮。
7.3 阈值校准
这是项目成功的关键。你需要根据迷迭香的实际生长环境和传感器读数来确定最佳阈值。
- 光照阈值
LIGHT_INTENSITY_THRESHOLD:- 在迷迭香所需的最佳光照环境下(例如,晴朗日子的窗边),用串口打印出此时的
light_lux值,记为一个参考值L_optimal。 - 将阈值设置为略低于
L_optimal的值,例如L_optimal * 0.7。这样当光照低于最佳值的70%时,系统开始补光。
- 在迷迭香所需的最佳光照环境下(例如,晴朗日子的窗边),用串口打印出此时的
- 土壤湿度阈值
SOIL_MOISTURE_THRESHOLD:- 当土壤湿度 适宜 时(即手指触摸感觉湿润但不粘手),将传感器插入土壤,通过串口打印
soil_adc值,记为ADC_moist。 - 当土壤 干燥 需要浇水时,再次测量
soil_adc值,记为ADC_dry。ADC_dry会明显大于ADC_moist。 - 将阈值设置为
ADC_moist和ADC_dry之间的一个值,例如(ADC_moist + ADC_dry) / 2。当测量值 大于 此阈值时,表示土壤偏干,启动浇水。
- 当土壤湿度 适宜 时(即手指触摸感觉湿润但不粘手),将传感器插入土壤,通过串口打印
7.4 功能联调
校准阈值后,将系统置于实际环境中运行。
- 遮挡光照传感器,观察补光灯是否自动点亮,并在
LED_WORK_TIME_MS后自动关闭。 - 将土壤湿度传感器置于干燥环境中(或用手捏住探头使其干燥),观察水泵是否自动启动,并在
PUMP_WORK_TIME_MS后自动停止。 - 测试同时需要补光和浇水的情况,观察两个执行器是否能独立工作。
8. 总结与展望
至此,一个完整的基于STM32F103的迷迭香智慧种植系统已经构建完成。本教程涵盖了从硬件选型、电路连接、软件环境搭建、代码编写到系统调试的全过程,所有代码均提供详细注释,力求让零基础的开发者也能一步步实现。
项目总结:
- 核心:利用STM32的ADC和I2C外设读取传感器数据,通过GPIO控制执行器。
- 关键点:硬件电路的正确连接、CubeMX的工程配置、传感器阈值的现场校准。
- 扩展性:本系统框架清晰,易于扩展更多功能。
未来优化方向:
- 增加显示模块:添加OLED屏幕,实时显示光照、湿度数值及系统状态。
- 增加通信模块:加入Wi-Fi(如ESP8266)或蓝牙模块,将数据上传至手机APP或云平台,实现远程监控。
- 增加数据存储:使用EEPROM或SD卡,记录历史环境数据,便于分析植物生长规律。
- 优化控制算法:引入PID控制或模糊控制,使补光和滴灌更加平滑、精准,避免频繁启停。
- 增加更多传感器:如温湿度传感器(DHT11)、CO2传感器等,构建更全面的植物工厂环境监控系统。
希望本教程能成为你嵌入式学习之路上的一个扎实的实践项目。祝你成功!