✔零知开源是一个真正属于国人自己的开源软硬件平台,在开发效率上超越了Arduino平台并且更加容易上手,大大降低了开发难度。零知开源在软件方面提供了完整的学习教程和丰富示例代码,让不懂程序的工程师也能非常轻而易举的搭建电路来创作产品,测试产品。快来动手试试吧!
✔访问零知开源平台,获取更多实战项目和教程资源吧!
目录
(1)项目概述
本教程将指导您构建一个基于STM32F103RBT6的零知标准板高精度TDS(总溶解固体)水质监测系统。项目结合了TDS-3传感器、ST7789显示屏和先进的三点校准算法,实现了±10ppm的高精度水质测量。系统采用直观的UI设计,通过颜色编码实时显示水质安全状态(绿/黄/红),是家庭水质监测、水培系统和水产养殖的理想解决方案。
(2)项目亮点
>三点校准算法实现±10ppm精度
>UI设计,颜色编码水质安全状态
>三阶多项式拟合校准最小二乘法参数
一、硬件系统设计
1.1 所需硬件
组件 | 型号 | 数量 | 备注 |
---|---|---|---|
开发板 | 零知标准板 | 1 | STM32F103RBT6 |
TDS传感器 | TDS BOARD | 1 | 水质检测探头 |
显示屏 | ST7789 2.4寸 | 1 | 240x320分辨率 |
水质检测仪 | TDS-3 | 1 | 校准水质传感器读取的数值 |
连接线 | 杜邦线 | 若干 | 公对公、母对公 |
1.2 接线方案
零知标准板(STM32F103RBT6) | TDS水质传感器 | ST7789(SPI) | 引脚功能说明 |
---|---|---|---|
3.3V | + | VCC | 电源 |
GND | - | GND | 接地 |
A0 | AO | / | 模拟引脚 |
10 | / | CS | 片选 |
8 | / | DC | 数据/命令选择 |
11 | / | SDA | 主出从入 |
13 | / | SCL | 时钟 |
9 | / | RES | 复位 |
1.3 连接硬件图
1.4 接线实物图
二、软件架构设计
2.1 校准算法实现
// 计算新系数
void calculateCoefficients() {
// 提取校准点电压
float V0 = calibVoltages[0]; // 干燥电压
float V1 = calibVoltages[1]; // 0ppm
float V2 = calibVoltages[2]; // 342ppm
float V3 = calibVoltages[3]; // 1000ppm
// 计算调整后电压
float v1 = V1 - V0;
float v2 = V2 - V0;
float v3 = V3 - V0;
// 三点校准公式
float denom = (v3*v3*v3 - v1*v1*v1)*(v3 - v1) - (v2*v2*v2 - v1*v1*v1)*(v2 - v1);
CALIB_A = (1000*(v3 - v1) - 342*(v2 - v1)) / denom;
CALIB_B = (342 - CALIB_A*(v2*v2*v2 - v1*v1*v1)) / (v2 - v1);
CALIB_C = (0 - CALIB_A*v1*v1*v1 - CALIB_B*v1*v1) / v1;
Serial.println("New Coefficients Calculated:");
Serial.print("A: "); Serial.println(CALIB_A);
Serial.print("B: "); Serial.println(CALIB_B);
Serial.print("C: "); Serial.println(CALIB_C);
Serial.print("V0: "); Serial.println(CALIB_V0);
}
2.2 UI设计
// 更新仪表填充
void updateGauge() {
// 计算填充高度(主体部分)
int fillHeight = constrain(map(tdsValue, 0, MAX_TDS, 0, GAUGE_HEIGHT - 2), 0, GAUGE_HEIGHT);
// 选择颜色(安全/警告)
uint16_t color;
if (tdsValue < 300) color = ST77XX_GREEN; // 安全
else if (tdsValue < 700) color = ST77XX_YELLOW; // 一般
else color = ST77XX_RED; // 警告
// 清除旧填充
tft.fillRect(GAUGE_X + 1, GAUGE_Y + 1, GAUGE_WIDTH - 2, GAUGE_HEIGHT - 2, ST77XX_BLACK);
// 绘制主体填充(从底部开始)
if (fillHeight > 0) {
int startY = GAUGE_Y + GAUGE_HEIGHT - fillHeight;
tft.fillRect(GAUGE_X + 1, startY, GAUGE_WIDTH - 2, fillHeight, color);
}
// 绘制底部小圆填充
if (tdsValue > 0) {
// 先清除小圆内部
tft.fillCircle(BULB_CENTER_X, BULB_CENTER_Y, BULB_RADIUS - 1, ST77XX_BLACK);
// 填充小圆(如果TDS值大于0)
tft.fillCircle(BULB_CENTER_X, BULB_CENTER_Y, BULB_RADIUS - 1, color);
} else {
// 当TDS为0时清除小圆
tft.fillCircle(BULB_CENTER_X, BULB_CENTER_Y, BULB_RADIUS - 1, ST77XX_BLACK);
}
}
2.3 中值滤波算法
// 中值滤波函数
int getMedianNum(int bArray[], int iFilterLen) {
int bTab[iFilterLen];
memcpy(bTab, bArray, iFilterLen * sizeof(int));
// 冒泡排序
for (int j = 0; j < iFilterLen - 1; j++) {
for (int i = 0; i < iFilterLen - j - 1; i++) {
if (bTab[i] > bTab[i + 1]) {
int bTemp = bTab[i];
bTab[i] = bTab[i + 1];
bTab[i + 1] = bTemp;
}
}
}
return (iFilterLen & 1) ?
bTab[(iFilterLen - 1) / 2] :
(bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
}
>> 对30个连续采样值进行排序并取中值,有效消除脉冲干扰。
2.4 温度补偿算法
float compensationCoefficient = 1.0 + 0.02 * (temperature - 25.0);
float compensationVolatge = averageVoltage / compensationCoefficient;
>> TDS测量受温度影响,每摄氏度变化约2%。此算法将测量值补偿到25℃基准温度。
2.5 最小二乘法算法
通过pycharm求解校准系数,结合特征矩阵X和目标向量y构建TDS模型,求解线性方程组 X · [a, b, c]^T = y 的最小二乘解
import numpy as np
# 输入数据 [电压, 真实TDS]
data = [
[0.10, 0], # 干燥空气视为0ppm
[1.72, 88], # 78ppm标准溶液
[2.89, 160] # 160ppm标准溶液
]
# 构建矩阵:y =40 a*v^3 + b*v^2 + c*v
X = np.array([[v**3, v**2, v] for v, _ in data])
y = np.array([tds for _, tds in data])
# 最小二乘法求解系数
coefficients = np.linalg.lstsq(X, y, rcond=None)[0]
print(f"CALIB_A = {coefficients[0]:.4f}")
print(f"CALIB_B = {coefficients[1]:.4f}")
print(f"CALIB_C = {coefficients[2]:.4f}")
print(f"CALIB_V0 = 0.0") # 零点已包含在校准中
> 将拟合模型输出的格式化系数值替换到零知IDE校准参数CALIB_A、CALIB_B、CALIB_C
// 校准参数(带默认值)
float CALIB_V0 = 0.0; // 零点电压
float CALIB_A = -10.4412; // 二次项系数
float CALIB_B = 50.5849; // 一次项系数
float CALIB_C = -4.9541; // 常数项
三、功能展示
3.1 TDS探测仪和TDS模块数据对比
TDS检测笔所测数据为88ppm,本模块所测数据为91ppm。经过参数校准后的TDS模块测试得到的数据精度在±10ppm之内
3.2 视频演示效果
TDS水质传感器数值读取和校准
零知标准板处理TDS水质模块数据显示到ST7789与TDS-3水质检测笔的数值进行对比
3.3 串口监视器数据
打开零知IDE的串口调试功能观察不同溶液的ppm数值变化
3.4 性能优化
测试条件 | 标准值 | 校准前 | 校准后 | 误差改善 |
---|---|---|---|---|
干燥空气 | 0ppm | 98ppm | 318ppm | -80ppm |
78ppm标准溶液 | 78ppm | 600ppm | 78ppm | -522ppm |
160ppm标准溶液 | 160ppm | 260ppm | 160ppm | -100ppm |
3.5 系统界面展示
>顶部:标题区域
>中部:当前TDS数值(120ppm)
>右侧:体温计式仪表(绿色填充表示安全水质)
四、TDS校准代码数学原理
将获取到的数值转化为求解超定方程组(方程组中的系数根据标准溶液测量得到的电压值替换):
a*(0.10)^3 + b*(0.10)^2 + c*(0.10) = 0
a*(1.72)^3 + b*(1.72)^2 + c*(1.72) = 88
a*(2.89)^3 + b*(2.89)^2 + c*(2.89) = 160
最小二乘法通过最小化残差平方和:
得到最优系数 [a, b, c],
分别带入零知IDE代码中的CALIB_A、CALIB_B、CALIB_C校准参数
五、常见问题解答
Q1:为什么需要三个校准点?
A:TDS传感器具有非线性特性
单点校准只能校正偏移,两点校准只能校正线性误差。三点校准可以更好地拟合非线性特性,提高全量程精度。
Q2:为什么需要温度补偿?
A:影响测量结果
水中的离子活性随温度升高而增强,导致电导率增加。TDS传感器通过电导率推算TDS值
Q3:为什么空气中显示非零值?
A:这是TDS传感器的正常现象,由以下原因造成:
探头表面微量电解质残留
环境湿度影响(>60%时显著)
电路基准电压微小波动
Q4:如何提高测量精度?
A:精度提升技巧
使用标准溶液校准时保持25℃恒温
校准前用蒸馏水彻底清洗探头
减少电磁干扰(远离手机、电机等设备)
增加硬件滤波电容(0.1μF并联在信号线)
六、结论
本方案通过零知IDE-Python协同工作,实现了高精度TDS测量系统:
精度提升:三点校准将平均误差从75ppm降至4.5ppm
非线性补偿:三阶多项式模型有效拟合传感器非线性特性
操作简便:图形化校准工具简化用户操作
成本效益:无需额外硬件实现高精度校准
项目资源:
三点校准数学原理:三点校准知识点
欢迎在评论区分享您的制作经验和使用效果!点击了解更多零知开发教程: