
简介这是一份面向电子信息、自动化及测控类专业学生的毕业设计参考资料围绕基于STM32的风速风向测量仪展开适合正在准备嵌入式课程设计或毕业设计、需要完整方案论证与软硬件实现思路的读者。资源为1个doc文档压缩包约681KB正文含摘要、目录、章节论述与附录等完整论文结构可直接作为撰写与排版参考。内容从方案比较入手先分析传统数字电路方案与单片机方案在实施难度、成本与开发周期上的差异进而确定以STM32为核心控制器硬件部分覆盖电源设计、STM32选型与引脚特性、显示模块以及风速仪、风向仪与光电编码器电路软件部分给出风向检测、风速检测与主程序流程最后以测试方法与结果分析收尾。读者可据此梳理系统框架论证逻辑、传感器数据采集与滤波处理思路并参考其章节组织方式完善自己的论文框架。目前已有181人学习下载。1. 从选题到落地风速风向测量仪到底要解决什么风杯在转风向标在摆这两路信号一路是频率一路是电压本质上都不是风速和风向只是两个需要被标定过的电信号。基于 STM32 的风速风向测量仪要干的事就是用一颗 MCU 同时把这两路信号变成能上报、能显示、能存进论文数据表的物理量并且在 0.5 m/s 的微风和 30 m/s 的强风之间都保持可接受的精度。这个题目之所以常年出现在毕业设计清单里是因为它把 STM32 的定时器输入捕获、ADC 多通道 DMA、串口通信、滤波算法全串了一遍硬件不复杂但每个环节都有真实的坑低频段测频分辨率不够、风向标电位器存在死区、风杯启动有阈值、温漂会让整条标定曲线平移。搞清这些才算是把测量仪做出来了而不是把传感器接上跑通一个 demo。2. 传感器与 STM32 资源分配先定方案再画板方案定型这一步决定了后面 80% 的工作量。风速和风向各选一种传感原理再把它们对 MCU 的资源需求列清楚板子画出来基本就不会返工。2.1 风速测量的三条路线与取舍风杯式含三杯、四杯是绝大多数教学项目和气象站的选择风杯带动同轴码盘或磁钢输出频率与风速近似线性。优点是便宜、皮实、接口简单缺点是启动风速通常在 0.30.8 m/s低于这个值它根本不转而且转动惯量让它对突变风的响应有滞后。超声波时差法是另一条路一对换能器对射顺风与逆风方向的传播时间差正比于风速分量。没有机械磨损、无启动阈值、能测到 0 m/s但换能器驱动需要高压脉冲、回波检测对阈值和温度补偿敏感成本高出几倍。热线式响应最快适合湍流测量但探头娇贵且需要恒温控制电路。方案输出形式量程启动阈值接口复杂度适合场景风杯 霍尔/干簧管脉冲频率0.545 m/s0.30.8 m/s低1 个定时器通道教学、气象站风杯 光电码盘脉冲频率0.360 m/s0.3 m/s低1 个定时器通道高精度计数超声波时差时间差/串口060 m/s无高高压驱动 高速采样无机械磨损场合热线恒温桥路电压030 m/s无中高模拟闭环湍流、快速响应我的建议是如果目标是做出一台可复现、可标定、论文数据能自圆其说的仪器选风杯脉冲方案把精力花在测频算法和标定上这两处的技术含量足够撑起整篇论文。超声波方案留给有模拟前端调试经验的人。2.2 风向测量的两类器件电位器与磁编码器风向标的位置检测主流有两类。第一类是环形电位器常见型号是 0360° 输出、5 kΩ 或 10 kΩ风向标轴带动滑臂输出电压与角度近似线性STM32 用一路 ADC 就能读。它的死区在 0° 附近滑臂跨过缺口时电压会跳变这是必须处理的。第二类是磁编码器比如 AS5600 这类 12 位 I²C 器件把磁铁装在转轴上直接读出 04095 对应 0360°。没有接触磨损、没有死区代价是多一路 I²C 和一颗磁铁的对中安装。器件接口分辨率死区长期可靠性备注环形电位器ADC 单通道取决于 ADC理论 12 位约 38°有磨损便宜需软件补死区AS5600 类磁编码I²C12 位0.088°无无接触需磁铁对中成本略高如果只是做一台样机电位器方案够用如果论文里要谈长期免维护磁编码器是更好的论据。2.3 STM32 引脚与定时器资源分配表以最常见的 STM32F103C8T6 为例下面这张分配表可以直接照着画原理图。功能外设引脚说明风速脉冲输入TIM2_CH1 输入捕获PA0上升沿捕获接传感器脉冲输出1 Hz 门闸定时TIM6 基本定时器内部用于 1 s 计数窗口风向标电压ADC1_IN0PA1电位器滑动端前端加分压与 RC电池/电源监测ADC1_IN1PA2可选用于低电压告警OLED 显示I²C1PB6/PB70.96 寸屏现场读数上位机通信USART1PA9/PA10115200 8N1上报 CSV 行调试口SWDPA13/PA14保留别复用分配时有一个原则风速脉冲一定要落在带输入捕获的定时器通道上不要图省事用外部中断 EXTI 去数脉冲。EXTI 在高频1 kHz下会被中断开销拖垮而且没有硬件滤波和预分频抖动会直接变成计数误差。2.4 供电与前端调理电路风杯传感器多为 524 V 供电的开集输出STM32 是 3.3 V 系统中间必须做电平处理。常见做法是 10 kΩ 上拉到 3.3 V加一级 RC 低通1 kΩ 100 nF截止约 1.6 kHz滤掉长线引入的尖峰再用施密特触发门整形。风向标电位器直接接 3.3 V 激励滑动端经过 10 kΩ 100 nF 进 ADC这一级 RC 很关键——没有它ADC 采样保持电容充放电会在读数里留下几十个 LSB 的噪声。注意风杯和风向标如果共地长距离走线地线上的压降会把脉冲边沿抬高出现多计一个脉冲的现象。传感器侧和 MCU 侧分别就近接地脉冲线用地线绞合屏蔽。3. 测频与采样STM32 端的两路信号怎么变成数硬件接好之后软件要做两件事把脉冲数成频率把电压读成角度。这两件事各自有一套什么时候该换算法的判断。3.1 输入捕获测频法门时间 1 s 的配置与代码风杯输出的是方波中心频率大致在 0200 Hz 区间对应 030 m/s。最直观的做法是定门时间计脉冲数也叫测频法开一个 1 s 的定时窗口数这个窗口里来了几个上升沿计数就是频率。CubeMX 里把 TIM2 配成输入捕获预分频器给 72-172 MHz → 1 MHz 计数时钟捕获边沿选上升沿开启捕获中断TIM6 配成 1 Hz 更新中断当作门闸。/* TIM2_CH1 输入捕获每个上升沿进一次中断只做计数 */ volatile uint32_t g_pulse_cnt 0; /* 门时间内的脉冲个数 */ volatile uint32_t g_freq_hz 0; /* 换算后的频率Hz */ void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if (htim-Channel HAL_TIM_ACTIVE_CHANNEL_1) { /* 读一次 CCR 清掉捕获标志值本身在测频法里用不到 */ (void)HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); g_pulse_cnt; /* 1 s 内累加溢出前最多 200 次 */ } } /* TIM6 更新中断1 Hz 门闸关窗、结算、清零 */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim-Instance TIM6) { g_freq_hz g_pulse_cnt; /* 门时间正好 1 s计数即 Hz */ g_pulse_cnt 0; /* 立刻清零避免跨窗口串数 */ } }逻辑说明捕获中断里刻意不做浮点运算、不打印、不换算只做一次自增保证高频下中断执行时间可控。真正的换算放到 1 Hz 的低优先级回调里做两者解耦。参数说明门时间取 1 s 是精度与刷新率的折中——窗口越长频率分辨率越高±1 Hz 相对误差越小但输出更新越慢。风杯在 5 m/s 时大约输出 45 Hz 左右1 s 窗口的相对误差约 2%对气象级应用可以接受如果要求更高把门时间改成 5 s代价是响应变慢。3.2 低频段的测周法什么时候必须换算法测频法在低频段会露馅。风速 0.5 m/s 时风杯可能只输出 25 Hz1 s 窗口数下 2 个脉冲读数是 2 Hz下一秒可能是 3 Hz量化噪声达到 ±50%。这种情况下要换成测周法测出相邻两个上升沿之间的时间间隔 T风速正比于 1/T。/* 测周法记录相邻两次捕获的时间戳求周期 */ volatile uint32_t g_ts_prev 0, g_ts_now 0, g_period_us 0; void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if (htim-Channel HAL_TIM_ACTIVE_CHANNEL_1) { uint32_t ccr HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); /* 计数器是 16 位、1 MHz溢出需在 TIM2 更新中断里累加高位 */ g_ts_now (g_overflow_hi 16) | ccr; g_period_us g_ts_now - g_ts_prev; /* 单位微秒 */ g_ts_prev g_ts_now; } } /* 频率 1e6 / g_period_us10 Hz 时切回测频法 */逻辑说明测周法把量化误差从±1 个脉冲转移到±1 个计数时钟1 MHz 时基下测 5 Hz 信号的周期为 200000 μs误差 1/200000几乎可以忽略。代价是需要处理定时器溢出且高频时周期太短反而不划算。工程上的常见做法是分段频率低于 10 Hz 走测周法高于 10 Hz 走测频法两者在交界处用同样的标定曲线避免切换时读数跳变。3.3 ADC 多通道 DMA 采风向标与中值滤波风向标一路用 ADC1 的规则组扫描模式配合 DMA 循环搬运CPU 完全不参与采样。CubeMX 里开 ADC1 的 IN0 和 IN1扫描模式使能连续转换使能DMA 请求设为循环。#define ADC_CH_NUM 2 uint16_t adc_buf[ADC_CH_NUM]; /* [0]风向标, [1]电源监测 */ /* 启动一次DMA 会一直循环刷新 adc_buf */ HAL_ADC_Start_DMA(hadc1, (uint32_t *)adc_buf, ADC_CH_NUM); /* 中值滤波三点取中专治电位器滑动端的孤立跳变 */ static uint16_t median3(uint16_t a, uint16_t b, uint16_t c) { if (a b) { uint16_t t a; a b; b t; } if (b c) { uint16_t t b; b c; c t; } if (a b) { uint16_t t a; a b; b t; } return b; /* 排序后中间那个 */ } /* 每 100 ms 取一次数三次连续采样做中值再送一级滑动平均 */ float read_wind_dir_raw(void) { uint16_t s1 adc_buf[0]; HAL_Delay(1); uint16_t s2 adc_buf[0]; HAL_Delay(1); uint16_t s3 adc_buf[0]; uint16_t med median3(s1, s2, s3); return (float)med; /* 原始码值换算在下一节 */ }逻辑说明中值滤波放在滑动平均之前。原因是电位器滑臂在振动环境下会产生单点跳变比如从 1200 突然跳到 3900 再跳回来均值滤波会把这种野值摊到好几个输出里中值滤波则能整点剔除。顺序颠倒效果差很多。参数说明采样间隔 1 ms 是为了让三次采样落在不同的 ADC 转换周期上避免采到同一个值。滑动平均窗口 N 建议取 816对应时间常数约 0.81.6 s风速风向的物理变化远慢于这个尺度不会引入可感知的滞后。3.4 频率转风速、电压转方位角两路原始值到手后换算成物理量。风速用线性式风向用分段查表。/* 风杯v b k * f 系数来自标定示例值必须自测 */ #define WIND_K 0.0877f #define WIND_B 0.1000f float freq_to_speed(float f_hz) { if (f_hz 1.0f) return 0.0f; /* 低于启动阈值直接判 0 */ return WIND_B WIND_K * f_hz; } /* 电位器0..4095 码值映射到 0..360 度含死区处理 */ float raw_to_dir_deg(uint16_t raw, float *last_valid) { float deg (float)raw * 360.0f / 4095.0f; /* 电位器在 0 度附近有缺口读数会从 358 跳到 2落在死区就保持上次有效值 */ if (deg 352.0f || deg 8.0f) { if (last_valid ! NULL) deg *last_valid; } else { if (last_valid ! NULL) *last_valid deg; } return deg; }逻辑说明风速那行if (f_hz 1.0f) return 0.0f是必要的。风杯静止时偶尔会因风抖动输出一两个脉冲不设阈值会出现无风报 0.2 m/s的假数据。死区保持策略比线性插值更简单也更稳因为死区里的电压本来就不代表角度。参数说明WIND_K和WIND_B只能是示例必须用自己的传感器实测。死区宽度 8° 是常见值具体看器件手册改这两个常量就能适配。方位角到 16 方位的换算用中心角加偏移量整除方位中心角判定区间方位中心角判定区间N0°348.7511.25S180°168.75191.25NNE22.5°11.2533.75SSW202.5°191.25213.75NE45°33.7556.25SW225°213.75236.25ENE67.5°56.2578.75WSW247.5°236.25258.75E90°78.75101.25W270°258.75281.25ESE112.5°101.25123.75WNW292.5°281.25303.75SE135°123.75146.25NW315°303.75326.25SSE157.5°146.25168.75NNW337.5°326.25348.75用index (int)((deg 11.25f) / 22.5f) % 16;一行就能落表比十六个 if 干净也方便论文里写成公式。4. 标定、滤波与误差分析论文数据章节怎么站得住做完上面两步示波器上能看到合理的读数但读数不等于测量值。论文里真正决定分数的是标定过程和数据可信度这一段必须有据可查。4.1 风洞/台架标定与最小二乘拟合没有风洞的情况下可以用标准风速仪做比对把自制的测量仪和一把经过校准的手持风速仪放在同一风源下工业风扇、可变风道都行改变风源档位等读数稳定后同时记录两边的值。每组至少记 30 秒的均值采 710 个档位覆盖量程。拿到频率—风速样本对之后做一次最小二乘线性拟合把斜率截距写进固件、也写进论文。import numpy as np # 风洞/比对实验采到的样本f 为自测频率v 为标准风速仪读数 f np.array([0.0, 5.2, 10.4, 20.1, 30.3, 40.2, 50.5]) v np.array([0.13, 0.55, 0.98, 1.86, 2.74, 3.62, 4.48]) A np.vstack([f, np.ones_like(f)]).T # 模型 v k*f b k, b np.linalg.lstsq(A, v, rcondNone)[0] resid v - (k * f b) # 残差 ss_res float(np.sum(resid ** 2)) ss_tot float(np.sum((v - v.mean()) ** 2)) print(fk {k:.5f} b {b:.4f}) print(fR^2 {1 - ss_res / ss_tot:.4f}) print(f最大残差 {np.abs(resid).max():.4f} m/s)逻辑说明用lstsq而不是手算公式是为了后面换二阶模型时只改A的构造。如果残差随风速呈明显弯曲两端偏大、中间偏小说明线性模型不够改成v a*f^2 b*f c把A换成[f**2, f, ones]即可np.linalg.lstsq本身不用动。参数说明R^2是论文里必须给的拟合优度低于 0.995 就要考虑二阶模型或分段标定。最大残差比平均残差更能说明问题——论文评审更关心最坏情况。同样的流程搬到风向给定标准角度用角度盘或电子罗盘记录每个角度下的 ADC 码值得到码值—角度映射表。如果电位器线性度差直接把这个表烧进固件做查表插值比强行用线性公式准得多。4.2 滤波参数怎么定滤波参数不是随手填的每个都要能说出为什么是这个值。环节参数取值依据调大/调小的后果风速门时间1 s5 m/s 时相对误差约 2%调大更准但更慢调小抖动明显风速滑动平均N 51 Hz时间常数 5 s远小于天气尺度变化调大更平滑阵风被抹平风向中值窗口3 点100 ms消除滑臂单点跳变调大对连续抖动无效风向滑动平均N 16100 ms时间常数 1.6 s调大滞后增加调小噪声留存死区保持宽度8°器件手册死区范围调大角度分辨率下降一个常被忽略的点滤波带来的滞后在论文里要量化写出来比如滑动平均 N 16 引入的阶跃响应 90% 上升时间约 3.6 s。评审很可能会问你的实时性如何答不上来就尴尬了。4.3 误差来源清单与余弦误差补偿论文的误差分析章节把下面几项逐条列出来配上实测数据比空谈存在一定误差强得多。第一是启动阈值误差。风杯低于启动风速不转这段区间只能报 0属于系统性的死区误差写清具体数值比如 0.4 m/s。第二是风向的余弦误差。风向标在不同风速下的指向会偏离真实风向偏离量随风速变化、随风向角呈余弦规律这是风向测量的主要误差源。改进办法是做一次风洞角度扫描把每个角度的偏差做成补偿表固件里查表修正。第三是温度漂移。电位器的阻值、ADC 的参考电压都随温度变化整条曲线会平移。条件允许时用外部基准源如 REF3033替代 MCU 内部参考或者把温度传感器读数和风向码值一起记录做一阶温度补偿。第四是安装误差。风向标的 0° 标记必须和仪器外壳的正北标记对齐偏了几度全量程就偏几度这是最容易被忽略也最容易验证的一项。5. 从能跑的 demo 到经得起追问的成品读数稳定之后剩下的工作往往决定这台仪器是能演示还是能用。先说上报与掉电。串口上报别用阻塞式HAL_UART_Transmit115200 下发 3 行 CSV 会占掉几毫秒期间捕获中断还在来容易丢脉冲。改成 DMA 加空闲中断的双缓冲发送或者干脆在主循环里攒够一行再发。同时开独立看门狗喂狗放在主循环一旦 ADC 的 DMA 卡死或者 I²C 显示挂起两秒内自动复位重启现场无人值守时这一步能救命。再说硬件上容易翻车的地方。风速脉冲线如果和 OLED 的 I²C 走同一个线束边沿耦合会让脉冲数偶尔多一两个把两路分开走、脉冲线加屏蔽并在 MCU 侧就近加 100 nF 到地实测能压下去。ADC 的地线要单独回到 MCU 的 AGND 引脚不要和传感器的功率地共用一段走线否则读数会随风杯转动同步跳动这种跟着转的噪声一眼就能看出来。关于论文本身有几个具体做法值得照搬。一是把每一次改参数前后的实测数据都存下来答辩时被问为什么用 N 16 不用 N 32直接翻出两组曲线对比比口头解释有说服力。二是系统框图和软件流程图里把测频法和测周法的切换点画清楚这是整个设计里最有技术含量的判断不要埋在代码注释里。三是误差分析章节的每一项都配一张实测散点图哪怕是手绘拍照贴上去的。最后给一个验证整机是否可信的小技巧把仪器静置在无风环境里连续跑 2 小时记录风速和风向的输出序列风速应该稳定在 0 且不出现偶发的 0.10.3 m/s 假读数风向的波动范围应该在一两个方位以内。如果静置时风向就在满量程乱跳问题几乎一定出在电位器采样前端——先查 ADC 参考电压稳不稳再查 RC 的时间常数是否太小最后才怀疑滤波参数。本文还有配套的精品资源点击获取