STM32:定时器中断立即起作用


10

这是我的STM32F429项目中的计时器代码:

//timer initialization
 void timerInit()
 {
  uwPrescalerValue2 = (uint32_t) ((SystemCoreClock / 2) / 100000) - 1;
  RS485Timer.Instance = TIM5;
  RS485Timer.Init.Period = 67400000; // high value to notice interrupt even without debugging
  RS485Timer.Init.Prescaler = 400000;
  RS485Timer.Init.ClockDivision = 0;
  RS485Timer.Init.CounterMode = TIM_COUNTERMODE_UP;
  HAL_TIM_Base_Init(&RS485Timer);
 }

 void timerReset()
 {
 HAL_TIM_Base_Stop_IT(&RS485Timer);
 HAL_TIM_Base_DeInit(&RS485Timer);
 HAL_TIM_Base_Init(&RS485Timer);
 HAL_TIM_Base_Start_IT(&RS485Timer);
 printf("%d timer reset\n", countereset);
 countereset++;
 } 

 void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
 {
  /*##-1- Enable peripherals and GPIO Clocks #################################*/
  /* TIMx Peripheral clock enable */
  __TIM5_CLK_ENABLE();

  /*##-2- Configure the NVIC for TIMx #########################################*/
  /* Set the TIMx priority */
  HAL_NVIC_SetPriority(TIM5_IRQn, 7, 1);

  /* Enable the TIMx global Interrupt */
  HAL_NVIC_EnableIRQ(TIM5_IRQn);
 }

 void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
 {
  __TIM5_FORCE_RESET();
  __TIM5_RELEASE_RESET();

  HAL_NVIC_DisableIRQ(TIM5_IRQn);
 }

 void TIM5_IRQHandler(void)
 {
  if (__HAL_TIM_GET_FLAG(&RS485Timer, TIM_FLAG_UPDATE) != RESET)      //In case other interrupts are also running
  {
   if (__HAL_TIM_GET_ITSTATUS(&RS485Timer, TIM_IT_UPDATE) != RESET)
   {
    __HAL_TIM_CLEAR_FLAG(&RS485Timer, TIM_FLAG_UPDATE);
    HAL_TIM_IRQHandler(&RS485Timer);
    printf("timer interrupt\n");
   }
  }
 }

timerReset()在程序中间运行函数后,中断不会在几秒钟后开始,而是几乎立即开始。我尝试了其他几个计时器来检查是否没有硬件问题,但是没有,不是。


我建议您在timerReset()函数中明确清除计时器中断标志。
brhans 2015年

1
在DeInit和Init之间添加__HAL_TIM_CLEAR_FLAG(&RS485Timer,TIM_FLAG_UPDATE); 和__HAL_TIM_CLEAR_FLAG(&RS485Timer,TIM_IT_UPDATE); 没有新的事情发生。
m0drzew

Answers:


9

我遇到了STM32F105。STM32F1xx标准外围设备库功能与您所使用的功能有所不同,但思路应相同。

发出TIM_TimeBaseInit()函数导致TIM_SR_UIF标志被设置。我还没有回过头来找出原因。一旦该位置1,中断将在启用后立即触发。

为了解决这个问题,在致电之后TIM_TimeBaseInit(),我立即致电TIM_ClearITPendingBit()。然后,我将使用启用中断TIM_ITConfig()。这解决了问题。

我完整的初始化例程如下所示:

// Enable the peripheral clock
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);

// Configure the timebase
TIM_TimeBaseInitStructure.TIM_Prescaler = 1;
TIM_TimeBaseInitStructure.TIM_Period = 35999;
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseInitStructure);

// That last function caused the UIF flag to get set. Clear it.
TIM_ClearITPendingBit(TIM5, TIM_IT_Update);

// Configure so that the interrupt flag is only set upon overflow
TIM_UpdateRequestConfig(TIM5, TIM_UpdateSource_Regular);

// Enable the TIM5 Update Interrupt type
TIM_ITConfig(TIM5, TIM_IT_Update, ENABLE);

2
使用HAL库的STM32L151上存在相同的问题。解决方法(例如对于TIM6):__HAL_TIM_CLEAR_FLAG(&htim6, TIM_SR_UIF);

3
新HAL驱动程序中的注释解释了原因:它们这样做是为了强制PSC值在初始化时进行更新,因为它仅在更新事件之后才实际加载到SR-> PSC中。
星系

不错,@ Galaxy,感谢您提供信息。
bitsmack

1

因为我遇到了类似的问题,但没有找到答案,所以我分享自己的经验,希望能帮助其他人。

我相信在您的情况下,在初始化计时器之前设置URS(更新请求源)也可以解决此问题。

就我而言,我使用的是低层驱动程序,因此示例代码为:

//Enables APB1 TIM16 peripheral clock
LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_TIM16);

//Sets update event source to counter overflows only
LL_TIM_SetUpdateSource(TIM16, LL_TIM_UPDATESOURCE_COUNTER);

//Configures the TIM16 time base
LL_TIM_InitTypeDef TIM_InitStruct;
TIM_InitStruct.Prescaler = 7999;
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
TIM_InitStruct.Autoreload = 2999;
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
TIM_InitStruct.RepetitionCounter = 0;
LL_TIM_Init(TIM16, &TIM_InitStruct);

//Enables update interrupt
LL_TIM_EnableIT_UPDATE(TIM16);

//Enables timer counter
LL_TIM_EnableCounter(TIM16);

//Enables Interrupt
NVIC_EnableIRQ(TIM16_IRQn);

问题是我使用了LL_TIM_SetPrescaler(TIM16, 7999)LL_TIM_SetAutoReload(TIM16, 2999)函数来配置时基,并且发现使用这些函数时,值没有被更新,因此我不得不生成一个事件来使用来更新值LL_TIM_GenerateEvent_UPDATE(TIM16)

然后,您可以LL_TIM_ClearFlag_UPDATE(TIM16)在启用中断之前使用清除事件标志,或者LL_TIM_SetUpdateSource(TIM16, LL_TIM_UPDATESOURCE_COUNTER)在生成事件之前使用。


1

我在One Pulse mod中遇到类似的问题,并且找到了HAL库的解决方案。当我在“ TIM2_IRQHandler”函数中控制计时器标志时,我看到“捕获比较标志1”已设置。因此,我清除了“捕获比较标志1”。但是这次我看到设置了“捕获比较标志2”。因此,通过使用以下代码,我清除了“ TIM2_IRQHandler”函数中的所有比较标志(从1到4)。

void TIM2_IRQHandler(void)
{
  /* USER CODE BEGIN TIM2_IRQn 0 */

  /* USER CODE END TIM2_IRQn 0 */
  HAL_TIM_IRQHandler(&htim2);
  /* USER CODE BEGIN TIM2_IRQn 1 */
  if(__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_CC1) != RESET)
  {
      timer2Proccess();
      __HAL_TIM_CLEAR_FLAG(&htim2,TIM_FLAG_CC1 );
      __HAL_TIM_CLEAR_FLAG(&htim2,TIM_FLAG_CC2 );
      __HAL_TIM_CLEAR_FLAG(&htim2,TIM_FLAG_CC3 );
      __HAL_TIM_CLEAR_FLAG(&htim2,TIM_FLAG_CC4 );
  }
  /* USER CODE END TIM2_IRQn 1 */
}

0

TIM_TimeBaseInit()和STM32F0xx同样存在问题。此函数的最后一个字符串:

  TIMx->EGR = TIM_PSCReloadMode_Immediate;

它在事件生成寄存器处设置更新事件。这就是为什么我将检查放在IRQ处理程序中的原因:

void TIM1_IRQHandler() {
if(TIM_GetFlagStatus(TIM1, TIM_FLAG_Update) == SET) {
    TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
    if((TIM1 -> CR1 & TIM_CR1_CEN) == 0) return; //Timer is not working
    //Interrupt code
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.