在STM32F103微控制器中,通过主从定时器模式将两个16位定时器级联为32位定时器,可显著扩展定时范围(最长可达数天)。以下是实现原理、配置步骤及代码示例:
⚙️ 一、实现原理
-
级联核心机制
- 主定时器(如TIM2):配置为周期性更新事件(如1ms),通过内部触发线(ITRx)输出触发信号。
- 从定时器 (如TIM3):工作于外部时钟模式 (
TIM_SlaveMode_External1
),将主定时器的触发信号作为计数时钟源。 - 协同计数 :主定时器每溢出一次,从定时器计数值加1,实现
主定时器周期 × 从定时器ARR值
的扩展定时。
-
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 -
使能时钟 :
cppRCC_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);
}
⚠️ 三、关键注意事项
-
触发模式匹配
- 主定时器需选择
TIM_TRGOSource_Update
(更新事件触发)。 - 从定时器必须选
TIM_SlaveMode_External1
(外部时钟模式)。
- 主定时器需选择
-
中断优化
- 仅需处理从定时器的更新中断,避免主定时器中断占用资源。
- 若需超高精度,禁用全局中断期间操作计数器。
-
预分频与周期计算
- 主定时器周期不宜过短(避免高频触发导致从定时器计数溢出)。
- 最大扩展周期公式:Tmax=72MHz(65535+1)×(65535+1)≈59.65小时
💡 四、应用场景
- 长周期任务:数据日志定时存储、设备状态巡检(小时/天级)。
- 步进电机控制 :精确输出指定数量的PWM脉冲(如
实现3个脉冲输出)。 - 低功耗定时唤醒:休眠模式下由级联定时器唤醒系统。
通过此方案,可将STM32F103的定时能力扩展至32位,兼顾精度与灵活性。实际代码需根据时钟频率调整预分频和ARR值。