## 为什么需要定时器级联? 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为例,详细介绍了级联定时和脉冲计数两种模式,并提供了完整代码。掌握此技术,可轻松应对长时间定时、高精度脉冲计数等场景,提升嵌入式系统设计的灵活性和效率。