STM32 定时器(级联实现32位定时器)

在STM32F103微控制器中,通过主从定时器模式将两个16位定时器级联为32位定时器,可显著扩展定时范围(最长可达数天)。以下是实现原理、配置步骤及代码示例:


⚙️ ​一、实现原理

  1. 级联核心机制

    • 主定时器(如TIM2):配置为周期性更新事件(如1ms),通过内部触发线(ITRx)输出触发信号。
    • 从定时器 (如TIM3):工作于外部时钟模式TIM_SlaveMode_External1),将主定时器的触发信号作为计数时钟源。
    • 协同计数 :主定时器每溢出一次,从定时器计数值加1,实现主定时器周期 × 从定时器ARR值的扩展定时。
  2. 32位扩展计算

    • 主定时器周期:Tmaster=(PSCmaster+1)×(ARRmaster+1) / fclock
    • 总定时周期:Ttotal=Tmaster×(ARRslave+1)
    • 最大定时范围:若 ARRslave=65535(16位),则总定时范围扩展至32位(约49.7天 @72MHz)。

🔧 ​二、配置步骤与代码(标准库实现)​

1. 硬件连接与时钟设置
  • 内部触发线选择

    主定时器 从定时器 内部触发线(ITRx)
    TIM2 TIM3 ITR1
    TIM3 TIM4 ITR2
  • 使能时钟

    cpp 复制代码
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3, ENABLE);
2. 主定时器配置(TIM2)​
cpp 复制代码
void TIM2_Master_Config(uint32_t prescaler, uint32_t period) 
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
    // 时基单元:1ms周期示例(72MHz时钟)
    TIM_TimeBaseStruct.TIM_Prescaler = prescaler;     // 预分频值(72-1 → 1MHz)
    TIM_TimeBaseStruct.TIM_Period = period;          // 重装载值(1000-1 → 1ms)
    TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStruct);

    // 触发输出:更新事件作为触发源
    TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
    TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);
    TIM_Cmd(TIM2, ENABLE);
}
3. 从定时器配置(TIM3)​
cpp 复制代码
void TIM3_Slave_Config(uint32_t slave_period) 
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
    // 时基单元:计数主定时器的溢出次数
    TIM_TimeBaseStruct.TIM_Period = slave_period;     // 从定时器ARR(扩展定时范围)
    TIM_TimeBaseStruct.TIM_Prescaler = 0;             // 无分频
    TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStruct);

    // 从模式:外部时钟模式 + ITR1触发
    TIM_SelectInputTrigger(TIM3, TIM_TS_ITR1);        // TIM2触发TIM3
    TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_External1); // 外部信号驱动计数
    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);        // 使能更新中断
    TIM_Cmd(TIM3, ENABLE);
}
4. 中断配置(处理定时完成事件)​
cpp 复制代码
void NVIC_Config(void)
 {
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;      // TIM3中断通道
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
}

// TIM3中断服务函数
void TIM3_IRQHandler(void) 
{
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) 
    {
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
        // 此处执行定时完成后的任务(如翻转LED、触发操作)
    }
}
5. 主函数调用
cpp 复制代码
int main(void) 
{
    // 配置60秒定时:主定时器1ms周期,从定时器计数60,000次(60s/1ms)
    TIM2_Master_Config(72-1, 1000-1);  // 1ms周期
    TIM3_Slave_Config(60000-1);         // 60秒总定时
    NVIC_Config();
    while(1);
}

⚠️ ​三、关键注意事项

  1. 触发模式匹配

    • 主定时器需选择 TIM_TRGOSource_Update(更新事件触发)。
    • 从定时器必须选 TIM_SlaveMode_External1(外部时钟模式)。
  2. 中断优化

    • 仅需处理从定时器的更新中断,避免主定时器中断占用资源。
    • 若需超高精度,禁用全局中断期间操作计数器。
  3. 预分频与周期计算

    • 主定时器周期不宜过短(避免高频触发导致从定时器计数溢出)。
    • 最大扩展周期公式:Tmax=72MHz(65535+1)×(65535+1)≈59.65小时

💡 ​四、应用场景

  • 长周期任务:数据日志定时存储、设备状态巡检(小时/天级)。
  • 步进电机控制 :精确输出指定数量的PWM脉冲(如
    实现3个脉冲输出)。
  • 低功耗定时唤醒:休眠模式下由级联定时器唤醒系统。

通过此方案,可将STM32F103的定时能力扩展至32位,兼顾精度与灵活性。实际代码需根据时钟频率调整预分频和ARR值。