在工业生产和环境监测领域,水位和水质数据的实时采集一直是个经典课题。传统的人工采样方式存在效率低、数据不连续、响应滞后等问题。我去年指导的一个毕业设计项目,采用STM32单片机为核心,构建了一套低成本、高可靠的水质水位监测系统,实测采样间隔可达到10秒/次,数据通过4G模块上传云端,实现了监测点的无人化值守。
这个系统的核心价值在于将物理传感技术、嵌入式开发和物联网传输有机结合。水位监测选用超声波传感器,水质参数则通过多探头阵列采集,包括pH值、浊度、溶解氧等关键指标。所有数据经单片机处理后,既可在本地LCD屏显示,又能通过移动网络同步到远程服务器。这种设计特别适合水库、污水处理厂、水产养殖等场景的长期监测需求。
我们对比了三种主流方案:
最终选择STM32主要基于三点考量:
| 传感器类型 | 型号示例 | 量程 | 精度 | 输出信号 | 供电需求 |
|---|---|---|---|---|---|
| 超声波水位 | US-100 | 2cm-4.5m | ±3mm | UART/TTL | 3.3-5V |
| pH值 | PH-4502C | 0-14pH | ±0.1pH | 0-3V模拟 | 5V |
| 浊度 | TS-300B | 0-1000NTU | ±5% | 0-4.5V模拟 | 5V |
| 溶解氧 | DO-802 | 0-20mg/L | ±0.3mg/L | I2C数字 | 3.3V |
特别注意:pH探头需要定期校准(建议每周一次),浊度传感器要避免阳光直射,否则读数会漂移。
考虑到监测点往往位于偏远区域,我们放弃了WiFi方案,测试了三种远程传输方案:
最终选用EC20模块是因为:
系统需要为不同部件提供三种电压:
采用两级转换方案:
c复制[12V铅酸电池] → [LM2596降压到5V] → [AMS1117-3.3稳压]
关键设计点:
pH传感器需要特殊处理:
超声波模块的软件消抖算法:
c复制#define SAMPLE_TIMES 5
uint32_t GetDistance(){
uint32_t sum=0;
for(uint8_t i=0;i<SAMPLE_TIMES;i++){
sum += HCSR04_Read();
delay_ms(20);
}
return sum/SAMPLE_TIMES;
}
在污水处理厂实测时遇到信号干扰问题,通过三项改进解决:
c复制void main(){
Hardware_Init();
while(1){
if(Flag_10s){ // 10秒定时器触发
Flag_10s = 0;
Read_Sensors();
Process_Data();
Display_Update();
if(Flag_Upload) Send_To_Cloud();
}
Handle_UART(); // 处理AT指令响应
}
}
pH值需要温度补偿:
c复制float Get_Real_pH(float raw_pH, float temp){
// 温度补偿公式
return raw_pH / (1 + 0.003*(temp-25));
}
浊度传感器的非线性校正:
c复制// 使用查表法+线性插值
const float Turbidity_Table[] = {0,50,100,200,500,1000}; // NTU
const float ADC_Table[] = {0.1,0.8,1.5,2.2,3.3,4.5}; // V
float Get_Turbidity(float adc_val){
for(uint8_t i=0;i<5;i++){
if(adc_val>=ADC_Table[i] && adc_val<=ADC_Table[i+1]){
return Turbidity_Table[i] + (adc_val-ADC_Table[i]) *
(Turbidity_Table[i+1]-Turbidity_Table[i]) /
(ADC_Table[i+1]-ADC_Table[i]);
}
}
return 0;
}
云端通信采用自定义紧凑协议:
code复制[HEAD][LEN][TIMESTAMP][DATA...][CRC]
示例代码:
c复制void Pack_Data(){
uint8_t buf[32];
buf[0] = 0xAA; // HEAD
buf[1] = 0x55;
buf[2] = 16; // LEN
memcpy(&buf[3], &sensor_data, 16); // 4个float
uint16_t crc = Calc_CRC16(buf, 19);
buf[19] = crc >> 8;
buf[20] = crc & 0xFF;
}
采用经典三层架构:
关键数据库表结构:
sql复制CREATE TABLE `water_data` (
`id` bigint NOT NULL AUTO_INCREMENT,
`device_id` varchar(32) NOT NULL,
`timestamp` datetime NOT NULL,
`water_level` float DEFAULT NULL,
`ph_value` float DEFAULT NULL,
`turbidity` float DEFAULT NULL,
`oxygen` float DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `idx_device_time` (`device_id`, `timestamp`)
) ENGINE=InnoDB;
基于滑动窗口的突变检测:
python复制def detect_anomaly(data, window_size=10, threshold=3):
rolling_mean = data.rolling(window=window_size).mean()
rolling_std = data.rolling(window=window_size).std()
upper_bound = rolling_mean + threshold * rolling_std
lower_bound = rolling_mean - threshold * rolling_std
return (data > upper_bound) | (data < lower_bound)
水位传感器安装:
水质传感器维护:
通过三项改进使待机功耗从85mA降至12mA:
关键代码:
c复制void Enter_Low_Power(){
HAL_GPIO_WritePin(SENSOR_PWR_GPIO, SENSOR_PWR_PIN, GPIO_PIN_RESET);
HAL_UART_DeInit(&huart1); // 关闭串口
HAL_ADC_DeInit(&hadc1); // 关闭ADC
// 配置RTC唤醒
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 4096, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
// 进入STOP模式
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// 唤醒后重新初始化
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
}
| 现象 | 可能原因 | 排查步骤 |
|---|---|---|
| pH读数漂移 | 电极老化/污染 | 1. 用标准缓冲液校准 2. 检查参比电极液接界 |
| 4G模块频繁掉线 | SIM卡接触不良 | 1. 清洁SIM卡触点 2. 检查APN设置 3. 测试信号强度(AT+CSQ) |
| 水位数据异常 | 水面泡沫干扰 | 1. 调整安装位置 2. 软件增加滤波算法 |
| 系统意外重启 | 电源波动 | 1. 测量电池电压 2. 检查TVS管是否击穿 |
在实际部署后,我们发现了三个有价值的改进点:
太阳能供电系统:为偏远监测点增加10W太阳能板+18650电池组,阴雨天可续航7天
边缘计算能力:在STM32上实现简单的LSTM预测算法,提前预警水质恶化趋势
LoRa中继组网:针对无4G信号的区域,采用LoRa模块将数据接力传输到有网络的位置
一个实用的水质预测算法示例:
python复制# 简化的LSTM预测模型
from keras.models import Sequential
from keras.layers import LSTM, Dense
model = Sequential()
model.add(LSTM(50, input_shape=(30, 4))) # 30个历史时间步,4个特征
model.add(Dense(4)) # 预测4个水质参数
model.compile(loss='mse', optimizer='adam')
这个项目从设计到部署共耗时4个月,期间最大的收获是认识到工业现场环境远比实验室复杂。比如在污水处理厂,传感器要经受酸碱腐蚀、湿度变化、电磁干扰等多重考验。我们的第三版电路板才最终达到稳定运行标准——增加三防漆涂层、改用工业级接插件、优化接地设计等措施缺一不可。