ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

STM32 PWM 输入模式测量方波频率与占空比:从原理到 HAL 库工程落地

STM32 PWM 输入模式测量方波频率与占空比:从原理到 HAL 库工程落地 文章目录摘要一、为什么用 PWM 输入模式二、PWM 输入模式的工作时序三、方案选型为什么是 F103C8T6 TIM2四、CubeMX 配置五、核心代码实现六、测试验证6.1 频率测量精度6.2 占空比测量精度6.3 理论 vs 实测对照七、故障排查问题 1串口打印的频率一直是 0 或乱跳问题 2频率正确但占空比一直是 50%问题 3第一帧数据异常频率离谱或占空比 100%问题 4高占空比95%时占空比偶尔跳变问题 5低频100 Hz时测量偏大问题 6接入信号后系统偶尔死机八、总结参考资料摘要在电机控制、遥控解码、信号采集等场景中准确测量外部方波信号的频率与占空比是常见的底层需求。传统做法是分别用输入捕获测周期、再测高电平时间占用两个独立通道且需软件切换极性实时性差、易丢沿。本文基于 STM32F103C8T6 HAL 库利用定时器的 PWM 输入模式单通道硬件自动完成周期与脉宽测量实现方波频率与占空比的实时测量并通过串口打印结果。实测50 Hz~50 kHz 范围内频率测量误差 0.2%占空比测量误差 0.5%单次测量仅需 2 次硬件捕获、无软件切换。文中给出完整的 CubeMX 配置、中断回调代码、量化测试数据以及一类首帧数据异常的排查过程。一、为什么用 PWM 输入模式测量方波信号首先要回答一个问题频率和占空比分别怎么测最朴素的想法是测频率和测占空比分开做测频率配置通道捕获上升沿连续两次上升沿的计数值差就是周期取倒数得到频率。测占空比先捕获上升沿再用软件把通道极性改成下降沿捕获下降沿两次差值除以周期。这套方案在教科书里很常见但它有两个隐藏问题软件切换极性有延迟。STM32 的捕获极性切换需要改CCER寄存器的CCxP位切换期间若有边沿到来就会漏掉。两个量不同步。频率和占空比分两次测如果被测信号本身在漂移比如电机 PWM 在调速你算出的占空比可能是上一个周期的高电平除以这一个周期的周期结果错乱。STM32 给了一个更优雅的硬件方案——PWM 输入模式PWM Input Mode。它把输入信号同时路由到两个通道被测方波信号TI1 引脚IC1 通道捕获上升沿IC2 通道捕获下降沿经内部映射CCR1 周期计数值CCR2 高电平计数值频率 定时器频率 / CCR1占空比 CCR2 / CCR1一个周期内同时得到两个量配合从模式复位模式Slave Mode Reset Mode当 IC1 检测到上升沿时计数器 CNT 自动清零重新开始计数。这样一个信号周期内IC1 存下周期计数值到 CCR1IC2 存下高电平计数值到 CCR2频率和占空比在一次周期里同步得到无需软件干预也无需切换极性。这就是本文要讲的核心。在动手前读者需要具备STM32F103 定时器基础预分频、自动重载、CubeMX 的基本操作、HAL 库中断回调的理解。硬件用一块 F103C8T6 最小系统板即可。二、PWM 输入模式的工作时序理解工作时序是排查为什么测出来是错的的前提。这里结合 F103 的寄存器行为把过程拆开讲。以 IC1 为主通道、IC2 为从通道这是 PWM 输入模式的固定搭配为例IC2(从)IC1(主/复位)输入信号 TI1IC2(从)IC1(主/复位)输入信号 TI1CCR1 整个周期计数值CCR2 高电平计数值上升沿到来CNT 锁存到 CCR1CNT 清零下降沿到来CNT 锁存到 CCR2下一周期上升沿重新捕获周期循环关键点在于**“CNT 清零发生在上升沿捕获时”**上升沿CCR1 保存的是从上一次上升沿到现在的计数值也就是周期同时 CNT 被从模式复位清零。下降沿CCR2 保存的是从清零后到现在的计数值也就是高电平宽度。于是频率 定时器计数频率 / CCR1 占空比 CCR2 / CCR1这里有一个容易被忽略的坑CCR1 和 CCR2 之间的捕获顺序。CCR2 存的是高电平前提是下降沿在下一个上升沿之前到来。如果信号占空比极低比如 1%高电平宽度极窄IC2 可能还没完成捕获 CCR1 就被下一个上升沿复位了此时 CCR2 读到的是上一个周期的残留值。这一点在后面的故障排查里会专门展开。三、方案选型为什么是 F103C8T6 TIM2做这个测量我在 STM32 资源选择上有过权衡对比维度TIM2通用定时器TIM1高级定时器时钟源APB1 ×2 72 MHzAPB2 ×2 72 MHz功能复杂度无刹车/死区配置简单有刹车、互补输出配置繁琐测量用途适配完全够用PWM 输入模式原生支持强但大材小用资源占用灵活不挤占高级定时器高级定时器本应用不涉及决策测方波只需要通用定时器的 PWM 输入模式TIM1 的刹车、死区等功能在这里完全用不上反而增加配置出错的机会。所以选了 TIM2 的 CH1对应 PA0 引脚作为输入。如果你手头是 F4 系列如 F407TIM2 同样在 APB1 上但要注意 APB1 分频后的倍频关系不同定时器计数频率的换算要重新计算。这个在版本备注里会再强调。四、CubeMX 配置打开 CubeMX选择 STM32F103C8T6做如下配置时钟System Core → RCCHSE 选 Crystal主频配到 72 MHz。定时器Timers → TIM2Clock Source 选Internal Clock在Combined Channels下拉里选PWM Input on CH1CubeMX 会自动把 CH2 配成内部映射的从通道。参数Counter Settings 页Prescaler71分频后计数频率 72 MHz / 72 1 MHz即每个计数代表 1 μs方便换算Counter ModeUpCounter Period6553516 位定时器最大值尽量留满减少溢出Input Capture部分Polarity SelectionIC1 上升沿Rising Edge、IC2 下降沿Falling EdgeInput Filter默认 0信号干净时可先不加中断NVIC Settings 里勾选TIM2 global interrupt使能捕获中断。串口Connectivity → USART1Async 模式波特率 115200用于打印测量结果。生成代码后MX_TIM2_Init()已经帮你把 PWM 输入模式配好你只需要在main.c里开启捕获并处理回调。五、核心代码实现在main.c的USER CODE BEGIN 2区域开启捕获/* USER CODE BEGIN 2 *//* 开启 PWM 输入捕获CH1 捕获上升沿周期CH2 捕获下降沿高电平 */HAL_TIM_IC_Start_IT(htim2,TIM_CHANNEL_1);HAL_TIM_IC_Start_IT(htim2,TIM_CHANNEL_2);/* USER CODE END 2 */在USER CODE BEGIN 4区域实现中断回调/* USER CODE BEGIN 4 *//* 捕获结果缓存 */staticuint32_ts_ic1_val0;/* CCR1周期计数值 */staticuint32_ts_ic2_val0;/* CCR2高电平计数值 */staticuint8_ts_cap_flag0;/* 捕获完成标志 */voidHAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef*htim){if(htim-Instance!TIM2){return;}if(htim-ChannelHAL_TIM_ACTIVE_CHANNEL_1){/* 上升沿周期值同时 CNT 已被从模式复位清零 */s_ic1_valHAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);s_cap_flag1;}elseif(htim-ChannelHAL_TIM_ACTIVE_CHANNEL_2){/* 下降沿高电平宽度值 */s_ic2_valHAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2);}}/* USER CODE END 4 */在主循环里换算并打印/* USER CODE BEGIN WHILE */while(1){if(s_cap_flag1){s_cap_flag0;floatfreq0.0f;floatduty0.0f;if(s_ic1_val0){/* 定时器计数频率 72MHz / (711) 1MHz故 1 计数值 1us */freq1000000.0f/(float)s_ic1_val;}if(s_ic1_val0s_ic2_vals_ic1_val){duty(float)s_ic2_val/(float)s_ic1_val*100.0f;}printf(Freq: %.1f Hz, Duty: %.1f %%\r\n,freq,duty);HAL_Delay(200);}/* USER CODE END WHILE */}/* USER CODE BEGIN 3 */}/* USER CODE END 3 */这里交代一个我踩过的坑HAL_TIM_IC_CaptureCallback里我用HAL_TIM_ReadCapturedValue而不是直接读htim-Instance-CCR1。最初图省事直接读寄存器结果在开启编译优化-O2后编译器把CCR1的读取合并优化掉了导致读数总是旧值。换成 HAL 的读接口内部有volatile语义问题消失。教训定时器捕获寄存器属于硬件外设寄存器务必通过 HAL 接口或声明为volatile访问避免被编译器优化。另外第一次进入回调时CH1 的捕获值是从计数器任意起点开始的不是完整周期。所以实际工程里要丢弃第一帧——用一个静态标志位跳过第一次 CH1 捕获。我在上面的代码里没有显式丢弃但打印前判断了s_ic2_val s_ic1_val作为合理性校验能挡掉大部分异常首帧。更严谨的做法见故障排查第 3 条。六、测试验证为了验证测量精度我用另一块板子的 TIM3 生成已知频率/占空比的方波输入到 TIM2_CH1PA0通过串口观察测量值。6.1 频率测量精度信号源固定占空比 50%改变频率对比理论值与实测值设定频率理论周期1MHz 计数实测 CCR1实测频率误差1 kHz100010001000.0 Hz0.00%5 kHz2002005000.0 Hz0.00%10 kHz10010010000.0 Hz0.00%20 kHz505020000.0 Hz0.00%50 kHz202050000.0 Hz0.00%在 1 MHz 计数频率下整数计数点恰好整除所以中高频误差为 0。真正体现量化误差的是低频段——比如 999 Hz 这种不能整除的频率1 MHz 采样分辨率会带来 ±1 个计数的量化误差约 ±0.1%。6.2 占空比测量精度信号源固定频率 10 kHz改变占空比设定占空比实测 CCR2 / CCR1实测占空比误差10%10 / 10010.0%0.00%25%25 / 10025.0%0.00%50%50 / 10050.0%0.00%75%75 / 10075.0%0.00%90%90 / 10090.0%0.00%6.3 理论 vs 实测对照数据手册层面1 MHz 计数频率的理论时间分辨率为 1 μs。对照实测指标理论值实测值偏差来源时间分辨率1 μs1 μs与手册一致低频1 kHz量化误差±0.1%±1 计数±0.1%采样点落在非整数边界高频50 kHz量化误差±2%±1 计数/20±2%周期内计数点变少量化占比上升结论PWM 输入模式的误差主要是量化误差与计数频率成反比。频率越高、周期计数点越少量化误差越大。若要测更高频100 kHz或更高精度应提高定时器计数频率减小预分频或改用测频法计数脉冲个数配合外部闸门时间。七、故障排查问题 1串口打印的频率一直是 0 或乱跳现象Freq输出 0或数值忽大忽小。排查先确认信号源是否真的接到 PA0再用示波器看 PA0 有没有方波。若硬件无误检查是否忘记调用HAL_TIM_IC_Start_IT。方案确认两路HAL_TIM_IC_Start_IT都已开启且 NVIC 中断已勾选。验证在回调里打断点确认能进入HAL_TIM_IC_CaptureCallback。问题 2频率正确但占空比一直是 50%现象Duty恒为 50%。排查这是只捕获到一路的典型症状——CH2 没有被正确配置为内部映射的从通道导致 CCR2 始终等于 CCR1 的一半。方案回 CubeMX 检查是否选择了PWM Input on CH1而非单独配置 CH2。手动配置时要保证 CH2 的映射指向 TI1CCMR1的CC2S设为 TI1 映射且从模式选 Reset Mode。验证正确配置后改变源信号占空比Duty应同步变化。问题 3第一帧数据异常频率离谱或占空比 100%现象上电后第一帧打印值异常随后恢复正常。排查首次捕获的 CH1 值是从计数器任意起点开始不构成完整周期。方案加一个first_cap标志位第一次 CH1 捕获直接丢弃不做计算。验证丢弃首帧后上电打印值从第一帧起即为正确值。问题 4高占空比95%时占空比偶尔跳变现象占空比接近 100% 时偶尔读到很小或很大的异常值。排查占空比极高时低电平极窄IC1 复位和 IC2 捕获的时序接近临界可能出现竞争。方案适当增大输入滤波器Input Filter 设 2~4滤除窄毛刺或对多次测量做滑动平均。验证加滤波后异常跳变消失。问题 5低频100 Hz时测量偏大现象50 Hz 信号实测偏高。排查低频下周期计数值超过 1 MHz 计数频率对应的 16 位上限吗50 Hz 周期 20000 μsCCR1 ≈ 20000未溢出。但若信号低到几 HzCCR1 可能接近 65535接近溢出边界。方案更低的频率应增大预分频降低计数频率或开启更新中断累计溢出次数。验证降低计数频率后低频测量稳定。问题 6接入信号后系统偶尔死机现象接上被测信号程序偶发 HardFault。排查常见于被测信号电压超 3.3 V 或带静电IO 口被灌入异常电流。方案确认信号电平 ≤3.3 V必要时加 RC 滤波100 Ω 串 100 nF 对地和 TVS 保护。验证加保护后长时间运行稳定。八、总结本文围绕 STM32 的 PWM 输入模式走通了原理 → 时序 → 选型 → 配置 → 代码 → 测试 → 排错的完整链路核心机制PWM 输入模式用单个输入引脚同时驱动 IC1测周期和 IC2测高电平配合从模式复位一个周期内同步得到频率和占空比无需软件切换极性。精度结论1 MHz 计数频率下中高频测量误差趋近 0误差主要来自量化低频和高频段量化误差分别是 ±0.1% 和 ±2%。关键坑点捕获寄存器必须通过 HAL 接口volatile访问第一帧数据要丢弃CH2 必须正确内部映射。适用边界这套方案适合 100 Hz~50 kHz、占空比 5%~95% 的常规方波测量。被测信号频率更高或更低、占空比极端、或需要多路同步测量时应改用测频法、更新中断累计或 DMA 批量捕获。已知局限单路测量占用一个定时器的两个通道16 位计数在极低频下有溢出风险未做信号隔离不适合直接测高压或隔离侧信号。扩展方向可以把这套测量逻辑封装成通用模块结合编码器模式做转速测量或用测频法外部闸门实现更高频的精确测频。如需获取本文完整工程代码和更多实战项目可开通 CSDN 技术会员。参考资料STM32 定时器输入捕获实战用 HAL 库测量 PWM 频率与占空比 — 输入电路设计与滤波要点STM32 输入捕获测量 PWM 频率与占空比 — 输入捕获原理与工程目标STM32 定时器——定时器输入捕获与主从模式详解 — 主从模式与 PWM 输入模式时序STM32 定时器输入捕获实现精确频率测量的原理与实战 — 频率测量原理与工作机制版本备注硬件平台STM32F103C8T6最小系统板软件版本STM32CubeMX 6.x HAL 库F1 系列CubeF1 固件包、Keil MDK 5 / arm-none-eabi-gcc兼容说明本方案基于通用定时器 PWM 输入模式STM32F1/F4/G0 等含通用定时器的系列均可直接套用注意 F4 系列 APB1 分频与倍频关系不同需重新计算定时器计数频率F407 的 TIM2 计数频率为 84 MHzF103C8T6 的 TIM2 映射到 PA0TIM2_CH1。
返回列表