零知开源——基于STM32F103RBT6的TDS水质监测仪数据校准和ST7789显示实战教程

  ✔零知开源是一个真正属于国人自己的开源软硬件平台,在开发效率上超越了Arduino平台并且更加容易上手,大大降低了开发难度。零知开源在软件方面提供了完整的学习教程和丰富示例代码,让不懂程序的工程师也能非常轻而易举的搭建电路来创作产品,测试产品。快来动手试试吧!

✔访问零知开源平台,获取更多实战项目和教程资源吧!

www.lingzhilab.com

目录

一、硬件系统设计

1.1 所需硬件

1.2 接线方案

1.3 连接硬件图

1.4 接线实物图

二、软件架构设计

2.1 校准算法实现

2.2 UI设计

2.3 中值滤波算法

2.4 温度补偿算法

2.5 最小二乘法算法

三、功能展示

3.1 TDS探测仪和TDS模块数据对比

3.2 视频演示效果

3.3 串口监视器数据

3.4 性能优化

3.5 系统界面展示

四、TDS校准代码数学原理

五、常见问题解答

Q1:为什么需要三个校准点?

Q2:为什么需要温度补偿?

Q3:为什么空气中显示非零值?

Q4:如何提高测量精度?

六、结论


(1)项目概述

        本教程将指导您构建一个基于STM32F103RBT6的零知标准板高精度TDS(总溶解固体)水质监测系统。项目结合了TDS-3传感器、ST7789显示屏和先进的三点校准算法,实现了±10ppm的高精度水质测量。系统采用直观的UI设计,通过颜色编码实时显示水质安全状态(绿/黄/红),是家庭水质监测、水培系统和水产养殖的理想解决方案。

(2)项目亮点

        >三点校准算法实现±10ppm精度
        >UI设计,颜色编码水质安全状态
        >三阶多项式拟合校准最小二乘法参数

一、硬件系统设计

1.1 所需硬件

组件型号数量备注
开发板零知标准板1STM32F103RBT6
TDS传感器TDS BOARD1水质检测探头
显示屏ST7789 2.4寸1240x320分辨率
水质检测仪TDS-31校准水质传感器读取的数值
连接线杜邦线若干公对公、母对公

1.2 接线方案

零知标准板(STM32F103RBT6)TDS水质传感器ST7789(SPI)引脚功能说明
3.3V+VCC电源
GND-GND接地
A0AO/模拟引脚
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]; // 0ppmfloat V2 = calibVoltages[2]; // 342ppmfloat 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 性能优化

测试条件标准值校准前校准后误差改善
干燥空气0ppm98ppm318ppm-80ppm
78ppm标准溶液78ppm600ppm78ppm-522ppm
160ppm标准溶液160ppm260ppm160ppm-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
        非线性补偿:三阶多项式模型有效拟合传感器非线性特性
        操作简便:图形化校准工具简化用户操作
        成本效益:无需额外硬件实现高精度校准

项目资源:

三点校准数学原理:三点校准知识点

欢迎在评论区分享您的制作经验和使用效果!点击了解更多零知开发教程:

https://www.lingzhilab.com/freesources.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/92332.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/92332.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

luogu P3387 【模板】缩点

原题链接 原题再现 题目描述 给定一个 n 个点 m 条边有向图&#xff0c;每个点有一个权值&#xff0c;求一条路径&#xff0c;使路径经过的点权值之和最大。你只需要求出这个权值和。 允许多次经过一条边或者一个点&#xff0c;但是&#xff0c;重复经过的点&#xff0c;权…

P1119 灾后重建【题解】

P1119 灾后重建 题目背景 B 地区在地震过后&#xff0c;所有村庄都造成了一定的损毁&#xff0c;而这场地震却没对公路造成什么影响。但是在村庄重建好之前&#xff0c;所有与未重建完成的村庄的公路均无法通车。换句话说&#xff0c;只有连接着两个重建完成的村庄的公路才能通…

Horse3D引擎研发笔记(二):基于QtOpenGL使用仿Three.js的BufferAttribute结构重构三角形绘制

在Horse3D引擎的研发过程中&#xff0c;我们致力于构建一个高效、灵活且易于扩展的3D图形引擎。在本篇博客中&#xff0c;我们将详细记录如何基于QtOpenGL框架&#xff0c;使用仿Three.js的BufferAttribute结构&#xff0c;重构三角形绘制流程。通过这一过程&#xff0c;我们希…

MCU程序段的分类

程序的下载&#xff08;烧录到存储器中&#xff09;通常是按照程序文件分段&#xff08;Code段、RO_data段、RW_data段、ZI_data段&#xff09;的方式存储的&#xff0c;但运行时内存的布局会按照程序进程分段&#xff08;TEXT段、DATA段、BSS段、堆栈段&#xff09;进行组织。…

综合项目记录:自动化备份全网服务器数据平台

一、项目背景与需求1.1项目概述该项目共分为2个子项目&#xff0c;由环境搭建和实施备份两部分组成1.2项目总体需求企业内部有一台web服务器&#xff0c;内部数据很重要&#xff0c;现需要为该web服务器数据做备份&#xff0c;这样在数据丢失时可以恢复。要求如下&#xff1a;每…

联合索引全解析:一棵树,撑起查询的半边天

目录 一、为什么联合索引是MySQL性能优化的“王牌”&#xff1f; &#xff08;一&#xff09;索引的基本结构&#xff1a;从聚簇到非聚簇 1. 聚簇索引&#xff08;Clustered Index&#xff09; 2. 非聚簇索引&#xff08;Secondary Index&#xff09; &#xff08;二&…

vue开发的计算机课程页面

课程信息展示页面设计与实现我将设计一个美观且实用的课程信息展示页面&#xff0c;重点展示计算机网络应用课程的相关信息。设计思路使用卡片式布局清晰展示课程各模块信息采用科技感配色方案&#xff0c;符合计算机网络课程主题添加动画效果增强用户体验响应式设计确保在各种…

MySQL 正则表达式详细说明

目录 MySQL 正则表达式详细说明 1. 基本操作符&#xff1a;REGEXP 和 RLIKE 2. 常用正则表达式模式 3. MySQL 正则表达式函数&#xff08;MySQL 8.0&#xff09; 4. 示例查询 5. 注意事项 6. 总结 MySQL 正则表达式详细说明 MySQL 支持正则表达式&#xff08;Regular Ex…

c++之 栈浅析

C之栈浅析 概要 通过可视化游戏梳理栈特点以及栈操作方式. 学习栈的工作原理就像往糖果罐里放糖果和拿糖果一样简单&#xff01; 栈特点 先进后出 技术名词解释 LIFO LIFO -> Last In, First Out 后进先出 可视化小游戏 游戏传送门

C++ 算术函子

在 C 中&#xff0c;算术函子&#xff08;Arithmetic Functors&#xff09; 是标准库 <functional> 中提供的一组函数对象&#xff0c;用于封装基本的算术运算&#xff08;如加、减、乘、除等&#xff09;。它们本质上是类模板&#xff0c;重载了 operator()&#xff0c;…

Flutter 事件总线 Event Bus

文章目录概要核心原理基本使用步骤优点注意事项适用场景小结概要 提示&#xff1a;这里可以添加技术概要 event_bus 是一个常用的第三方库&#xff0c;用于实现跨组件 / 跨页面的事件通信&#xff0c;基于发布 - 订阅模式&#xff08;Publish-Subscribe Pattern&#xff09;工…

数据库管理系统:入门需要了解的内容

数据库管理系统&#xff1a;数字化时代的基石 在信息技术飞速发展的今天&#xff0c;我们生活在一个被数据包围的世界里。从日常使用的社交媒体、电商平台&#xff0c;到企业运营的核心业务系统&#xff0c;再到政府部门的政务管理&#xff0c;数据无处不在。而数据库管理系统&…

安装CST时,报错问题处理

今天安装这个软件的时候&#xff0c;发现一个问题一直处理不了&#xff0c;然后看网上的一些解决方法&#xff0c;最终得到处理&#xff0c;这里就简单记录下解决方法。问题&#xff1a;处理方案&#xff1a;1.问题原因&#xff1a;crack中的CST Studio Suite 2022未配置成功。…

分治-快排-215.数组中的第k个最大元素-力扣(LeetCode)

一、题目解析1、需返回排序好的第k个最大元素2、要求时间复杂度为O(N)二、算法原理解法1&#xff1a;堆排序(大根堆) k*O(N)借用大堆的性质&#xff0c;将元素插入到大堆中&#xff0c;按照k输出堆顶第k个元素解法2&#xff1a;堆排序(小根堆) (N-k)*O(logN)先建k个小堆&#x…

新手向:Python实现图片转ASCII艺术

Python实现图片转ASCII艺术&#xff1a;从零开始的完整指南Python实现图片转ASCII艺术的技术解析ASCII艺术是一种使用字符组合来表现图像的技术&#xff0c;这种技术源于早期计算机显示器的图形限制&#xff0c;如今已成为一种独特的数字艺术形式。ASCII艺术的应用场景十分广泛…

6.类与对象(二)

总结 本章写了封装、static成员以及代码块。 一、封装 1.封装的概念 封装简单来说就是被密封起来&#xff08;不让我们看见的东西&#xff09;&#xff0c;即被隐藏。 对于用户来说&#xff0c;并不需要关心的类&#xff0c;所实现的细节就会被封装&#xff08;隐藏&#x…

流形折叠与条件机制

1. 为什么要防止流形折叠&#xff08;mode collapse&#xff09; 流形折叠 生成器只学会输出极少数甚至单一模式&#xff08;mode&#xff09;的样本&#xff0c;而完全忽略数据分布的多样性。 后果一句话&#xff1a;“模型看起来生成了很多图&#xff0c;其实都在重复同一张…

《从零构建大语言模型》学习笔记2,文本数据处理1(以及tiktoken库无法下载gpt2参数,调用get_encoding时SSL超时的解决方法)

《从零构建大语言模型》学习笔记2&#xff0c;文本数据处理1 文章目录《从零构建大语言模型》学习笔记2&#xff0c;文本数据处理1前言1、分词2.将把提取出来的词元转换为数字ID3.添加特殊上下文标记4. 字节对编码&#xff08;以及tiktoken库无法下载gpt2参数&#xff0c;调用g…

【AI工具】解放双手,操控浏览器的工具对比,来了

&#x1f4d2;前言在github上面&#xff0c;有几个操作浏览器的mcp工具&#xff1a;browser-use / browser-usemicrosoft / playwright-mcpAgentDeskAI / browser-tools-mcphangwin / mcp-chrome想知道他们的区别吗&#xff0c;想知道那个更适合你吗&#xff0c;想。。。&#…

Linux 操作系统基础知识总结

1、操作系统总体介绍 CPU&#xff1a; 就像人的大脑&#xff0c;主要负责相关事情的判断以及实际处理的机制。 查询指令&#xff1a; cat /proc/cpuinfo 内存&#xff1a; 大脑中的记忆区块&#xff0c;将皮肤、眼睛等所收集到的信息记录起来的地方&#xff0c;以供CPU进行判断…