STM32F429第十九篇之基本定时器实验详解

阅读: 评论:0

STM32F429第十九篇之基本定时器实验详解

STM32F429第十九篇之基本定时器实验详解

文章目录

  • 前言
  • 结构体
    • TIM_HandleTypeDef
      • Instance(句柄对应时钟)
      • Init(初始化结构体)
      • Channel(通道)
      • hdma(DMA句柄)
      • Lock(锁)
      • State(状态)
    • TIM_Base_InitTypeDef
      • Prescaler(预分频)
      • CounterMode(计数模式)
      • Period(周期数)
      • ClockDivision(时钟分频)
      • RepetitionCounter(重复计数)
      • AutoReloadPreload(自动重载影子寄存器使能)
  • 源代码
    • 主函数
    • 配置
      • TIM3_Init
      • HAL_TIM_Base_Init
      • HAL_TIM_Base_MspInit
      • TIM_Base_SetConfig
      • HAL_TIM_Base_Start_IT
    • 中断响应
      • TIM3_IRQHandler
      • HAL_TIM_IRQHandler
      • HAL_TIM_PeriodElapsedCallback
  • 自我实现

前言

本次博客更新了HAL库的版本。以后的博客都会采用此HAL库版本。

HAL库版本:

  • STM32Cube_FW_F4_V1.25.0

本篇博客主要介绍基本定时器中的源码解析,会涉及以下三个部分:

  • 以整点原子定时器中断实验的程序为蓝本的程序解析
  • 重点的结构体介绍
  • 个人根据解析结果,最后分享自己的写的源代码

需要注意的是:本文介绍的源代码使用的并非基本定时器TIM6或者TIM7,而是通用定时器TIM3。但是,他们程序上是兼容的,只需将TIM3当做基本定时器即可。在最后的自我分享代码中,会严格的使用TIM6.

由于基本定时器不会与外界有直接的硬件连接,本文就不介绍硬件情况。

结构体

TIM_HandleTypeDef

/*** @brief  TIM Time Base Handle Structure definition*/
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
typedef struct __TIM_HandleTypeDef
#else
typedef struct
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
{TIM_TypeDef                 *Instance;     /*!< Register base address             */TIM_Base_InitTypeDef        Init;          /*!< TIM Time Base required parameters */HAL_TIM_ActiveChannel       Channel;       /*!< Active channel                    */DMA_HandleTypeDef           *hdma[7];      /*!< DMA Handlers arrayThis array is accessed by a @ref DMA_Handle_index */HAL_LockTypeDef             Lock;          /*!< Locking object                    */__IO HAL_TIM_StateTypeDef   State;         /*!< TIM operation state               */#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)void (* Base_MspInitCallback)(struct __TIM_HandleTypeDef *htim);              /*!< TIM Base Msp Init Callback                              */void (* Base_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim);            /*!< TIM Base Msp DeInit Callback                            */void (* IC_MspInitCallback)(struct __TIM_HandleTypeDef *htim);                /*!< TIM IC Msp Init Callback                                */void (* IC_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim);              /*!< TIM IC Msp DeInit Callback                              */void (* OC_MspInitCallback)(struct __TIM_HandleTypeDef *htim);                /*!< TIM OC Msp Init Callback                                */void (* OC_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim);              /*!< TIM OC Msp DeInit Callback                              */void (* PWM_MspInitCallback)(struct __TIM_HandleTypeDef *htim);               /*!< TIM PWM Msp Init Callback                               */void (* PWM_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim);             /*!< TIM PWM Msp DeInit Callback                             */void (* OnePulse_MspInitCallback)(struct __TIM_HandleTypeDef *htim);          /*!< TIM One Pulse Msp Init Callback                         */void (* OnePulse_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim);        /*!< TIM One Pulse Msp DeInit Callback                       */void (* Encoder_MspInitCallback)(struct __TIM_HandleTypeDef *htim);           /*!< TIM Encoder Msp Init Callback                           */void (* Encoder_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim);         /*!< TIM Encoder Msp DeInit Callback                         */void (* HallSensor_MspInitCallback)(struct __TIM_HandleTypeDef *htim);        /*!< TIM Hall Sensor Msp Init Callback                       */void (* HallSensor_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim);      /*!< TIM Hall Sensor Msp DeInit Callback                     */void (* PeriodElapsedCallback)(struct __TIM_HandleTypeDef *htim);             /*!< TIM Period Elapsed Callback                             */void (* PeriodElapsedHalfCpltCallback)(struct __TIM_HandleTypeDef *htim);     /*!< TIM Period Elapsed half complete Callback               */void (* TriggerCallback)(struct __TIM_HandleTypeDef *htim);                   /*!< TIM Trigger Callback                                    */void (* TriggerHalfCpltCallback)(struct __TIM_HandleTypeDef *htim);           /*!< TIM Trigger half complete Callback                      */void (* IC_CaptureCallback)(struct __TIM_HandleTypeDef *htim);                /*!< TIM Input Capture Callback                              */void (* IC_CaptureHalfCpltCallback)(struct __TIM_HandleTypeDef *htim);        /*!< TIM Input Capture half complete Callback                */void (* OC_DelayElapsedCallback)(struct __TIM_HandleTypeDef *htim);           /*!< TIM Output Compare Delay Elapsed Callback               */void (* PWM_PulseFinishedCallback)(struct __TIM_HandleTypeDef *htim);         /*!< TIM PWM Pulse Finished Callback                         */void (* PWM_PulseFinishedHalfCpltCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM PWM Pulse Finished half complete Callback           */void (* ErrorCallback)(struct __TIM_HandleTypeDef *htim);                     /*!< TIM Error Callback                                      */void (* CommutationCallback)(struct __TIM_HandleTypeDef *htim);               /*!< TIM Commutation Callback                                */void (* CommutationHalfCpltCallback)(struct __TIM_HandleTypeDef *htim);       /*!< TIM Commutation half complete Callback                  */void (* BreakCallback)(struct __TIM_HandleTypeDef *htim);                     /*!< TIM Break Callback                                      */
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
} TIM_HandleTypeDef;

相对于低版本的HAL库,此处最大的改动就是增加了宏USE_HAL_TIM_REGISTER_CALLBACKS。若此宏有效,则表明每个句柄都有独立的中断回调函数,定义在结构体中。默认情况下,该宏为无效,所以为了方便,舍去无意义代码,变为:

/*** @brief  TIM Time Base Handle Structure definition*/
typedef struct
{TIM_TypeDef                 *Instance;     /*!< Register base address             */TIM_Base_InitTypeDef        Init;          /*!< TIM Time Base required parameters */HAL_TIM_ActiveChannel       Channel;       /*!< Active channel                    */DMA_HandleTypeDef           *hdma[7];      /*!< DMA Handlers arrayThis array is accessed by a @ref DMA_Handle_index */HAL_LockTypeDef             Lock;          /*!< Locking object                    */__IO HAL_TIM_StateTypeDef   State;         /*!< TIM operation state               */
} TIM_HandleTypeDef;

Instance(句柄对应时钟)

此用于选择时钟源,可以选择的参数如下:

#define TIM1                ((TIM_TypeDef *) TIM1_BASE)
#define TIM2                ((TIM_TypeDef *) TIM2_BASE)
#define TIM3                ((TIM_TypeDef *) TIM3_BASE)
#define TIM4                ((TIM_TypeDef *) TIM4_BASE)
#define TIM5                ((TIM_TypeDef *) TIM5_BASE)
#define TIM6                ((TIM_TypeDef *) TIM6_BASE)
#define TIM7                ((TIM_TypeDef *) TIM7_BASE)
#define TIM8                ((TIM_TypeDef *) TIM8_BASE)
#define TIM9                ((TIM_TypeDef *) TIM9_BASE)
#define TIM10               ((TIM_TypeDef *) TIM10_BASE)
#define TIM11               ((TIM_TypeDef *) TIM11_BASE)
#define TIM12               ((TIM_TypeDef *) TIM12_BASE)
#define TIM13               ((TIM_TypeDef *) TIM13_BASE)
#define TIM14               ((TIM_TypeDef *) TIM14_BASE)

Init(初始化结构体)

该结构体将在TIM_Base_InitTypeDef详细介绍,主要与初始化参数相关。

Channel(通道)

用于选择通道,具体的参数定义如下:

/*** @brief  HAL Active channel structures definition*/
typedef enum
{HAL_TIM_ACTIVE_CHANNEL_1        = 0x01U,    /*!< The active channel is 1     */HAL_TIM_ACTIVE_CHANNEL_2        = 0x02U,    /*!< The active channel is 2     */HAL_TIM_ACTIVE_CHANNEL_3        = 0x04U,    /*!< The active channel is 3     */HAL_TIM_ACTIVE_CHANNEL_4        = 0x08U,    /*!< The active channel is 4     */HAL_TIM_ACTIVE_CHANNEL_CLEARED  = 0x00U     /*!< All active channels cleared */
} HAL_TIM_ActiveChannel;

hdma(DMA句柄)

DMA相关的句柄,此处不再详细讲解。

Lock(锁)

HAL库的锁,具体定义如下:

/** * @brief  HAL Lock structures definition  */
typedef enum 
{HAL_UNLOCKED = 0x00U,HAL_LOCKED   = 0x01U  
} HAL_LockTypeDef;

State(状态)

时钟的状态,参数可以如下选择:

/*** @brief  HAL State structures definition*/
typedef enum
{HAL_TIM_STATE_RESET             = 0x00U,    /*!< Peripheral not yet initialized or disabled  */HAL_TIM_STATE_READY             = 0x01U,    /*!< Peripheral Initialized and ready for use    */HAL_TIM_STATE_BUSY              = 0x02U,    /*!< An internal process is ongoing              */HAL_TIM_STATE_TIMEOUT           = 0x03U,    /*!< Timeout state                               */HAL_TIM_STATE_ERROR             = 0x04U     /*!< Reception process is ongoing                */
} HAL_TIM_StateTypeDef;

TIM_Base_InitTypeDef

/*** @brief  TIM Time base Configuration Structure definition*/
typedef struct
{uint32_t Prescaler;         /*!< Specifies the prescaler value used to divide the TIM clock.This parameter can be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */uint32_t CounterMode;       /*!< Specifies the counter mode.This parameter can be a value of @ref TIM_Counter_Mode */uint32_t Period;            /*!< Specifies the period value to be loaded into the activeAuto-Reload Register at the next update event.This parameter can be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF.  */uint32_t ClockDivision;     /*!< Specifies the clock division.This parameter can be a value of @ref TIM_ClockDivision */uint32_t RepetitionCounter;  /*!< Specifies the repetition counter value. Each time the RCR downcounterreaches zero, an update event is generated and counting restartsfrom the RCR value (N).This means in PWM mode that (N+1) corresponds to:- the number of PWM periods in edge-aligned mode- the number of half PWM period in center-aligned modeGP timers: this parameter must be a number between Min_Data = 0x00 and Max_Data = 0xFF.Advanced timers: this parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF. */uint32_t AutoReloadPreload;  /*!< Specifies the auto-reload preload.This parameter can be a value of @ref TIM_AutoReloadPreload */
} TIM_Base_InitTypeDef;

Prescaler(预分频)

预分频的取值范围:0-65535。经过分频后的时钟

o u t p u t = i n p u t p r e s c a l e r + 1 output=frac{input}{prescaler+1} output=prescaler+1input​

即分配系统为寄存器值+1.

CounterMode(计数模式)

计数模式可以从以下参数中选取:

/** @defgroup TIM_Counter_Mode TIM Counter Mode* @{*/
#define TIM_COUNTERMODE_UP                 0x00000000U                          /*!< Counter used as up-counter   */
#define TIM_COUNTERMODE_DOWN               TIM_CR1_DIR                          /*!< Counter used as down-counter */
#define TIM_COUNTERMODE_CENTERALIGNED1     TIM_CR1_CMS_0                        /*!< Center-aligned mode 1        */
#define TIM_COUNTERMODE_CENTERALIGNED2     TIM_CR1_CMS_1                        /*!< Center-aligned mode 2        */
#define TIM_COUNTERMODE_CENTERALIGNED3     TIM_CR1_CMS                          /*!< Center-aligned mode 3        */
/*** @}*/

Period(周期数)

周期数的取值范围为0-65535。其作用形式等同于预分频,周期数为寄存器值家1.

ClockDivision(时钟分频)

参数选取为:

/** @defgroup TIM_ClockDivision TIM Clock Division* @{*/
#define TIM_CLOCKDIVISION_DIV1             0x00000000U                          /*!< Clock division: tDTS=tCK_INT   */
#define TIM_CLOCKDIVISION_DIV2             TIM_CR1_CKD_0                        /*!< Clock division: tDTS=2*tCK_INT */
#define TIM_CLOCKDIVISION_DIV4             TIM_CR1_CKD_1                        /*!< Clock division: tDTS=4*tCK_INT */
/*** @}*/

RepetitionCounter(重复计数)

该值只有高级时钟才会使用。

AutoReloadPreload(自动重载影子寄存器使能)

用于控制自动重载寄存器的影子寄存器是否使能。取值范围为:

/** @defgroup TIM_AutoReloadPreload TIM Auto-Reload Preload* @{*/
#define TIM_AUTORELOAD_PRELOAD_DISABLE                0x00000000U               /*!< TIMx_ARR register is not buffered */
#define TIM_AUTORELOAD_PRELOAD_ENABLE                 TIM_CR1_ARPE              /*!< TIMx_ARR register is buffered *//*** @}*/

源代码

主函数

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "timer.h"int main(void)
{HAL_Init();                     //初始化HAL库   Stm32_Clock_Init(360,25,2,8);   //设置时钟,180Mhzdelay_init(180);                //初始化延时函数LED_Init();                     //初始化LED TIM3_Init(5000-1,9000-1);       //定时器3初始化,定时器时钟为90M,分频系数为9000-1,//所以定时器3的频率为90M/9000=10K,自动重装载为5000-1,那么定时器周期就是500mswhile(1){LED0=!LED0;                 //LED0翻转delay_ms(200);              //延时200ms}
}

在主函数中,主要调用了TIM3_Init来配置定时器TIM3。最红通过延时程序,在while循环中实现LED0的循环点亮。而与定时器相关的LED1则是通过定时器触发中断的方式来实现改变状态的。

配置

TIM3_Init

/** * @brief 计时器TIM3配置* @note 无* @param {u16} arr 自动装载值* @param {u16} psc 预分频数* @retval 无*/
void TIM3_Init(u16 arr, u16 psc)
{/* 1.使能时钟 */__HAL_RCC_TIM3_CLK_ENABLE(); //使能TIM3时钟/* 2.初始化配置 */TIM3_Handler.Instance = TIM3;                             //通用定时器3TIM3_Handler.Init.Prescaler = psc;                        //分频系数TIM3_Handler.Init.CounterMode = TIM_COUNTERMODE_UP;       //向上计数器TIM3_Handler.Init.Period = arr;                           //自动装载值TIM3_Handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; //时钟分频因子HAL_TIM_Base_Init(&TIM3_Handler);/* 3.启动时钟 */HAL_TIM_Base_Start_IT(&TIM3_Handler); //使能定时器3和定时器3更新中断:TIM_IT_UPDATE
}

该段程序由正点原子实现的。主要分成三个部分:

  1. 使能时钟
  2. 初始化定时器
  3. 启动时钟

其中,调用了库函数HAL_TIM_Base_InitHAL_TIM_Base_Start_IT。下面将重点介绍着两个函数。

HAL_TIM_Base_Init

/*** @brief  Initializes the TIM Time base Unit according to the specified*         parameters in the TIM_HandleTypeDef and initialize the associated handle.* @note   Switching from Center Aligned counter mode to Edge counter mode (or reverse)*         requires a timer reset to avoid unexpected direction*         due to DIR bit readonly in center aligned mode.*         Ex: call @ref HAL_TIM_Base_DeInit() before HAL_TIM_Base_Init()* @param  htim TIM Base handle* @retval HAL status*/
HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim)
{/*********************1.参数检查********************************//* 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));/*********************2.配置底层信息********************************/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;/*********************3.配置定时器基本信息********************************//* 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;
}

该函数分成以下几个步骤:

  1. 检查参数类型
  2. 底层初始化
  3. 计时器初始化

状态变化:

  1. HAL_TIM_STATE_RESET——初始状态,未初始化过
  2. HAL_TIM_STATE_BUSY——底层初始化之后,要进行计时器的配置
  3. HAL_TIM_STATE_READY——配置完成,计时器可以使用

其中调用了两个函数:

  • HAL_TIM_Base_MspInit——底层配置
  • TIM_Base_SetConfig——定时器配置

HAL_TIM_Base_MspInit

/** * @brief 底层驱动* @note 无* @param {TIM_HandleTypeDef} *htim 计时器句柄* @retval 无*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{if (htim->Instance == TIM3){HAL_NVIC_SetPriority(TIM3_IRQn, 1, 3); //设置中断优先级,抢占优先级1,子优先级3HAL_NVIC_EnableIRQ(TIM3_IRQn);         //开启ITM3中断}
}

该函数由自己实现,主要参考了正点原子的代码。实现的功能很简单,就是配置中断的优先级,使能中断。

TIM_Base_SetConfig

/*** @brief  Time Base configuration* @param  TIMx TIM peripheral* @param  Structure TIM Base configuration structure* @retval None*/
void TIM_Base_SetConfig(TIM_TypeDef *TIMx, TIM_Base_InitTypeDef *Structure)
{/*********************1.设置CR1寄存器********************************/uint32_t tmpcr1;tmpcr1 = TIMx->CR1;/* Set TIM Time Base Unit parameters ---------------------------------------*/if (IS_TIM_COUNTER_MODE_SELECT_INSTANCE(TIMx)) //1,2,3,4,5,8:可以选择计数器的方向{/* Select the Counter Mode */tmpcr1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);tmpcr1 |= Structure->CounterMode;}if (IS_TIM_CLOCK_DIVISION_INSTANCE(TIMx)) //除了6,7:可以设置时钟分频{/* Set the clock division */tmpcr1 &= ~TIM_CR1_CKD;tmpcr1 |= (uint32_t)Structure->ClockDivision;}/* Set the auto-reload preload */MODIFY_REG(tmpcr1, TIM_CR1_ARPE, Structure->AutoReloadPreload); //设置自动加载寄存器的影子寄存器TIMx->CR1 = tmpcr1;/*********************2.设置ARR寄存器********************************//* Set the Autoreload value */TIMx->ARR = (uint32_t)Structure->Period; //设置时钟的周期/*********************3.设置PSC寄存器********************************//* Set the Prescaler value */TIMx->PSC = Structure->Prescaler; //设置时钟的预分频/*********************4.设置RCR  寄存器********************************/if (IS_TIM_REPETITION_COUNTER_INSTANCE(TIMx)) //1,8:支持重复计数器,高级时钟{/* Set the Repetition Counter value */TIMx->RCR = Structure->RepetitionCounter;}/*********************5.设置EGR  寄存器********************************//* Generate an update event to reload the Prescalerand the repetition counter (only for advanced timer) value immediately */TIMx->EGR = TIM_EGR_UG;
}

在该函数中,总共设置5组寄存器。但需要注意的是,对于基本定时器而言,其实只有1,2,3,5步骤是有意义的。尤其需要注意的有两点:

  1. 在第1步中,唯一有意义的就是设置自动加载寄存器的影子寄存器。
  2. 在第5步中,通过设置UG,触发更新事件,将影子寄存器的值生效,也就是将刚刚写入的预分频寄存器的数据生效。

HAL_TIM_Base_Start_IT

/*** @brief  Starts the TIM Base generation in interrupt mode.* @param  htim TIM Base handle* @retval HAL status*/
HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)
{uint32_t tmpsmcr;/*********************1.检测参数********************************//* Check the parameters */assert_param(IS_TIM_INSTANCE(htim->Instance));/*********************2.使能向上计数中断********************************//* Enable the TIM Update interrupt */__HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE);/*********************3.使能外设********************************//* Enable the Peripheral, except in trigger mode where enable is automatically done with trigger */tmpsmcr = htim->Instance->SMCR & TIM_SMCR_SMS;/*********************4.使能计时器********************************/if (!IS_TIM_SLAVEMODE_TRIGGER_ENABLED(tmpsmcr)){__HAL_TIM_ENABLE(htim);}/* Return function status */return HAL_OK;
}

该函数大致分成4各部分:

  1. 检测参数
  2. 使能计数器中断
  3. 使能外设
  4. 使能定时器

其中,与基本定时器相关的为2与4步。他们的宏定义如下所示:

/** @brief  Enable the specified TIM interrupt.* @param  __HANDLE__ specifies the TIM Handle.* @param  __INTERRUPT__ specifies the TIM interrupt source to enable.*          This parameter can be one of the following values:*            @arg TIM_IT_UPDATE: Update interrupt*            @arg TIM_IT_CC1:   Capture/Compare 1 interrupt*            @arg TIM_IT_CC2:  Capture/Compare 2 interrupt*            @arg TIM_IT_CC3:  Capture/Compare 3 interrupt*            @arg TIM_IT_CC4:  Capture/Compare 4 interrupt*            @arg TIM_IT_COM:   Commutation interrupt*            @arg TIM_IT_TRIGGER: Trigger interrupt*            @arg TIM_IT_BREAK: Break interrupt* @retval None*/
#define __HAL_TIM_ENABLE_IT(__HANDLE__, __INTERRUPT__)    ((__HANDLE__)->Instance->DIER |= (__INTERRUPT__))
/*** @brief  Enable the TIM peripheral.* @param  __HANDLE__ TIM handle* @retval None*/
#define __HAL_TIM_ENABLE(__HANDLE__)                 ((__HANDLE__)->Instance->CR1|=(TIM_CR1_CEN))

都是通过直接设置寄存器实现。

中断响应

TIM3_IRQHandler

/** * @brief TIM3中断响应函数* @note   自动被调用* @param {*}无* @retval 无*/
void TIM3_IRQHandler(void)
{HAL_TIM_IRQHandler(&TIM3_Handler);
}

在中断响应中,直接调用HAL_TIM_IRQHandler()来判断中断类型。

HAL_TIM_IRQHandler

/*** @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);
#elseHAL_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);
#elseHAL_TIM_OC_DelayElapsedCallback(htim);HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;}}}/* Capture compare 2 event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC2) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC2) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC2);htim->Channel = HAL_TIM_ACTIVE_CHANNEL_2;/* Input capture event */if ((htim->Instance->CCMR1 & TIM_CCMR1_CC2S) != 0x00U){
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->IC_CaptureCallback(htim);
#elseHAL_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);
#elseHAL_TIM_OC_DelayElapsedCallback(htim);HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;}}/* Capture compare 3 event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC3) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC3) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC3);htim->Channel = HAL_TIM_ACTIVE_CHANNEL_3;/* Input capture event */if ((htim->Instance->CCMR2 & TIM_CCMR2_CC3S) != 0x00U){
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->IC_CaptureCallback(htim);
#elseHAL_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);
#elseHAL_TIM_OC_DelayElapsedCallback(htim);HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;}}/* Capture compare 4 event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC4) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC4) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC4);htim->Channel = HAL_TIM_ACTIVE_CHANNEL_4;/* Input capture event */if ((htim->Instance->CCMR2 & TIM_CCMR2_CC4S) != 0x00U){
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->IC_CaptureCallback(htim);
#elseHAL_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);
#elseHAL_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);
#elseHAL_TIM_PeriodElapsedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}}/* TIM Break input event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_BREAK) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_BREAK) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_IT_BREAK);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->BreakCallback(htim);
#elseHAL_TIMEx_BreakCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}}/* TIM Trigger detection event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_TRIGGER) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_TRIGGER) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_IT_TRIGGER);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->TriggerCallback(htim);
#elseHAL_TIM_TriggerCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}}/* TIM commutation event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_COM) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_COM) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_FLAG_COM);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->CommutationCallback(htim);
#elseHAL_TIMEx_CommutCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}}
}

首先,通过中断标志位来判断响应的是哪一个中断。可以抽取该函数的骨架来看:

其中每个分支的实现方式大致相同,本文选基本定时器功能来讲解:

    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);
#elseHAL_TIM_PeriodElapsedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}}

该函数主要实现功能:

  1. 判断该中断标志位是否置1以及该中断是否使能,若两者皆是,则响应该中断。
  2. 清除中断标志位。
  3. 调用中断回调函数。

以上步骤也是经典的HAL库对于中断的处理方法。
其中,判断中断位和判断中断源的宏定义为:

/** @brief  Check whether the specified TIM interrupt flag is set or not.* @param  __HANDLE__ specifies the TIM Handle.* @param  __FLAG__ specifies the TIM interrupt flag to check.*        This parameter can be one of the following values:*            @arg TIM_FLAG_UPDATE: Update interrupt flag*            @arg TIM_FLAG_CC1: Capture/Compare 1 interrupt flag*            @arg TIM_FLAG_CC2: Capture/Compare 2 interrupt flag*            @arg TIM_FLAG_CC3: Capture/Compare 3 interrupt flag*            @arg TIM_FLAG_CC4: Capture/Compare 4 interrupt flag*            @arg TIM_FLAG_COM:  Commutation interrupt flag*            @arg TIM_FLAG_TRIGGER: Trigger interrupt flag*            @arg TIM_FLAG_BREAK: Break interrupt flag*            @arg TIM_FLAG_CC1OF: Capture/Compare 1 overcapture flag*            @arg TIM_FLAG_CC2OF: Capture/Compare 2 overcapture flag*            @arg TIM_FLAG_CC3OF: Capture/Compare 3 overcapture flag*            @arg TIM_FLAG_CC4OF: Capture/Compare 4 overcapture flag* @retval The new state of __FLAG__ (TRUE or FALSE).*/
#define __HAL_TIM_GET_FLAG(__HANDLE__, __FLAG__)          (((__HANDLE__)->Instance->SR &(__FLAG__)) == (__FLAG__))/*** @brief  Check whether the specified TIM interrupt source is enabled or not.* @param  __HANDLE__ TIM handle* @param  __INTERRUPT__ specifies the TIM interrupt source to check.*          This parameter can be one of the following values:*            @arg TIM_IT_UPDATE: Update interrupt*            @arg TIM_IT_CC1:   Capture/Compare 1 interrupt*            @arg TIM_IT_CC2:  Capture/Compare 2 interrupt*            @arg TIM_IT_CC3:  Capture/Compare 3 interrupt*            @arg TIM_IT_CC4:  Capture/Compare 4 interrupt*            @arg TIM_IT_COM:   Commutation interrupt*            @arg TIM_IT_TRIGGER: Trigger interrupt*            @arg TIM_IT_BREAK: Break interrupt* @retval The state of TIM_IT (SET or RESET).*/
#define __HAL_TIM_GET_IT_SOURCE(__HANDLE__, __INTERRUPT__) ((((__HANDLE__)->Instance->DIER & (__INTERRUPT__)) == (__INTERRUPT__)) ? SET : RESET)

都是直接查询寄存器获得,此处不再详细分析。

HAL_TIM_PeriodElapsedCallback

中断回调函数由用户自己实现,正点原子的代码为:

/** * @brief 中断回调函数* @note 在HAL_TIM_IRQHandler函数中调用* @param {TIM_HandleTypeDef} *htim 中断句柄* @retval */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim == (&TIM3_Handler)){LED1 = !LED1; //LED1反转}
}

该函数很简单,通过判断句柄来确定中断源,从而实现自己的功能。

自我实现

参考博客<STM32CubeMX第四篇之基本定时器>

本文发布于:2024-02-04 10:20:58,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170704978354711.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:定时器   详解
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23