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

STM32F103R6T中HAL_GetTick精度异常问题求助

STM32F103R6T自定义定时器与HAL_GetTick()计时偏差问题解决

问题现象

在STM32F103R6T上通过TIM2周期中断实现自定义毫秒计数器milliseconds,每次中断加1。系统时钟配置为64MHz(APB1=32MHz、APB2=64MHz),TIM2预分频器设为127,周期值设为500。示波器测试中断触发的引脚翻转得到预期1ms半周期,但与HAL_GetTick()对比输出后,发现HAL_GetTick()计时速度更快,二者差值随时间持续增大,实测HAL_GetTick()周期为998us而非预期1ms。

原因分析

1. TIM2中断周期计算误差

STM32F1系列中,挂载在APB1的定时器(如TIM2),当APB1预分频系数不为1时,定时器时钟为APB1时钟×2。此处APB1分频为HCLK/2(HCLK=64MHz),因此TIM2时钟为64MHz。

定时器中断周期公式为:
中断周期 = (预分频器值 + 1) × (自动重装载值 + 1) / 定时器时钟频率

当前配置代入计算:
(127+1)×(500+1)/64MHz = 128×501/64000000 = 1.002ms

即自定义计数器每1.002ms才加1,而HAL_GetTick()实际周期为998us,因此HAL_GetTick()的数值增长更快,差值逐渐扩大。

2. HAL_GetTick()的HSI时钟精度问题

HAL_GetTick()基于SysTick定时器,其时钟来自系统核心时钟(64MHz),而系统时钟由HSI(内部RC振荡器)经PLL倍频得到。HSI本身精度有限(典型误差±1%),实际频率可能偏离8MHz,导致PLL输出与理论64MHz存在偏差,最终使SysTick周期偏离1ms。

解决办法

1. 修正TIM2周期值,确保中断周期为1ms

根据公式反推正确的自动重装载值:
总计数周期 = 定时器时钟频率 × 目标中断周期 = 64MHz × 1ms = 64000
自动重装载值 = (总计数周期 / (预分频器值 + 1)) - 1 = (64000/128) -1 = 499

修改MX_TIM2_Init()中的周期配置:

htim2.Init.Period = 499;

2. 优化HAL_GetTick()计时精度(可选)

  • 使用外部晶振(HSE)替代HSI:外部晶振精度远高于内部RC,能大幅降低时钟误差。
  • 校准HSI:通过调整RCC_OscInitStruct.HSICalibrationValue校准HSI频率,减小偏差。

3. 变量类型统一(可选)

将自定义计数器milliseconds改为uint32_t类型,与HAL_GetTick()返回值类型保持一致,避免潜在的符号问题:

uint32_t milliseconds = 0;

关键修改代码片段

中断回调函数

uint32_t milliseconds = 0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
{
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_9);
    milliseconds++;
}

TIM2初始化函数

static void MX_TIM2_Init(void)
{
    TIM_ClockConfigTypeDef sClockSourceConfig = {0};
    TIM_MasterConfigTypeDef sMasterConfig = {0};
    htim2.Instance = TIM2;
    htim2.Init.Prescaler = 127; // 分频系数=127+1=128
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim2.Init.Period = 499; // 修正后的值,确保1ms中断
    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
    {
        Error_Handler();
    }
    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
    {
        Error_Handler();
    }
    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
    {
        Error_Handler();
    }
}

内容的提问来源于stack exchange,提问作者Spitfire1.2

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 16:45:35