目录
[2.1 模块特点](#2.1 模块特点)
[2.2 电气特性](#2.2 电气特性)
[2.3 模块接口说明](#2.3 模块接口说明)
[2.4 结构与工作原理](#2.4 结构与工作原理)
[2.5 实际应用注意事项](#2.5 实际应用注意事项)
[3.1 硬件组成](#3.1 硬件组成)
[3.2 硬件连接](#3.2 硬件连接)
[4.1 开发环境配置](#4.1 开发环境配置)
[4.2 关键代码实现](#4.2 关键代码实现)
一、模块概述
浑浊度是衡量水体清澈程度的重要指标,广泛应用于水质监测、污水处理、饮用水生产等领域。浑浊度传感器是一种基于光学传感原理的模拟输出传感器,通过测量水中悬浮物对光的散射程度来间接反映水的浑浊度。本指南详细介绍了如何利用性价比较高的STM32F103C8T6最小系统板及其标准外设库,实现对浑浊度传感器数据的准确采集与处理。
二、模块简介
模块实物图:

2.1 模块特点
-
工作原理: 采用光学感应,内置红外LED光源和光电晶体管。
-
输出信号: 模拟电压信号输出,浑浊度越高,输出电压越高。
-
测量范围: 通常可测量0~1000 NTU ( Nephelometric Turbidity Unit ) 或更宽范围(具体需参考产品手册)。
-
易于集成: 接口简单,只需供电和读取模拟电压即可。
-
需注意点: 测量结果易受环境光、液体颜色、气泡等因素干扰。
2.2 电气特性
-
工作电压: 通常为5V DC(务必确认模块规格书,部分型号可能为3.3V-5V宽电压)。
-
输出信号: 0 ~ 4.5V 模拟电压(在5V供电下)。
-
工作电流: 约40mA。
2.3 模块接口说明
浑浊度传感器模块通常引出3个引脚(有的模块多一个DO数字信号输出引脚):
|----|-----|----------|
| 编号 | 名称 | 功能 |
| 1 | GND | 供电电压负极 |
| 2 | VCC | 供电电压正极 |
| 3 | AO | 模拟信号输出引脚 |
2.4 结构与工作原理
浑浊度传感器通过测量水中悬浮固体总量(TSS)的变化,来测量水中悬浮颗粒物的光透过率和散射率,利用光来检测悬浮颗粒物。随着 TTS 增加,液体浊度水平增加。
传感器头部包含一个红外LED和一个光电晶体管。LED向水中发射光线,水中的悬浮颗粒会导致光线发生散射。散射光的角度和强度与颗粒物的数量(浑浊度)相关。光电晶体管用于检测与入射光呈90°方向的散射光强度,并将其转换为电流信号,内部电路再将电流信号处理并放大为一个线性的电压信号输出。

传感器输出电压值大小受温度影响,输出电压与温度曲线关系如下图所示。进行浊度测量时需进行温度补偿以保证测量精度。
温度校正公式:∆U=- 0.0192×(T-25)
上式中∆ U 为温度变化引起的电压差; T 为当前测量温度值。

2.5 实际应用注意事项
-
校准: 输出电压与浑浊度并非简单的线性关系,通常需要根据传感器手册提供的曲线或通过实验数据进行校准(例如使用标准浊度液),建立电压值与NTU值的对应公式。
-
环境光屏蔽: 传感器头部应做好遮光处理,防止环境光进入干扰测量结果。
-
气泡干扰: 水中的气泡会强烈散射光线,导致读数异常偏高,测量时应避免气泡。
-
污染: 长期使用后,传感器光学窗口可能会被污染,需要定期清洁以保证精度。
-
电源去耦: 在VCC附近并联一个100nF的电容到GND,以抑制电源噪声,提高ADC采样稳定性。
三、硬件设计
3.1 硬件组成
-
主控单元: STM32F103C8T6最小系统板
-
传感单元: 浑浊度传感器模块
-
供电电源: 5V USB电源(同时为开发板和传感器供电)
-
连接线: 杜邦线若干
3.2 硬件连接
STM32F103C8T6引脚 | 浑浊度传感器引脚 | 功能说明 |
---|---|---|
5V | VCC | 为传感器供电 |
GND | GND | 共同地 |
PA1 (或其他ADCx) | AOUT | 模拟信号输入 |
四、软件设计
4.1 开发环境配置
-
IDE: Keil uVision5 MDK
-
固件库: 使用STM32F10x_StdPeriph_Lib_V3.5.0标准外设库。
4.2 关键代码实现
#include "stm32f10x.h"
#include "stdio.h" // 如果使用printf重定向
// 简单的延时函数
void Delay_ms(uint32_t nCount) {
for(; nCount != 0; nCount--) {
for(uint32_t i = 0; i < 8000; i++);
}
}
// ADC初始化函数
void ADC1_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
// 1. 开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
// 2. 配置PA1为模拟输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 3. 复位并配置ADC1参数
ADC_DeInit(ADC1);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 单通道,非扫描模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;// 单次转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 软件触发
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; // 要转换的通道数量为1
ADC_Init(ADC1, &ADC_InitStructure);
// 4. 配置ADC通道规则组
// 参数:ADCx, 通道号(PA1对应ADC1的通道1),采样顺序1,采样时间55.5个周期
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);
// 5. 使能ADC
ADC_Cmd(ADC1, ENABLE);
// 6. ADC校准(提高精度)
ADC_ResetCalibration(ADC1); // 重置校准寄存器
while(ADC_GetResetCalibrationStatus(ADC1)); // 等待重置完成
ADC_StartCalibration(ADC1); // 开始校准
while(ADC_GetCalibrationStatus(ADC1)); // 等待校准完成
}
// 读取指定ADC通道的转换值
uint16_t Get_ADC_Value(uint8_t ch) {
// 1. 配置规则组通道(这里固定为通道1,可根据参数ch修改使其更通用)
// ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_55Cycles5);
// 2. 启动软件转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
// 3. 等待转换结束
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
// 4. 清除EOC标志位并返回转换结果
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
return ADC_GetConversionValue(ADC1);
}
int main(void) {
uint16_t adc_value = 0;
float voltage = 0.0f;
// float turbidity_ntu = 0.0f; // 用于存储计算后的NTU值
// 初始化系统时钟等(默认使用内部8MHz RC振荡器,HCLK=72MHz)
// 此处省略SystemInit(),因为最小系统板通常已配置好时钟
ADC1_Init(); // 初始化ADC
while(1) {
// 1. 读取ADC原始值(12位精度,0-4095)
adc_value = Get_ADC_Value(ADC_Channel_1);
// 2. 将ADC值转换为电压值(单位:伏特)
// 假设Vref+ = 3.3V (STM32F103C8T6的VDDA通常接3.3V)
voltage = (float)adc_value * 3.3f / 4095.0f;
// 3. (可选) 将电压值转换为浑浊度值(NTU)
// 这一步需要根据传感器的校准曲线或公式进行。
// 例如:turbidity_ntu = voltage * k + b; (k和b为校准系数)
// 示例公式,请根据实际传感器校准修改!
// turbidity_ntu = -1120.4 * voltage * voltage + 5742.3 * voltage - 4352.9;
// 4. 打印结果(需实现printf重定向至串口,此处省略实现)
// printf("ADC: %d, Voltage: %.2f V\r\n", adc_value, voltage);
// 或者通过其他方式显示,如OLED
// 5. 延时一段时间后进行下一次采集
Delay_ms(1000); // 每秒采样一次
}
}
1. 初始化 (ADC1_Init):
-
首先开启GPIOA和ADC1的时钟。
-
配置PA1引脚为模拟输入模式(GPIO_Mode_AIN),这是ADC输入的正确模式。
-
使用ADC_Init函数设置ADC的工作模式为独立、单次转换、软件触发、数据右对齐。
-
使用ADC_RegularChannelConfig指定要转换的通道(通道1)及其采样时间(55.5周期,提供足够的采样时间保证精度)。
-
使能ADC并进行校准,这是一个重要步骤,可以减少内部电容带来的误差。
2. 读取转换值 (Get_ADC_Value):
-
该函数启动一次软件转换,并等待转换结束标志(EOC)置位。
-
读取ADC1->DR寄存器中的转换结果并返回。由于是单通道,结果直接存放在这个寄存器中。
3. 主循环 (main):
-
循环调用Get_ADC_Value获取原始ADC值。
-
根据ADC的参考电压(假设为3.3V)将原始值(0-4095)转换为实际的电压值。
-
关键步骤: 根据校准数据将电压值转换为有物理意义的浑浊度值(NTU)。
-
最后延时1秒,控制采样频率。
五、功能实现与优化
-
基本功能实现: 上述代码成功实现了对TSW-30传感器输出电压的周期性采样和电压值计算。
-
软件滤波: 为了抑制随机噪声,可以在软件中实现滤波算法。例如:
**- 多次采样求平均: 连续采样N次(如10次),然后取算术平均值作为最终结果。
- 中值滤波: 采样N次,排序后取中值,能有效滤除脉冲干扰。**
六、常见问题解决
- Q1: 读取的ADC值始终为0或4095。
- A1: 检查硬件连接是否正确可靠,特别是GND是否共地。检查传感器供电电压是否正常。确认STM32的ADC引脚配置是否正确(必须为模拟输入`GPIO_Mode_AIN`)。
- Q2: 读数波动非常大,不稳定。
- A2:
-
检查电源质量,在传感器VCC和GND之间并联一个100nF和一个10uF的电容。
-
实施软件滤波(如平均值滤波)。
-
确保传感器光学窗口清洁且无气泡,并处于遮光环境中。
-
尝试增加ADC的采样时间(ADC_SampleTime),让采样电容充分充电。
- Q3: 转换得到的电压值/浑浊度值不准。
- A3:
-
确认STM32的ADC参考电压是否准确。如果板载LDO质量差或负载重,3.3V可能不准,可以使用外部精密基准电压源。
-
必须进行传感器校准。未经校准的读数只有相对参考意义,无法反映绝对物理值。
- Q4: 传感器对光线变化没反应。
- A4: 检查传感器供电。用万用表测量AOUT引脚对地电压,并尝试遮挡传感器探头,观察电压是否有变化。若无变化,可能是传感器已损坏或接线错误。
七、总结
本文详细阐述了如何使用STM32F103C8T6最小系统板和标准库驱动浑浊度传感器。核心在于正确配置ADC外设以读取传感器的模拟电压输出,并通过校准将电压值转换为有意义的浑浊度数值。硬件上需要注意电源质量和抗干扰,软件上则强调滤波和校准的重要性。
通过本项目,开发者可以掌握STM32 ADC的基本应用、传感器数据采集的基本流程以及数据处理的基本方法。此方案为基础框架,开发者可根据具体应用需求,进一步添加显示、通信、报警等功能,构建完整的水质监测系统。