STM32 定时器级联:实现长时间定时与脉冲计数
👁 2 阅读 · 2026-08-19 · STM32 定时器
STM32定时器资源丰富,但单个16位定时器在长时间定时或高频脉冲计数时往往力不从心。本文深入讲解定时器级联原理,通过主从模式将两个定时器串联,实现超过65535个时钟周期的长时间定时,以及利用外部脉冲触发级联计数。文章提供基于STM32F1的完整配置代码(HAL库),涵盖原理、步骤、代码与注意事项,帮助开发者轻松突破定时器位数限制。
## 为什么需要定时器级联?
STM32的通用定时器(如TIM2、TIM3)多为16位,最大计数值为65535。当需要定时超过1秒(假设72MHz主频,预分频为7200,则单次定时最大约0.91秒)或对外部高频脉冲进行长时间计数时,单个定时器会溢出。虽然可以使用中断计数扩展,但会占用CPU且精度受限。定时器级联通过硬件将两个定时器串联,形成32位甚至更宽的计数器,无需CPU干预,实现高精度长时间定时或大范围脉冲计数。
## 级联原理:主从模式
级联的核心是**主从模式**(Master-Slave)。主定时器(Master)在发生特定事件(如更新事件、触发输出)时,通过内部触发信号(ITRx)驱动从定时器(Slave)的时钟或使能。常见两种用法:
- **级联定时**:主定时器输出一个周期性的触发信号,作为从定时器的时钟源,从定时器对主定时器的溢出次数进行计数,从而扩展定时范围。
- **脉冲计数**:外部脉冲输入到主定时器的ETR引脚,主定时器对脉冲计数,溢出时触发从定时器加1,实现大范围脉冲计数。
STM32的触发连接关系固定:TIM1触发TIM2/TIM5,TIM2触发TIM3/TIM4,TIM3触发TIM4,TIM4触发TIM2等。本文以TIM2作为主,TIM3作为从,实现32位定时器。
## 硬件连接与配置步骤
### 硬件准备
- STM32F103C8T6最小系统板
- 外部脉冲源(如信号发生器或按键电路)
- 杜邦线若干
### 配置步骤(以STM32CubeMX + HAL库为例)
1. **时钟配置**:将系统时钟配置为72MHz(APB1定时器时钟为72MHz)。
2. **TIM2配置(主)**:
- 选择内部时钟源(Internal Clock)。
- 设置预分频器(PSC)和自动重载值(ARR),例如PSC=7199,ARR=999,则溢出周期为 (7199+1)*(999+1)/72MHz = 0.1秒。
- 在Trigger Output (TRGO)中选择Update Event,即每次溢出产生触发信号。
3. **TIM3配置(从)**:
- 选择时钟源为External Clock Mode 1,并设置触发源为ITR2(因为TIM2触发TIM3的ITR2)。
- 设置预分频器为0,自动重载值设为65535(或更大,但16位最大65535)。
- 使能TIM3的更新中断,用于在总定时达到后处理。
4. **中断配置**:使能TIM3全局中断,并设置优先级。
5. **生成代码**:在CubeMX中生成工程,然后添加用户代码。
## 完整代码示例
以下代码基于STM32CubeMX生成的工程,实现TIM2+TIM3级联,定时总时长为 0.1秒 * 65536 ≈ 6553.6秒(约1.82小时)。
```c
/* 在main.c中 */
// 全局变量,用于记录级联溢出次数
volatile uint32_t total_ticks = 0;
// 初始化函数(CubeMX已生成,此处补充用户代码)
void MX_TIM2_TIM3_Cascade_Init(void)
{
// TIM2配置为主,TIM3配置为从,已在CubeMX中完成
// 启动级联定时器
HAL_TIM_Base_Start(&htim2); // 启动主定时器
HAL_TIM_Base_Start(&htim3); // 启动从定时器,并开始计数
HAL_TIM_Base_Start_IT(&htim3); // 使能从定时器更新中断
}
// 中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM3) {
total_ticks++;
// 此处可添加用户处理,如翻转LED
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
}
}
// 主函数中调用
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
MX_TIM3_Init();
MX_TIM2_TIM3_Cascade_Init();
while (1)
{
// 主循环可读取total_ticks,计算总时间
// 例如:总时间 = total_ticks * 0.1秒 + 当前TIM3计数值*0.1秒/65536
}
}
```
### 脉冲计数模式代码
若需对外部脉冲计数,将TIM2配置为外部时钟模式,ETR引脚接脉冲源,TIM3仍作为从。配置要点:
- TIM2的时钟源选择ETR,预分频和ARR可设为最大值(如ARR=65535)。
- TIM2的TRGO选择Update Event。
- TIM3配置与上述相同。
```c
// TIM2外部脉冲计数初始化(CubeMX配置)
void MX_TIM2_ETR_Init(void)
{
// 在CubeMX中设置TIM2 Clock Source为ETR2,Prescaler=0,ARR=65535
// 使能TIM2的TRGO为Update Event
}
// 启动计数
HAL_TIM_Base_Start(&htim2);
HAL_TIM_Base_Start(&htim3);
HAL_TIM_Base_Start_IT(&htim3);
// 在中断回调中,total_ticks即为脉冲数的高16位
// 总脉冲数 = (total_ticks << 16) | __HAL_TIM_GET_COUNTER(&htim2);
```
## 注意事项
- **触发源选择**:务必确认主定时器对应的从定时器触发源(如TIM2->TIM3是ITR2,TIM3->TIM4是ITR1等),错误配置将导致无法级联。
- **预分频与ARR设置**:主定时器的溢出频率决定了从定时器的计数频率,需根据所需精度计算。从定时器的ARR应设为65535以最大化范围,但也可根据需求调整。
- **中断处理**:从定时器溢出中断频率较高(本例为10Hz),中断服务函数应尽量简短,避免影响实时性。
- **32位扩展**:级联后实际计数为32位(主16位+从16位),但需注意从定时器的计数方向(向上/向下)需与主定时器匹配。
- **调试技巧**:使用逻辑分析仪观察主定时器的TRGO引脚(可映射到GPIO)验证触发信号。
- **功耗考虑**:级联定时器在低功耗模式下可能无法工作,需根据应用场景选择。
## 总结
定时器级联是STM32高级定时功能之一,通过硬件自动连接,无需CPU干预即可实现32位计数。本文以TIM2+TIM3为例,详细介绍了级联定时和脉冲计数两种模式,并提供了完整代码。掌握此技术,可轻松应对长时间定时、高精度脉冲计数等场景,提升嵌入式系统设计的灵活性和效率。