• HAL库 TIM计数器及中断开启过程


    1、初始化TIM基本计数器参数

    void MX_TIM2_Init(void)
    {
      TIM_ClockConfigTypeDef sClockSourceConfig = {0};
      TIM_MasterConfigTypeDef sMasterConfig = {0};
    
      htim2.Instance = TIM2;
      htim2.Init.Prescaler = 36000-1;
      htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
      htim2.Init.Period = 2000-1;
      htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
      htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
      if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
      {
        Error_Handler();
      }
      sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
      if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
      {
        Error_Handler();
      }
      sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
      sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
      if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
      {
        Error_Handler();
      }
    
    }

    2、HAL_TIM_Base_Init(&htim2)应用参数基本参数配置

    HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim)
    {
      /* Check the TIM handle allocation */
      if (htim == NULL)
      {
        return HAL_ERROR;
      }
    
      /* Check the parameters */
      assert_param(IS_TIM_INSTANCE(htim->Instance));
      assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));
      assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));
      assert_param(IS_TIM_AUTORELOAD_PRELOAD(htim->Init.AutoReloadPreload));
    
      if (htim->State == HAL_TIM_STATE_RESET)
      {
        /* Allocate lock resource and initialize it */
        htim->Lock = HAL_UNLOCKED;
    
    #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
        /* Reset interrupt callbacks to legacy weak callbacks */
        TIM_ResetCallback(htim);
    
        if (htim->Base_MspInitCallback == NULL)
        {
          htim->Base_MspInitCallback = HAL_TIM_Base_MspInit;
        }
        /* Init the low level hardware : GPIO, CLOCK, NVIC */
        htim->Base_MspInitCallback(htim);
    #else
        /* Init the low level hardware : GPIO, CLOCK, NVIC */
        HAL_TIM_Base_MspInit(htim);
    #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
      }
    
      /* Set the TIM state */
      htim->State = HAL_TIM_STATE_BUSY;
    
      /* Set the Time Base configuration */
      TIM_Base_SetConfig(htim->Instance, &htim->Init);
    
      /* Initialize the TIM state*/
      htim->State = HAL_TIM_STATE_READY;
    
      return HAL_OK;
    }

    3、HAL_TIM_Base_MspInit(htim) 初始化中断信息(该函数需要重写,CubeMX在配置生成代码时会自动重写该函数)

    /**
      * @brief  Initializes the TIM Base MSP.
      * @param  htim TIM Base handle
      * @retval None
      */
    __weak void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
    {
      /* Prevent unused argument(s) compilation warning */
      UNUSED(htim);
    
      /* NOTE : This function should not be modified, when the callback is needed,
                the HAL_TIM_Base_MspInit could be implemented in the user file
       */
    }

    重写实现

    void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
    {
    
      if(tim_baseHandle->Instance==TIM2)
      {
      /* USER CODE BEGIN TIM2_MspInit 0 */
    
      /* USER CODE END TIM2_MspInit 0 */
        /* TIM2 clock enable */
        __HAL_RCC_TIM2_CLK_ENABLE();
    
        /* TIM2 interrupt Init */
        HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
        HAL_NVIC_EnableIRQ(TIM2_IRQn);
      /* USER CODE BEGIN TIM2_MspInit 1 */
    
      /* USER CODE END TIM2_MspInit 1 */
      }
    }

    4、使能TIM中断

    虽然经过以上配置,TIM的参数信息都已完整应用,但是TIM的中断并没用真正使能.这个地方困扰了我好久(运行没错误,但是计数中断就不触发, 不计数),必需调用以下函数使能中断,串口中断使能也是类似的.

    HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *TIM);//开启定时器中断

    该函数的调用地点只要是在 HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) 函数之后就行,可以在main.c中也可以在上面的代码之后.

    下面的代码存在一个BUG,如果 HAL_TIM_Base_Start_IT 函数调用写在下面的位置,虽然可以使能中断,但会造成MCU上电即触发中断的情况.

    HAL_TIM_Base_MspInit调用之后会重新设置寄存器的值,__HAL_TIM_CLEAR_FLAG(tim_baseHandle, TIM_SR_UIF)清理的寄存器被改写.

    void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
    {
    
      if(tim_baseHandle->Instance==TIM2)
      {
      /* USER CODE BEGIN TIM2_MspInit 0 */
    
      /* USER CODE END TIM2_MspInit 0 */
        /* TIM2 clock enable */
        __HAL_RCC_TIM2_CLK_ENABLE();
    
        /* TIM2 interrupt Init */
        HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
        HAL_NVIC_EnableIRQ(TIM2_IRQn);
      /* USER CODE BEGIN TIM2_MspInit 1 */
        //清理TIM开启时的中断标识
        __HAL_TIM_CLEAR_FLAG(tim_baseHandle, TIM_SR_UIF);//添加这条语句解决问题
        //htim2.Instance->SR = 0; //这是另一种解决办法
        //使能TIM中断
        HAL_TIM_Base_Start_IT(tim_baseHandle);
      /* USER CODE END TIM2_MspInit 1 */
      }
    }

    正确的做法是在 HAL_TIM_Base_Init(&htim2) 之后使能TIM中断,并清理TIM的更新中断寄存器

    void MX_TIM2_Init(void)
    {
      TIM_ClockConfigTypeDef sClockSourceConfig = {0};
      TIM_MasterConfigTypeDef sMasterConfig = {0};
    
      htim2.Instance = TIM2;
      htim2.Init.Prescaler = 36000-1;
      htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
      htim2.Init.Period = 10000-1;
      htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
      htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
      if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
      {
        Error_Handler();
      }
      sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
      if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
      {
        Error_Handler();
      }
      sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
      sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
      if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
      {
        Error_Handler();
      }
    
        //清理TIM开启时的中断标识
        __HAL_TIM_CLEAR_IT(&htim2, TIM_IT_UPDATE);
        //使能TIM中断
        HAL_TIM_Base_Start_IT(&htim2);
    }

    5、计数中断处理

    /**
      * @brief This function handles TIM2 global interrupt.
      */
    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 */
    
      /* USER CODE END TIM2_IRQn 1 */
    }
    HAL_TIM_IRQHandler(&htim2)中断函数处理
    /**
      * @brief  This function handles TIM interrupts requests.
      * @param  htim TIM  handle
      * @retval None
      */
    void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim)
    {
      /* Capture compare 1 event */
      if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC1) != RESET)
      {
        if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC1) != RESET)
        {
          {
            __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC1);
            htim->Channel = HAL_TIM_ACTIVE_CHANNEL_1;
    
            /* Input capture event */
            if ((htim->Instance->CCMR1 & TIM_CCMR1_CC1S) != 0x00U)
            {
    #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
              htim->IC_CaptureCallback(htim);
    #else
              HAL_TIM_IC_CaptureCallback(htim);
    #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
            }
            /* Output compare event */
            else
            {
    #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
              htim->OC_DelayElapsedCallback(htim);
              htim->PWM_PulseFinishedCallback(htim);
    #else
              HAL_TIM_OC_DelayElapsedCallback(htim);
              HAL_TIM_PWM_PulseFinishedCallback(htim);
    #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
            }
            htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
          }
        }
      }
    ........................
    ........................
      /* TIM Update event */
      if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET)
      {
        if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET)
        {
          __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
    #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
          htim->PeriodElapsedCallback(htim);
    #else
          HAL_TIM_PeriodElapsedCallback(htim);
    #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
        }
      }
    ........................
    ........................
    
    }
    HAL_TIM_PeriodElapsedCallback(htim);当计数溢出时调用的回调函数,需要用户根据实际需求具体实现
    /**
      * @brief  Period elapsed callback in non-blocking mode
      * @param  htim TIM handle
      * @retval None
      */
    __weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
      /* Prevent unused argument(s) compilation warning */
      UNUSED(htim);
    
      /* NOTE : This function should not be modified, when the callback is needed,
                the HAL_TIM_PeriodElapsedCallback could be implemented in the user file
       */
    }

    6、实现计数完成回调函数,调试代码,查看计数器中断效果.

  • 相关阅读:
    LeetCode 516. Longest Palindromic Subsequence
    LeetCode 432. All O`one Data Structure
    LeetCode 450. Delete Node in a BST
    LeetCode 460. LFU Cache
    LeetCode 341. Flatten Nested List Iterator
    LeetCode 381. Insert Delete GetRandom O(1)
    LeetCode 380. Insert Delete GetRandom O(1)
    LintCode Coins in a Line III
    LintCode Coins in a Line II
    LintCode Coins in a Line
  • 原文地址:https://www.cnblogs.com/dw039/p/11629744.html
Copyright © 2020-2023  润新知