You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32F411RE定时器计数值验证脉冲宽度及预分频器计算咨询

问题分析与解决方案

一、计数值波动大的根本原因

你当前代码的核心问题是在EXTI中断回调函数中做阻塞式while循环,这完全违背了中断服务函数的设计原则:

  • 中断服务函数必须尽可能短,不能做任何阻塞操作,否则会导致系统无法响应其他中断、甚至死机
  • 循环内重复读GPIO电平的方式,无法可靠捕获下降沿,还可能因为GPIO电平抖动、中断优先级冲突等导致计数错误

正确的做法是给输入引脚配置上升沿+下降沿双触发EXTI中断,分别在上升沿启动定时器并记录初始值,下降沿停止定时器并记录当前值,最后计算差值:

#include <stdint.h>

volatile uint32_t timerStartValue = 0;
volatile uint32_t timerEndValue = 0;
volatile uint32_t timeDifference = 0;
const uint32_t counterMaxValue = UINT32_MAX; // 用标准库宏更规范

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if(GPIO_Pin == GATE1_Pin)
    {
        if(HAL_GPIO_ReadPin(GATE1_GPIO_Port, GATE1_Pin) == GPIO_PIN_SET)
        {
            // 上升沿:清零计数器并启动定时器
            __HAL_TIM_SET_COUNTER(&htim2, 0);
            HAL_TIM_Base_Start(&htim2);
            timerStartValue = TIM2->CNT;
        }
        else
        {
            // 下降沿:停止定时器并计算差值
            HAL_TIM_Base_Stop(&htim2);
            timerEndValue = TIM2->CNT;
            
            // 处理计数器溢出与正常情况的差值计算
            if(timerEndValue >= timerStartValue)
            {
                timeDifference = timerEndValue - timerStartValue;
            }
            else
            {
                timeDifference = counterMaxValue - timerStartValue + timerEndValue + 1;
            }
        }
    }
}

二、验证计数值与示波器测量值的匹配方法

要验证计数值是否准确,需先明确定时器的计数时钟周期,核心公式如下:

计数时钟频率 = APB1时钟频率 / (预分频器值 + 1)
计数周期 = 1 / 计数时钟频率
实际脉冲宽度 = timeDifference × 计数周期

以你当前配置为例:

  • APB1时钟=80MHz,预分频器=39999
  • 计数时钟频率=80MHz/(39999+1)=2kHz
  • 计数周期=1/2kHz=0.5ms
  • 示波器测量的4.16ms脉冲,对应的理论计数值=4.16ms / 0.5ms≈8(误差±1个计数周期为正常范围)

你之前得到的15764、61454等数值明显不符合,也印证了原代码逻辑的错误。

验证步骤:

  1. 用示波器测量准确的脉冲宽度T(比如4.16ms)
  2. 按公式计算理论计数值N = T / 计数周期
  3. 运行修正后的代码,读取timeDifference,对比N和实际值,误差在±1个计数周期内即为正常

三、正确计算预分频器值

预分频器的选择需要平衡测量分辨率和最大测量范围,TIM2是32位定时器,最大计数值为UINT32_MAX(4294967295),计算规则如下:

计算逻辑

  1. 确定需要的最小分辨率(比如1us、10us、1ms)
  2. 根据分辨率计算计数时钟频率:计数时钟频率 = 1 / 分辨率
  3. 预分频器值 = (APB1时钟频率 / 计数时钟频率) - 1

示例计算(基于80MHz APB1时钟)

  • 需求1:1us分辨率(适合窄脉冲测量)
    计数时钟频率=1MHz,预分频器=(80MHz/1MHz)-1=79
    最大测量时间=4294967295×1us≈4295秒(约71分钟),完全覆盖100Hz脉冲(周期10ms)

  • 需求2:10us分辨率(适合宽脉冲测量,降低溢出概率)
    计数时钟频率=100kHz,预分频器=(80MHz/100kHz)-1=799
    最大测量时间=4294967295×10us≈42949秒(约12小时)

  • 需求3:1ms分辨率(适合超宽脉冲)
    计数时钟频率=1kHz,预分频器=(80MHz/1kHz)-1=79999
    最大测量时间=4294967295×1ms≈4295000秒(约49.7天)

注意事项

  • 预分频器值必须是0~65535之间的整数(STM32预分频器为16位寄存器)
  • 优先选择满足分辨率需求的最小预分频器(即最高计数时钟频率),以保证测量精度

内容的提问来源于stack exchange,提问作者Ariarikta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 02:24:56