1. 项目概述
作为一名嵌入式开发工程师,我最近完成了一个基于STM32的自动浇花系统项目。这个系统能够实时监测植物的光照和土壤湿度情况,并根据预设的阈值自动调节LED补光灯亮度以及控制水泵的启停。整套系统采用模块化设计,硬件部分包含STM32F103C8T6最小系统板、BH1750光照传感器、YL-69土壤湿度传感器、OLED显示屏、LED补光灯和水泵驱动电路等;软件部分则实现了传感器数据采集、PWM调光、自动控制逻辑和人机交互等功能。
这个项目特别适合那些经常出差或者容易忘记给植物浇水的朋友。我自己就曾经因为工作太忙,导致家里的绿植干枯了好几盆。有了这个自动浇花系统后,再也不用担心植物会因为缺水或光照不足而枯萎了。系统运行稳定可靠,成本也不高,全部硬件成本在200元以内就能搞定。
2. 硬件系统设计
2.1 主控芯片选型
我选择STM32F103C8T6作为主控芯片,主要基于以下几点考虑:
- 性能足够:72MHz主频的Cortex-M3内核,完全能满足传感器数据采集、PWM输出和逻辑控制的需求
- 外设丰富:内置ADC、定时器、I2C等必要外设,减少外围电路复杂度
- 开发资源多:STM32生态完善,有大量开源库和参考设计
- 性价比高:价格在10元左右,非常适合DIY项目
这个芯片采用LQFP48封装,焊接难度适中。对于新手来说,建议使用现成的开发板,可以省去最小系统搭建的麻烦。
2.2 传感器选型与电路设计
2.2.1 BH1750光照传感器
BH1750是一款数字式环境光强度传感器,相比模拟光敏电阻有以下优势:
- 直接输出数字信号,无需额外AD转换
- 测量范围宽(1-65535lx)
- 精度高,受温度影响小
- I2C接口,接线简单
接线方式:
- VCC -> 3.3V
- GND -> GND
- SDA -> PB7
- SCL -> PB6
- ADDR -> GND(固定地址0x46)
注意:BH1750的工作电压是3.3V,不要接5V,否则可能损坏传感器。
2.2.2 YL-69土壤湿度传感器
YL-69是电阻式土壤湿度传感器,原理是通过测量土壤电阻来间接反映湿度。它的优点是:
- 价格便宜(5元左右)
- 使用简单,模拟输出
- 探头可更换
但需要注意:
- 长期使用容易氧化腐蚀,建议每3-6个月更换一次探头
- 不同土壤类型的校准值不同,需要根据实际情况调整
- 不要长时间通电,测量时上电,测量完断电可以延长寿命
接线方式:
- VCC -> 5V
- GND -> GND
- AO -> PA1(ADC1通道1)
2.3 显示与人机交互
2.3.1 OLED显示屏
选用0.96寸I2C接口的OLED屏幕,分辨率128x64,具有以下特点:
- 自发光,无需背光
- 对比度高,可视角度大
- 功耗低
- I2C接口节省IO资源
接线与BH1750共用I2C总线:
- VCC -> 3.3V
- GND -> GND
- SDA -> PB7
- SCL -> PB6
2.3.2 按键电路
设计了4个独立按键用于参数设置:
- 按键1(PA3):增加光照阈值
- 按键2(PA4):减少光照阈值
- 按键3(PA5):增加湿度阈值
- 按键4(PA6):减少湿度阈值
按键采用内部上拉模式,按下时接地,软件实现消抖和多级加速功能。
2.4 执行机构设计
2.4.1 LED补光灯驱动
使用STM32的TIM2通道1(PA0)输出PWM信号控制LED亮度:
- PWM频率:100Hz(周期10ms)
- 分辨率:10000级(ARR=9999)
- 驱动方式:直接IO驱动,串联限流电阻
提示:LED电流不要超过20mA,根据LED正向电压计算合适的限流电阻值。
2.4.2 水泵驱动电路
采用5V继电器模块驱动水泵,具有以下优点:
- 隔离控制,保护单片机
- 驱动能力强(可达10A)
- 内置保护电路
接线方式:
- VCC -> 5V
- GND -> GND
- IN -> PA2(控制信号)
3. 软件系统实现
3.1 开发环境搭建
使用Keil MDK作为开发环境,配置步骤如下:
- 安装Keil MDK-ARM
- 安装STM32F1xx Device Family Pack
- 新建工程,选择STM32F103C8T6器件
- 配置工程选项,设置头文件路径和库文件
- 配置调试器为ST-Link,接口SWD
3.2 系统初始化
系统初始化流程如下:
c复制void System_Init(void)
{
RCC_Configuration(); // 时钟配置
GPIO_Configuration(); // GPIO初始化
USART_Init(); // 串口初始化(调试用)
I2C_Configuration(); // I2C初始化
BH1750_Init(); // 光照传感器初始化
ADC1_Init(); // ADC初始化
TIM2_PWM_Init(); // PWM定时器初始化
TIM3_Init(); // 系统定时器初始化
OLED_Init(); // OLED初始化
KEY_Init(); // 按键初始化
PUMP_Init(); // 水泵初始化
}
3.3 传感器数据采集
3.3.1 光照数据采集
BH1750数据采集流程:
- 发送测量命令(一次高精度模式)
- 等待120ms转换时间
- 读取2字节光照数据
- 转换为lux值(原始数据/1.2)
关键代码:
c复制float Get_BH1750_Data(void)
{
uint16_t light_data = 0;
float lux = 0;
I2C_WriteByte(BH1750_ADDR, BH1750_ONE_TIME_H_RES_MODE);
Delay_ms(120);
light_data = I2C_ReadWord(BH1750_ADDR);
lux = (float)light_data / 1.2;
return lux;
}
3.3.2 土壤湿度采集
ADC采集流程:
- 启动ADC转换
- 等待转换完成
- 读取转换结果
- 多次采样取平均
- 映射为百分比湿度值
关键代码:
c复制uint8_t Get_Soil_Humidity(void)
{
uint32_t adc_sum = 0;
uint16_t adc_value = 0;
uint8_t humidity = 0;
for(int i=0; i<10; i++) {
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
adc_sum += ADC_GetConversionValue(ADC1);
Delay_ms(10);
}
adc_value = adc_sum / 10;
humidity = Map(adc_value, DRY_VALUE, WET_VALUE, 0, 99);
return humidity;
}
注意:DRY_VALUE和WET_VALUE需要根据实际测量校准,不同土壤类型值不同。
3.4 控制逻辑实现
3.4.1 PWM调光控制
LED亮度控制算法:
c复制void Light_Control(float light, float light_threshold)
{
if(light < light_threshold) {
uint16_t duty = (uint16_t)((light_threshold - light) * PWM_SCALE);
TIM_SetCompare1(TIM2, duty);
} else {
TIM_SetCompare1(TIM2, 0); // 关闭LED
}
}
3.4.2 自动浇水控制
水泵控制逻辑:
c复制void Pump_Control(uint8_t humidity, uint8_t humi_threshold)
{
static uint32_t pump_timer = 0;
if(humidity < humi_threshold) {
PUMP_ON();
pump_timer = 0;
} else {
if(pump_timer++ > 100) { // 延时关闭,防止抖动
PUMP_OFF();
}
}
}
3.5 人机交互实现
3.5.1 OLED显示
显示内容布局:
code复制-----------------
|光照: 2560 lx |
|光照阈值: 3000 |
|湿度: 45% |
|水泵: OFF |
-----------------
刷新频率设置为2Hz,避免闪烁。
3.5.2 按键处理
采用状态机实现按键检测,支持短按和长按:
c复制typedef enum {
KEY_IDLE,
KEY_DEBOUNCE,
KEY_PRESSED,
KEY_RELEASE
} KEY_STATE;
void KEY_Scan(void)
{
static KEY_STATE key_state = KEY_IDLE;
static uint32_t key_timer = 0;
switch(key_state) {
case KEY_IDLE:
if(KEY_Read() == 0) {
key_state = KEY_DEBOUNCE;
key_timer = 0;
}
break;
case KEY_DEBOUNCE:
if(++key_timer > 8) { // 80ms消抖
if(KEY_Read() == 0) {
key_state = KEY_PRESSED;
key_timer = 0;
} else {
key_state = KEY_IDLE;
}
}
break;
case KEY_PRESSED:
if(KEY_Read() == 1) {
key_state = KEY_RELEASE;
} else {
// 长按处理
if(++key_timer > 100) { // 1s长按
KEY_LongPress_Handler();
key_timer = 0;
}
}
break;
case KEY_RELEASE:
KEY_ShortPress_Handler();
key_state = KEY_IDLE;
break;
}
}
4. 系统调试与优化
4.1 常见问题排查
-
BH1750读取失败
- 检查I2C接线是否正确
- 用逻辑分析仪抓取I2C波形
- 确认上拉电阻(4.7kΩ)已接
- 检查设备地址(0x46)
-
土壤湿度值不准确
- 重新校准干湿值(DRY_VALUE和WET_VALUE)
- 检查探头是否氧化,必要时更换
- 尝试不同的采样次数和滤波算法
-
PWM调光闪烁
- 提高PWM频率(建议100Hz以上)
- 检查LED驱动电流是否足够
- 确保电源稳定
-
水泵不工作
- 检查继电器控制信号
- 测量水泵两端电压
- 确认水泵功率不超过继电器额定值
4.2 性能优化建议
-
低功耗优化
- 采用间歇工作模式,降低平均功耗
- 传感器测量间隙进入睡眠模式
- 选用低功耗元器件
-
稳定性增强
- 增加看门狗定时器
- 关键数据EEPROM存储
- 异常状态自动恢复机制
-
功能扩展
- 添加WiFi/蓝牙远程监控
- 支持多区域独立控制
- 增加历史数据记录功能
5. 实际应用效果
经过一个月的实际测试,系统表现出色:
- 光照检测误差<5%
- 湿度控制精度±3%
- 平均功耗<0.5W
- 连续运行无故障
我的绿植现在长势良好,完全不需要人工干预。系统能够根据环境变化自动调节,既不会让植物缺水,也不会过度浇水。LED补光功能在阴雨天特别有用,植物没有出现徒长现象。
这个项目完全开源,所有硬件设计和软件代码都可以在GitHub上找到。对于想要DIY的朋友,我有几点建议:
- 先从现成的开发板开始,熟悉基本功能
- 分模块调试,不要一次连接所有外设
- 做好电源隔离,避免水泵干扰单片机
- 根据实际植物需求调整控制参数
