1. 项目概述
水位监测是工业控制和智能家居中常见的需求场景。作为一名嵌入式开发者,我最近在几个农业灌溉项目中频繁使用STM32配合水位传感器实现液位检测功能。这种方案成本低廉(整套硬件不超过50元)、响应速度快(采样周期可控制在100ms内),特别适合中小型水箱、鱼缸、水塔等场景的液位监控。
传统的水位检测方案主要有浮球式、压力式和电极式三种。我们这次使用的是最经济的电极式水位传感器,它的核心原理是通过检测电极间的导电性变化来判断水位高度。虽然存在电解腐蚀的问题,但通过合理的电路设计和定期维护(每月擦拭电极),在普通清水环境中可以稳定工作1-2年。
2. 硬件准备与电路设计
2.1 器材选型要点
在选择水位传感器时需要注意几个关键参数:
- 工作电压:常见的有3.3V和5V两种,建议选用5V版本以获得更好的抗干扰能力
- 输出类型:模拟量输出(AO)更适合精确测量,数字量(DO)仅适合阈值报警
- 电极材质:不锈钢电极比铜电极更耐腐蚀
- 防护等级:IP68级可完全防水,适合长期浸泡场景
我的实际配置清单如下:
- 5V模拟输出水位传感器 ×1(长约20cm,10个检测点)
- STM32F103C8T6最小系统板 ×1
- 5V/2A电源适配器 ×1
- 杜邦线(公对母) ×10根
重要提示:切勿将传感器直接接入超过5V的电源,否则会永久损坏内部电路。若使用3.3V系统,建议在VCC和GND之间并联一个100μF的电解电容以稳定供电。
2.2 电路连接详解
标准接线方式如下表所示:
| 传感器引脚 | STM32连接点 | 备注 |
|---|---|---|
| VCC | 5V输出 | 开发板的5V引脚 |
| GND | GND | 共地连接 |
| AO | PC1(ADC_IN11) | 模拟信号输入通道 |
| DO | 可不接 | 数字输出暂不使用 |
实际接线时我推荐使用以下技巧:
- 先给传感器套上热缩管,只露出金属探头部分
- 用焊锡固定杜邦线与传感器引脚的连接处
- 在AO线上串接一个1kΩ电阻作为简单保护
- 电源正极最好先经过一个自恢复保险丝
3. 软件实现与ADC配置
3.1 标准库开发流程
对于使用标准库的开发者,ADC配置需要关注以下几个关键点:
c复制void ADC_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// 1. 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC2, ENABLE);
// 2. 配置GPIO为模拟输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// 3. ADC参数设置
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(ADC2, &ADC_InitStructure);
// 4. 校准ADC
ADC_ResetCalibration(ADC2);
while(ADC_GetResetCalibrationStatus(ADC2));
ADC_StartCalibration(ADC2);
while(ADC_GetCalibrationStatus(ADC2));
// 5. 启用ADC
ADC_Cmd(ADC2, ENABLE);
ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_55Cycles5);
ADC_SoftwareStartConvCmd(ADC2, ENABLE);
}
3.2 HAL库开发优化
使用HAL库时,CubeMX可以自动生成大部分配置代码。但有几个关键参数需要特别注意:
- 时钟分频:建议设置为PCLK2的8分频(ADC时钟不超过14MHz)
- 采样时间:对于水位传感器这种慢变信号,选择239.5周期可获得更好稳定性
- DMA配置:如果需要连续采样,建议启用DMA循环模式
典型的中断处理函数如下:
c复制void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
if(hadc->Instance == ADC1) {
uint32_t value = HAL_ADC_GetValue(hadc);
float voltage = value * 3.3f / 4095.0f;
// 电压-水位转换逻辑...
}
}
4. 数据处理与水位计算
4.1 原始数据处理技巧
从ADC获取的原始值需要经过以下处理流程:
- 移动平均滤波:建议使用8-16点的滑动窗口
c复制#define SAMPLE_SIZE 10
uint16_t samples[SAMPLE_SIZE];
uint8_t sample_index = 0;
uint16_t get_filtered_value(uint16_t new_sample)
{
samples[sample_index++] = new_sample;
if(sample_index >= SAMPLE_SIZE) sample_index = 0;
uint32_t sum = 0;
for(int i=0; i<SAMPLE_SIZE; i++) {
sum += samples[i];
}
return sum / SAMPLE_SIZE;
}
- 电压-水位转换:
c复制float adc_to_water_level(uint16_t adc_value)
{
const float dry_voltage = 0.5f; // 无水时的基准电压
const float wet_voltage = 2.8f; // 全浸时的电压
float voltage = adc_value * 3.3f / 4095.0f;
if(voltage < dry_voltage) return 0.0f;
if(voltage > wet_voltage) return 100.0f;
return (voltage - dry_voltage) / (wet_voltage - dry_voltage) * 100.0f;
}
4.2 分段检测实现
对于需要多点水位检测的场景,可以采用比较器方式:
c复制typedef enum {
WATER_LEVEL_LOW,
WATER_LEVEL_MEDIUM,
WATER_LEVEL_HIGH
} WaterLevelState;
WaterLevelState check_water_level(float level)
{
if(level < 30.0f) return WATER_LEVEL_LOW;
else if(level < 70.0f) return WATER_LEVEL_MEDIUM;
else return WATER_LEVEL_HIGH;
}
5. 实际应用中的问题排查
5.1 常见问题与解决方案
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| ADC值跳动大 | 电源干扰 | 增加滤波电容,使用屏蔽线 |
| 读数始终为0 | 接线错误 | 检查VCC和GND连接 |
| 数值随温度变化 | 电极氧化 | 用细砂纸打磨电极表面 |
| 水位变化响应延迟 | 采样周期过长 | 减小ADC采样时间,优化代码 |
| 不同水位读数相同 | 传感器损坏 | 更换传感器 |
5.2 电极维护经验
在实际项目中我总结出以下电极保养技巧:
- 每月用酒精棉片擦拭电极
- 在非金属容器中使用时,确保电极不要接触容器壁
- 长期不使用时,应将传感器取出晾干
- 可在清水中加入少量食用盐(不超过0.1%)提高导电性
6. 项目扩展思路
这个基础方案可以进一步优化:
- 多传感器网络:通过RS485连接多个传感器实现大范围监测
- 无线传输:搭配ESP8266模块将数据上传到云平台
- 自动控制:当检测到低水位时自动启动水泵
- 历史记录:使用SD卡模块存储水位变化数据
一个典型的自动灌溉系统控制逻辑如下:
c复制void water_control_task(void)
{
float level = get_water_level();
if(level < 30.0f) {
start_water_pump();
while(get_water_level() < 80.0f) {
delay_ms(1000);
}
stop_water_pump();
}
}
对于需要更高精度的场合,可以考虑改用超声波测距模块,虽然成本会提高3-5倍,但使用寿命可达5年以上且无需接触水体。我在一个商业化鱼塘监控系统中就采用了这种方案,通过Modbus协议将数据传输到上位机,实现了±1cm的测量精度。