水质监测 · 嵌入式

测量一杯水的
纯净度

TDS(Total Dissolved Solids,总溶解固体)是衡量水质纯净度的核心指标之一。 本演示使用 STM32F103C8T6 通过 ADC 采集 TDS 传感器模拟输出, 经电压–浓度映射后实时显示在 OLED 屏上。

MCU STM32F103C8T6
ADC 12-bit / PA0
显示 0.96" OLED
周期 1s
TDS:0.0
Live · OLED_CenterPrintf(24, "TDS:%.1f", TDS)
OLED.CenterPrintf(24, "TDS:%.1f", TDS);
// 01

传感器原理与功能

— 从电导率到 ppm

① 什么是 TDS

TDS(Total Dissolved Solids)指水中溶解性固体的总浓度, 单位通常为 ppm(mg/L)。 它包含 Ca²⁺、Mg²⁺、Na⁺、K⁺ 等阳离子和 Cl⁻、HCO₃⁻、SO₄²⁻ 等阴离子, 反映水的纯净度与矿物质含量。

  • 纯净水:< 50 ppm
  • 自来水:50 ~ 300 ppm
  • 矿泉水:300 ~ 1000 ppm
  • 高污染水:> 1000 ppm

② 测量原理

纯净水几乎不导电,水中溶解的盐分越多,电导率越高。 TDS 传感器在两根电极之间施加交流激励信号, 通过测量回路电流换算水溶液电阻 → 电导 → TDS 值。

  • 电极:不锈钢/镀金探针,间距固定
  • 激励:交流信号(避免电极极化)
  • 输出:0 ~ 3.3V 模拟电压,与 TDS 正相关
  • 板载电路:整流 + 滤波 + 运放跟随

③ 模块功能

本模块将探头、信号调理电路、连接器集成在一块 PCB 上, 输出模拟电压信号,可直接接入 MCU 的 ADC 引脚。

  • 工作电压:DC 3.3 ~ 5.5V
  • 接口:3 线制:VCC / GND / AO
  • 探头:BNC 接头,约 60cm 线长
  • 应用:净水器 · 水族箱 · 水培 · 实验教学

④ 程序参数

本示例的采集与换算参数,均直接来自源码,可在 main.c / adc.c 中核对。

  • ADC 精度:12-bit(满量程 4095)
  • 参考电压:3.3V
  • 采样周期:1s(HAL_Delay 1000)
  • 显示:0.96" OLED · TDS:%.1f
  • 换算:三次多项式拟合

⚡ 测量原理动画 · 三级联动

滑动条改变"水的纯净度",三个模块将同步联动:探杯 → ADC 采集 → TDS 计算

Step 1 · 探杯
电极 + 水溶液
浓度: 0 ppm
模拟电压
Step 2 · ADC
电压采集
3.3V
0.00 V
12-bit ADC @ PA0
数字量
Step 3 · 计算
TDS 实时读数
TDS
000
ppm
05001000+
纯净
200 ppm
// 02

硬件展示

— 实物外观 / 电路设计

实物外观 Group 1

TDS 模块由信号板 + 探头 + 3P 连接线组成,探头通过 BNC 接头接入信号板。

电路设计 Group 2

模块对外只有 3 个引脚。VCC 接 5V 供电,AO 输出与 TDS 浓度正相关的模拟电压,MCU 通过 ADC 采集 AO 即可换算出 ppm 值。

Pin 1 · GND
电源地,与 MCU 共地
接地
Pin 2 · +5V
模块供电,3.3~5.5V 均可
VCC
Pin 3 · AO
模拟输出 → STM32 PA0 (ADC1_IN0)
ADC
供电电压
5.0 V
MCU 主频
72 MHz
ADC 精度
12 bit
采样周期
1 s
// 03

程序分析

— STM32F103C8T6 · HAL · ADC1

主循环流程图

main() 系统启动 HAL_Init() 复位外设 SystemClock_Config() 72MHz MX_GPIO_Init() / MX_ADC1_Init() OLED_Init() 显示初始化 while (1) ↓ 主循环 ↓ HAL_GetTick() - Time_Now ≥ 1000 ms ? YES NO ADC_Start → Poll → GetValue(12-bit) TDS = 66.71·V³ − 127.93·V² + 428.7·V 电压 → ppm 三次多项式 OLED_Clear → CenterPrintf(24, "TDS:%.1f") 循环
// STEP 1 · 初始化
系统启动
HAL_Init() → SystemClock_Config() 设置 72MHz 主频;APB2 时钟驱动 ADC1。
// STEP 2 · 外设
GPIO + ADC + OLED
MX_GPIO_Init() 配置 PA0 为模拟输入;MX_ADC1_Init() 配置 ADC1 通道 0,单次转换,239.5 周期采样;OLED_Init() 完成 0.96" OLED 初始化。
// STEP 3 · while(1) 主循环
进入无限循环
主循环持续运行,每轮检查是否到达 1 秒节拍。
// STEP 4 · 节拍判断
1 秒到了吗?
HAL_GetTick() 与 Time_Now 比较,差值 ≥ 1000ms 才执行采样,否则继续循环等待,避免屏幕闪烁。
// STEP 5 · ADC 采集
读取 12-bit 数字量
HAL_ADC_Start() 启动软件触发;HAL_ADC_PollForConversion() 阻塞等待;HAL_ADC_GetValue() 取出 0~4095 数字量。
// STEP 6 ★ 核心
电压 → TDS 换算
先 (ADC/4095)×3.3 得到电压 V,再用三次多项式 TDS = 66.71·V³ − 127.93·V² + 428.7·V 拟合出 ppm 值。
// STEP 7 · 显示
OLED 刷新
OLED_Clear() → OLED_CenterPrintf(24, "TDS:%.1f", TDS) → OLED_Update(),最后更新时间戳,回到 while(1) 顶部继续。

📝 关键代码片段

以下摘自 Core/Src/main.c、adc.c,可点击切换查看。

main.c · 主循环
adc.c · ADC 配置
公式推导
/* 1 秒节拍,采集 + 换算 + 显示 */
while (1)
{
    if (HAL_GetTick() - Time_Now >= 1000)
    {
        // ---- 单通道 ADC 采集 ----
        HAL_ADC_Start(&hadc1);
        if (HAL_ADC_PollForConversion(&hadc1, 999) == HAL_OK)
            float V = (HAL_ADC_GetValue(&hadc1) / 4095.0) * 3.3;
        HAL_ADC_Stop(&hadc1);

        // ---- 三次多项式拟合 ----
        float TDS = 66.71*V*V*V - 127.93*V*V + 428.7*V;

        // ---- OLED 显示 (Y=24 居中) ----
        OLED_Clear();
        OLED_CenterPrintf(24, "TDS:%.1f", TDS);
        OLED_Update();

        Time_Now = HAL_GetTick();
    }
}
/* ADC1 初始化:通道 0(PA0),单次软件触发 */
ADC_HandleTypeDef hadc1;

void MX_ADC1_Init(void)
{
    hadc1.Instance               = ADC1;
    hadc1.Init.ScanConvMode      = ADC_SCAN_DISABLE;
    hadc1.Init.ContinuousConvMode= DISABLE;
    hadc1.Init.ExternalTrigConv  = ADC_SOFTWARE_START;
    hadc1.Init.DataAlign         = ADC_DATAALIGN_RIGHT;
    hadc1.Init.NbrOfConversion   = 1;
    HAL_ADC_Init(&hadc1);

    // 配置通道 0 = PA0,采样 239.5 周期
    sConfig.Channel      = ADC_CHANNEL_0;
    sConfig.Rank         = ADC_REGULAR_RANK_1;
    sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}
// ① ADC 数字量 → 电压
V = ADC / 4095 × 3.3V
    = 12-bit 满量程映射(0~3.3V)

// ② 电压 → TDS(ppm)三次多项式
TDS = 66.71·V³ − 127.93·V² + 428.7·V

// ③ 数值实例:
//  V = 1.20V → TDS ≈ 66.71·1.728 − 127.93·1.44 + 428.7·1.20
//              ≈ 115.3 − 184.2 + 514.4 ≈ 445 ppm
TDS = 66.71·V³ − 127.93·V² + 428.7·V
电压 V 由 ADC 采集值换算得到 · 三次多项式拟合(系数取自示例程序 main.c)