1. 项目背景与硬件选型
STM32F103C8T6驱动LM393土壤湿度传感器是一个典型的嵌入式物联网应用场景,特别适合智能农业、自动灌溉系统等需要监测土壤含水量的场景。这个方案之所以被广泛采用,主要基于以下技术考量:
STM32F103C8T6作为Cortex-M3内核的经典MCU,具有72MHz主频和丰富的外设资源,其ADC模块的12位分辨率(0-4095量程)能够满足土壤湿度的测量精度要求。而LM393模块则因其双输出模式(数字量DO和模拟量AO)提供了灵活的接口选择,模块上的可调电位器可以设置湿度触发阈值,使得系统设计更加便捷。
在实际项目中,我通常会根据应用场景选择不同的工作模式:
- 对于只需要阈值报警的简单应用(如缺水提醒),直接使用DO数字输出即可
- 对于需要精确监测的应用(如精准灌溉),则需要采集AO模拟量并通过ADC转换
2. 硬件连接与电路设计
2.1 模块引脚定义
LM393土壤湿度传感器通常有4个引脚:
- VCC:3.3-5V供电
- GND:地线
- DO:数字输出(高/低电平)
- AO:模拟输出(0-VCC电压)
2.2 STM32连接方案
推荐以下两种连接方式:
基础连接方案(仅使用DO):
plaintext复制LM393 STM32
VCC -> 3.3V
GND -> GND
DO -> PA1(配置为上拉输入)
高精度连接方案(使用AO):
plaintext复制LM393 STM32
VCC -> 3.3V
GND -> GND
AO -> PA5(ADC1通道5)
注意:实际使用中发现,当供电电压不同时,AO输出值会有差异。建议统一使用3.3V供电以保证测量一致性。
2.3 硬件设计要点
- 在AO线路串联一个1kΩ电阻可有效抑制高频干扰
- 对于长距离布线(>30cm),建议在VCC和GND之间加装0.1μF去耦电容
- 传感器探针部分应做防水处理,但感应区域需保持裸露
3. 软件驱动实现
3.1 ADC初始化配置
以下是基于标准外设库的ADC初始化代码,关键配置参数解析:
c复制void ADC_SOILHUMIDITY_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_55Cycles5);
ADC_Cmd(ADC1, ENABLE);
// ADC校准流程(必须执行)
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
3.2 数据采集与处理
实际项目中,我推荐采用以下优化算法来提高测量稳定性:
c复制#define SAMPLE_TIMES 10 // 采样次数
uint16_t Get_SoilHumidity(void)
{
uint32_t sum = 0;
for(int i=0; i<SAMPLE_TIMES; i++){
sum += ADC_GetConversionValue(ADC1);
delay_ms(10); // 间隔采样
}
uint16_t average = sum / SAMPLE_TIMES;
// 转换为百分比(需根据实际校准调整)
uint16_t humidity = 100 - (average * 100 / 4095);
return humidity > 100 ? 100 : humidity; // 限幅处理
}
3.3 数字输出处理
对于只需要阈值检测的应用,可以直接读取DO引脚状态:
c复制bool Is_SoilDry(void)
{
return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == Bit_SET;
}
4. 校准与优化技巧
4.1 传感器校准方法
通过实测发现,不同土壤类型的电阻特性差异很大,建议采用三点校准法:
- 完全干燥状态:将传感器置于干燥土壤中,记录ADC值(通常≈4095)
- 完全湿润状态:将传感器浸入水中,记录ADC值(通常≈800-1200)
- 理想湿度状态:将传感器置于湿度适中的土壤中,记录ADC值
校准数据示例:
| 状态 | ADC值 | 对应湿度 |
|---|---|---|
| 完全干燥 | 4095 | 0% |
| 理想湿度 | 2500 | 40% |
| 完全湿润 | 1000 | 100% |
4.2 软件滤波算法
在实际环境中,我推荐采用加权移动平均滤波:
c复制#define FILTER_DEPTH 5
uint16_t humidity_history[FILTER_DEPTH] = {0};
uint16_t Filtered_Humidity(uint16_t new_value)
{
// 滑动窗口更新
for(int i=FILTER_DEPTH-1; i>0; i--){
humidity_history[i] = humidity_history[i-1];
}
humidity_history[0] = new_value;
// 加权计算(最近数据权重高)
uint32_t sum = 0;
for(int i=0; i<FILTER_DEPTH; i++){
sum += humidity_history[i] * (FILTER_DEPTH - i);
}
return sum / (FILTER_DEPTH*(FILTER_DEPTH+1)/2);
}
5. 常见问题与解决方案
5.1 测量值不稳定
现象:ADC读数波动较大
解决方法:
- 检查电源稳定性,建议使用LDO供电
- 增加软件滤波算法
- 在传感器VCC与GND之间并联100μF电解电容
5.2 传感器腐蚀问题
现象:长期使用后测量不准
预防措施:
- 采用镀金探针的传感器模块
- 间歇工作模式(如每小时只通电测量5分钟)
- 在非金属容器上打孔安装,减少探针直接接触土壤
5.3 ADC读数异常
典型表现:读数始终为0或4095
排查步骤:
- 检查硬件连接是否正确
- 确认ADC初始化流程完整(特别是校准步骤)
- 测量AO引脚实际电压,验证传感器输出是否正常
6. 实际应用案例
在智能花盆项目中,我采用以下方案实现自动灌溉:
c复制void Watering_Task(void)
{
uint16_t humidity = Get_SoilHumidity();
if(humidity < 30){ // 干旱阈值
Pump_On(); // 启动水泵
while(Get_SoilHumidity() < 70); // 达到目标湿度
Pump_Off();
// 记录灌溉日志
printf("[%lu] Watering completed. Humidity: %d%%\n",
HAL_GetTick(), Get_SoilHumidity());
}
delay_ms(60000); // 每分钟检测一次
}
这个方案在实际运行中表现出色,但需要注意:
- 灌溉后应延迟至少1分钟再测量,避免水分未均匀渗透
- 不同植物需要设置不同的湿度阈值
- 建议增加土壤温度补偿(湿度测量受温度影响)
对于需要更高精度的场合,可以考虑以下改进:
- 采用四线制测量法消除导线电阻影响
- 增加土壤温度传感器进行补偿校准
- 使用FDC1004等专用电容式测量芯片替代LM393
