在嵌入式开发中,定时器中断是最基础也最核心的功能之一。我使用STM32系列芯片开发已有七年时间,从最早的STM32F1到现在的STM32H7,定时器模块虽然功能越来越丰富,但基本的中断配置逻辑始终未变。今天要分享的是实际工程中最常用的定时中断配置方法,特别是内外时钟源的选择技巧。
定时器中断的典型应用场景包括:
选择内部时钟源(如APB总线时钟)还是外部时钟源(如外部晶振或信号发生器),主要取决于项目对定时精度的要求。内部时钟配置简单但精度受温度影响,外部时钟更稳定但需要额外硬件支持。
以STM32F4系列为例,其定时器分为三类:
所有定时器都挂载在APB总线上,时钟源选择通过RCC模块配置。关键寄存器包括:
STM32的时钟树非常灵活但也容易配置错误。定时器时钟源主要有两种选择:
内部时钟(默认):
外部时钟模式1:
重要提示:使用外部时钟时,必须确保信号电平符合STM32的电气特性(通常3.3V CMOS电平)
以下是使用内部时钟源的完整配置示例(以TIM3为例):
c复制// 时钟使能
__HAL_RCC_TIM3_CLK_ENABLE();
// 时基初始化
TIM_HandleTypeDef htim3;
htim3.Instance = TIM3;
htim3.Init.Prescaler = 8399; // 84MHz/(8399+1)=10kHz
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 9999; // 10kHz/(9999+1)=1Hz
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim3);
// 中断配置
HAL_NVIC_SetPriority(TIM3_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
// 启动定时器
HAL_TIM_Base_Start_IT(&htim3);
关键参数计算原理:
若要使用外部时钟源,需增加以下配置:
c复制// 时钟输入配置
TIM_ClockConfigTypeDef sClockSourceConfig;
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_ETRMODE2; // 外部时钟模式2
sClockSourceConfig.ClockPolarity = TIM_CLOCKPOLARITY_NONINVERTED;
sClockSourceConfig.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1;
sClockSourceConfig.ClockFilter = 0;
HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig);
// ETR引脚配置(以PA0为例)
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
c复制void TIM3_IRQHandler(void) {
HAL_TIM_IRQHandler(&htim3); // HAL库中断处理
}
// 回调函数重写
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if(htim->Instance == TIM3) {
// 用户代码区
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
}
}
__HAL_TIM_CLEAR_FLAG手动清除标志位实测数据对比:
c复制__HAL_RCC_TIMx_CLK_ENABLE();
c复制if(__HAL_TIM_GET_FLAG(&htim3, TIM_FLAG_UPDATE)) {
// 标志位已置位
}
通过主从模式实现长周期定时:
c复制// TIM2作为主定时器
TIM_MasterConfigTypeDef sMasterConfig;
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);
// TIM3作为从定时器
TIM_SlaveConfigTypeDef sSlaveConfig;
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_EXTERNAL1;
sSlaveConfig.InputTrigger = TIM_TS_ITR1; // TIM2→TIM3
HAL_TIM_SlaveConfigSynchronization(&htim3, &sSlaveConfig);
使用GPIO翻转法:
c复制HAL_GPIO_TogglePin(TEST_PIN_GPIO_Port, TEST_PIN_Pin);
用逻辑分析仪测量脉冲间隔
通过输入捕获测量:
实测案例:
c复制htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4;
c复制HAL_TIM_OnePulse_Init(&htim3, TIM_OPMODE_SINGLE);
配置RTC唤醒时钟:
c复制// 设置唤醒时钟为LSI(约32kHz)
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 3276, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
实测功耗对比: