水温+浑浊度+pH三参数监测、超标自动换水、手机APP远程查看,附"摘要吹溶氧氨氮、图注抄成GPS"翻车实录
养鱼先养水。鱼缸水质崩了,鱼翻肚往往就在一夜之间------等你肉眼发现水浑、鱼浮头,亚硝酸盐早就爆表了。市面上一支带温度补偿的 pH 笔就要上百,溶氧仪更是几百起步。其实用 STM32 + 三支传感器,一百出头就能做一套水温、浑浊度、pH 三参数实时监测 + 超标报警 + 自动换水 + 手机远程查看的系统。
一、系统功能拆解
| 功能域 | 模块 | 说明 |
|---|---|---|
| 水质监测 | DS18B20 防水探头 | 水温检测,超阈值报警 |
| 水质监测 | SEN0189 红外浑浊度 | 水中颗粒物散射测浑浊,超阈值报警 |
| 水质监测 | PH-4502C + pH 电极 | 酸碱度检测,超标触发换水泵 |
| 人机交互 | OLED12864 | 实时显示三参数 |
| 人机交互 | 4 按键 | 本地设置阈值 |
| 远程通信 | ESP8266(MQTT→阿里云) | 数据上云,APP 远程查看+设阈值 |
| 报警执行 | 蜂鸣器 + LED | 超限声光报警 |
| 换水执行 | 继电器 + 小水泵 | pH 超标自动换水(带防抽干保护) |
主逻辑:初始化 → 循环采集三参数 → OLED 刷新 → MQTT 上云 → 水温/浑浊度超阈值声光报警 → pH 超标启动换水泵(限时保护)→ 响应按键与 APP 指令。
二、器件选型对比
2.1 主控:STM32F103C8T6 vs STM32F407VG
三路采集里两路是 ADC(浑浊度、pH),C8T6 自带 2 个 12 位 ADC、10 个通道完全够用,选它合理。
2.2 水温:DS18B20 vs LM35
DS18B20 提供了更高的测量精度和更广泛的温度范围------LM35 精度 ±0.25°C 高于 DS18B20 的 ±0.5°C,量程 150°C 也宽于 125°C。DS18B20 真正的优势是防水封装成品探头 + 数字输出免标定,鱼缸场景就该选它,但理由得写对。
2.3 浑浊度:SEN0189 红外 vs SEN0176 激光
| 对比项 | SEN0189(红外 850nm) | SEN0176(激光) |
|---|---|---|
| 原理 | 红外 LED + 光电管测散射 | 激光散射,分辨率高 |
| 价格 | ≈45 元 | ≈200+ 元 |
| 适用 | 家用浑浊度粗判 | 精密测量 |
家用鱼缸只需要知道"水是否开始浑了",SEN0189 够用。注意:SEN0189 输出的是模拟电压,"浑浊度百分比"并没有严格的物理单位,正规写法应换算 NTU 或直接以电压/ADC 值表征。
2.4 pH:PH-4502C vs SEN0161
PH-4502C(±0.1pH,配 BNC 电极)比 SEN0161(±0.2pH)精度高一档,做水质监测选它合理。
2.5 通信与显示
ESP8266-01S(家庭 Wi-Fi 直连)+ OLED12864(I2C),常规选择。
2.6 BOM 成本清单
| 器件 | 参考价 |
|---|---|
| STM32F103C8T6 最小系统板 | ≈15 元 |
| DS18B20 防水探头 | ≈8 元 |
| SEN0189 浑浊度模块 | ≈45 元 |
| PH-4502C + pH 玻璃电极 | ≈30 元 |
| ESP8266-01S | ≈10 元 |
| OLED12864(I2C) | ≈10 元 |
| 继电器 + 5V 小水泵 | ≈15 元 |
| 蜂鸣器、LED、按键、洞洞板 | ≈10 元 |
| 合计 | ≈143 元 |
三、硬件接线
| 模块 | 引脚 | 说明 |
|---|---|---|
| DS18B20 DQ | PB8 | 4.7kΩ 上拉,防水探头直接入水 |
| SEN0189 AO | PA1(ADC1_IN1) | 5V 供电,AO 输出注意量程 |
| PH-4502C OUT | PB1(ADC1_IN9)→ 分压后 | ⚠️ 见接线坑 1 |
| OLED SDA/SCL | PB6/PB7(I2C1) | --- |
| ESP8266 TX/RX | PA2/PA3(USART2) | 115200bps |
| 继电器(水泵) | PA0 | 高电平吸合 |
| 蜂鸣器 | PB9 | 高电平响 |
| 按键×4 | PB12~PB15 | 内部上拉 |
接线坑三条:
- PH-4502C 的 5V/3.3V 混搭问题 :板子 5V 供电,OUT 静态输出约 2.5V、极限可到 5V,直接接 F103 的 ADC 有过压风险(F103 引脚耐压 3.6V,ADC 满量程 3.3V)。用两个 10kΩ 分压成 0~2.5V 再进 ADC,标定时把分压比一起标进去。
- 两个 ADC 别用 ADC3 :原文 pH 章节调用
Get_Adc3------C8T6 根本没有 ADC3(ADC3 只在 100 脚以上的 F103 才有),浑浊度章节又用 ADC2。实际两路都挂 ADC1 的不同通道即可,代码抄大的芯片的工程就会出这种错。 - 水泵走继电器隔离:5V 潜水泵启动电流是标称的 3~5 倍,别用 IO 直推;继电器线圈两端并一个续流二极管(1N4007),否则断电瞬间反向电动势会打坏驱动管。
四、软件设计
4.1 主程序框架
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
delay_init();
TIM4_Init(300, 7200); /* 1ms 时基 */
OLED_Init();
DS18B20_Init(); /* PB8 水温 */
Relay_init(); /* PA0 换水泵 */
KEY_Init(); /* PB12~PB15 */
Beep_init(); /* PB9 */
Adc_Init(); /* PA1 浑浊度 / PB1 pH */
ALi_ESP8266_GPIO_Init();
MQTT_Buff_Init();
AliIoT_Parameter_Init();
while (1)
{
Sensor_Update(); /* 三参数采集 */
OLED_Display_Cotrol(); /* 显示刷新 */
Alarm_Check(); /* 水温/浑浊度超限 -> 声光报警 */
PH_AutoWater(); /* pH 超标 -> 换水(限时保护) */
Key_Scan(); /* 阈值设置 */
MQTT_Loop(); /* 上报 + 响应 APP 指令 */
}
}
4.2 关键子程序一:DS18B20 非阻塞读水温
void DS18B20_Task(void)
{
static u8 phase = 0;
static u32 t0;
switch (phase) {
case 0: /* 发起转换 */
DS18B20_Reset();
DS18B20_WriteByte(0xCC); /* 跳过ROM */
DS18B20_WriteByte(0x44); /* 启动转换 */
t0 = GetTick();
phase = 1;
break;
case 1: /* 750ms 后再读,期间不阻塞主循环 */
if (GetTick() - t0 >= 750) {
DS18B20_Reset();
DS18B20_WriteByte(0xCC);
DS18B20_WriteByte(0xBE); /* 读暂存器 */
u8 tl = DS18B20_ReadByte();
u8 th = DS18B20_ReadByte();
water_temp = ((s16)((th << 8) | tl)) * 0.0625f;
phase = 0;
}
break;
}
}
4.3 关键子程序二:pH 两点校准(原文完全没做的一步)
pH 电极的能斯特响应是一条直线 pH = K * V + B,K 和 B 由两种标准液标定:
typedef struct { float v4, v7; } PH_Calib; /* 标定电压 */
float PH_GetValue(PH_Calib *c)
{
float v = Adc_ReadAvg(CH_PH, 20) * 3.3f / 4095; /* 分压后电压 */
/* 两点法:pH4.01 对应 v4,pH6.86 对应 v7 */
float k = (4.01f - 6.86f) / (c->v4 - c->v7);
float ph = 6.86f + k * (v - c->v7);
/* 温度补偿:水温每偏离 25°C,斜率约变化 0.3%/°C */
ph -= (ph - 7.0f) * (water_temp - 25.0f) * 0.003f;
return ph;
}
标定流程:电极依次插入 pH6.86 和 pH4.01 标液,各按一次"校准键"记录电压,存 Flash。电极每 1~2 个月要重校,玻璃电极干放后要先浸泡活化。
4.4 关键子程序三:SEN0189 浑浊度采样
u16 Turbidity_GetAdc(void)
{
u32 sum = 0;
u8 i;
for (i = 0; i < 20; i++) {
sum += Get_Adc(CH_TURB);
delay_ms(2);
}
return (u16)(sum / 20); /* 均值滤波 */
}
表述建议:显示"浑浊度 ADC 值/电压"并标注"数值越大水越浑"即可;硬要 NTU 需要专业浊度仪对比标定。
4.5 关键子程序四:pH 超标自动换水(带防抽干保护)
#define PUMP_MAX_RUN_MS 60000 /* 单次最多抽 60s(按缸容积算好) */
#define PH_HYST 0.5f /* 回差,防止在阈值附近反复启停 */
void PH_AutoWater(void)
{
static u32 t_start;
static u8 running = 0;
float ph = PH_GetValue(&ph_calib);
if (!running) {
if (ph > ph_high_th + PH_HYST || ph < ph_low_th - PH_HYST) {
running = 1;
t_start = GetTick();
Relay_On(); /* 开泵抽旧水 */
}
} else {
if (GetTick() - t_start >= PUMP_MAX_RUN_MS) {
Relay_Off(); /* 限时到,强制停 */
running = 0;
Beep_On(); /* 提醒用户手动补新水 */
}
}
}
想做成真"自动换水":加水位传感器(或双泵 + 蓄水桶),按"抽 20% → 补 20%"流程闭环;pH 偏酸用小苏打、偏碱用榄仁叶纠正------换水本身只是稀释,不能定向调 pH。
五、系统调试验证
| 测试项 | 方法 | 预期结果 |
|---|---|---|
| 水温 | 与温度计对比 | 误差 ±0.5°C 内 |
| 浑浊度 | 清水 vs 投饵后水样 | ADC 值明显区分,阈值可调 |
| pH 校准 | 6.86/4.01 标液两点标定 | 标液回测误差 ≤±0.1pH |
| pH 精度 | 测 pH5/7/9 缓冲液 | 误差 ≤±0.2pH |
| 报警 | 人为调低阈值触发 | 蜂鸣+LED,APP 收到推送 |
| 自动换水 | pH 超上限 | 泵启动 60s 后自动停止并提示 |
| 通信 | 关 Wi-Fi 30s 再开 | 自动重连,数据续传 |
六、可扩展方向
- 补氨氮/亚硝酸盐:虽然低成本离子选择性电极精度一般,但可以做趋势预警;比摘要空吹强;
- 真·自动换水:双泵 + 蓄水桶 + 水位/霍尔传感器,抽补联动闭环;
- 加热棒联动:水温低于设定自动开加热棒(继电器+防水加热棒),养热带鱼刚需;
- 喂食提醒:RTC 定时 + APP 推送,把系统升级为完整"智能鱼缸管家"。
八、资料内容完整工程资料(原理图、PCB、代码、元件清单)
九、资料获取方式

