1. 项目概述:打造高性价比水质监测站
去年在参与一个社区净水项目时,我深刻体会到实时水质监测的重要性。市面上专业设备动辄上万元,而用STM32搭建的这套系统成本不到200元,精度却足以满足日常监测需求。核心控制器选用STM32F103C8T6这款经典"蓝药丸"芯片,不仅因为其72MHz主频足够处理传感器数据,更因其丰富的外设接口和成熟的生态支持。
系统架构分为三个主要部分:传感器采集层采用DS18B20数字温度传感器和TSW-30浊度传感器构成数据输入端;主控层负责信号处理、阈值判断和数据整合;显示报警层则通过OLED屏幕和蜂鸣器实现人机交互。这种分层设计使得后期功能扩展非常方便,比如我就曾在此基础上增加了pH值检测模块。
关键设计原则:模拟电路与数字电路严格分区布局,传感器信号线尽量缩短,所有接口都预留ESD保护。这些措施使系统在潮湿环境下仍能稳定工作。
2. 硬件设计详解
2.1 核心元器件选型
主控芯片选择STM32F103C8T6主要基于三点考量:首先其内置12位ADC能满足浊度传感器的精度要求;其次具备硬件I2C接口可驱动OLED;最后是SWD调试接口方便烧录和调试。实际使用中,这颗芯片的GPIO驱动能力也足够直接驱动有源蜂鸣器。
温度传感器选用DS18B20而非DHT11,虽然后者集成度更高,但DS18B20的±0.5℃精度和防水封装更适合水质监测场景。需要注意的是,每个DS18B20都有唯一64位序列号,多设备组网时这点非常有用。
浊度传感器最终选定TSW-30而非更便宜的KEYES模块,因其采用光学透射原理,相比散射式传感器受环境光影响更小。该传感器需要独立的5V供电,输出信号范围0-4.5V,因此必须通过运放进行电平转换。
2.2 电路设计要点
电源部分采用两级稳压设计:第一级AMS1117-5.0将USB输入的5V稳压,第二级AMS1117-3.3为MCU和数字电路供电。模拟电路部分单独使用一颗LM1117-3.3,并在输入端加入π型滤波电路(10μF+100nF+10μF)。
信号调理电路是设计难点。TSW-30的输出信号需要经过以下处理流程:
code复制传感器输出 → 电压跟随器 → 反相放大器(增益0.73) → 电压抬升电路
最终将0-4.5V转换为0-3.3V范围。这里选用LMV358运放因其轨到轨输出特性,能在单电源供电下工作良好。
PCB布局特别注意以下几点:
- 将运放电路布置在靠近传感器接口的位置
- 数字地和模拟地通过0Ω电阻单点连接
- 所有长信号线都伴随地线走线
- 电源入口处放置TVS二极管防静电
3. 软件实现解析
3.1 传感器驱动开发
DS18B20的驱动最考验时序控制能力。其单总线协议要求严格的时序:
- 复位脉冲:MCU拉低480μs后释放
- 存在脉冲:传感器会在60-240μs内响应
- 写时隙:拉低至少1μs后,在15μs内设置数据线状态
- 读时隙:拉低至少1μs后,在15μs内采样数据线
具体实现时,我使用了STM32的硬件定时器生成精确延时:
c复制void DS18B20_Delay_us(uint16_t us) {
__HAL_TIM_SET_COUNTER(&htim1, 0);
while(__HAL_TIM_GET_COUNTER(&htim1) < us);
}
浊度传感器的ADC采集配置为12位分辨率、连续转换模式,启用DMA传输:
c复制hadc1.Instance = ADC1;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.NbrOfConversion = 1;
HAL_ADC_Init(&hadc1);
3.2 数据处理算法
浊度值转换采用分段线性化处理:
c复制float ConvertTurbidity(float voltage) {
if(voltage < 1.0)
return 0.5 * voltage; // 低浊度区间
else if(voltage < 3.0)
return 0.5 + (voltage-1.0)*1.25;
else
return 3.0 + (voltage-3.0)*4.0;
}
这个算法基于传感器特性曲线拟合得出,实测误差小于±5%。温度补偿则通过以下公式实现:
code复制NTU_corrected = NTU_raw / (1 + 0.02*(T-25))
3.3 用户界面设计
OLED显示采用双层缓冲机制:先在内存中构建完整帧数据,再一次性刷新到屏幕。这避免了直接操作显存导致的闪烁问题。界面布局如下:
code复制+-------------------+
| 水温:25.3℃ |
| 浊度:1.2 NTU |
| 状态:优良 |
| 最后更新:14:25 |
+-------------------+
报警逻辑实现为三态检测:
c复制if(ntu > 5.0) status = ALARM;
else if(ntu > 3.0) status = WARNING;
else status = NORMAL;
4. 调试经验与优化
4.1 常见问题排查
-
ADC读数不稳定
- 检查模拟电源滤波电容是否足够(建议100nF+10μF并联)
- 确保传感器信号线远离数字线路
- 尝试在ADC输入端加入0.1μF电容
-
DS18B20无响应
- 确认4.7kΩ上拉电阻已连接
- 检查时序延时是否精确
- 尝试降低总线速度(将延时增加20%)
-
OLED显示异常
- 检查I2C地址是否正确(通常0x78或0x7A)
- 确认初始化序列完整发送
- 尝试降低通信频率(100kHz→50kHz)
4.2 性能优化技巧
-
电源管理优化:
- 在ADC采样期间关闭不必要的外设
- 使用停机模式降低待机功耗
- 动态调整系统时钟频率
-
软件滤波算法:
c复制#define FILTER_DEPTH 5 float moving_average(float new_val) { static float buffer[FILTER_DEPTH]; static uint8_t index = 0; buffer[index++] = new_val; if(index >= FILTER_DEPTH) index = 0; float sum = 0; for(int i=0; i<FILTER_DEPTH; i++) sum += buffer[i]; return sum/FILTER_DEPTH; } -
校准方法改进:
- 准备标准浊度液(如0NTU、5NTU、10NTU)
- 记录各点ADC原始值
- 使用最小二乘法拟合校准曲线
5. 扩展应用方向
5.1 物联网功能扩展
通过ESP-01S模块添加WiFi功能:
-
硬件连接:
code复制ESP-01S STM32 TXD → PA3(RX) RXD → PA2(TX) CH_PD → 3.3V VCC → 3.3V GND → GND -
AT指令示例:
c复制void ESP_SendData(float temp, float ntu) { char cmd[128]; sprintf(cmd, "AT+CIPSTART=\"TCP\",\"api.thingspeak.com\",80\r\n"); HAL_UART_Transmit(&huart2, (uint8_t*)cmd, strlen(cmd), 100); sprintf(cmd, "GET /update?api_key=XXX&field1=%.1f&field2=%.1f\r\n", temp, ntu); sprintf(cmd, "AT+CIPSEND=%d\r\n", strlen(cmd)); HAL_UART_Transmit(&huart2, (uint8_t*)cmd, strlen(cmd), 100); }
5.2 多参数检测升级
可扩展添加以下传感器:
- pH传感器:采用模拟输出型号,需额外ADC通道
- 电导率传感器:需要交流激励电路
- 溶解氧传感器:需配合专用驱动电路
硬件改造建议:
- 使用STM32F103CBT6(128KB Flash)替代C8T6
- 增加多路模拟开关(如CD4051)
- 设计传感器接口扩展板
6. 项目总结与改进
经过三个版本迭代,当前系统已实现:
- 温度测量范围0-50℃,精度±0.5℃
- 浊度检测范围0-20NTU,精度±5%
- 连续工作时间≥72小时
- 防水等级IP65
实测对比专业设备:
| 参数 | 本系统 | 专业设备 | 误差 |
|---|---|---|---|
| 25℃清水 | 0.8NTU | 0.7NTU | +14% |
| 30℃混水 | 8.2NTU | 7.9NTU | +3.8% |
| 响应时间 | 2.1s | 1.5s | +0.6s |
下一步改进方向:
- 改用STM32G0系列降低功耗
- 增加SD卡本地存储功能
- 开发手机APP可视化工具
- 优化机械结构实现自动清洗
这个项目最让我满意的不是技术实现,而是它实际解决了社区居民对饮用水质量的担忧。有位老人每天都会来看显示屏上的数据,这种成就感是纯软件开发难以获得的。硬件项目的魅力就在于此——你的代码实实在在地改变了物理世界。