三杯式风速传感器

STM32F103C8T6 · HAL库开发 · ADC模拟采集

工作电压
3.3V ~ 5V
通信方式
ADC模拟量
采集精度
12-bit
更新周期
500ms

01传感器原理与功能

1.1 工作原理

三杯式风速传感器由三个半球形风杯组成,以120°等分安装在垂直旋转轴上。当风吹过时,由于风杯的凹面和凸面受到的风阻力不同(凹面阻力远大于凸面),产生扭矩差驱动转轴旋转。风杯的转速与风速呈线性正比关系。

传感器内部集成了信号转换电路,将转轴的机械旋转转换为模拟电压信号输出。风速越大,转速越快,输出电压越高。STM32通过ADC采集该模拟电压,经过公式换算即可得到实际风速值(m/s)。

🌀

风速检测

通过三杯旋转结构,将风速转化为转速,再经内部电路输出与风速成正比的模拟电压信号,实现实时风速测量。

⚡

模拟量输出

AO引脚输出连续变化的模拟电压,STM32的12位ADC采集后转换为0~4095的数字量,精度高、响应快。

📊

数据计算

ADC采集值经标定公式换算为风速值,支持浮点运算,结果以m/s为单位显示在OLED屏幕上。

🛠

实时显示

配合0.96寸OLED显示屏,每500ms刷新一次风速数据,直观展示当前环境风速状态。

1.3 引脚定义

引脚名称功能STM32连接
1AO模拟电压输出(风速信号)PA0 (ADC1_IN0)
2GND电源地GND

02模块外观展示

03原理图与PCB封装

原理图
PCB封装

PA0连接传感器AO模拟输出,ADC1通道0采集风速模拟电压信号

04程序分析

4.1 系统时钟配置

使用外部高速晶振(HSE 8MHz),通过PLL倍频9倍得到72MHz系统主频。ADC时钟由PCLK2(72MHz)8分频得到9MHz,满足ADC最高14MHz的时钟要求。FLASH等待周期设为2个。

Core/Src/main.c — SystemClock_Config()
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

    /* HSE 8MHz + PLLx9 = 72MHz */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
        Error_Handler();

    /* SYSCLK=72MHz, AHB=72MHz, APB1=36MHz, APB2=72MHz */
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
        Error_Handler();

    /* ADC时钟 = PCLK2/8 = 72MHz/8 = 9MHz */
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
    PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV8;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
        Error_Handler();
}

4.2 ADC1初始化配置

配置ADC1通道0(PA0引脚),12位分辨率(0~4095),单次转换模式,软件触发启动。数据右对齐,采样时间239.5个ADC时钟周期(约26.6μs),确保采样精度。PA0配置为模拟输入模式,无上下拉电阻。

Core/Src/adc.c — MX_ADC1_Init()
void MX_ADC1_Init(void)
{
    ADC_ChannelConfTypeDef sConfig = {0};

    hadc1.Instance = ADC1;
    hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;          // 非扫描模式
    hadc1.Init.ContinuousConvMode = DISABLE;              // 单次转换
    hadc1.Init.DiscontinuousConvMode = DISABLE;           // 禁用间断模式
    hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;     // 软件触发
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;           // 数据右对齐
    hadc1.Init.NbrOfConversion = 1;                    // 1个转换通道
    if (HAL_ADC_Init(&hadc1) != HAL_OK)
        Error_Handler();

    sConfig.Channel = ADC_CHANNEL_0;                      // 通道0 = PA0
    sConfig.Rank = ADC_REGULAR_RANK_1;                    // 第1转换序列
    sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;  // 239.5周期采样
    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
        Error_Handler();
}

/* ADC1底层初始化 — PA0配置为模拟输入 */
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if(adcHandle->Instance == ADC1)
    {
        __HAL_RCC_ADC1_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE();
        /* PA0-WKUP → ADC1_IN0 模拟输入 */
        GPIO_InitStruct.Pin = GPIO_PIN_0;
        GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    }
}

4.3 OLED显示驱动

使用0.96寸OLED显示屏(128×64),通过软件模拟I2C通信。SCL接PB15,SDA接PB14。支持居中字符串显示函数OLED_CenterPrintf(),风速数据以"风速:X.Xm/s"格式居中显示在第24行。

HAL/OLED/OLED.h — 引脚定义
/* OLED I2C引脚定义 */
#define SCL_Port  GPIOB
#define SCL_Pin   GPIO_PIN_15
#define SDA_Port  GPIOB
#define SDA_Pin   GPIO_PIN_14

/* 核心显示函数 */
void OLED_Init(void);                        // OLED初始化
void OLED_Clear(void);                       // 清屏
void OLED_Update(void);                      // 更新显存到屏幕
void OLED_CenterPrintf(int16_t Y, char *format, ...);  // 居中格式化打印

4.4 主程序与while(1)循环

系统初始化后进入主循环,使用HAL_GetTick()实现500ms定时采样。每次触发时启动ADC单次转换,读取12位ADC值并代入标定公式计算风速,最后在OLED上居中显示。非阻塞定时设计允许CPU在间隔期间执行其他任务。

Core/Src/main.c — main() 主循环
uint32_t Time_Now;
float air_speed;                    // 风速变量

int main(void)
{
    HAL_Init();                       // HAL库初始化
    SystemClock_Config();             // 系统时钟配置 72MHz
    MX_GPIO_Init();                   // GPIO初始化
    MX_ADC1_Init();                   // ADC1初始化
    OLED_Init();                      // OLED显示屏初始化

    while (1)
    {
        if(HAL_GetTick() - Time_Now >= 500)    // 500ms更新一次
        {
            // 单通道数据获取
            HAL_ADC_Start(&hadc1);
            if(HAL_ADC_PollForConversion(&hadc1, 999) == HAL_OK)
                air_speed = HAL_ADC_GetValue(&hadc1)/4095.0*33.0*2.7;  // 获取风速
            HAL_ADC_Stop(&hadc1);

            OLED_Clear();                                               // 清屏
            OLED_CenterPrintf(24, "风速:%.1fm/s", air_speed);      // 显示风速
            OLED_Update();                                             // 更新显示

            Time_Now = HAL_GetTick();                              // 更新时间戳
        }
    }
}

4.5 风速计算公式解析

ADC采集的12位原始值(0~4095)经以下公式转换为风速(m/s)。公式中各系数为传感器标定参数,根据传感器输出特性确定。

air_speed = ADC_Value/4095.0*33.0*2.7;

05程序流程图

开始 HAL_Init() — HAL库初始化 SystemClock_Config() — 时钟72MHz GPIO_Init / ADC1_Init / OLED_Init while(1) HAL_GetTick() - Time_Now ≥ 500? 否 是 HAL_ADC_Start() 启动转换 HAL_ADC_GetValue() 读取ADC值 air_speed = ADC/4095.0*33.0*2.7 OLED清屏/显示风速/更新 Time_Now = HAL_GetTick()

06交互式动画演示

三杯式风速传感器模拟

OLED显示与数据仪表

风速:0.0m/s
当前风速
0.0 m/s

动画说明

左侧为三杯式风速传感器的模拟实物,三个半球形风杯安装在120°等分的旋转臂上。拖动滑块模拟不同风速,风杯转速随风速增大而加快,同时左侧出现风流粒子动画。右侧实时显示OLED屏幕内容和风速仪表盘,所有数据均按照源程序中的标定公式 air_speed = ADC/4095.0*33.0*2.7 实时计算。