1. 项目概述与核心功能
水位检测与自动控制系统是工业自动化和智能家居领域的基础应用之一。这次我们要用STM32F103单片机配合Proteus仿真工具,打造一个完整的仿真方案。这个系统最实用的地方在于它能实时监测水位变化,自动控制水泵工作,还能通过LCD1602显示屏和上位机双渠道显示数据。
系统默认设置当水位低于150cm时会触发蜂鸣器报警,如果拨动开关处于接通状态,水泵就会自动开始抽水。我在实际测试中发现,用滑动变阻器模拟水位传感器时,阻值调到约3kΩ对应150cm报警阈值效果最稳定。你完全可以通过按键自定义这个报警值,长按设置键进入调整模式后,用加减键修改参数,这个设计在需要频繁调整阈值的场景特别实用。
2. 硬件设计详解
2.1 核心元件选型
主控选用STM32F103R6这款性价比极高的Cortex-M3内核单片机,它有8个12位ADC通道,正好满足水位检测需求。传感器方面,Proteus里用10kΩ滑动变阻器模拟真实的水位传感器,实际项目中可以用MPX5010这类压阻式传感器。显示模块选用经典的LCD1602,它的并行接口与STM32连接简单稳定,我调试时发现加上10kΩ电位器调节对比度显示效果会更好。
水泵驱动部分要注意,直接使用单片机GPIO驱动大电流设备风险很高。我的方案是用S8050三极管搭建放大电路,当PC13引脚输出高电平时,三极管导通,继电器吸合。曾有个坑是忘记加续流二极管,导致三极管在继电器断开时被感应电动势击穿,后来在继电器线圈两端并联1N4007就解决了。
2.2 关键电路设计
ADC采样电路必须重视抗干扰设计:
- 在传感器输出端加0.1μF去耦电容
- PCB布局时模拟和数字地分开走线
- 软件上采用均值滤波算法
蜂鸣器驱动电路有个细节要注意:电磁式蜂鸣器需要至少15mA驱动电流。我设计的电路是把蜂鸣器正极接5V,负极接NPN三极管集电极,基极通过1kΩ电阻连接PB8引脚。测试时用万用表测得过三极管的Ice=28mA,完全满足发声需求。
3. 软件开发实战
3.1 开发环境搭建
建议使用Keil MDK 5.25以上版本,安装时记得勾选STM32F1系列DFP支持包。新建工程后要配置:
- 在Options for Target的Target选项卡勾选Use MicroLIB
- 在C/C++选项卡的Define框添加USE_STDPERIPH_DRIVER
- 在Debug选项卡选择ST-Link Debugger
Proteus我用的是8.9专业版,新建工程时单片机选STM32F103R6,频率设为72MHz。有个小技巧:在元件属性里把Advanced Properties里的"Disable Power Rail Checking"勾选上,可以避免不必要的电源警告。
3.2 核心代码解析
ADC初始化代码要特别注意时钟配置:
void ADC1_Init(void) { ADC_InitTypeDef ADC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); 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_0, 1, ADC_SampleTime_239Cycles5); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); }水位值计算采用滑动平均滤波:
#define SAMPLE_NUM 10 uint16_t Get_WaterLevel(void) { static uint16_t buf[SAMPLE_NUM]; static uint8_t index = 0; uint32_t sum = 0; buf[index++] = ADC_GetConversionValue(ADC1); if(index >= SAMPLE_NUM) index = 0; for(uint8_t i=0; i<SAMPLE_NUM; i++){ sum += buf[i]; } return (sum/SAMPLE_NUM)*330/4096; // 转换为cm单位 }4. 仿真调试技巧
4.1 Proteus仿真要点
在Proteus中加载hex文件后,建议先做这些检查:
- 确认单片机晶振频率与代码配置一致
- 检查所有元件的电源和地连接
- 给ADC输入引脚添加电压探针
调试时我习惯用虚拟终端显示串口数据,波特率设为115200。遇到仿真卡死的情况,可以尝试:
- 重置单片机
- 降低ADC采样频率
- 检查是否有逻辑死循环
4.2 常见问题解决
- LCD显示乱码:
- 检查初始化时序是否满足40ms延时
- 调整电位器改变对比度
- 确认数据线连接顺序正确
- 水泵不工作:
- 用电压表测量三极管基极电压
- 检查继电器线圈两端是否有12V电压
- 确认续流二极管方向正确
- 报警阈值保存异常:
- 检查Flash编程电压设置
- 增加写入前的擦除延时
- 验证CRC校验值
5. 进阶优化建议
5.1 功能扩展方向
可以尝试添加这些实用功能:
- 通过蓝牙模块连接手机APP
- 增加温度传感器DS18B20监测水温
- 实现Modbus RTU协议与PLC通信
- 添加SD卡存储历史数据
5.2 性能优化技巧
提升系统稳定性的几个关键点:
- 在ADC输入端加RC低通滤波(1kΩ+0.1μF)
- 采用看门狗定时器防止程序跑飞
- 对关键变量进行范围检查
- 增加软件去抖算法处理按键
电源管理方面,实测发现给STM32的模拟电源引脚加10μF钽电容后,ADC采样波动从±5LSB降到±2LSB。如果系统需要低功耗,可以配置单片机进入Stop模式,仅通过外部中断唤醒,这样整机电流可以从25mA降到150μA左右。