STM32F103C8T6 × HAL库 × ADC模拟采集 × OLED显示
HB-S33浊度传感器由转换板与奥松AZDM01浊度探头组成,采用光散射法检测液体浊度。
AZDM01探头内部含有一对红外LED发射管与光电接收管。发射管发出的红外光穿过被测液体,当液体中悬浮颗粒较少(浊度低)时,大部分光直接穿透,光电接收管收到的散射光少,输出电压较高;当液体中悬浮颗粒增多(浊度高)时,颗粒使光发生散射,接收管收到的散射光增强,但穿透光减弱,转换板输出的模拟电压随之降低。
转换板将探头信号调理为0~3.3V模拟电压输出,STM32通过ADC采集该电压,经滑动平均滤波后利用公式 NTU = 2174 × (0.43 - Voltage) 计算浊度值(单位:NTU),并在OLED屏幕上实时显示。
转换板上设有一个电位器(可调电阻),用于校准传感器的输出基准。通过旋转电位器旋钮,可以调节转换板的信号放大增益或比较阈值,使传感器在不同水质环境下输出合适的模拟电压范围。实际使用时,将探头置于标准浊度液中,调节电位器使输出电压与标定曲线匹配,即可完成校准。
利用红外LED发射光束穿透液体,通过光电接收管检测散射光强度,实现非接触式浊度测量
转换板输出0~3.3V模拟电压,电压越低浊度越高,可直接连接STM32 ADC引脚采集
转换板内置电位器,可调节输出基准电压,将探头置于标准浊度液中旋转校准,适配不同水质环境
通过标定公式将电压值转换为标准浊度单位NTU,量程0~1000 NTU,适用于水质监测
每10ms采样一次ADC,累积50次后取平均值计算,有效滤除噪声干扰,提高测量稳定性
| 引脚 | 名称 | 功能 | 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模拟输出。
总体视图 — 转换板与AZDM01浊度探头
转换板正面 — 信号调理电路
转换板背面 — 焊接面
外部高速晶振HSE = 8MHz,通过PLL倍频9倍得到系统时钟72MHz。ADC时钟由PCLK2(72MHz)8分频得到9MHz,满足STM32F103 ADC最大14MHz的限制。
// 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;
使用ADC1通道0(PA0引脚),12位分辨率(0~4095),右对齐,软件触发,单次转换模式。采样时间设为239.5个ADC时钟周期(约26.6μs),确保模拟信号稳定采集。
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); }
PA0配置为模拟模式(ADC输入),OLED的SCL(PB15)和SDA(PB14)配置为推挽输出,通过软件模拟I2C时序。
// 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
主循环以10ms为间隔采样ADC值,累积50次(共500ms)后进行滑动平均计算。先求平均ADC值,再转换为电压,最后用标定公式计算NTU浊度值,并在OLED上居中显示。
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(); } }
电压转换公式:
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量程。
| 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。
左侧红外LED发射光束穿过液体,右侧光电接收管检测穿透光。液体中悬浮颗粒越多,散射越强,穿透光越弱,输出电压越低,浊度(NTU)越高。转换板上的电位器可校准输出基准电压。拖动上方滑块可手动调节浊度浓度。
模拟STM32主循环:每10ms采样ADC,累积50次(500ms)后取平均,计算NTU值并更新OLED显示。滑块调节浊度时,液体颗粒密度、光束散射和NTU值实时联动变化。