浊度传感器 HB-S33

STM32F103C8T6 × HAL库 × ADC模拟采集 × OLED显示

工作电压: 5V DC 通信方式: ADC模拟输出 检测范围: 0~1000 NTU 组成: 转换板 + AZDM01探头 MCU: STM32F103C8T6

01传感器原理与功能

1.1 工作原理

HB-S33浊度传感器由转换板与奥松AZDM01浊度探头组成,采用光散射法检测液体浊度。

AZDM01探头内部含有一对红外LED发射管与光电接收管。发射管发出的红外光穿过被测液体,当液体中悬浮颗粒较少(浊度低)时,大部分光直接穿透,光电接收管收到的散射光少,输出电压较高;当液体中悬浮颗粒增多(浊度高)时,颗粒使光发生散射,接收管收到的散射光增强,但穿透光减弱,转换板输出的模拟电压随之降低。

转换板将探头信号调理为0~3.3V模拟电压输出,STM32通过ADC采集该电压,经滑动平均滤波后利用公式 NTU = 2174 × (0.43 - Voltage) 计算浊度值(单位:NTU),并在OLED屏幕上实时显示。

转换板上设有一个电位器(可调电阻),用于校准传感器的输出基准。通过旋转电位器旋钮,可以调节转换板的信号放大增益或比较阈值,使传感器在不同水质环境下输出合适的模拟电压范围。实际使用时,将探头置于标准浊度液中,调节电位器使输出电压与标定曲线匹配,即可完成校准。

1.2 核心功能

💡

光散射检测

利用红外LED发射光束穿透液体,通过光电接收管检测散射光强度,实现非接触式浊度测量

📊

模拟量输出

转换板输出0~3.3V模拟电压,电压越低浊度越高,可直接连接STM32 ADC引脚采集

🔧

电位器校准

转换板内置电位器,可调节输出基准电压,将探头置于标准浊度液中旋转校准,适配不同水质环境

🔢

NTU量化

通过标定公式将电压值转换为标准浊度单位NTU,量程0~1000 NTU,适用于水质监测

📉

滑动平均滤波

每10ms采样一次ADC,累积50次后取平均值计算,有效滤除噪声干扰,提高测量稳定性

1.3 引脚定义

引脚 名称 功能 STM32连接
1 VCC 电源正极(5V DC) 5V / VCC
2 GND 电源地 GND
3 AO 模拟电压输出(0~3.3V) PA0(ADC1_IN0)
4 DO 数字阈值输出(可选) 未使用

注:AZDM01探头通过排线连接至转换板,转换板对外提供VCC/GND/AO/DO四个引脚。本次演示仅使用AO模拟输出。

02模块外观展示

总体视图

总体视图 — 转换板与AZDM01浊度探头

转换板正面

转换板正面 — 信号调理电路

转换板背面

转换板背面 — 焊接面

03原理图与PCB封装

原理图
PCB封装
AZDM01探头 AO → 转换板调理 → PA0(ADC1_IN0);OLED: SCL→PB15, SDA→PB14

04程序分析

4.1 系统时钟配置

外部高速晶振HSE = 8MHz,通过PLL倍频9倍得到系统时钟72MHz。ADC时钟由PCLK2(72MHz)8分频得到9MHz,满足STM32F103 ADC最大14MHz的限制。

SystemClock_Config() — main.c
// HSE 8MHz → PLL ×9 → SYSCLK 72MHz
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;

// ADC时钟 = PCLK2 / 8 = 72MHz / 8 = 9MHz
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV8;

4.2 ADC1配置

使用ADC1通道0(PA0引脚),12位分辨率(0~4095),右对齐,软件触发,单次转换模式。采样时间设为239.5个ADC时钟周期(约26.6μs),确保模拟信号稳定采集。

MX_ADC1_Init() — adc.c
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;         // 右对齐12位
    hadc1.Init.NbrOfConversion = 1;                   // 1个转换通道
    HAL_ADC_Init(&hadc1);

    sConfig.Channel = ADC_CHANNEL_0;                // PA0 → ADC1_IN0
    sConfig.Rank = ADC_REGULAR_RANK_1;
    sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; // 239.5周期采样
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}

4.3 GPIO配置

PA0配置为模拟模式(ADC输入),OLED的SCL(PB15)和SDA(PB14)配置为推挽输出,通过软件模拟I2C时序。

HAL_ADC_MspInit() — adc.c & OLED.h 宏定义
// ADC引脚配置: PA0 → 模拟输入
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

// OLED I2C引脚宏定义 (软件模拟I2C)
#define SCL_Port  GPIOB
#define SCL_Pin   GPIO_PIN_15        // PB15 → OLED SCL
#define SDA_Port  GPIOB
#define SDA_Pin   GPIO_PIN_14        // PB14 → OLED SDA

4.4 主循环逻辑 — 数据采集与浊度计算

主循环以10ms为间隔采样ADC值,累积50次(共500ms)后进行滑动平均计算。先求平均ADC值,再转换为电压,最后用标定公式计算NTU浊度值,并在OLED上居中显示。

while(1) — main.c
while (1)
{
    static uint32_t Total;
    static uint8_t CNT;
    float Voltage;             // 实时电压

    if(HAL_GetTick() - Time_Now >= 10)
    {
        // 单通道数据获取
        HAL_ADC_Start(&hadc1);
        if(HAL_ADC_PollForConversion(&hadc1, 999) == HAL_OK)
            ad_val = HAL_ADC_GetValue(&hadc1);
        HAL_ADC_Stop(&hadc1);

        // 滑动平均滤波
        if(CNT < 50)
        {
            Total += ad_val;
            CNT++;
        }
        else                    // 500ms计算一次浊度
        {
            // 1. ADC均值 → 电压 (12位ADC, 参考电压3.3V)
            Voltage = (Total/50.0) / 4095.0 * 3.3;

            // 2. 电压 → NTU浊度值 (标定公式)
            NTU = 2174 * (0.43 - Voltage);
            if(NTU < 0) NTU = 0;

            CNT = 0;
            Total = 0;

            // 3. OLED显示浊度值
            OLED_Clear();
            OLED_CenterPrintf(24, "NTU:%.1f", NTU);
            OLED_Update();
        }

        Time_Now = HAL_GetTick();
    }
}

4.5 数据计算公式解析

电压转换公式:

Voltage = (Total / 50.0) / 4095.0 × 3.3

Total为50次ADC采样的累加值,除以50得到平均ADC值(0~4095),再除以满量程4095并乘以参考电压3.3V,得到实际模拟电压。

浊度计算公式:

NTU = 2174 × (0.43 - Voltage)

该公式由传感器标定得到。电压越高(水质越清澈),(0.43 - Voltage)越小,NTU值越低;电压越低(水质越浑浊),NTU值越高。当计算结果为负时,说明电压超过0.43V(极清水),强制置0。

注意:STM32F103的ADC参考电压为3.3V,采集电压范围为0~3.3V,对应ADC原始值0~4095。当传感器输出电压在0.43V~3.3V范围内时,NTU计算结果均为负值并截断为0,即水质被视为清澈。实际有效的浊度测量区间为0~0.43V,对应NTU 0~935。转换板上的电位器可用于校准,使清水时输出电压略高于0.43V、浊水时输出电压接近0V,从而充分利用ADC量程。

4.6 浊度状态对照表

NTU值 水质状态
0 极清水
0 清水(临界值)
~174 轻微浑浊
~391 浑浊
~609 较浑浊
~935 极浑浊

注:STM32 ADC参考电压为3.3V,采集电压范围为0~3.3V。当电压 > 0.43V 时,NTU计算结果为负值,程序中通过 if(NTU < 0) NTU = 0 截断为0。因此实际有效的浊度测量区间为 0~0.43V,对应NTU 0~935。

05程序流程图

开始 HAL_Init() 硬件初始化 SystemClock_Config() 72MHz MX_GPIO_Init / MX_ADC1_Init OLED_Init() OLED初始化 while(1) 主循环 HAL_GetTick() - Time_Now ≥ 10? 否 是 HAL_ADC_Start / GetValue 启动ADC采集, 读取ad_val CNT < 50? 是 Total += ad_val CNT++ 否 Voltage = Total/50/4095*3.3 NTU = 2174*(0.43-V) Time_Now = HAL_GetTick()

06交互式动画演示

20%

浊度传感器模拟

组件说明

左侧红外LED发射光束穿过液体,右侧光电接收管检测穿透光。液体中悬浮颗粒越多,散射越强,穿透光越弱,输出电压越低,浊度(NTU)越高。转换板上的电位器可校准输出基准电压。拖动上方滑块可手动调节浊度浓度。

OLED显示 & 数据仪表

OLED 0.96" SSD1306
NTU:0.0
浊度值
0.0
NTU
水质状态
清澈
 

运行机制

模拟STM32主循环:每10ms采样ADC,累积50次(500ms)后取平均,计算NTU值并更新OLED显示。滑块调节浊度时,液体颗粒密度、光束散射和NTU值实时联动变化。